簡體   English   中英

如何讓 Atmega328 定時器中斷每 1 秒滴答一次?

[英]How to make Atmega328 timmer interrupt tick every 1 second?

我有一個 Atmega328p 並且我已經將一個 LED 連接到它的 D4 引腳,我希望它每隔一秒打開/關閉 LED。

我找到了這個教程,我根據一些在線 AVR 定時器計算器和我使用過的 12MHZ 外部晶體對其進行了更改:

#define F_CPU 12000000UL
#include <avr/io.h>
#include <avr/interrupt.h>


int main(void)
{

    DDRD |= 1 << 4;
    PORTD |= 1 << 4;

    ICR1 = 0xB71B;

    TCCR1B |= (1 << WGM12);
    // Mode 4, CTC on OCR1A

    TIMSK1 |= (1 << ICIE1);
    //Set interrupt on compare match

    TCCR1B |= (1 << CS12);
    // set prescaler to 256 and starts the timer


    sei();
    // enable interrupts


    while (1)
    {
        // we have a working Timer
    }
}

ISR (TIMER1_COMPA_vect)
{
    PORTD |= 0 << 4;
    // action to be done every 200ms
}

無論我如何更改 ICR1 值,LED 始終亮起或熄滅。 我怎樣才能讓它工作?

計時器初始化看起來不錯(請參閱其他答案) ,但您似乎沒有正確切換 LED。

PORTD |= 0 << 4; 什么也不做。

假設您直接驅動 LED,請使用PORTD |= (1 << 4); 打開 LED, PORTD &= ~(1 << 4); 關閉 LED 和PORTD ^= (1 << 4); 切換輸出狀態。

由於您只想切換 LED 狀態,最后一個選項顯然是最好的選擇,因為您不必檢查輸出引腳的當前狀態來決定是否需要打開或關閉。

TCCR1B |= (1 << WGM12);
    // Mode 4, CTC on OCR1A

評論是正確的:設置位WGM12 (而其他WGM1x位是零)將打開CTC(時清零比較匹配)與定義TOP值模式OCR1A

但!

ICR1 = 0xB71B;

您正在將 TOP 值寫入輸入捕獲寄存器ICR1 (也有這樣一種模式,WGM12:WGM11:wGM11:WGM10 設置為 1110,但它需要使用另一個中斷)。

您希望將該值寫入OCR1A

12 000 000 / 256 (timer prescaller) - 1 = 46874 ,即 0xB71A,而不是 0xb71B:你忘了減 1。

由於定時器從零開始計數,那么 TOP 值比定時器的整個周期小 1

在這種情況下,最好使用十進制或公式來使代碼更具可讀性。

OCR1A = (F_CPU / 256) - 1; // 46874 

還。 正如 Rev1.0 所指出的,您需要在中斷中切換輸出。

您可以通過使用按位互斥或^

    PORTD ^= 1 << 4;

或者,在 Atmega328P 中,您只需將 1 寫入PINx寄存器即可切換PORTx的位值:

    PIND = 1 << 4;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM