我的Arduino atmega328p-pu上有16MHz时钟的定时器有问题。
我只有一个定时器,两个ISR和一个引脚。
该计划执行以下操作: 通过“序列”来迭代这些序列。并将pin4分别设置为高电平或低电平。然而,它并没有在整个时期设置高位,只有1/12。您在下面看到的是一个从0到340计数的单个计时器。在28处有ISRB,然后ISRA发生在340,然后它循环(这是CTC模式所做的,在ISRA之后循环)。 ISRB总是关闭引脚,ISRA处理引脚是否应该为高电平。
现在问题了。所有时序都适用于每个位,但由于某种原因,环回事件会导致脉冲间隔为SHORTEN。是缩短,而不是加宽(如果由于执行循环事件的额外时钟周期,我会期望什么)。
它使波形看起来像这样。
_|_|_|_|_ _ _ _ _|_|_|_||_|_|_|_ _ _ _
您可以看到问题存在于两个数据包之间的连接中,但剩下的时间是好的。我似乎无法追查原因。
#include <stdint.h>
uint32_t sequence =0b111100001111; // example data sequence
uint8_t packetlength = 12;
uint8_t index = 0;
void setup(){
DDRD = 0xFF; // all port D as input
bitSet(DDRD, 4); // board pin 4 output
bitSet(PORTD, 4); // start high
// initialize timer1
TCCR1A = 0; // zeros timer control register
TCCR1B = 0;
TCNT1 = 0; // sets timer counter to 0
OCR1A = 340; // compare match register 340*62.5ns = 21.25us
OCR1B = 28; // 28*62.5ns = 1.75us
TIMSK1 = 0;
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS10); // CS10 no prescaler (use CS12 for 256 prescaler for testing)
TIMSK1 |= (1 << OCIE1A); // enable timer compare A interrupt
TIMSK1 |= (1 << OCIE1B); // enable timer compare B interrupt
}
ISR(TIMER1_COMPA_vect){ // controls bit repeat rate
if (bitRead(sequence,index) == 1){
bitSet(PORTD, 4); //set high
}
index ++;
if (index == packetlength){ //loop over when end reached.
index = 0;
}
}
ISR(TIMER1_COMPB_vect){ // controls duty cycle
bitClear(PORTD, 4); // set low
}
void loop(){
//nothing
}
编辑:4月5日。范围照片显示脉冲间期缩短。 重要的测量值是BX-AX
答案 0 :(得分:1)
我不明白为什么你应该期望在比特输出上有精确的时序。中断在请求延迟后开始,这将根据在被中断的任何内容中运行的每条指令的指令执行时间而变化。我怀疑(在您的报告中没有看到问题的证据)您看到的变化与指令执行时间变化相同。
如果您需要精确的硬件输出时序,则必须使用永不中断的编程I / O或使用uP硬件外设集的各种翻转位定时器比较功能。 ISR可用于为下一次比较设置内容,但不能直接翻转输出位。
一旦你弄清楚如何在比较器匹配时设置硬件要执行的操作,在单个ISR中完成所有操作会更简单。该服务例程可以安排条件位集和随后的无条件位清除。您可能希望ISR在周期的较长部分运行,以便您的 [a] ISR代码的实际运行中的延迟不会导致设置太晚。
[一个。除了您的ISR代码之外,编程环境还会导致一些上下文保存还原以包装您编写的内容。这可以添加可能不期望的执行周期。自动生成的上下文保存/恢复通常对于隐藏状态非常奢侈,因此天真的程序员不会被奇怪的前景 - 背景交互所迷惑。 ]