[英]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.