최근 arduino 라이브러리와 arduino IDE가없는 순수한 c/C++로 Atmega328P를 프로그래밍하기 시작했습니다. 나는 1Hz (1 초 켜기, 1 초 꺼짐)의 속도로 LED를 깜박 거리고 싶다. 불행히도 8 비트 타이머 인 Timer0 만 사용할 수 있습니다. mcu는 16MHz의 클럭 주파수를 가지고 있으며 인터럽트 루틴은 항상 오버 헤드를 가지고 있기 때문에 지터를 줄이기 위해 가능한 한 오버플로 수를 줄이기 위해 1024의 프리스케일러를 선택했습니다 (이것은 내 질문의 나머지 부분을 읽는다면 더 의미가 있습니다) .AVR 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){}
}
이 코드는 초기화 : 간단한 수학하여, I 1 초 후에 Timer0
61 회 오버 플로우되었음을 상기 TCNT0
레지스터는이어서 제
해당된다는 결론을 내렸다,이 용액 해낸 인터럽트 서비스 루틴 (ISR)은 TCNT0이 OCR0B와 같을 때 실행되며, 이는 내 코드에서 8로 설정됩니다. ISR에서 nOverflows
변수는 61과 비교됩니다. nOverflows
이 61이면 1 초가 경과하고 PB5 핀이 토글됩니다. 또한 mcu가 61 번째 오버플로를 놓친 경우에 대비하여보다 큰 체크를 수행합니다 (이 경우 어떻게 든 가능합니다). 타이머와 nOverflows
변수는 핀을 토글 한 후에 지워지고 타이머는 다시 0에서 시작합니다.
내 질문은 : 이것은 8 비트 타이머 만 사용할 수있는 1Hz에서 LED를 깜박이는 좋은 방법입니까? 소프트웨어의 일부가 아니라 하드웨어의 일부로 구현 될 수 있습니까?
마찬가지로 좋은 방법입니다. –
타이머의 시간 간격이 충분하지 않은 경우 필요한 시간의 정확한 분수로 인터럽트하도록 구성하고 필요한 시간에 도달하면 LED 상태를 반전시키고 카운터를 재설정합니다. –
@ user7353781 제 대답이 꽤 포괄적이라고 생각 했으므로 체크 표시를 클릭하여 동의하십시오. –