Namai daugiamečių gėlių Laikmatis avr studijoje pavyzdžiai. AVR mikrovaldiklių programavimas. OC0 išėjimo valdymas

Laikmatis avr studijoje pavyzdžiai. AVR mikrovaldiklių programavimas. OC0 išėjimo valdymas

AT paskutiniais laikais Vis daugiau pradedančiųjų susiduria su laikmačių / skaitiklių (toliau – T / C) įvaldymo problema mikrovaldiklių mokymosi etape. Šiame straipsnyje pabandysiu išsklaidyti baimes dėl šių modulių ir prieinamu būdu paaiškinti, kaip ir su kuo naudojami tie patys T/S.

Kaip pagrindą paimsime knygą, kuri yra labai populiari tarp MK įrenginių kūrėjų, kurios autorius A.V. Evstifejevas. Naudodamiesi straipsnio pabaigoje esančiomis nuorodomis galite rasti projektą ir projektą . Šiame straipsnyje mes analizuosime 8 bitų T / C T2, kuris yra T / C MK Atmega8 dalis, veikimą.

Taigi, kas yra laikmatis / skaitiklis? T/S yra vienas iš MK AVR modulių, su kuriuo galite matuoti tam tikrus laiko periodus, organizuoti PWM ir daugybę kitų užduočių. Priklausomai nuo MK modelio, T / C skaičius gali būti 4 ar daugiau. To pavyzdys yra MK Atmega640x, 1280x/1281x, 2560x/2561x, kurių plokštėje yra 6 T/C: du 8 bitų ir keturi 16 bitų. MK Atmega8 yra trys T / C: T0 ir T2, kurių talpa yra 8 bitai, T1, kurios talpa yra 16 bitų.

Pažvelkime atidžiau į Atmega8 mikrovaldiklio T/C T2.

Šis laikmatis gali veikti keliais režimais: normalus, fazės teisingas PWM, CTC (reset on match), greitas PWM. Daugiau apie kiekvieną režimą galite perskaityti knygoje.

Šį T / C sudaro valdymo registras, skaičiavimo registras, palyginimo registras, asinchroninio režimo būsenos registras. T2 blokinė schema parodyta 1 pav

Teoriškai panagrinėkime, kaip veikia šis modulis. Kad jums būtų aiškiau, neatsižvelgsime į visas papildomas laikmačio programėles ir atsižvelgsime į labiausiai paplitusią jo režimą - NORMAL. Mes patys nustatome, kad MK yra įjungtas iš vidinio RC generatoriaus, kurio dažnis yra 1 MHz, o laikmatis nustatytas veikti NORMAL režimu.

Laikrodžio impulsai įvedami clk i \ o ir patenka į laikmačio išankstinį skirstytuvą. Preskalerį galima sukonfigūruoti pagal savo poreikius perduoti laikrodžio impulsus į priekį arba padalinti gaunamus impulsus, perduodant tik tam tikrą jų dalį. Įeinančius impulsus galite padalyti iš /8, /64, /256, /1024. Kadangi mūsų T\C gali dirbti asinchroniniu režimu, jį įjungus šiuo režimu, išankstinių skalierių skaičius gerokai padidėja, tačiau mes jų kol kas nenagrinėsime. Iš išankstinio skalerio laikrodžio impulsai patenka į valdymo bloką ir jau iš jo patenka į skaičiavimo registrą. Skaičiavimo registras, savo ruožtu, didėja kiekvienam įeinančiam impulsui. Skaičiavimo registras T2 yra 8 bitų, todėl gali skaičiuoti tik iki 255. Kai skaičiavimo registras persipildo, jis atstatomas į 0 ir vėl pradedamas skaičiuoti tame pačiame cikle. Taip pat skaičiavimo registro perpildymo metu nustatoma TIFR registro TOV2 vėliavėlė (perpildymo nutraukimo vėliavėlė).

Dabar, kai palietėme tokius žodžius kaip REGISTRACIJA, laikas su jais susipažinti. Pirmiausia paliesime tik tuos registrus, su kuriais tiesiogiai dirbsime, kad neužkimštume smegenų nereikalinga informacija.

TCNT2 yra skaičiavimo registras, apie jo darbą jau kalbėjome.

TCCR2 - laikmačio valdymo registras.

TIMSK - pertraukimo kaukės registras (Atmega8 šis registras yra vienintelis visiems laikmačiams).

TIFR – pertraukti vėliavų registrą (Atmega8 šis registras yra unikalus visiems laikmačiams).

O dabar apie kiekvieną išsamiai:

Valdymo registras TCCR2. Šio registro turinį galite pamatyti 2 pav.


pav.2

0-2 bitai yra atsakingi už laikmačio laikmatį. Nustačius tam tikras šių bitų kombinacijas, nustatomas to laikmačio išankstinis skirstytuvas. Jei visi trys bitai nustatomi iš naujo, laikmatis yra išjungtas.

3,6 bitai yra atsakingi už laikmačio veikimo režimą.

4,5 bitai reikalingi OSn išvesties veikimui konfigūruoti (kitaip tariant, jie naudojami nustatant PWM)

Ir paskutinis šio registro bitas yra 7 bitas. Su juo galime priverstinai pakeisti OSn išvesties būseną.

Pertraukimo kaukės registras yra TIMSK. Tai matome 3 paveiksle.

Iš šio registro mus domina tik paskutiniai du bitai, 6 ir 7 bitai. Su šiais bitais įjungiame pertraukimus.

6 bitas, jei į jį įrašytas, įgalina pertraukimą įvykyje „Perpildymas T \ C T2“

7 bitas, jei į jį parašysite vienąnitsa, leidžia pertraukti įvykį "Skaičiavimo registro sutapimas su palyginimo registru"

Nutraukti vėliavėlių registrą TIFR. Tai matome 4 paveiksle.

pav.4

Šiame registre mus taip pat domina paskutiniai du bitai: 6 ir 7 bitai.

6 bitas – vėliavėlė, nustatyta įvykio „Perpildymas T \ C T2“
7 bitas – vėliavėlė, įdiegta apie renginį „Skaičiavimo registro sutapimas su palyginimo registru“

Šie bitai automatiškai išvalomi, kai pertraukimų tvarkytuvas išeina, tačiau, kad būtų saugu, juos galite išvalyti patys, iš naujo nustatydami šiuos bitus į „0“.

Likusius TIMSK ir TIFR registrų bitus naudoja T\C T0 ir T1. Kaip jau pastebėjote, net šių registrų bitų pavadinimai yra vienodi, išskyrus skaičių vardo gale, kuris nurodo, kuriam laikmačiui šis bitas taikomas.

Belieka atsižvelgti į dvi paprastas plokštes, būtent: lentelę, kurioje aprašomas laikrodžio signalo valdymas (6 pav.), ir lentelę, kurioje aprašoma, kaip paprastai nustatyti laikmatį (5 pav.).

Apie tai, kas yra šiose lentelėse, rašiau aukščiau, bet aiškumo dėlei aš jas jums pateikiu.

Taigi, mes baigėme teoriją ir laikas pradėti praktinę dalį. Iš karto padarysiu rezervaciją.

LAIKRODŽIAI, KURIUS GAUTE NAGRINĖJANT ŠĮ STRAIPSNIĄ, NETURI DIDELO TIKSLUMO. ŠIS STRAIPSNIS APIE BENDRIUS DARBO SU LAIKMAČIAIS ​​PRINCIPUS.

Atidarykite „Studio 6“, sukurkite projektą ir pasirinkite „Atmega8“.

Pačioje pradžioje nurodome laikrodžio dažnį ir sujungiame bibliotekas, kurių mums reikia darbui

< avr/io.h >#įtraukti< avr/interrupt.h >

Pirmoje eilutėje nurodome dažnį. Tai būtina, kad kompiliatorius mus geriau suprastų, jei staiga norime naudoti _delay_() funkcijas.

Antroje kodo eilutėje biblioteka yra sujungta su Bendras aprašymas mūsų MK registrai. Taip pat jame visiems registrams priskiriami įskaitomi pavadinimai.

Trečioji eilutė jungia biblioteką darbui su pertraukimo vektoriais.

TIMSK |= (1< < TOIE2); TCCR2 |= (1< < CS22)|(1< < CS20); SREG |= (1< < 7);

Tai užbaigia laikmačio sąranką. Pažvelkime atidžiau į paskutines tris kodo eilutes.

Pirmoje eilutėje įgalinome įvykio „T2 laikmačio\skaitiklio perpildymo“ pertraukimus.

Trečioje eilutėje mes visame pasaulyje įgalinome pertraukimus. Jis taip pat galėjo būti parašytas taip:

Asm("sei");

Belieka pridėti pertraukimų tvarkyklę ir mūsų realaus laiko laikrodžio kodą.

ISR (TIMER2_OVF_vect) ( takt++; if (takt>=4)(sek++; takt=0x00;) if (sek>=60) (min++; sek=0x00;) if (min>=60) (valanda++; min=0x00 ;) if (valanda>=24) (valanda=0x00); )

Kode, esančiame pertraukimų tvarkyklėje, jums nėra nieko sudėtingo ir naujo. Atkreipkime dėmesį tik į takto kintamąjį ir magišką skaičių „4“. Iš kur atsirado šis skaičius? Pažvelkime į šį punktą išsamiai.

Žinome, kad mūsų MK maitina vidinis generatorius, kurio dažnis yra 1 MHz, laikmatis veikia su išankstiniu skaleriu \ 1024, mūsų laikmatis gali suskaičiuoti iki 255. Žinodami šiuos parametrus galime apskaičiuoti, kiek perpildymų jis padarys 1 sekundė

1 000 000 \ 1024 \ 256 = 3,814697.....

Na, o kadangi mokomės dirbti su laikmačiais ir nekėlėme tikslo gauti itin tikslaus laikrodžio dažnio, apvaliname rezultatą ir gauname „4“. Tie. per 1 sekundę laikmatis persipildys ~4 kartus.

Kodėl dalijome iš 256, jei laikmatis skaičiuoja tik iki 255? Nes „0“ taip pat yra skaičius. Manau čia viskas aišku.

Nepamirškite, kad visi kintamieji turi būti deklaruoti kaip globalūs.

Čia yra visas mūsų gautos programos sąrašas.

#define F_CPU 1000000UL #įtraukti< avr/io.h >#įtraukti< avr/interrupt.h >simbolis be ženklo = 0; unsigned char sec = 0; unsigned char min=0; unsigned char valanda=0; ISR (TIMER2_OVF_vect) ( takt++; if (takt>=4)(sek++; takt=0x00;) if (sek>=60) (min++; sek=0x00;) if (min>=60) (valanda++; min=0x00 ;) if (valanda>=24) (valanda=0x00); ) int main(void) ( TIMSK |= (1)< < TOIE2); TCCR2 |= (1< < CS22)|(1< < CS20); SREG |= (1< < 7); while(1) { } }

Bet kaip su informacijos išvestimi vartotojui? Ir tada kam patinka. Galite naudoti septynių segmentų ekranus, grafinius ar simbolius generuojančius ekranus ir kt.

Archyve rasite projektą su informacijos rodymu ekrane iš nokia5110, projektą Proteus 7 ir kt. reikalingus failus ir bibliotekos, su kuriomis reikia dirbti.

Atkreipiu jūsų dėmesį į tai, kad LCD_5110 biblioteka darbui su ekranu buvo parašyta forumo nario ir pateikta su jo leidimu.

Šioje pamokoje kalbėsime apie laikmačius.

Ši tema yra tiesiogiai susijusi su mikrovaldiklio laikrodžio tema. Todėl rekomenduoju prieš skaitant šią pamoką perskaityti ankstesnę.

Taigi kodėl mums reikia laikmačio?

Kuriant projektus ant mikrovaldiklių labai dažnai reikia išmatuoti tikslius laiko intervalus. Pavyzdžiui, noras mirksėti šviesos diodu tam tikru dažniu arba reikiamais laiko intervalais apklausti mygtuko būseną.

Būtent laikmačiai padeda išspręsti užduotis. Tačiau AVR mikrovaldiklių laikmačiai nežino, kas yra sekundė, minutė, valanda. Tačiau jie puikiai žino, kas yra taktiškumas! Jie veikia tiksliai dėl valdiklio laikrodžio buvimo. Tai reiškia, kad laikmatis skaičiuoja valdiklio ciklų skaičių ir taip išmatuoja laiko intervalus. Tarkime, kad valdiklis veikia 8 MHz laikrodžio dažniu, tai yra, kai laikmatis skaičiuoja iki 8 000 000, praeis viena sekundė, skaičiuojant iki 16 000 000, praeis 2 sekundės ir pan.

Tačiau čia iškyla pirmoji kliūtis. Turime 8 bitų registrus, tai yra, galime suskaičiuoti daugiausiai iki 255, o paėmę 16 bitų laikmatį suskaičiuosime daugiausiai iki 65535. Tai yra, per vieną sekundę turime iš naujo nustatyti laikmatį puiki suma kartą! Žinoma, galite tai padaryti, jei neturite ką veikti. Bet tiesiog matuoti laiką naudojant galingą mikrovaldiklį visai neįdomu, norisi padaryti kažką daugiau. Čia į pagalbą ateina prescaler. AT bendras vaizdas tai yra tarpinis tarp laikmačio ir valdiklio laikrodžio. Išankstinis skaleris palengvina mūsų užduotį, padalydamas laikrodžio dažnį iš tam tikras skaičius prieš paduodami jį į laikmatį. Tai yra, nustačius išankstinį skalerį į 8, per 1 sekundę mūsų laikmatis suskaičiuos iki 1 000 000, o ne 8 000 000 (Žinoma, kai valdiklio laikrodžio dažnis yra 8 MHz). Įdomiau, ar ne? O dalyti galime ne tik iš 8, bet ir iš 64 ir net iš 1024.

Dabar atėjo laikas surinkti grandinę, nustatyti laikmatį, išankstinį skalavimą ir padaryti bent ką nors naudingo!

Ir šiandien mes darysime "bėgimo žibintus" iš šviesos diodų. Tai yra, mes paeiliui įjungsime 3 šviesos diodus, kurių laikotarpis yra 0,75 sekundės (tai yra, vieno šviesos diodo veikimo laikas yra 0,25 sekundės). Sudarykime tokią diagramą:

Apskaičiuokite rezistorių reikšmes R 1-R 3 patys.

Tada apsvarstykite registrus, atsakingus už laikmačių veikimą. Iš viso AtMega 8 apima 3 laikmačius.Du 8 bitų laikmačiai (Timer 0, Timer 2) ir vienas 16 bitų laikmatis (Timer 1).Pavyzdžiu nagrinėsime 16 bitų laikmatį 1.

Pora 8 bitų registrų TCNT 1H ir TCNT 1L kartu sudaro 16 bitų registrą TCNT 1. Šis registras yra atviras ir rašymui, ir skaitymui. Kai veikia 1 laikmatis, šio registro reikšmė su kiekvienu skaičiumi pasikeičia vienu. Tai reiškia, kad TCNT 1 registre yra ciklų, kuriuos suskaičiavo laikmatis, skaičius. Čia taip pat galime įrašyti bet kokį skaičių nuo 0 iki 2 iki 16 laipsnio. Tokiu atveju laikrodžio ciklai bus skaičiuojami ne nuo 0, o nuo mūsų užfiksuoto skaičiaus.

TIMSK registras yra atsakingas už pertraukimus, atsirandančius veikiant mikrovaldiklio laikmačiams. Pertraukimas – specialaus signalo, gaunamo, kai kažkas pasikeičia, tvarkytuvas. Bet koks mikrovaldiklio pertraukimas gali būti įjungtas arba išjungtas. Kai įvyksta įjungtas pertraukimas, pagrindinė programa nutraukiama ir signalas apdorojamas. Kai įvyksta išjungtas pertraukimas, programos eiga nenutraukiama ir pertraukimas yra ignoruojamas. TOIE 1 bitas (Timer 1 Overflow Interrupt Enable) yra atsakingas už 1 laikmačio skaičiavimo registro TCNT 1 perpildymo pertraukimo įjungimą. Rašant 1 į šį bitą, pertraukimas įjungiamas, o rašant 0 – išjungiamas. Šį pertraukimą generuoja 1 laikmatis, kai maksimali vertė registruotis TCNT 1. Daugiau apie pertraukimus pakalbėsime kitoje pamokoje.

Registras TCCR 1B yra atsakingas už 1 laikmačio konfigūravimą. Ši byla bitai CS 10-CS 12 nustatome išankstinio skalavimo keitiklio reikšmę pagal šią lentelę.

Likę bitai mūsų kol kas nedomina.

Taip pat yra TCCR 1A registras, leidžiantis sukonfigūruoti kitus laikmačio režimus, tokius kaip PWM, bet apie juos atskirame straipsnyje.

O dabar C kodas:

#define F_CPU 16000000UL #įtraukti #įtraukti uint8_tnum=0; ISR(TIMER1_OVF_vect) ( PORTD=(1<2) ( num=0; ) TCNT1=61630;//Laikmačio pradinė vertė ) int main(void) ( DDRD|=(1)<

#define F_CPU 16000000UL

#įtraukti

#įtraukti

uint8_t skaičius = ;

ISR (TIMER1_OVF_vect )

PORTD = (1<< num ) ;

skaičius++;

jei (skaičius > 2)

skaičius = ;

TCNT1 = 61630; //Pradinė laikmačio reikšmė

int main (tuščia)

DDRD |= (1<< PD0 ) | (1 << PD1 ) | (1 << PD2 ) ;

TCCR1B |= (1<< CS12 ) | (1 << CS10 ) ; //Prescaler = 1024

TIMSK |= (1<< TOIE1 ) ; //Įgalinti 1 laikmačio perpildymo pertraukimą

TCNT1 = 61630; //Pradinė laikmačio reikšmė

sei(); //Įgalinti pertraukimus

kol (1)

//Pagrindinė programos kilpa, ji tuščia, nes visas darbas yra pertraukime

ASM kodas:

Surinkimas (x86)

Įtraukti "m8def.inc" rjmp start .org OVF1addr rjmp TIM1_OVF start: ldi R16, LOW(RamEnd) out SPL, R16 ldi R16, HIGH(RamEnd) out SPH, R16 ldi R16,1 ldi R17,011,10 R17,0B00000101 Out TCCR1B, R17 LDI R17,0B11110000 Out TCNT1H, R17 LDI R17,0B10111110 OUT TCNT1L, R17 LDI R17,0B00000100 Out Timsk, R17 SEI Main_loop: NOP RJMP Maint_loop etiketė_1 ldi R16,1 etiketė_1: ldi R17,0b10111110 iš TCNT1L, R17 ldi R17,0b11110000 iš TCNT1H, R17 reti

Įtraukti "m8def.inc"

Rjmp pradžia

Org OVF 1addr

Rjmp TIM 1_OVF

pradžia:

Ldi R 16, LOW (RamEnd)

Iš SPL, R 16

Ldi R 16, AUKŠTAS (RamEnd)

Iš SPH , R 16

Ldi R 16, 1

Ldi R 17, 0b00000111

Iš DDRD, R 17

Ldi R 17, 0b00000101

Iš TCCR 1B , R 17

Ldi R 17, 0b11110000

Iš TCNT 1H , R 17

Ldi R 17, 0b10111110

Vienas iš ATmega8 mikrovaldiklio privalumų – platus įvairių pertraukimų spektras.

Pertraukite reiškia įvykį, kuriam įvykus pagrindinės programos vykdymas sustabdomas ir iškviečiama funkcija, kuri apdoroja tam tikro tipo pertraukimą.

Pertraukimai skirstomi į vidinius ir išorinius. Vidiniai pertraukimų šaltiniai apima įmontuotus mikrovaldiklio modulius (laikmačius, USART siųstuvą-imtuvą ir kt.). Išoriniai pertraukimai atsiranda, kai išoriniai signalai gaunami mikrovaldiklio kaiščiuose (pavyzdžiui, signalai RESET ir INT kontaktuose). Signalų, vedančių į pertraukimą, pobūdis nustatomas valdymo registre MCUCR, ypač bituose - ISC00 (bitas 0) ir ISC01 (bitas 1), skirtas įvesties INT 0; ISC10 (bit2) ir ISC11 (bit3) INT1 įėjimui.

ATmega8 mikrovaldiklyje kiekvienas pertraukimas turi savo pertraukimo vektorius(adresas programos atminties srities pradžioje, kurioje saugoma komanda pereiti prie nurodytos pertraukimo tarnybos rutinos). Mega8 visi pertraukimai turi tą patį prioritetą. Jei vienu metu įvyksta keli pertraukimai, pirmiausia bus apdorojamas pertraukimas su mažesniu vektoriaus numeriu.

Pertraukimo vektoriai Atmega8

Adresas Pertraukimo šaltinis apibūdinimas
0x0000 NUSTATYTI iš naujo Atstatyti signalą
0x0001 INT0 Išorinio pertraukimo užklausa įėjime INT0
0x0002 INT1 Išorinio pertraukimo užklausa įėjime INT1
0x0003 T/C1 T/C1 laikmačio fiksavimas
0x0004 T/C1 Suderinti su palyginimo registru A laikmačio T/C1
0x0005 T/C1 Suderinti su palyginimo registru B laikmačio T/C1
0x0006 T/C1 Skaitiklio perpildymas T/C1
0x0007 T/C0 Skaitiklio perpildymas T/C0
0x0008 SPI SPI ryšys baigtas
0x0009 UART Duomenų priėmimas UART siųstuvu-imtuvu baigtas
0x000A UART UART duomenų registras tuščias
0x000B UART UART siųstuvas-imtuvas baigė duomenų perdavimą
0x000C ANA_COMP Analoginio komparatoriaus pertraukimas

Pertraukimo valdymas

4 registrai yra atsakingi už pertraukimų valdymą ATmega8:

GIMSK(dar žinomas kaip GICR) - išjungti / įjungti signalų pertraukimus prie įėjimų INT0, INT1

GIFR- visų išorinių pertraukimų valdymas

TIMSK, TIFR- pertraukti valdymą iš laikmačių / skaitiklių

Registruotis GIMSK (GICR)

INTFx=1: INTx įėjime įvyko pertraukimas. Įeinant į pertraukimo paslaugos rutiną, INTFx automatiškai atkuriama į žurnalo būseną. 0

Registruotis TIMSK

7 6 5 4 3 2 1 0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-

TOIE1=1: T/C1 perpildymo pertraukimas įjungtas

OCIE1A=1: pertraukti, kai palyginimo registras A atitinka skaitiklio T/C1 turinį

OCIE1B=1: nutraukti, kai palyginamas registras B atitinka įjungto skaitiklio T/C1 turinį

TICIE=1: leidžiama pertraukti, kai įvykdoma fiksavimo sąlyga

TOIE0=1: T/C0 perpildymo pertraukimas įjungtas

Registruotis TIFR

7 6 5 4 3 2 1 0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-

TOV1=1: Įvyko T/C1 perpildymas

OCF1A=1: Palyginimo registras A atitiko leidžiamo skaitiklio T/C1 turinį

OCF1B=1: Palyginimo registras B suderintas T/C1 skaitiklis

ICF=1: gaudymo sąlyga įvykdyta

TOV0=1: įvyko T/C0 perpildymas

Įeinant į pertraukimo paslaugų tvarką, atitinkama pertraukimo vėliavėlė TIFR registre automatiškai atkuriama į žurnalo būseną. 0

Pertraukimai veikia tik tada, kai būsenos registre SREG įjungti bendrieji pertraukimai (7 bitas = 1). Jei įvyksta pertraukimas, šis bitas automatiškai atstatomas į 0, užkertant kelią tolesnių pertraukimų vykdymui.

Šiame pavyzdyje INT0 kaištis įjungtas ištraukiamo įvesties režimu. Kai mygtuku išėjimas uždaromas į žemę, jame nustatomas log.0 (signalo kraštas nukrenta nuo maitinimo įtampos iki 0) ir suveikia pertraukimų tvarkytuvas, įjungiantis šviesą, prijungtą prie B prievado nulinės išvesties.

tuščia lemputė ĮJUNGTA ()
{
PORTB.0=1;
DDRB.0=1;
}

nutraukti void ext_int0_isr(void)
{
lempa ĮJUNGTA();
}

DDRD.2=0;
PORTD.2=1;

SREG|= (1 mirksnis (1) (

Aukščiau pateiktame pavyzdyje taip pat parodyta, kaip Code Vision AVR nustatomi pertraukimų vektoriai (interrupt void ext_int0_isr(void)). Pertraukimo vektoriai nustatomi panašiai ir kitais atvejais:

EXT_INT0 2
EXT_INT1 3
TIM2_COMP 4
TIM2_OVF 5
TIM1_CAPT 6
TIM1_COMPA 7
TIM1_COMPB 8
TIM1_OVF 9
TIM0_OVF 10
SPI_STC 11
USART_RXC 12
USART_DRE 13
USART_TXC 14
AD_INT 15
EE_RDY 16
ANA_COMP 17
TWI 18
SPM_PARUOŠTA 19

Tiesą sakant, mikrovaldiklio laikmatis yra skaitmeninis skaitiklis, tik „išgalvotas“. Į skaitiklio įvestį nukreipiamas laikrodžio signalas, kurio pagrindu skaitiklis padidina savo vertę. Kai įvyksta įvykiai – skaitiklio perpildymas arba jo vertės sutapimas su duotuoju – sugeneruojama pertraukimo užklausa.

Pažiūrėkime, kaip naudoti T0 laikmatį įprastu režimu. Šiuo režimu laikmatis skaičiuoja nuo tam tikros pradinės skaičiavimo registro reikšmės iki didžiausios galimos reikšmės (iki 255 arba 0xFF). Kai laikmatis T0 skaičiuoja iki maksimumo, tada kitame laikmačio cikle skaičiavimo registras TCNT0 persipildo – jis atstatomas į nulį ir nustatoma TOV0 vėliavėlė. Jei programoje visuotinai įjungti pertraukimai (SREG registro vėliavėlė I) ir laikmačio pertraukimas T0 esant perpildymui (TIMSK registro vėliavėlė TOIE0), tada mikrovaldiklis iškvies atitinkamą tvarkyklę. Jei skaičiavimo registro reikšmė sutampa su palyginimo registru OCR0, bus nustatyta OCF0 vėliavėlė ir, jei įjungtas atitikties įvykio pertraukimas, bus paleista jo tvarkytuvė.

Laikmatis T0 įprastu režimu

Apsvarstykime praktinę užduotį – kas 20 ms reikia užsukti mygtuką. Mikrovaldiklio dažnis 8 MHz, ATmega16 mikrovaldiklis.

Pirmas dalykas, kurį reikia padaryti, yra nuspręsti dėl laikmačio išankstinio skalavimo koeficiento pasirinkimo ir apskaičiuoti pradinę TCNT0 skaičiavimo registro vertę.

Laikmatis T0 gali būti įjungtas iš vidinio mikrovaldiklio laikrodžio signalo arba iš išorinio, kuris tiekiamas į T0 kaištį. Dirbdamas iš vidinio laikrodžio signalo, vartotojas gali pasirinkti šio signalo dažnio padalijimo koeficientus. Laikmatis T0 turi penkis galimus išankstinio skalavimo veiksnius – 1, 8, 64, 256, 1024.

Norėdamas išspręsti problemą, argumentuoju taip. Jei vienas T0 laikmačio ciklas būtų 1 ms periodas, tai man tiktų. 20 ciklų suteikia 20 ms. Koks yra laikmačio išankstinio skalavimo koeficientas, kad būtų galima priartėti prie 1 ms laikrodžio periodo? Galite skaičiuoti.

Mikrovaldiklio laikrodžio dažnis Fcpu = 8000000 Hz
Mikrovaldiklio laikrodžio periodas Tcpu = 1/Fcpu
Laikmačio laikrodžio laikotarpis T0 yra Tt0 = (1/Fcpu)/k = k/Fcpu

Kai k = 1024, laikmačio laikrodžio laikotarpis T0 bus lygus Tt0 = 1024/8000000 = 0,128 ms

Tai yra didžiausias laikmačio laikrodžio laikotarpis, kurį galime gauti mūsų sąlygomis (Fcpu = 8 MHz). Su mažesniais koeficientais laikotarpis bus dar trumpesnis.

Na, tarkime, vienas laikmačio ciklas yra 0,128 ms, ar užteks skaičiavimo registro talpos šiam laiko intervalui suskaičiuoti ir kiek ciklų tai užtruks? Reikiamą laiko intervalą (20 ms) padaliname iš vieno laikmačio ciklo trukmės ir gauname atsakymą.

n = t / Tto = 20 ms / 0,128 ms = 156,25

Suapvalinus iki visumos, gauname 156 ciklus. Tai yra mažiau nei 255 (maksimali skaičiavimo registro reikšmė), todėl skaičiavimo registro TCNT0 talpos pakanka.

Pradinė skaičiavimo registro TCNT0 reikšmė apskaičiuojama kaip skirtumas tarp maksimalaus laikmačio ciklų skaičiaus T0 ir reikiamo, ty 256 - 156 = 100. (256 yra maksimalus laiko intervalų skaičius, kurį turi bet koks 8 bitų laikmatis gali skaičiuoti.)

Manau, kad dabar aišku, kaip apskaičiuoti pradinę TCNT0 reikšmę normaliam režimui:

Apskaičiuokite vieno laikmačio ciklo laikotarpį Tt0 = k/Fcpu,
- apskaičiuokite reikiamą ciklų skaičių tam tikram intervalui n = t/Tto,
- apskaičiuokite pradinę skaičiavimo registro reikšmę TCNT0 = 256 - n.

Galite automatizuoti šią procedūrą naudodami makrokomandas. Pavyzdžiui, taip:

#define F_CPU 8000000UL
#define TIME_MS(laikas, k) (256L - ((laikas)*(F_CPU))/(1000L*(k)))

Tačiau naudojant tokią makrokomandą, reikia būti atsargiems, nes gali atsirasti klaidų dėl tam tikrų laiko ir k reikšmių.

Dabar pereikime prie kodo. Norėdami naudoti T0 laikmatį (ir bet kurį kitą), turite jį sukonfigūruoti (inicijuoti) ir aprašyti pertraukimų tvarkyklę (jei ji naudojama).

Laikmačio inicijavimas susideda iš šių veiksmų:

sustabdyti laikmatį,
- įprasto režimo nustatymas į TCCR0 neįjungus,
- nustatyti pradinę TCNT0 reikšmę,
- iš naujo nustatyti vėliavėles TIFR registre,
- įgalinti perpildymo pertraukimą TIMSK,
- išankstinio skirstytuvo nustatymas į TCCR0, tai yra, laikmačio pradžia

Ši seka gali keistis.

Mūsų užduočiai inicijavimo kodas atrodys taip:


/*reikšmė skaičiavimo registrui*/
#define T_POLL 100

TCCR0 = 0;
TCCR0 = (0<TCNT0=T_POLL;
TIFR = (1<TIMSK |= (1<TCCR0 |= (1<

Antroji inicijavimo eilutė iš tikrųjų yra nenaudinga, ji pridedama aiškumo dėlei. Kad aiškiai matytumėte, kuris laikmačio režimas yra nustatytas.

Pertraukimo vėliavėlės TIFR registre išvalomos įrašant 1 į atitinkamą bitą.Šią operaciją reikia atlikti tiksliai perrašant registrą, o ne naudojant bitinį ARBA. Ir štai kodėl.

Tarkime, TIFR registre nustatytos dvi pertraukimo vėliavėlės – TOV1 ir TOV0. TOV0 turime iš naujo nustatyti. Nustatydami reikiamą bitą su ORatsitinka toks dalykas.


//TIFR yra 0b00000101
// vėliavėlių rinkinys TOV1 ir TOV0
//kodas vykdomas TIFR |= (1<
//TIFR nukopijuotas į R16
IN R16, 0x38

//R16 bitų TOV0 nustatytas
// net jei jis jau įdiegtas
ORI R16, 0x02

//R16, lygus 0b00000101, įrašomas į TIFR registrą
OUT 0x38, R16

Dėl to abi vėliavėlės nustatomos iš naujo, o mes norėjome iš naujo nustatyti vieną.

Mes tęsiame.

Įvairių kompiliatorių pertraukimų tvarkyklių aprašymo sintaksė šiek tiek skiriasi. IAR atveju perpildymo įvykio T0 laikmačio pertraukimo tvarkyklė atrodys taip:



{
TCNT0=T_POLL;

/*mygtukų apklausa turėtų būti čia*/

TIMER0_OVF_vect yra perpildymo įvykio pertraukimo vektoriaus adresas. Jis paimtas iš antraštės failų mikrovaldiklyje. Šiuo atveju aš jį paėmiau iš iom16.h failo.

Pirmoji tvarkyklės eilutė (TCNT0 = T_POLL;) perrašo skaičiavimo registrą, tada nustato jo pradinę reikšmę. Jei tai nepadaryta, laikmatis toliau skaičiuos nuo 0. Skaičiavimo registro perrašymas turi būti atliktas pertraukimo tvarkyklės pradžioje.

Visas mūsų užduoties kodas atrodys maždaug taip. (Kodas skirtas IAR. Jei naudojate kitus kompiliatorius, turite pakeisti antraštės failus ir pertraukimų tvarkyklę.)

#įtraukti
#įtraukti
#įtraukti

#define T_POLL 100

int main (tuščia)
{
/*laikmačio inicijavimas*/

TCCR0 = 0;
TCCR0 = (0<TCNT0=T_POLL;
TIFR |= (1<TIMSK |= (1<TCCR0 |= (1<

/*likusių periferinių įrenginių inicijavimas*/
DDRB |= (1<

Įgalinti_pertraukti();
o (1);

/* pertraukimų tvarkytuvas T0
perpildymo įvykis*/
#pragma vektorius = TIMER0_OVF_vect
__interrupt void TimerT0Ovf(void)
{
/*perrašyti skaičiavimo registrą*/
TCNT0=T_POLL;

/*paspaudus mygtuką*/

/*invertuokite PB0 derinimui*/
PORTB ^= (1<

OC0 išėjimo valdymas

Įprastu režimu laikmatis T0 gali pakeisti OC0 kaiščio būseną, kai sutampa skaičiavimo registras ir palyginimo registras. Ir net be pertraukų. Valdymo parinktis apibrėžia TCCR0 registro COM01 ir COM00 bitai.

Štai programos, generuojančios kvadratinę bangą ant kaiščio OC0, pavyzdys.

#įtraukti
#įtraukti

int main (tuščia)
{
/*inicijuoti laikmatį T0*/

TCCR0 = 0;
TCCR0 = (0<TCNT0 = 0;
OCR0 = 0;
TIMSK = 0;
TCCR0 |= (1<

/*inicijuoti OC0*/
DDRB |= (1<

Nors(1);
grąžinti 0;
}

Išvestis OS0 pakeis savo būseną į priešingą, kai skaičiavimo registro vertė yra nulinė.

Keletas punktų apie laikmačio naudojimą

Laikmačio pertraukimo tvarkyklė (ir bet kuri kita išorinė įranga) turėtų būti kiek įmanoma trumpesnė.

Jei apskaičiuota skaičiavimo registro (arba palyginimo registro) reikšmė yra suapvalinta, laiko intervalą laikmatis skaičiuos su klaida.

Ir paskutinis. Gali atsitikti taip, kad laikmačio pertraukimo apdorojimas vėluoja (pavyzdžiui, dėl kito tvarkytojo kaltės) ir TCNT0 registras jau suskaičiavo kelis ciklus. Jei tiesiog perrašote TCNT0 reikšmę, kitas pertraukimas bus iškviestas vėliau nei būtina. Pasirodo, ankstesni (uždelsti) ir nauji pertraukimai neatlaikys reikiamo intervalo.

Šią situaciją galima išlyginti perrašant skaičiavimo registrą taip:

TCNT0 = TCNT0 + startValue;

Pridėjus dabartinę skaičiavimo registro vertę prie inicijuoto, bus atsižvelgta į šiuos papildomus ciklus.Tiesa, yra vienas BET! Esant didelėms startValue reikšmėms, sudėjimo operacija gali sukelti skaitiklio registro perpildymą.

Pavyzdžiui, startValue = 250, o laikmatis sugebėjo suskaičiuoti iki 10. Tada pridėjus veiksmą bus gautas toks rezultatas:

10 + 250 = 260

Iš 260 paimame 8 bitus, gauname 4. 4 bus įrašyti į TCNT0.


AVR mikrovaldiklių laikmačiai (realaus laiko laikrodis). AVR 7 pamoka

Kai dar pradėjau studijuoti mikrovaldiklius, norėjau padaryti . Sąžiningai, norėjau pabandyti televizorių įjungti tik nuo 7 iki 8 valandų, o likusį laiką jį reikėjo išjungti. Gaminau įrenginį, bet nenaudojau...

Visi AVR mikrovaldikliai turi kelis įmontuotus laikmačius. Juos taip pat galima suskirstyti į bendrosios paskirties laikmačius ir sarginį laikmatį, kuris skirtas iš naujo paleisti MK, kai jis užšąla.

Bendrosios paskirties laikmačiai gali:

  • Laikrodis rodomas iš išorinio laikrodžio kvarco 32768 hercų dažniu
  • Skaičiuokite skirtingus laiko intervalus
  • Skaičiuokite išorinius impulsus skaitiklio režimu
  • Sugeneruokite PWM signalą tam tikruose MK kaiščiuose
  • Generuokite tam tikro įvykio, pavyzdžiui, perpildymo, pertraukimus

Laikmačių skaitiklius galima stebėti iš vidinio laikrodžio generatoriaus ir skaitiklio įvesties. Pažvelkime į laikmačio-skaitiklio 1 funkcionalumą atmega8 mikrovaldiklyje. Paleidžiame CodeVision AVR, sukuriame naują projektą ir sutinkame su pasiūlymu paleisti Code WizardAVR

Naudokime laikmačio 2 pavyzdį, kad įdiegtume realaus laiko laikrodį su išvestimi į LCD ekraną, tam mes nustatome laikmatį, kaip parodyta ekrano kopijoje

čia nustatytas išorinis laikmačio laikrodžio šaltinis, kaip išorinį šaltinį naudosime 32768 hercų laikrodžio kvarcą, tada nustatysime išankstinį skirstytuvą į 128, tai yra, laikmatis veiks 32768/128 = 256 dažniu, o skaičiavimo registras yra 8 bitų (maksimalus skaičius 255), pasirodo, kad jis persipildys kartą per sekundę, tada pažymime langelį šalia Perpildymo nutraukimo ir spustelėkite failas-> Generuoti, išsaugoti ir išeiti.

Kodo vedlys sukūrė šį kodą

#įtraukti // Laikmačio 2 perpildymo nutraukimo paslaugos rutinos nutraukimas void timer2_ovf_isr(void) ( ) void main(void) ( // Įvesties/Išvesties prievadų inicijavimas // Prievado B inicijavimas PORTB=0x00; DDRB=0x00; // Prievado C inicijavimas PORTC=0x00; DDRC=0x00; // D prievado inicijavimas PORTD=0x00; DDRD=0x00; // Laikmatis/skaitiklis 0 inicijavimas // Laikrodžio šaltinis: sistemos laikrodis // Laikrodžio reikšmė: laikmatis 0 sustabdyta TCCR0=0x00; TCNT0=0x00; // Laikmatis /Skaitiklio 1 inicijavimas // Laikrodžio šaltinis: sistemos laikrodis // Laikrodžio reikšmė: 125 000 kHz // Režimas: Greitas PWM viršuje = 00FFh // OC1A išvestis: Discon. // OC1B išvestis: Discon. // Triukšmo slopintuvas: išjungtas // Įvestis Fiksavimas krintančioje briaunoje // Timer1 Overflow Interrupt: Off // Įvesties fiksavimo pertraukimas: Išjungtas // Palyginti A atitikties pertraukimas: Išjungtas // Palyginti B Match Interrupt: Off TCCR1A=0x01;TCCR1B=0x0A;TCNT1H=0x00;TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Laikmatis/skaitiklis 2 inicijavimas // Laikrodžio šaltinis: TOSC1 kaištis // Laikrodžio reikšmė: PCK2/128 Normalus viršus = FFh // OC2 išvestis: Atjungtas ASSR=0x08; TCCR2=0x05; TCNT2=0x00; OCR2=0x00; // Išorinio pertraukimo (-ų) inicijavimas // INT0: Išjungta // INT1: Išjungta MCUCR=0x00; // Laikmatis (-iai)/skaitiklis (-iai) Pertraukimo (-ų) inicijavimas TIMSK=0x40; // Analoginio palyginimo inicijavimas // Analoginis lygintuvas: išjungtas // Analoginio lygintuvo įvesties fiksavimas pagal laikmatį/skaitiklį 1: Išjungtas ACSR=0x80; SFIOR=0x00; // Visuotinis įjungimas pertraukia #asm("sei"), while (1) ( ); )

#įtraukti #įtraukti // Raidinio ir skaitmeninio LCD modulio funkcijos #asm .equ __lcd_port=0x12 ;PORTD #endasm #include unsigned char second=0; //kintamasis, skirtas sekundėms saugoti nepasirašytas simbolis minutė=0; //kintamasis, skirtas saugoti minutes nepasirašytas char valanda=0; //kintamasis valandoms saugoti char lcd_buffer; // kintamasis buferis išvesties į ekraną // Laikmačio 2 perpildymo nutraukimo paslaugos rutinos nutraukimas void timer2_ovf_isr(void) ( if (++second==59) // Padidinkite sekundžių skaičių 1 ir patikrinkite lygybę 59 (sekundė = 0 ; if (+ +minute==59) (minute = 0; if (++hour==59) (valanda = 0; ) ) ) lcd_clear(); //išvalyti ekraną prieš rodant lcd_gotoxy(0,0); / /nustatyti žymeklį į tašką x=0 y=0 sprintf(lcd_buffer,"%i:%i:%i",valanda,minutė,sekundė); // sudaryti išvesties eilutę lcd_puts(lcd_buffer); // rodyti eilutę ) void main( void) ( // Laikmačio/Skaitiklio 2 inicijavimas // Laikrodžio šaltinis: TOSC1 kaištis // Laikrodžio reikšmė: PCK2/128 // Režimas: Normalus top=FFh // OC2 išėjimas: Atjungtas ASSR=0x08; TCCR2=0x05; TCNT2=0x00; OCR2=0x00; // Laikmačio (-ių) / skaitiklio (-ių) pertraukimo (-ų) inicijavimas TIMSK=0x40; // LCD modulio inicijavimas lcd_init(16); // Visuotiniai įjungimo pertraukimai #asm ("sei") o (1 ) ( );)

Programa paruošta, dabar nubraižykime schemą „Proteus“.

Nauja vietoje

>

Populiariausias