Mega2560定时器和uSec

时间:2016-11-20 14:41:51

标签: timer avr atmega

我知道这里有很多关于计时器以及如何配置和使用它们的问题,我已经查看了所有我能找到的但却无法弄清楚我做错了什么。

我需要一个包含与Arduino micros()函数基本相同的功能的类。我想留直AVR。这是我到目前为止,我正在使用Timer4,所以我不踩任何脚趾,这是一个16位定时器,我使用的是8的预分频,它应该在每个时钟周期使用Mega2560给我.5us,不会这相当于TCNT4 = 2 = 1us?

为了验证我的计时功能是否正确,我创建了一个只包含Timer的简单程序和来自“util / delay.h”的几个延迟。结果输出不是我的预期。所以这是我的问题,我不确定_delay_us是否实际上延迟了正确的时间或者我的计时器/数学是否已关闭。

我意识到没有检查溢出或任何东西,我只关注让计时器首先输出正确的值。

SYSTEMTIME:

class SystemTime{
    unsigned long ovfCount = 1;

    public:
        SystemTime();
        void Overflow();
        uint32_t Micro();
        void Reset();
};

/**
 * Constructor
 */
SystemTime::SystemTime() {

    TCCR4B |= (1 << CS41);  //Set Prescale to 8
    TIMSK4 |= (1 << TOIE4); //Enable the Overflow Interrupt
}

/**
 * Increase the Overflow count
 */
void SystemTime::Overflow(){

    this->ovfCount++;
}

/**
 * Returns the number of Microseconds since start
 */
uint32_t SystemTime::Micro(){
    uint32_t t;

    t = (TCNT4 * 2) * this->ovfCount;

    return t;
}

/**
 * Resets the SystemTimer
 */
void SystemTime::Reset(){
    this->ovfCount = 0;
    TCNT4 = 0;

}

SystemTime sysTime;

ISR(TIMER4_OVF_vect){
    sysTime.Overflow();
}

主要

#include "inttypes.h"
#include "USARTSerial.h"
#include "SystemTime.h"
#include "util/delay.h"

#define debugSize 50

void setup(){

    char debug1[debugSize];
    char debug2[debugSize];
    char debug3[debugSize];
    char debug4[debugSize];


    uSerial.Baudrate(57600);
    uSerial.Write("Ready ...");

    uint32_t test;

    sysTime.Reset();

    test = sysTime.Micro();
    sprintf(debug1, "Time 1: %lu", test);
    _delay_us(200);

    test = sysTime.Micro();
    sprintf(debug2, "Time 2: %lu", test);
    _delay_us(200);

    test = sysTime.Micro();
    sprintf(debug3, "Time 3: %lu", test);
    _delay_us(200);

    test = sysTime.Micro();
    sprintf(debug4, "Time 4: %lu", test);

    uSerial.Write(debug1);
    uSerial.Write(debug2);
    uSerial.Write(debug3);
    uSerial.Write(debug4);

}

void loop(){

}

输出:

Ready ...
Time 1: 0
Time 2: 144
Time 3: 306
Time 4: 464

更新

感谢您帮助我,我想发布工作代码以防其他人遇到问题或需要知道如何做到这一点。要记住的一件事是进行Micros计算所需的时间。它看起来(至少在我的Mega2560上)需要大约36us来执行计算,因此需要调整定时器预分频比或消除双倍乘法的数学运算。尽管这个类的工作原理不是这样,但绝不是优化的。

#define F_CPU 16000000L

#include <stdio.h>
#include <avr/interrupt.h>

class SystemTime {
    private:
        unsigned long ovfCount = 0;

    public:
        SystemTime();
        void Overflow();
        uint32_t Micro();
        void Reset();

};

/*
    *   Constructor, Initializes the System Timer for keeping track
    * of the time since start.
    */
SystemTime::SystemTime() {
    TCCR4B |= (1 << CS41);  //Set Prescale to 8
    TIMSK4 |= (1 << TOIE4); //Enable the Overflow Interrupt

    //Enable Interrupts
    sei();
}

/**
* Increase the Overflow count
*/
void SystemTime::Overflow() {
    this->ovfCount++;
}

/**
    * Resets the SystemTimer
    */
void SystemTime::Reset() {
    this->ovfCount = 0;
    TCNT4 = 0;
}

/**
    * Returns the number of Microseconds since start
    */
uint32_t SystemTime::Micro() {
    uint32_t t;

    t = (TCNT4 * 0.5) + ((this->ovfCount * sizeof(this->ovfCount)) * 0.5);

    return t;
}

SystemTime sysTime;

ISR(TIMER4_OVF_vect) {
    sysTime.Overflow();
}

1 个答案:

答案 0 :(得分:0)

假设您的MCU确实在16 MHz上运行,我会在您的代码中更改以下内容。

  • 如果一个定时器增量为0.5μs,则应将TCNT4的值除以2,而不是乘以。因为它是TCNT4倍0.5μs。
  • this->ovfCount用法也是错误的。启动后经过的微秒数等于: TCNT4 * 0.5 + this->ovfCount * 65535 * 0.5 。因此,当前的增量数(TCNT4)乘以0.5μs加上溢出计数(this->ovfCount)乘以最大增量计数(2 16 -1 = 65535)乘以0.5μs

    uint32_t SystemTime::Micro(){
        uint32_t t;
    
        t = (TCNT4 * 0.5) + this->ovfCount * 65535 * 0.5;
    
        return t;
    }
    
  • 最后,我看不到你在sei()的任何地方启用全局中断。