错误的脉冲串时序

Erroneous Pulsetrain Timing

我在使用 16MHz 时钟的 Arduino atmega328p-pu 上的定时器时遇到一些问题。

我有一个非常简单的程序,只有一个定时器、两个 ISR 和一个引脚。

该程序执行以下操作: 遍历 'sequence' 的位并分别将 pin4 设置为高电平或低电平。然而,它并没有在整个期间将位设置为高电平,只有 1/12。您在下面看到的是一个从 0 到 340 计数的单个计时器。在 28 处有 ISRB,然后 ISRA 在 340 处发生,然后它循环(这就是 CTC 模式所做的,在 ISRA 之后循环)。 ISRB 始终关闭引脚,ISRA 处理引脚是否应为高电平。

那么问题来了。所有时序都适用于每一位,但由于某种原因,循环事件导致脉冲间隔缩短。是缩短,而不是加宽(如果有什么是我所期望的,因为执行循环事件的额外时钟周期)。

它使波形看起来像这样。

_|_|_|_|_ _ _ _ _|_|_|_||_|_|_|_ _ _ _

可以看出问题出在两个数据包的连接处,但其余时间都很好。我似乎无法找到原因。

#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

正常。 340 + 6 个计算时钟周期(范围内的最佳估计)

不好。定时器在中断触发前仅计数 284 个周期。

也很糟糕,但问题不大。这个脉冲太宽了,无法通过将位设置为低所需的时钟周期来合理解释。似乎需要 17 个,我预计需要 3 个。

我不明白为什么您应该期待位输出的精确计时。中断在请求延迟后开始,这将根据每条指令的指令执行时间而有所不同 运行 在任何被中断的情况下。我怀疑(没有在您的问题报告中看到证据)您看到的变化与指令执行时间变化相同。

如果您想要精确的硬件输出时序,您必须使用 never-interrupted 编程 I/O 或使用 uP 硬件外设集的各种 flip-bit-upon-timer-compare 功能。 ISR 可用于为下一次比较进行设置,但不能直接翻转输出位。

一旦您了解了如何设置硬件在比较器匹配时执行的操作,在单个 ISR 中完成所有操作会更简单。该服务例程可以安排条件位设置和随后的无条件位清除。您可能希望 ISR 在周期的较长部分 运行,以便 您的 [a] ISR 代码的实际 运行 中的延迟不会导致设置太晚了。

[一个。除了您的 ISR 代码之外,编程环境还导致一些上下文保存恢复以包装您编写的内容。这可能会增加预期之外的执行周期。 Auto-generated context save/restore 通常会过度隐藏状态,这样天真的程序员就不会被奇怪的 foreground-background 交互所迷惑。 ]