最近、純粋なc/C++で、arduinoライブラリとarduino IDEを一切使わずにAtmega328Pをプログラミングし始めました。 LEDを1Hz(1秒オン、1秒オフ)の速度で点滅させたい。残念ながら、私は8ビットタイマTimer0しか使用できません。 mcuは16MHzのクロック周波数を持っています。割り込みルーチンが常にオーバーヘッドを持っているので、ジッタを減らすためにできるだけオーバーフローの数を減らすために1024のプリスケーラを選択しました(これは私の質問の残りの部分を読んでください) 。簡単な数学を使用して、私は1秒後に、Timer0
は61回オーバーフローしたこととTCNT0
レジスタはその後8AVR 8ビットタイマ - 比較値がレジスタに収まらない場合の処理は?
に等しいという結論に達しました、私はこの解決策を考え出した:
#define F_CPU 16000000ul
#include <avr/io.h>
#include <avr/interrupt.h>
#define bit(b) (1 << (b))
void initBlinkTimer()
{
//Timer0 with CTC Mode
TCCR0A |= bit(WGM01) | bit(WGM00);
//Compare TCNT0 with 8
OCR0B = 8;
//Interrupt at OCR0B compare match aka: execute interrupt when TCNT0 equals 8
TIMSK0 |= bit(OCIE0B);
//Set PB5 as output
DDRB |= bit(PB5);
//Set the prescaler to 1024
TCCR0B |= bit(CS02) | bit(CS00);
//Enable global interrupts, so that the interrupt routine can be executed upon the OCR0B compare match
sei();
}
//Keeps track of the number of overflows
volatile unsigned char nOverflows = 0;
ISR(TIMER0_COMPB_vect)
{
if(nOverflows >= 61)
{
//Toggle PB5
PORTB ^= bit(PB5);
//Reset timer
nOverflows = 0;
TCNT0 = 0;
}
else
{
nOverflows++;
}
}
int main()
{
initBlinkTimer();
while(1){}
}
このコードは、初期化プリスケーラが1024の8ビットCTCタイマです。TCNT0がOCR0Bに等しいときに割り込みサービスルーチン(ISR)が実行されます。これはコードで8に設定されています。 ISRでは、nOverflows
の変数が61と比較されます。nOverflows
が61の場合、1秒が経過し、PB5ピンがトグルされます。 mcuが61番目のオーバーフローを逃した場合(これは何らかの形でこの場合可能です)、より大きいチェックを実行します。タイマとnOverflows
変数はピンをトグルした後にクリアされ、その後タイマは再びゼロから始まります。
私の質問は:1HzでLEDを点滅させるには良い方法ですか、8ビットタイマだけが利用できるのですか?これの一部をソフトウェアではなくハードウェアで実装することはできますか?
これは他の方法と同じように便利です.... –
タイマーに十分な時間がない場合は、必要な時間の正確な分だけ割り込みが発生するように設定し、必要な時間に達すると、LED状態を反転してカウンタをリセットします。 –
@ user7353781私の答えはかなり包括的だと思ったので、チェックマークをクリックしてそれを受け入れることを検討してください。 –