ATMega644,EvB-příklad na časovač/čítač, rozdíl oproti smyčce

Ahoj všem, mám vývojový kit 4.3 s ATMega644, nikdy jsem nepracovala v čítači a časovači,může mi někdo vysvětlit princip. Pročetla jsem si datasheet, ale moc moudrá z toho nejsem.
Když chci například spoždění 1s, tak aby mi blikala LED dioda. Nevím co přesně si představit pod definicemi TCCR1A…TIMSK1. A jak vše nastavit, abych docílila požadovaného spoždění.
Chápu to správně, že když použiji časovač tak během času 1s se může vykonávat program ve smyčce while(1), naopak když použiji delay_ms(1000) tak program vykonává pouze smyčku spoždění 1s a nic jiného.

#include <avr/io.h> 
#include <util/delay.h> 
#include <avr/interrupt.h> 

# define F_CPU 2000000UL
uint16_t decimal;

void tim1Start(void) 
{ 
   TCCR1A ??? 
   TCCR1B ??? 
   TCCR1B ??? 
   ICR1 = ??? 
   TIMSK1 ??? |= 1<<TOIE1;  //povoleni preteceni

} 

ISR(TIMER1_OVF_vect) 
{ 
   // 
   PORTB ^= 1<<PB1;   // blikani na PB1 s periodou ???ms
} 


int main(void) 
{ 
   // 
   DDRB |= 1<<PB1; 
   tim1Start(); 
   sei();                     //povoleni preruseni
   // main loop 
   while(1) 
   { 
      // hlavni program		
   } 
}

:arrow_right: administrator: přejmenováno z "ATMega644 časovač/čítač, přerušení"

Zdravím,

nevím jestli jste měnila nastavení kmitočtu ale, v první řadě se ujistěte, že vám atmega běží opravdu na vámi zadaných 20MHz. Nevím jestli to již atmel změnil, ale když jsem s nimi dělával tak bývaly nastaveny z výroby na 1MHz.

TCCR1A - registr, který slouží k nastavení činnosti timeru, např. k nastavení PWM apod., v tvém případě z tohoto registru nepoužiješ nic, takže
TCCR1A = 0b00000000

TCCR1B - z tohoto registru jsou momentálně pro vás zajímavé tři nejnižší bity, tj. bit 2, bit 1 a bit 0, dle tabulky na straně 128 datasheetu si nastavíte děličku kmitočtu pro timer. Pro zpoždění 1s doporučuji nastavit na kmitočet měnší než je 65535 Hz, pro frekvenci 20Mhz je to ten největší dělící poměr a to je 1024, takže 20 000 000 / 1024 = 19 531, 25. Po zaokrouhlení je to 19531 Hz. Z tabulky vyplývá, že pro dělící poměr 1024 musí být nastaven bit 2 a bit 0, tj
TCCR1B = 0b00000101

TCNT1H a TCNT1L jsou registry které obsahují načítanou hodnotu. Při nastavené frekvenci 19 531Hz bude v těchto registrech za 1s

TCNT1H = 0x4C
TCNT1L = 0x4B

protože 0x4C4B = 19531 dekadicky

z tohoto všeho vyplývá, že přerušení přetečením se vyvolá za
65535 / 19531 = 3,355s

Abyste dostala tu svoji požadovanou 1s, tak do přerušení vložíte

TCNT1H = 0xB3
TCNT1L = 0xB5

protože 65535 - 19531 = 46 005 tj hexa B3B5

tímto vlastně nastavíte hodnotu čítače při každém přetečení.

ICR1H, ICR1L, OCR1AH, OCR1AL, OCR1BH, OCR1BL - tyto registry prozatím nepoužijete.

TIMSK1 - registr který slouží k povolení přerušení od timeru1 -přetečení, porovnání, input capture.

Ve vašem případě nastavíte bit 0 tj.

TIMSK1 = 0b00000001

To asi tak vše k základu, samozřejmě vámi požadovaná 1s jde pomocí timeru1 udělat i jinak, ale myslím, že pro vysvětlení je toto nejjednodušší způsob.

K poslední otázce - ano, chápete to správně, v tomto je právě to kouzlo použití periferií mcu navíc požadovaná doba je i přesnější než při použití funkce delay.

Snad jsem nic nepopletl, už jsem s atmegou dlouho nedělal a pokud budete mít i další dotazy, klidně sem napište, pokud budu vědět, rád odpovím.

Dá se počítat i takto

Oscilátor f = 2 MHz
Perioda oscilátoru = 1/f = 0,5 microsec.
Bez předděliče trvá 1 krok čítače 0,5 us.
Zvolíme předdělič 64.
S předděličem 64 trvá jeden krok 64*0,5 = 32 us.
Pro jednu vteřinu potřebujeme 1000000/32 = 31250 kroků.

[code]void tim1Start(void)
{
// nastavíme předdělič 64
TCCR1B = 0b00000011;
//povolíme přerušení od přetečení Timer1
TIMSK1 = 1<<TOIE1;
// čítač přeteče při hodnotě 65536, proto ho přednastavíme na hodnotu o 31250 menší
TCNT1 = 65536-31250;
}

ISR(TIMER1_OVF_vect) // přeteče 1x za vteřinu
{
//přednastavíme čítač
TCNT1 = 65536-31250;
PORTB ^= 1<<PB1; // invertujeme portb.1
}
[/code]

Děkuji za vysvětlení, oba dva způsoby fungují bezvadně, jen bych chtěla vědět proč v simulátoru program nikdy neskočí do smyčky while(1)?

Vlož do té smyčky nějaký příkaz, třeba
PORTC = PORTC;

Ve smyčce mám kod, jen jsem to neuváděla pro přehlednost, už to v simulátoru funguje měla jsem ho špatně nastavený. Teď je to už super,takže když budu potřebovat nastavit čítač/časovač nastavím to dle příkladu výše,nebo jsou potřeba ještě další registry pro čítač/časovač pro další funkce,které bych mohla někdy v budoucnu potřebovat?

Dále kdybych chtěla počítat čas od zapnutí, budu dělat to stejné a jen v přerušení po 1s příčítat k nějaké proměnné jedničku a pak si odvodit hodiny atd.

Níže jsou uvedeny všechny registry pro TIMER1

TCCR1A
TCCR1B
TCNT1H
TCNT1L
ICR1H
ICR1L
OCR1AH
OCR1AL
OCR1BH
OCR1BL
TIMSK1

no a to jestli jich budete někdy potřebovat, už záleží na aplikaci kterou budete dělat.

TIMER1 má celkem 15 módů, dle tabulky na str. 127 DS

Pokud např. budete chtít použít PWM, tak použijete i registry OCR1, ICR1 k nastavení šířky pulzů a frekvence.

ano přesně tak.