我知道这里有很多关于计时器以及如何配置和使用它们的问题,我已经查看了所有我能找到的但却无法弄清楚我做错了什么。
我需要一个包含与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();
}
答案 0 :(得分:0)
假设您的MCU确实在16 MHz上运行,我会在您的代码中更改以下内容。
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()
的任何地方启用全局中断。