Mega2560 定时器和 uSec

Mega2560 Timer and uSec

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

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

为了验证我的计时功能是否正确,我创建了一个简单的程序,其中仅包含计时器和来自 "util/delay.h" 的几个延迟。结果输出不是我所期望的。所以这是我的问题,我不确定 _delay_us 是否真的延迟了正确的时间,或者我的 timer/math 是否关闭。

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

系统时间:


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

更新:

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

#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();
}

假设您的 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)乘以最大增量数(216-1 = 65535 ) 乘以 0.5 μs.

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