Na początku zaznaczę, że siedziałem nad tym ostatnie 3 dni. Jestem z tego powodu CHOLERNIE WKURZONY.
Ostatnie doświadczenia z kompilatorem AVR-GCC i obsługą TIMER0 i TIMER2 doprowadziły mnie do konkluzji, iż w Nocie Atmegi128 lub w headerach jest błąd.
Spójrzmy na tabele preskalera TIMER2.
Oto prosty programik:
Uruchamia timer 2 i zapala diodę jeżeli wartość TCNT2 będzie większa od 100.
Dzielnik ustawiony na 1024.
Czy program zadziała? Nie!
Nie działa, w żaden sposób.
Idźmy dalej...
Zmienił się tylko preskaler. Zgodnie z tabelą, będzie to 128.
Czy program zadziała? Tak! Jaki będzie preskaler? Nie... nie 128
Będzie to 1024.
Następna tabela wyjaśni czemu tak jest. Jest to preskaler TIMER0:
Teraz popatrzmy co się stało.
Ustawiając preskaler na 1024 tak naprawdę ustawiliśmy go na zewnętrzny sygnał zegarowy T0.
Poniższy program udowadnia, że to najprawdopodobniej błąd w nocie katalogowej.
Przerwanie wykonuje się poprawnie.
Widziałem kilka wątków gdzie ludzie mieli problem z TIMER'ami. Czasami działały, czasami nie. Także chodziło tylko i wyłącznie o preskaler.
Pozdrawiam
Damian Kmiecik
Ostatnie doświadczenia z kompilatorem AVR-GCC i obsługą TIMER0 i TIMER2 doprowadziły mnie do konkluzji, iż w Nocie Atmegi128 lub w headerach jest błąd.
Spójrzmy na tabele preskalera TIMER2.
Oto prosty programik:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>
ISR(TIMER2_OVF_vect)
{
PORTC &= ~_BV(PC2);
asm volatile("nop");
}
int main(void)
{
DDRC = 0xFF;
PORTC |= _BV(PC2);
_delay_ms(1000);
PORTC &= ~_BV(PC2);
_delay_ms(1000);
PORTC |= _BV(PC2);
_delay_ms(1000);
TCNT2 = 100;
TCCR2 = _BV(CS22)|_BV(CS21)|_BV(CS20);
//TIMSK = 0b1000000;
//sei();
for(;;)
{
_delay_us(10);
PORTC ^= _BV(PC3);
if (TCNT2 > 100)
PORTC &= ~_BV(PC2);
}
}Uruchamia timer 2 i zapala diodę jeżeli wartość TCNT2 będzie większa od 100.
Dzielnik ustawiony na 1024.
Czy program zadziała? Nie!
Nie działa, w żaden sposób.
Idźmy dalej...
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>
ISR(TIMER2_OVF_vect)
{
PORTC &= ~_BV(PC2);
asm volatile("nop");
}
int main(void)
{
DDRC = 0xFF;
PORTC |= _BV(PC2);
_delay_ms(1000);
PORTC &= ~_BV(PC2);
_delay_ms(1000);
PORTC |= _BV(PC2);
_delay_ms(1000);
TCNT2 = 100;
TCCR2 = _BV(CS22)|_BV(CS20);
//TIMSK = 0b1000000;
//sei();
for(;;)
{
_delay_us(10);
PORTC ^= _BV(PC3);
if (TCNT2 > 100)
PORTC &= ~_BV(PC2);
}
}Zmienił się tylko preskaler. Zgodnie z tabelą, będzie to 128.
Czy program zadziała? Tak! Jaki będzie preskaler? Nie... nie 128
Będzie to 1024.
Następna tabela wyjaśni czemu tak jest. Jest to preskaler TIMER0:
Teraz popatrzmy co się stało.
Ustawiając preskaler na 1024 tak naprawdę ustawiliśmy go na zewnętrzny sygnał zegarowy T0.
Poniższy program udowadnia, że to najprawdopodobniej błąd w nocie katalogowej.
Przerwanie wykonuje się poprawnie.
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>
ISR(TIMER0_OVF_vect)
{
PORTC &= ~_BV(PC2);
asm volatile("nop");
}
ISR(TIMER2_OVF_vect)
{
asm volatile("nop");
}
int main(void)
{
DDRC = 0xFF;
PORTC |= _BV(PC2);
_delay_ms(1000);
PORTC &= ~_BV(PC2);
_delay_ms(1000);
PORTC |= _BV(PC2);
_delay_ms(1000);
TCNT0 = 100;
TCCR0 = _BV(CS02)|_BV(CS00);
TIMSK = _BV(TOIE0);
sei();
for(;;)
{
_delay_us(10);
PORTC ^= _BV(PC3);
}
}
Widziałem kilka wątków gdzie ludzie mieli problem z TIMER'ami. Czasami działały, czasami nie. Także chodziło tylko i wyłącznie o preskaler.
Pozdrawiam
Damian Kmiecik
