6.6. Ajastin/laskuri - Timer/Counter 6.1.2008 pva, kuvat jma



Samankaltaiset tiedostot
6.2. AVR_rauta. Analogia-komparaattori-ohjelmointia , pva

6.3. AVR_rauta. EEPROM-muisti pva

Taitaja2005/Elektroniikka. 1) Resistanssien sarjakytkentä kuormittaa a) enemmän b) vähemmän c) yhtä paljon sähkölähdettä kuin niiden rinnankytkentä

7.3. Oheisrautaa. DS

5.6. C-kielen perusteet, osa 6/8, Taulukko , pva, kuvat jma

6.1. AVR_rauta. ADC-ohjelmointi pva, kuvat jma

ELEC-A4010 Sähköpaja Arduinon ohjelmointi. Jukka Helle

KILPAILIJAN TEHTÄVÄT ARVIOINTIOSA 5

Tällä ohjelmoitavalla laitteella saat hälytyksen, mikäli lämpötila nousee liian korkeaksi.

Digitaalitekniikka (piirit) Luku 15 Sivu 1 (17) Salvat ja kiikut 1D C1 C1 1T 1J C1 1K S R

Taitaja2007/Elektroniikka

Mikrokontrollerit. Mikrokontrolleri

LUKUJA, DATAA KÄSITTELEVÄT FUNKTIOT JA NIIDEN KÄYTTÖ LOGIIKKAOHJAUKSESSA

- Käyttäjä voi valita halutun sisääntulon signaalin asetusvalikosta (esim. 0 5V, 0 10 V tai 4 20 ma)

TAITAJA 2007 ELEKTRONIIKKAFINAALI KILPAILIJAN TEHTÄVÄT. Kilpailijan nimi / Nro:

Taitaja semifinaali 2010, Iisalmi Jääkaapin ovihälytin

- Käyttäjä voi valita halutun sisääntulon signaalin asetusvalikosta (esim. 0 5V, 0 10 V tai 4 20 ma)

Flash AD-muunnin. Ominaisuudet. +nopea -> voidaan käyttää korkeataajuuksisen signaalin muuntamiseen (GHz) +yksinkertainen

AUTO3030 Digitaalitekniikan jatkokurssi, harjoitus 2, ratkaisuja

Sulautettujen järjestelmien kilpailutehtävä

Sekvenssipiirin tilat

LUMA SUOMI -kehittämisohjelma LUMA FINLAND -utvecklingsprogram LUMA FINLAND development programme Ohjelmointia Arduinolla

Liikennevalot. Arduino toimii laitteen aivoina. Arduinokortti on kuin pieni tietokone, johon voit ohjelmoida toimintoja.

KÄYTTÖOHJE PEL 1000 / PEL 1000-M

S Elektroniikan häiriökysymykset. Laboratoriotyö, kevät 2010

Laitteita - Yleismittari

5.4. Sulautetun järjestelmän C-kielen perusteet. 4/8. Ohjausrakenteet pva

NiMH Laturi. Suunnittelu Olli Haikarainen

Ohjelmoitava magneettivastuksellinen kuntopyörä. LCD-Näyttö BC-81295

BL40A1711 Johdanto digitaaleketroniikkaan: Sekvenssilogiikka, pitopiirit ja kiikut

6. Analogisen signaalin liittäminen mikroprosessoriin Näytteenotto analogisesta signaalista DA-muuntimet 4

Taitaja2008, Elektroniikkalajin semifinaali

A/D-muuntimia. Flash ADC

Operaatiovahvistimen vahvistus voidaan säätää halutun suuruiseksi käyttämällä takaisinkytkentävastusta.

DC-moottorin pyörimisnopeuden mittaaminen back-emf-menetelmällä

TiiMi Talotekniikka. LATTIALÄMMITYS- TERMOSTAATTI TiiMi 7250TL. v. 1.0

Successive approximation AD-muunnin

Digitaalitekniikka (piirit), kertaustehtäviä: Vastaukset

Ajastin tarjoaa erilaisia toimintoja, kuten "Clock Display", "sekuntikello", "lähtölaskenta", "CountUp", "jaksoajastimen ja "Fight Gone Bad" -ajastin.

KÄYTTÖOHJE PEL 2500 / PEL 2500-M

Käyttöohje EMT757 / 3567 Ohjelmoitava digitaalinen kellokytkin

1 Muutokset piirilevylle

Ohjelmoinnin peruskurssi Y1

Ohjelmoitava päävahvistin WWK-951LTE

KÄYTTÖOHJE PEL / PEL-M

1. Yleistä. 2. Ominaisuudet. 3. Liitännät

Opas toimilohko-ohjelmointiin

KÄYTTÖOHJE HLS 35. Versio (6) TOIMINTOKAAVIO

Arduino. Kimmo Silvonen (X)

Q = pienin suunniteltu ilmamäärä ja k = puhaltimen tai iirispellin k-arvo.

Varauspumppu-PLL. Taulukko 1: ulostulot sisääntulojen funktiona

5.2. Sulautetun järjestelmän C-kielen perusteet 2/8, käsitteet pva

Verilogvs. VHDL. Janne Koljonen University of Vaasa

VLT 6000 HVAC vakiopaineen säädössä ja paine-erosäädössä. (MBS 3000, 0-10V)

Ohjelmoitava päävahvistin WWK-951. Anvia TV Oy Rengastie Seinäjoki

Radioamatöörikurssi 2015

LOPPURAPORTTI Lämpötilahälytin Hans Baumgartner xxxxxxx nimi nimi

ELEC-C6001 Sähköenergiatekniikka, laskuharjoitukset oppikirjan lukuun 10 liittyen.

Käyttäjän opas Kaukosäädin Invest Living ROOM 5

Näppäimistö CT Käyttäjäopas. Global Safety & Security Solutions Oy info@globalsafety.fi. CT1000v.5

ASM-kaavio: reset. b c d e f g. 00 abcdef. naytto1. clk. 01 bc. reset. 10 a2. abdeg. 11 a3. abcdg

KÄYTTÖOHJE HIRVIMATIC (2V0)

Kauko-ohjaimen käyttöohje. Part No.: R OM-GS (0)-Acson FAN SWING MODE TURBO TIMER OFF CANCEL. Acson A5WM15JR Acson A5WM25JR

OPERAATIOVAHVISTIN. Oulun seudun ammattikorkeakoulu Tekniikan yksikkö. Elektroniikan laboratoriotyö. Työryhmä Selostuksen kirjoitti

Nopeuden mittaaminen

Ongelma(t): Miten tietokoneen komponentteja voi ohjata siten, että ne tekevät yhdessä jotakin järkevää? Voiko tietokonetta ohjata (ohjelmoida) siten,

Toiminnallinen määrittely versio 1.2

10. Kytkentäohje huonetermostaateille

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

Kontrollerin tehonsäätö

Tämä on PicoLog Windows ohjelman suomenkielinen pikaohje.

OPERAATIOVAHVISTIMET 2. Operaatiovahvistimen ominaisuuksia

////// VENETIETO.FI \\\\\\ //// Autopilotti 2014 \\\\ //-PID säätimellä. #include <EEPROM.h> #include <SoftwareSerial.h>

Sangean PR-D4 Käyttöohjeet

ELEC-A4010 Sähköpaja Arduinon ohjelmointi. Peter Kronström

Digitaalitekniikka (piirit) Luku 14 Sivu 1 (16) Sekvenssipiirit. Kombinaatiopiiri. Tilarekisteri

Mittalaitetekniikka. NYMTES13 Vaihtosähköpiirit Jussi Hurri syksy 2014

ELEKTRONISET TOIMINNOT

2_1----~--~r--1.~--~--~--,.~~

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli


Telecrane F24 Käyttö-ohje

CROSSTRAINER (Model E 7000P)

TKT224 KOODIN KOON OPTIMOINTI

GSM OHJAIN FF KÄYTTÖOHJE PLC MAX S03

AU Automaatiotekniikka. Funktio FC

GREDDY PROFEC B SPEC II säätäminen

Arto Salminen,

PR SARJA ASENNUS JA KYTKENTÄ

KÄYTTÖOHJE ELTRIP-R6. puh fax PL Kajaani

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

MrSmart 8-kanavainen lämpötilamittaus ja loggaus, digitoija ja talletusohjelma

////// VENETIETO.FI \\\\\\ //// Autopilotti 2014 \\\\ #include <EEPROM.h> #include <SoftwareSerial.h> SoftwareSerial gps(10, 0); // RX, TX -pinnit

ROSSI-AVR Versio 1.1, päivitetty

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

AU Automaatiotekniikka. Toimilohko FB

1. Yleistä. Kuva 1. Graafinen ohjauspaneeli LCD-näytöllä. Taajuusmuuttajan tila. Panel Ready. 3 Motor Current 3.4 A PAINONÄPPÄIMET

DIGITAALINEN AJASTIN ULKOKÄYTTÖÖN

Digitaalilaitteen signaalit

padvisor - pikaohje - työkalu SATRON Smart/Hart dp- ja painelähettimiä varten

Transkriptio:

6.6. Ajastin/laskuri - Timer/Counter 6.1.2008 pva, kuvat jma "Everything should be made as simple as possible, but not simpler." - Albert Einstein Sisältö 1. yleistä 2. ajastin-timer 1 a. ylivuototila, overflow mode, mallikoodi b. vertailutila, compare mode, 2 mallikoodia c. kaappaustila, capture mode, mallikoodi d. pulssinleveysmodulaattori, PWM, 3. sovelluksia kello, 2 mallikoodia audio, 2 mallikoodia pitkä viive, long delay, mallikoodi 4. ajastin-timer2 32,768 khz, async mode, mallikoodi reaaliaikakello, Real Time Clock, RTC, mallikoodi pulssinleveysmodulaattori, PWM, mallikoodi Ajastimet, timerit, ovat mikro-ohjaimien ehdottomasti monimutkaisin ja samalla monipuolisin oheislaite.tarkempi tutustuminen niihin saattaa tuntua työläältä. Ja sitä se valitettavasti on! Mutta, jollet täsmälleen tiedä mitä milloinkin teet, siis mitä mikin rekisterin bitin asetus vaikuttaa toimintaan ja lopputulokseen, niin eivät siinä paljoa velhot auta. Mutta onneksi apua on tässä. Joten, jos aiot käyttää ajastin/laskuri-toimintoja tehokkaasti, seuraavat sivut tulee käydä läpi huolellisesti. Atmelin dokumentissa on perusteellinen selvitys timerin toiminnasta ja rekistereistä. Tutustu siihen, kunhan ensin olet perehtynyt tämän dokumentin olennaiseen osaamiseen ja timereitten perusohjelmointiin. 1

Yleistä Ajastin/laskuri lienee eniten käytetty mikro-ohjaimen oheispiiri, sillä sulautetuissa järjestelmissä ajan tai tapahtumien laskeminen ja erilaisten ohjauspulssien tekeminen ja mittaaminen ovat hyvin useasti tarvittavia toimintoja. Timer voi olla 8- tai 16-bittinen ja se voi laskea järjestelmän kellopulsseja tai ulkoisia tapahtumia. Timerin lähtö voi antaa pulsseja suoraan portin pinniin tai generoida keskeytyksen. Lue eteenpäin, niin kaikki selkiytyy. Ajastin-timer on oikeastaan yksinkertainen pulsseja laskeva laskuri. Mutta se on ohjelmoitava laskuri. Ajastin voidaan asettaa monenlaiseen eri toimintaan, modeen, ohjausrekistereitä sopivasti manipuloimalla. Toiminnan kannalta tärkeää on ymmärtää se, että laskenta tapahtuu muusta ohjelmakoodista riippumatta. Timer toimii itsenäisesti. Mutta samalla se tarvittaessa reagoi ulkoisiin oheislaitteisiin ja tapahtumiin ja ohjaa niitä koodin käskyjen määräysten mukaan. Ajastimia voidaan käyttää kahdella eri tavalla: - tarkan ajoituksen aikaansaamiseen (timer) - tapahtumien laskurina (counter) Ajastinta tarvitaan mm. - kun tehdään ajallisesti tarkkoja viiveitä riippumatta muusta koodista - erilaisten kellojen (mm. real time clock) tekemiseen - pulssien, kierrosluvun ja tapahtumien laskentaan - pulssin/tapahtuman keston mittaukseen - kun generoidaan taajuudeltaan erilaisia äänitaajuus- ym. signaaleja - taajuuksien jakamiseen - pulssin leveyden ohjaamiseen/säätämiseen tai mittaamiseen - aikataulullisesti tärkeät tapahtumat, kuten liipaisemaan ADC toimimaan juuri tiettynä aikana - mittaamaan aikaa kahden tapahtuman välillä - laskemaan alaspäin esiasetetusta arvosta kohti nollaa ja sitten generoidaan keskeytys - vahtikoiratoiminne - jne. 2

Pulssitaajuus vs. aika Pienin aika jonka timerilla voi mitata, on kahden laskettavan pulssin välinen aika. Esim. jos laskettavan signaalin pulssitaajuus on 100 Hz, niin Timer Resolution = (1 / taajuus) Timer Resolution = (1 / 100) Timer Resolution = 0,01 sekuntia Jos lasketaan vaikka 50 pulssia, kokonaisaika on 50 kertaa 0.01 sekunttia eli 0,50 sekuntia. Miksi erilaisia timereitä? Timer/ajastimia on ominaisuuksiltaan erilaisia. Toisissa on perustoiminteen eli ylivuototilan (overflow mode) lisäksi, vertailutoiminta (compare mode), jopa kaksikin, joissain voi olla kaappausominaisuus (capture mode) ja pulssinleveysmodulointi (PWM) monella eri tavalla, jne. AVR-ohjaimissa on lyhyeeseen laskentaan 8- ja pitkään laskentaan 16-bittiset ajastin/laskurit. Useimmissa, kuten ATmega32:ssa, 8-bittisiä on kaksi kappaletta, Timer 0 ja Timer 2 (sis. async toiminnon = oma kello) ja monipuolisin ominaisuuksin varustettu 16-bittinen Timer 1. Joskus tarvitaan erityisen pitkää ajastusta, silloin eri timereitä voidaan kytkeä toimimaan peräkkäin, kaskadoida. TCNT1, Timer/Counter1 Atmelin ATmega32-ohjaimen ajastintoimintojen ytimenä on TCNT1-rekisteri, joka koostuu rinnakkain kytketyistä kiikuista. Liittämällä 16 kpl kiikkuja yhteen saadaan 16-bittinen laskuri, jolla voidaan laskea nollasta (0x0000) aina 65536-1 (0xFFFF) asti. TCNT1 H bits 15 14 13 12 11 10 9 8 L bits 7 6 5 4 3 2 1 0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer Counter 1 Register Laskurina toimiva 16-bittinen rekisteri. Se laskee tavallisesti ylöspäin. Siihen voidaan asettaa alkuarvo. Timer Counter TCNT1 koostuu kahdesta 8-bittisestä rekisteristä, High ja Low. Resetoinnin jälkeen laskurin alkuarvo on nolla, siis sen kaikki bitit ovat nollia. Laskenta voidaa aloittaa siitä. Rekisteriä voidaan sekä lukea että siihen voidaan kirjoittaa mikä tahansa 16-bittinen luku. Eli laskennan alkuarvo on ohjelmoijan määritettävissä. Laskenta tapahtuu tavallisesti ylöspäin eli 0 -> 65535 = 0xFFFF. Kun laskuri on täynnä, siis 0xFFFF, niin seuraava tuleva pulssi aiheuttaa laskurin ylivuodon, 3

jolloin se nollaantuu ja aloittaa laskemisen alusta. PWM-modessa laskentasekvenssi voi olla myös alaspäin, 0xFFFF => 0. Timer/Counter1 perustoiminnat 1. Overflow Mode, ylivuototila 2. Compare Mode, vertailutila 3. Capture Mode, kaappaustila 4. Pulse Width Modulator Mode, pulssin leveyden modulointitila Kolme tapaa monitoroida ja reagoida timeriin 1. pollataan status flag keskeytyslippua, harvinainen tapa 2. hypätään ISR-keskeytysfunktioon, yleisin tapa 3. muutetaan timerin lähtöpinnin tilaa automaattisesti, helppo tapa Timerin toimintaan reagoidaan yleensä keskeytyksellä. Keskeytys on mahdollista: - timerin ylivuoto - vertailu, compare, timerin ja vertorekisterin välillä, matsaus = interrupt - input capture-, eli ICP-pin, kaappauskeskeytys ulkoisen pinnin tapahtumasta Kun timer-keskeytys on asetettu toimintaan, se toimii itsenäisesti jatkuvasti riippumatta itse koodista. Kuva 6.6.1. ATmega32 Timer/Counter lohkokaavio. 4

Laskuri laskee systeemin kellon generoimia pulsseja. Silloin käytössä on ajastintimer-toiminta. Yleensä tulevat pulssit viedään ensin esijakajaan, prescaler, joka ohjelmallisesti asetetaan jakamaan pulssit ennen varsinaiseen laskentaan menoa. Jakotaajuus valitaan ohjausrekisterillä TCCR1B. Jakotaajuuksien määritykset kerrotaan rekisterien esittelyn yhteydessä. Laskentapulssit voidaan tuoda myös ohjaimen ulkopuolelta T1-pinniin. Se on B-portin 1-bitti. Silloin puhutaan laskincounter-toiminnasta ja tapahtumien laskennasta. Kirjoittamalla rekisteriin nolla, laskuri nollataan. Kirjoittamalla sinne jokin muu arvo, ladataan laskuriin sopiva alkuarvo. Laskuri pysäytetään kirjoittamalla esijakajan jakoluvuksi nolla. Mikro-ohjaimiin liitettyjä ajastin/laskureita voidaan ohjelmallisesti kytkeä toimimaan erilaisissa toimintamoodeissa. Ne valitaan ohjausrekistereillä TCCR1A ja TCCR1B. Mahdolliset timerin generoimat keskeytykset valitaan TIMSK-rekisterin biteillä. Timerin kulloinenkin tila indikoidaaan TIFR-lippurekisterillä. Timerin eräs toimintatila on vertailutila, compare mode, joita varten on kaksi ohjausrekisteriä OCR1A ja OCR1B. Timerin tila tiettynä hetkenä voidaan kaapata ICR1- rekisteriin tuomalla ICP1-tuloon sopiva liipaisupulssi. Timerin toimintatiloja ovat mm: määrätään laskuri aloittamaan laskenta nollasta tai jostain tietystä ladattavasta alkuarvosta, load määrätään laskenta lopetettavaksi, kun laskuri on tullut täyteen, stop määrätään laskenta jatkumaan nollasta, kun laskuri on tullut täyteen, overflow mode verrataan laskurin arvoa johonkin ennalta määrättyyn arvoon, compare mode, ja siitä seuraa keskeytyspyyntö tai lähtöpinnin asetus, kaapataan, capture mode, jollakin tietyllä tapahtumalla tai ajanhetkellä laskurin arvo talteen eräs tärkeä timer-sovellus on vahtiajastin,watchdog Timer. jne. Laskurin askeltaminen voi tapahtua kahdella eri tapaa: Ajastin Timer toiminto: - laskee systeemin kellon pulsseja, eli mitataan aikaa. Laskuri Counter toiminto: - laskee ulkoiseen pinniin tuotuja oheislaitteista tulevia pulsseja, tapahtumia. Joissakin, kuten tässä ATmega32:ssa on mahdollisuus käyttää timerin kellokiteenä 32,768 khz kidettä, (sama kuin PC:n kello) jolla saadaan tarkkoja sekunteja. Timer2:n RTC-oskillaattori on optimoitu tälle kellokiteelle. 5

Miten timer startataan? Kirjoittamalla esijakajan jakoluvuksi joku muu kuin nolla. Miten timer stopataan? Kirjoittamalla esijakajan jakoluvuksi nolla. Timerin pollaus (kiertokysely) Aloitetaan timereihin tutustuminen yksinkertaisella pollausohjelmalla. Tässä ei pollata kesketyslippua vaan timerin tilaa, kuten koodista selviää. Pollaus-malli /********************************************************** Project : eka_timer_t1.c Date : 14.10.2007 Hardware: PV-M32 (4 MHz) + PV-LEDIT on PORTB Software: WinAVR-20070525 Author : pva Comments: Timer1, laskee pulsseja ja vilkuttelee LEDiä **********************************************************/ #include <avr/io.h> #define MASKI 1<<0 int main (void) DDRB = (1 << 0); // 0-bitti on output PORTB = 1<<0; TCCR1B = (1 << CS11); // timer laskee ja jakoluku clk/8 // kello on 4 000 000 Hx, siis 4'000'000 pulssia on 1 sek // jakoluku 8, 4000000/8 = 500'000 pulssia on 1 sek // 50'000 pulssia, 500'000/50'000 = 10 kertaa 1 sekunnissa for (;;) // pollataan timeria, // jos true = tosi eli saavuttanut arvon 50000, // käännetään LEDin tila, nollataan laskuri // ja aloitetaan laskenta alusta if (TCNT1 >= 50000) PORTB = PORTB ^ MASKI; // Toggle LED TCNT1 = 0; // nollaa timeri Analysointi Koodissa on timerin initialisointi hoidettu seuraavasti: 6

TCCR1B = (1 << CS11); // timer laskee ja jakoluku clk/8 // kello on 4 000 000 Hx, siis 4'000'000 pulssia on 1 sek // jakoluku 8, 4000000/8 = 500'000 pulssia on 1 sek // 50'000 pulssia, 500'000/50'000 = 10 kertaa 1 sekunnissa Ikuisessa silmukassa pollataan (=kysellään jatkuvasti) timerin arvoa ja kun se ylittää 50000, mennään muuttamaan=kääntämään B-portin bitin tila. Pollaten timerillä sekunteja tekemään /********************************************************** Project : eka_timer_t1_2.c Date : 14.10.2007 Hardware: PV-M32 (4 MHz) + PV-LEDIT on PORTB Software: WinAVR-20070525 Author : pva Comments: Timer1, laskee pulsseja ja vilkuttelee LEDiä **********************************************************/ #include <avr/io.h> #define MASKI 1<<0 int main (void) DDRB = 0xFF; // output PORTB = 1<<0; TCCR1B = (1 << CS12); // timer clk/256 // 4'000'000/256 = 15625 // eli 15625 pulssia on 1 sekunti for (;;) // jos sama, on laskettu 1 sek if (TCNT1 >= 15625) PORTB = PORTB ^ MASKI; // Toggle the LED TCNT1 = 0; // Reset timer Analysointi Tutki kommentteja. 7

Timer1, Ylivuototila, Overflow Mode Ajatellaanpa tilannetta, että asetamme laskurin laskemaan tulevia pulsseja nollasta ylöspäin. Kun laskuri tulee niin sanotusti täyteen (0xFFFF, laskuri on 16-bittinen), niin silloin kaikissa sen lähdöissä on ykkönen. Jos vielä tämän jälkeen tulee yksi pulssi kellotuloon, niin laskuri pyörähtää ympäri, rolls over ja ylivuotolähdössä, overflow output, näkyy pulssi, joka kertoo laskurin ylivuodosta. Tätä ylivuotopulssia voidaan käyttää ajastin/laskuri-keskeytyksen aktivoijana. Rolls overin jälkeen laskenta aloitetaan alusta, tavallisimmin nollasta. Tämä ylivuoto on tärkeä ominaisuus, siitä saadaan tieto laskurin täyttymisestä. Kun ylivuoto on tapahtunut, ylivuoto-lippu Timer Overflow Flag, TOV1, asettuu TIFR-rekisterissä Timer Interrupt Flag Register. Kuva 6.6.2. Timer/Counter1 Overflow Mode. Toiminta lyhyesti Timer/Counter1 TCNT1 laskee systeemin kellopulsseja, joko suoraan tai jakajan kautta tulevia. Toisaalta se voi laskea ulkoisia pulsseja (tapahtumia) jotka tuodaan T1- pinniin PB1. Jakajan jakoluku valitaan TCCR1B-ohjausrekisterillä. Laskurin ylivuoto aiheuttaa TOV1-keskeytyslipun asettumisen TIFR-lippurekisterissä. Jos TIMSKrekisterin TOIE1-bitti ja SREG-rekisterin I-bitti (global interrupt) on asetettu ( 1 ), siitä aiheutuu keskeytyspyyntö ja ohjelma siirtyy suorittamaan keskeytysaliohjelmaa, jonka formaatti on; ISR(TIMER1_OVF_vect) // jotain koodia 16-bittisen rekisterin käytöohje: Kirjoita ensin RHigh ja vasta sitten RLow Lue ensin RLow ja vasta sitten RHigh 8

Timer1 rekisterit, Ylivuototila, Overflow Mode Toimintaa ohjaavat ja muut tarvittavat rekisterit on esitelty seuraavassa. Huomaa, että eräät rekisterit ovat yhteiskäytössä, esim. TIMSK ohjaa muitakin toimintoja kuin overflow-keskeytystä ja muittenkin timerien eri toimintoja. TIMSK Bit 7 6 5 4 3 2 1 0 OCIE2 TOIE2 TCIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Interrupt Mask Register TOIE1, T/1 Overflow Interrupt 0: disable, 1: enable TIMSK-rekisterin TOIE1-bitin asetus ykköseksi ( 1 ) mahdollistaa ylivuotokeskeytyksen (jos globaali keskeytysbitti SREG-rekisterissä on 1 ). Init Value on bitin tila resetin jälkeen. Bitit, joita ei tarvita tässä yhteydessä on tummennettu. Kaikkien bittien tila voidaan joko lukea tai kirjoittaa, R/W, read/write. TCCR1B Bit 7 6 5 4 3 2 1 0 ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10 Read/write R/W R/W R R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Control Register B Tässä valitaan toimintatila ja kellopulssien jakoluku allaolevan taulukon mukaan. CS12 CS11 CS10 Kellon valinta 0 0 0 Stop, Timer 1 stopped 0 0 1 Järjestelmän kello, CK 0 1 0 Järjestelmän kello/8, CK/8 0 1 1 Järjestelmän kello/64, CK/64 1 0 0 Järjestelmän kello/256, CK/256 1 0 1 Järjestelmän kello/1024, CK/1024 1 1 0 Ulkoinen T1-pinni, laskee laskevasta reunasta 1 1 1 Ulkoinen T1-pinni, laskee nousevasta reunasta Timeriin menevien kellopulssien jakoluku valitaan CS12, CS11 ja CS10 biteillä ylläolevan taulukon mukaan. Timer overflow - timer on tullut täyteen, 0xFFFF - ja seuraava pulssi aiheuttaa timerin nollaantumisen, 0x0000. 9

TIFR Bit 7 6 5 4 3 2 1 0 OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCF0 TOV0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Interrupt Flag Register TOV1, Overflow Flag asettuu, kun timer overflow nollaantuu, kun keskeytysfunktio ajetaan Timer Interrupt with a Maximum Accuracy, ovrflow mode Tavallisesti Timer-keskeytys ei ala välittömästi kun Timer Overflow-ylivuoto tapahtuu. AVR nimittäin tarvitsee aikaa hoitaakseen edellisen käskyn ensin valmiiksi. Aika voi vaihdella nollasta kolmeen kellopulssiin riippuen työn alla olevasta käskystä ja hetkestä jolloin ylivuoto tapahtuu. Tästä voi tulla ongelmia, jos tarvitaan ehdotonta tarkkuutta. Muutama korjausehdotus: Kirjoita yksinkertaista koodia. Saatat pärjätä jopa ilman timeriä tai keskeytystä. Käytä SLEEP komentoa ja AVR menee Idle mode 0:n sähkönsäästötilaan. Kun nyt overflow tapahtuu, se herättää AVR:n ja ajaa suoraan keskeytysohjelman. Tällöin AVR:llää ei ole edellistä käskyä viimeisteltävänä joten keskeytys käsitellään välittömästi. Voit lukea timerin ja tutkia paljonko aikaa on kulunut ennenkuin ylivuoto ilmeni. Voit kompensoida ajan ajamalla extra käskyjä ennen kriittistä koodia. Timer1 overflow-ylivuoto mallikoodi /********************************************************** Project : timer1_ovf_1.c Date : 10.12.2007 Hardware: PV-M32 (4 MHz) + PV-TINT Software: WinAVR-20070525 Author : pva Comments: Timer1, overflow mode keskeytystoiminne, vilkuttelee PD.4 RED-LED (OC1B) **********************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #define MASKI 1<<4 void wait(uint16_t time); // function prototype ISR(TIMER1_OVF_vect) PORTD = PORTD ^ MASKI; // invertoi PD.4 eli RED-LED void Timer_init(void) TCCR1B = (1<<CS11) (1<<CS10); // timer start, jakoluku CLK/64 TIMSK = 1 << TOIE1; // TOIE1, timer1 overflow interrupt enable 10

int main(void) DDRD = 1<<4; // RED-LED PORTD = 1<<4; // 0001 0000 Timer_init(); sei(); // Global Interrupt Enable while(1) ; While-silmukassa ei tehdä mitään, kulutetaan vain aikaa. Itse LEDin vilkutuksen hoitaa ylivuotokeskeytysfunktio TCNT1-timerin ohjaamana. Jakolukua muuttamalla voidaan LEDin vilkkumistaajuutta muuttaa. Se tapahtuu TCCR1B-rekisterin CSbittejä manipuloimalla. 2. Timer 1, Vertailutila, Output Compare mode Eräs tyypillisiä timer/counterin käyttötapoja on vertotila eli Output Compare Mode. Tässä toiminnossa verrataan kaiken aikaa TCNT1-timerin ja vertailurekisterin OCR1A (tai OCR1B) arvoja. Kun ne matsaavat eli ovat yhtäsuuret, niin seuraavalla kellopulssilla TIFR-lippurekisterin Output Compare Flag-lippu asettuu. Jos Output Compare Interrupt-keskeytys on määritetty (ja globaali keskeytysbitti sen sallii), hypätään keskeytysfunktioon ISR(TIMER1_COMPA_vect) tai ISR(TIMER1_COMPB_vect) Kuva 6.6.3. Timer Counter Output Compare Mode. Keskeytysohjelma nollaa OCF1x-lipun automaattisesti. Se voidaan tehdä myös ohjelmallisesti kirjoittamalla looginen ykkönen ko. bittiin. 11

Toinen Compare Match Moden toimintatapa on se, että matsaustoiminne asettaa, nollaa tai invertoi automaattisesti ilman eri asetuksia timerin lähtöpinnin OC1A (tai OC1B). Tällä ominaisuudella voidaan helposti generoida eritaajuisia suorakulma- eli kanttipulsseja. Niistä voidaan suodattamalla kehitellä vaikka audiotaajuisia siniaaltoja. Lähtöportin suuntarekisterin vastaava pinni, OC1A = PD.5 ja OC1B = PD.4 täytyy asettaa ulos-out eli ykköseksi. Tämä on edullinen toimintamode siinä suhteessa, että se toimii itsenäisesti taustalla, eikä vie prosessoriaikaa. Timer 1 Output Compare Mode rekisterit Toimintaa ohjaavat ja muut tarvittavat rekisterit on esitelty seuraavassa. Huomaa, että tässä on esitetty vain ne rekisterit ja ne bitit jotka ovat käytössä Compare Modessa. OCR1A/B H bits 15 14 13 12 11 10 9 8 L bits 7 6 5 4 3 2 1 0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Output Compare Register 1 A/B Vertailurekisterien vertoarvo. OCR1A- tai OCR1B-rekisteriin kirjoitetaan vertailuarvo. Kun timerin arvo on vertoarvon kanssa yhtä, hypätään joko keskeytysohjelmaan tai muutetaan OC1A/Blähtöpinnin tila. TCCR1A Bit 7 6 5 4 3 2 1 0 COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10 Read/write R/W R/W R/W R/W W W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Control Register A Määritetään normal operation tai OC1A/OC1Blähtöpinnnin käyttö COM1A1/COM1B1 COM1A0/COM1B0 Kuvaus 0 0 Normal port operation, OC1A/OC1B disconnected 0 1 Toggle OC1A/OC1B on compare match 1 0 Clear OC1A/OC1B on compare match, Out = 0 1 1 Set OC1A/OC1B on compare match, Out = 1 WGM13 WGM12 WGM11 WGM10 T/C Mode of Operation TOP Update of OCR1x 0 0 0 0 Normal 0xFFFF 0 1 0 0 CTC, Clear Timer on Compare match OCR1A Immediate 12

Katso tarkemmin Atmelin doc2503.pdf-dokumentin taulukkoa Table 47 sivulla 109, Waveform Generation Mode Bit Description. TCCR1B Bit 7 6 5 4 3 2 1 0 ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10 Read/write R/W R/W R R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Control Register B Tässä valitaan toimintatila ja kellopulssien jakoluku allaolevan taulukon mukaan. CS12 CS11 CS10 Kellon valinta 0 0 0 Stop, Timer 1 stopped 0 0 1 Järjestelmän kello, CK 0 1 0 Järjestelmän kello/8, CK/8 0 1 1 Järjestelmän kello/64, CK/64 1 0 0 Järjestelmän kello/256, CK/256 1 0 1 Järjestelmän kello/1024, CK/1024 1 1 0 Ulkoinen T1-pinni, laskee laskevasta reunasta 1 1 1 Ulkoinen T1-pinni, laskee nousevasta reunasta TIMSK Bit 7 6 5 4 3 2 1 0 OCIE2 TOIE2 TCIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Interrupt Mask Register OCIE1A/B, Output Compare A/B Match Interrupt Enable 0: disable, 1: enable TIMSK-rekisterin OCIE1A/B-bitin asetus mahdollistaa Output Compare Mode keskeytyksen. TIFR Bit 7 6 5 4 3 2 1 0 OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCF0 TOV0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Interrupt Flag Register OCF1A/B, Output Compare A/B Match Flag Lippu asettuu kun timer matsaa vertoarvon kanssa ja nollaantuu, kun interrupt ajetaan TCNT1-timerin ja vertailurekisterin arvon ollessa sama TIFR-rekisterin vastaava lippu, OCF1A tai OCF1B asettuu. Note that reading a 16-bit OCR register does not use the TEMP register; writing a 16-bit OCR register does. 13

CTC, Clear Timer on Compare Match Mode Toinen Output Compare Match toiminne on CTC, Clear Timer On Compare Match. Tässä toiminnassa laskuri laskee normaalisti ylöspäin. Kun timerin arvo on sama kuin OCR1A-vertorekisterin, timer nollataan ja laskenta alkaa alusta. Samalla lähtöpinni OC1A voidaan asettaa ykköseksi, tai se voidaan nollata tai sen tila invertoida, toggletoiminto. Ko. lähtöpinnin eli siis D-portin 5-bitin suunta on oltava ulos-out, siis ko. bitti on suuntarekisterissä DDRD oltava 1. TCNT1 nollaantuu kun TCNT1 == OCR1A tai ICR1 CTC mallikoodi, ilman keskeytystä /********************************************************** Project : kello_malli.c Hardware: PV-M32 (4 MHz) + PV-LEDIT on PORTD Software: WinAVR-20070525 Date: 08.10.2007 Author: pva Comments: Timer1, compare-mode PD.5 vilkkuu 1 sek välein **********************************************************/ #include <avr/io.h> int main (void) DDRD = 1<<5; // OC1A = out OCR1A = 15625; // vertoarvo TCCR1A = _BV(COM1A0); // toggle OC1A = PD.5 TCCR1B = _BV(CS12) 1<<WGM12; // clk/256 = 4000000/256 = 15625 ==> 1 sek // 1<<WGM12 = CTC = Clear Timer on Compare Match for(;;) // ikuinen ; Analyysi Timer1 OC1A-lähtö invertoidaan aina kun timer1 ja OCR1A-rekisterin arvo ovat yhtäsuuret. Samalla timer1 nollataan ja aletaan alusta. Jakoluku on 256 eli kun vertailuarvo 15625 saavutetaan, on kulunut 1 sekunti. CTC mallikoodi, keskeytyksellä /********************************************************** Project : kello_malli_interrupt.c Date : 08.10.2007 Hardware: PV-M32 (4 MHz) + PV-LEDIT on PORTD Software: WinAVR-20070525 Author : pva Comments: Timer1, output compare match mode CTC, Clear Timer1 on Compare Match vilkuttelee = toggle PD.5 (OC1A) 1 sek. **********************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #define MASKI 1<<5 14

ISR(TIMER1_COMPA_vect) PORTD = PORTD ^ MASKI; // XOR void Timer_init(void) TCCR1A = 0x00; // timer normal operation TCCR1B = (1<<WGM12) (1<<CS12); // WGM12 = CTC1 = Clear Timer1 on Compare Match // CS12 ==> jakoluku CLK/256 TIMSK = 1 << OCIE1A; // OCIE1A = bit5, // Timer1 Output Compare A Match Interrupt Enable uint16_t verto = 15625; OCR1A = verto; int main(void) DDRD = 1<<5; PORTD = 1<<5; Timer_init(); sei(); // global keskeytys sallittu while(1) ; Analysointi Rekisterien initialisoinnin (alkuasetukset) yhteydessä määritetään toimintamode ja keskeytys. Sen jälkeen laskuri laskee ylöspäin. Kun TCNT1 ja vertoarvo ovat samat, hypätään keskeytysohjelmaan ja käännetään LEDin tila PORTD = PORTD ^ MASKI; // XOR // invertoi PD.5 3. Kaappaustila, Input Capture Mode Kun käytössä on timerin kaappaustoiminto, siinä tietyn ulkoisen pinnin tilan muutos saa aikaan toiminnon, jossa timerin sen hetkinen tila kaapataan talteen erityiseen kaappausrekisteriin. Muutoksen indikointi on ohjelmoitavissa, se voi olla ylös- tai alaspäin aktiivinen. Kaappaustoiminnan avulla voidaan mitata pulssien pituuksia, kahden pulssin välinen aika, signaalin taajuutta, tai laskea vaikka moottorin kierrosluku, ym. Capture- eli kaappaustila tarkoittaa ajastimen/ laskurin toimintaa siten, että laskurin laskiessa vapaasti tietty ulkoinen liipaisutieto voi siirtää laskurin sen hetkisen arvon erilliseen rekisteriin myöhempää käsittelyä varten. Kaappausmodessa laskuri laskee jatkuvasti from BOTTOM to MAX. BOTTOM on 0x0000 ja MAX on 0xFFFF. Kellopulssit valittavissa kuten edellä on kerrottu. 15

Jos AVR-ohjaimen ICP1-pinniin (PD.6) tuodaan pulssin laskeva tai nouseva reuna liipaisupulssiksi, se aiheuttaa laskurin kaappauksen, capture. TCNT1-laskurin liipaisuhetken tila kopioidaan kaappausrekisteriin Input Capture Register, ICR1. Samaan aikaan Capture Flag ICF1 asettuu TIFR1-lippurekisterissä. Jos keskeytys on määritetty, ohjelmassa hypätään keskeytysohjelmaan. ICR1-rekisteri on vain luettavissa ja se on luettava talteen välittömästi, koska seuraava bittiarvo on mahdollisesti jo tulossa ja se kirjoittaa rekisterin uusiksi. Rekisterin taltiointi tapahtuu keskeytysohjelmassa. Kuva 6.6.4. Input Capture-mode, kaappaustoiminta. Esijakajan toiminnan määritys tapahtuu ohjausrekisterillä, samoin input-multiplekserin ohjaus ja muut capture-toiminnan asetukset. TCCR1B-rekisterin ICES1- bitti, input capture edge select bit, määrittää liipaisun suunnan pinnissä ICP = PD.6 ja itse liipaisu määrittää kaappaushetken ajankohdan. Jos se on 1, kaappaus tapahtuu ylösnousevalla pulssilla, jos se on 0, laskevalla reunalla. Liipaisu voidaan aktivoida myös analogia-komparaattorin avulla, asettamalla ACIC-bitti ykköseksi ACSRrekisterissä. Lisää toiminnasta mallikoodissa. ICNC1 on ICP-inputin, Input Capture Noice Canceller, kohinan suodatin. Se estää häiriöiden vaikutuksen ICP-pinniin. Häiriöt saattavat johtaa siihen, että kaappaus voi tapahtua väärään aikaan. Tulosignaalista otetaan 4 näytettä, ennen kuin sieppaus liipaistaan. 16

Kun timerin arvon sieppaus tapahtuu, on tiedettävä, onko se tapahtuman alku vai loppu. Tapahtuman alussa laskurin arvo käydään kaappaamassa, capture ja tapahtuman lopussa tehdään sama temppu. Kummatkin kaappausarvot on talletettava omaan muuttujaansa. Kun jälkimmäinen arvo vähennetään ensimmäisestä arvosta, saadaan tapahtumaan kulunut aika, kunhan tunnetaan pulssin kesto. AVR ATmega32, Timer/Counter 1, Input Capture -rekisterit ICR1 Input Capture Register 1 H bits 15 14 13 12 11 10 9 8 L bits 7 6 5 4 3 2 1 0 Read/write R/W R/W R/W R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Kaappausrekisterin on oltava 16-bittinen kuten TCNT1. Kaappausrekisteri, Input Capture Mode TCCR1B Bit 7 6 5 4 3 2 1 0 ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10 Read/write R/W R/W R R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Control Register B Tässä valitaan toimintatila ja kellopulssien jakoluku allaolevan taulukon mukaan. CS12 CS11 CS10 Kellon valinta 0 0 0 Stop, Timer 1 stopped 0 0 1 Järjestelmän kello, CK 0 1 0 Järjestelmän kello/8, CK/8 0 1 1 Järjestelmän kello/64, CK/64 1 0 0 Järjestelmän kello/256, CK/256 1 0 1 Järjestelmän kello/1024, CK/1024 1 1 0 Ulkoinen T1-pinni, laskee laskevasta reunasta 1 1 1 Ulkoinen T1-pinni, laskee nousevasta reunasta Bitti Nimi Merkitys Toiminto 7 ICNC1 Input Capture Noise Canceler, kohinan ICP1: 0: disable, 1: activate suoto 6 ICES1 Input Capture Edge Select, kaappausmoden valinta ICP1: 0: laskeva reuna, 1: nouseva reuna 17

TIMSK Bit 7 6 5 4 3 2 1 0 OCIE2 TOIE2 TCIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0 Init. value 0 0 0 0 0 0 0 0 Timer/Counter Interrupt Mask Register TICIE1 Timer/Counter1 Input Capture Interrupt Enable 0: disable, 1: enable TIMSK-rekisterin TCIE1-bitin asetus mahdollistaa timerin arvon kaappauksen. TIFR Bit 7 6 5 4 3 2 1 0 OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCR0 TOV0 Init. value 0 0 0 0 0 0 0 0 Timer/Counter Interrupt Flag Register ICF1 Input Capture Flag1 Kun ICP1 aktivoi kaappauksen, asettuu (1). Nollautuu (0), kun Input Capture Interrupt Vector is executed. Mitataan kahden tapahtuman välinen aika: - kun tapahtuma1 tapahtuu, talleta timer arvo as K - kun tapahtuma2 tapahtuu, lue timer arvo ja vähennä K - ero on aika kahden tapahtuman välillä Capture Mode, Kaappaustila, mallikoodi /********************************************************** Project : timer1_capture.c Hardware: PV-M32 (4 MHz) + PV-EMO Software: WinAVR-20070525 Date: 06.10.2007 Author: pva Comments: Timer1, capture-mode Painele S4-nappia. Se tuo Input Capture-pinniin ICP=PD6 +5 V laskevan reunan. Tulostus => LCD. lcd_tat.c ja lcd_tat.h tiedostojen on oltava samassa hakemistossa kuin käännettävä koodi **********************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include "lcd_tat.h" // Timer1 capture-mode keskeytys ISR(TIMER1_CAPT_vect) uint16_t kaappa = 0; kaappa = ICR1; LCD_SetCursorXY(0, 1); printf("a: %.5d", kaappa); // <--- did the trick!! TCNT1 = 0; // aloitetaan alusta 18

void Timer_init(void) TCCR1B = (1<<CS12) (1<<CS10); // laskevasta reunasta kaappaa, jakoluku 1024 TIMSK = 1<<TICIE1; // Enable Timer1 Capture Interrupt int main(void) DDRC = 0xFF; Timer_init(); LCD_init(1, 0, 0); // Otetaan prinft()-funktio käyttöön siten, että tulostus // ohjataan LCD_WriteChar()-funktioon = LCD-näytölle. fdevopen((void *) LCD_WriteChar, NULL); LCD_WriteString("Capture_reg:"); sei(); // globaali keskeytyksen sallinta while(1) ; // ei tehdä mitään Analysointi Tämä on vain yksinkertainen demo-ohjelma, jonka toiminta selviää kommenteista. TIMSK kummankin timerin (T0/T1) erilaisten keskeytysten esto/sallinta TIFR Keskeytysliput (T1) TCCR0/TCCR1A/B esijakajan asetukset ulkoisen pinnin reunan indikointi modes on/ei (output compare, input capture, PWM) OCR1A/B (T1 only) vertailuarvo, johon timer1:n arvoa verrataan, kun sama -> keskeytys ICR1 (T1 only) Nouseva tai laskeva reuna kaappauspinnissä ICP1 aikaansaa sen, että senhetkinen timer1 arvo kaapataan tähän rekisteriin. Samaan aikaan ICF1-lippu asetetaan 1. Keskeytys, jos sallittu. 19

Sovelluksia 1. Kello Kello on tyypillinen timerilla tehtävä sovellus. /***************************************************************** Project : Teemun_kello.c Hardware: PV-M32 (4 MHz) + PV-EMO Software: WinAVR 20070525 Date : 14.10.2003 + 24.07.2005_pva & 1.6.2006 Author : Teemu Varpula 0103513 + pva update 05.11.2007 Comments: Tulostaa kellon h.min.s.sadasosat ******************************************************************/ #include <avr/io.h> #include <stdio.h> #include <avr/interrupt.h> #include "lcd_tat.h" #define TAUSTAVALO 1<<0 // globaalit muuttujat uint8_t tunnit=0, minuutit=0, sekunnit=0, sadasosat, msekunnit=0; ISR(TIMER1_OVF_vect) TCNT1H = 0x63; // Write High First TCNT1L = 0xC0; // // laskenta alkaa 0x63C0=25536 -> 40000 = 65536 eli timer "täynnä" // 40000*1/4usek = 10 ms, keskeytys tulee 10 ms välein = sadasosat sadasosat++; if(sadasosat==100) // Kun sadasosat tulevat täyteen sekunnit++; sadasosat = 0; // aloitetaan laskut alusta if(sekunnit==60) minuutit++; sekunnit = 0; if(minuutit==60) tunnit++; minuutit = 0; if(tunnit==24) tunnit = 0; void Timer_init(void) TCCR1B = 1<<0; // Lähteeksi Järjestelmän kello, CK TIMSK = 1<<TOIE1; // T/C1 overflow interrupt enable TCNT1H = 0x63; TCNT1L = 0xC0; 20

int main(void) DDRC = TAUSTAVALO; PORTC = TAUSTAVALO; Timer_init(); LCD_init(1, 0, 0); sei(); // Global interrupt enable while(1) LCD_SetCursorXY(0, 0); LCD_WriteString("Kello:"); LCD_SetCursorXY(0, 1); fdevopen((void *) LCD_WriteChar, NULL); // Ohjataan oletuslaitteeksi LCD_WriteChar printf(" %d:%d:%d:%d", tunnit, minuutit, sekunnit, sadasosat); 21

2. Audio Osoituksena mitä kaikkea Timer1:n ajastin/laskuri-toiminnolla voi tehdä, esimerkkinä ohjelma, joka tekee laskurista audiogeneraattorin. Se tapahtuu ohjelmoimalla Timer1 siten, että se ohjaa OC1A/OC1B-liitäntään halutun taajuista kanttiaaltoa. Viemällä tämä signaali vahvistimeen ja edelleen kaiuttimeen, saadaan, ohjelmasta riippuen, kuulumaan erilaisia audiotaajuuksia. PV-TINT-kortilla voi tehdä audiota. Toinen tapa tehdä ääniä on ottaa tavallinen 4 ohmin kaiutin, kytkeä sen toinen johdin PV-EMO-kortin +5V napaan ja toinen johdin noin 100 ohmin sarjavastuksen kautta OUT2- tai OUT3-naparuuvin alle (katso ohjetta koodissa). Tässä mallikoodi miten tehdään timerilla 1000 Hz:n audiosignaali /********************************************************** Project : 1000Hz.c Hardware: PV-M322 (4 MHz) + PV-EMO + kaiutin tai PV-TINT Software: AVRStudio4.13 + WinAVR-20071221 Date : 02.01.2008 Author : pva Comments: Kytke 100R vastus 4R kaiuttimen kanssa sarjaan, liitä kaiuttimen johto +5V ja vastuksen johto OUT2=PD5=OCR1A tai käytä PV-TINT-korttia 4 MHz kello, 1/4 us pulssit, 1000Hz=> 1ms pulssit 4000 pulssia = 1 ms = 1000Hz Pulssi on "0" ja "1" tasot, eli kun laskuri laskee 2*2000 pulssia saadaan 1 khz audiosignaali. **********************************************************/ #include <avr/io.h> int main(void) DDRD = 1<<PD5; // aseta PD5 = OCR1A output OCR1A = 2000; // vertorekisteriin TCCR1A = 1<<COM1A0; // OC1A-pin toggles on compare match TCCR1B = 1<<CS10; // start timer1 without prescaler TCCR1B = 1<< WGM12; // CTC, Clear Timer on Compare match for(;;) // loop forever 22

Analysointi 1/s on Hz 1000/s on khz 1 jakso on 0 ja 1, kumpikin kestää 0,5 ms, yht 1 ms, saadaan 1000 per sek. 4 MHz kello on ¼ us per pulssi 1/8us 1 + 1/8us 0 jakso on ¼ us näitä 1000 saadaan 1 ms joka on 1000 Hz Skooppikuvat on otettu PD5-pinniin kytketyn transistorin kollektorilta. Kuten skooppikuvista näkee, PD5-pinni on 0.5 ms alhaalla ja 0.5 ms ylhäällä, eli yksi pulssi kestää 1 ms joka vastaa 1000 Hz:n taajuutta (1 khz). Audiosignaaleja generoimalla oppii timereitten toimintaa havainnollisesti. Kaksois-audio /******************************************************************** Project : kaksois_audio.c Date : 21.10.2007 Hardware: PV-M32 (4 MHz) + PV-TINT Software: WinAVR-20070525 Author : pva Comments: Timer1, output compare B match mode jolloin tarvitaan keskeytystoiminne ja keskeytysfunktiossa timeri on nollattava output compare A mode, output toggle OC1A toggle ja OC1B keskeytyksen kautta ohjaavat kaiutinta ********************************************************************/ 23

#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define MASK_2 1<<4 // function prototype void wait(uint16_t time); ISR(TIMER1_COMPB_vect) TCNT1 = 0; static uint16_t lasku = 0; lasku++; if(lasku > 2000) PORTD = PORTD ^ MASK_2; // käännetään kaiutinta ohjaavan transistorin ohjaus ON/EI lasku = 0; void Timer_init(void) TCCR1A = 1 << COM1A0; // ajastin-toiminta ja compare mode select // toggle to output line = OC1A, jossa on kaiutin // eli lähtö vaihtelee (101010..) // Toggle OC1A on compare match OCR1A = 300; // ON/EI OCR1B = 320; // keskeytykseen ja timer1 nollaus TCCR1B = 1<<CS10; // timer start // CS10 = 1 ==> jakoluku CLK/1 TIMSK = 1 << OCIE1B; // OCIE1B = b4, Output Compare A Match Interrupt Enable int main(void) DDRD = 1<<5; // kaiutin on täällä DDRD = 1<<4; // ja täällä PORTD = 1<<4; // 0001 0000 PORTD = 1<<5; Timer_init(); sei(); // Global Interrupt Enable while(1) // wait(2); // vaatii toimiakseen pienen viiveen // "jotta timeri ehtii mukaan" Analysointi 24

Kolmas esimerkki samasta asiasta, kannattaa tutkia kommentteja, niistä selviää mitä tehdään ja mitä on tehtävissä. /********************************************************** Project : sireeni.c Date : 05.12.2007 Hardware: PV-M32 (4 MHz) + PV-TINT Software: WinAVR-20070525 Author : pva Comments: Timer1, Output Compare Match Mode ==>> sireeni OC1A invertoidaan kun "matsaa" CTC Clear Timer On Compare Match **********************************************************/ #include <avr/io.h> #include <util/delay.h> // function prototype void wait(uint16_t time); void Timer_init(void) TCCR1A = 1<<COM1A0; // ajastin-toiminta ja compare mode select // toggle to output line = OC1A, jossa on kaiutin // Toggle OC1A/OC1B on compare match TCCR1B = (1<<WGM12) (1<<CS10); // CS10 = 1 ==> jakoluku CLK/1 // kun WGM12 eli CTC-bitti on 1, // T/C1 resetoidaan 'after compare match' int main(void) DDRD = 1<<5; // kaiutin on täällä uint16_t pwm = 500; // määrää audion ylärajataajuuden Timer_init(); while(pwm) wait(1); // pieni viive, jotta timer ehtii mukaan pwm++; OCR1A = pwm; if(pwm > 3000) // määrää audion alarajataajuuden pwm = 500; Analysointi 25

3. Reaktioaika testeri Tästä saat pienen pelin, jolla voit järjestää kilpailuja kavereitten kesken. /********************************************************** Project : reaktio_aika_m32.c, Hardware: PV-M32, 4 MHz + PV-EMO Software: WinAVR-20070525 Date : 11.11.2007 Author : pva Comments: mittaa rektioajan, Paina S1 1 sek ajan Kopioi lcd_tat.c ja lcd_tat.h koodin kansioon. Paina hiiren oikealla Source Files, Add Existing...lcd_tat.c **********************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "lcd_tat.h" #define WAIT(time) for(uint16_t i=0;i<2000;i++)_delay_loop_2(time); void Timer_init(void) TCCR1B = 0x00; // Timer stopped TIMSK = 1<<TOIE1; // T/C1 Overflow interrupt enable // Timer1 ylivuotokeskeytys // Tänne mennän jos testaaja "nukahtaa" ISR(TIMER1_OVF_vect) TCCR1B = 0x00; // Timer1 stopped LCD_SetCursorXY(0, 2); LCD_WriteString("ylitit ajan"); int main(void) DDRC = 1<<1; PORTD = (1<<2) (1<<3); uint16_t laskuri = 0; Timer_init(); LCD_init(1, 0, 0); LCD_WriteString("Paina S2 1s ajan"); sei(); // Global Interrupt Enable loop_until_bit_is_clear(pind, 2); TCCR1B = 1<<CS12 1<<CS10; // Timer1 ON, clk/1024 PORTC = 1<<1; // RED-LED ON WAIT(5); // kytkinvärähtelyjen eliminointi loop_until_bit_is_set(pind, 2); TCCR1B = 0x00; // Timer1 stopped PORTC &= ~(1<<1); // RED_LED OFF laskuri = TCNT1/6; LCD_SetCursorXY(0, 2); LCD_WriteUINT(laskuri); Analysointi. Kommentit kertovat olennaisen. 26

Paina S2-nappia 1 s ajan, ja vapauta kytkin. Kuka osaa arvoida ajankulun parhaiten ja pääsee lähemmäksi 1000 ms aikaa, on voittaja. Ohjelma on tarkoituksella keskeneräinen, jotta voit parantaa sen ulkoasua, LCDnäyttöön tulevia ohjeita ja tulostuksia mieleiseksi. Pitkä viive, Long delay Joskus on tarvetta pitkälle viiveelle. Silloin on neljä mahdollisuutta toteuttaa se: 1. Käytetään suurinta laskuria, 16-bittinen, ja pienintä mahdollista kellotaajuutta. Jos systeemin kello on 4 MHz, timerille menee kellopulssi joka 0.25 usek välein. Jos se viedään jakajan kautta, suurin jakoluku on 1024, timerille menee pulssi aina 256 usek välein. 16-bittinen timeri laskee 65535 asti, jolloin timerin täyttöön menee 16776960 usek joka 16,777 sek. Ei riittävä. 2. Lisätään kohdan 1. tilanteeseen koodia, funktio, joka pitää tukkimiehen kirjanpidolla kirjaa kuluvasta ajasta. Ei hyvä, sillä se vaatii koodia, joka vääristää ajanlaskentaa ja ei toimi, jos pitää sähköä säästää (sleep-mode). 3. Käytetään timeria varten ulkoista hyvin pienitaajuista oskillaattoria. Muuten hyvä, mutta tarvii ulkoisia komponentteja ja kustannukset kasvavat. 4. Kytketään kaksi timeria sarjaan. Ensin timer1 laskee em. 16 sek ja sillä ohjataan timer 0:aa. Timer 1 lähtö on OC1A ja se liitetään kaapelilla Timer0:n ulkoiseen inputtiin T0, joka on PB.0. Timer0 on 8-bittinen, mutta sillä saadaan aikaa pidennettyä 255*16 sek, joka on jo aika paljon eli noin 4080 sek, eli 68 min eli 1 h ja 8 min. Hyvä. Timerien kaskadikytkentä. 27

Timerien kaskadikytkentä, perusteellisempi versio. Pitkä viive, Mallikoodi /********************************************************** Project : long_delay.c Hardware: PV-M32 + PV-LEDIT Software: WinAVR 20060421 Date : 25.12.2006 Author : pva Comments: Timer1 ja Timer0 sarjaankytkentä, kaskadi Timer0 Overflow Interrupt Timer1 Output Compare Match Mode, output toggle eli lähtö OC1A invertoituu Timer1 lähtö OC1A ohjaa Timer0 ulkoista inputtia T0 siksi kytke johto OC1A=PD.5 --> T0=PB.0 vilkuttaa A-portin LEDejä **********************************************************/ #include <avr/io.h> #include <avr/interrupt.h> // Timer0 overflow-keskeytysohjelma *********************** ISR(TIMER0_OVF_vect) PORTA = ~PORTA; // invertoidaan bitit 28

// Timerien rekisterien asetukset ************************* void Timer_init(void) TCCR0 = (1<<CS02) (1<<CS01) (1<<CS00); // T0 laskee ulkoisesta nousevasta reunasta TIMSK = 1<<TOIE0; // Salli T0 overflow interrupt TCCR1A = 1<<COM1A0; // Toggle OC1A on compare match // lähtöpinnin tila invertoidaan TCCR1B = (1<<WGM12) (1<<CS10); // CTC eli nollataan counter kun matsaus tapahtunut // jakoluku 1, muuta tätä OCR1AH = 0x5F; // write High Byte first, OCR1AL = 0x00; // muuta High-arvoa, niin viive muuttuu sei(); // globaali keskeytys ON int main(void) // ***************************************** DDRA = 0xFF; // LEDIT PORTA = 0x0F; DDRD = 1<<PD5; // OC1A lähtö DDRB = ~(1<<PB0); // T0 tulo Timer_init(); while(1) ; // ei tehdä mitään Analyysi 29

5. Pulse Width Modulator Mode, Pulssin leveysmodulaattori Varoitus Jos timerit ovat mikro-ohjaimen monimutkaisin ja suuritöisin asia oppia, niin PWM on 16-bittisen timerin monimutkaisin toimintamode. Yleistä PWM tulee sanoista Pulse Width Modulation ja se tarkoittaa modulaatiota, jossa pulssin pituutta (kesto) muutetaan jonkun funktion mukaisesti. Se on timerin erikoistoiminne, jolloin timeri toimii (tavallisimmin) ylös-alas-laskurina. Laskuri laskee ylös maksimiarvoonsa ja kun se sen saavuttaa alkaa laskemaan alaspäin kohti nollaa. Ja sama uudelleen ja uudelleen. PWM-modessa toiminta voidaan ohjelmoida monella eri tavalla. PWM perustuu kolmiovertailijaan eli siinä tarkkaillaan tuotetun kolmioaallon (pengerfunktion) ja asetusarvon välistä suuruutta. AVR laskee minimi- ja maksimiarvojen välillä 0 => 0xFFFF, joko yhdensuuntaisesti ylös tai sekä ylös että saman tien alas. Kuva 6.6.x. PWM periaate. Timer lähtee laskemaan pulsseja ja vertailija (ouput compare) vertailee laskurin arvoa ja OCR1-rekisterin asetusarvoon ja kun laskurin arvo on sama kuin asetusarvo, asetetetaan lähtöpinni OC1A-PD5 ylös (tai alas, riippuen ohjausrekisterin asetuksista). Kun timer on laskenut täyteen = TOP, se alkaa laskemaan alaspäin. Kohdatessaan OCR1-rekisterin arvon, lähtöpinnin tila invertoidaan. Sieltä saadaan siis kanttiaaltoa ulos. Muuttamalla vertailtavaa arvoa suuremmaksi tai pienemmäksi, laskurin kestää saavuttaa vertoarvo lyhyemmän tai pidemmän aikaa, eli lähtö-pinnin tilanmuutos tulee aiemmin tai myöhemmin. 30

PWM eli Pulse Width Modulation eli pulssinleveysmodulaatio tarkoittaa modulaatiota, jossa pulssien pituutta (kestoa) muutetaan jonkun funktion mukaisesti. PWM:n käyttökohteita Moottorin nopeuden säätö Valojen himmennys, ledin kirkkaussäätö Jännitteen vakavointi Tehon säätö DA-muunnos PWM rekisterit TCCR1A Bit 7 6 5 4 3 2 1 0 COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10 Read/write R/W R/W R/W R/W W W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Control Register A Määritetään normal operation tai OC1A/OC1Blähtöpinnnin käyttö COM1A1/COM1B1 COM1A0/COM1B0 Kuvaus 0 0 Normal port operation, OC1A/OC1B disconnected 0 1 Toggle OC1A/OC1B on compare match 1 0 Clear OC1A/OC1B on compare match, Out = 0 1 1 Set OC1A/OC1B on compare match, Out = 1 WGM13 WGM12 WGM11 WGM10 T/C Mode of Operation TOP Update of OCR1x 0 0 0 0 Normal 0xFFFF 0 1 0 0 CTC, Clear Timer on Compare match OCR1A Immediate Katso tarkemmin Atmelin doc2503.pdf-dokumentin taulukkoa Table 47 sivulla 109, Waveform Generation Mode Bit Description. TCCR1B Bit 7 6 5 4 3 2 1 0 ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10 Read/write R/W R/W R R/W R/W R/W R/W R/W Init. Value 0 0 0 0 0 0 0 0 Timer/Counter Control Register B Tässä valitaan toimintatila ja kellopulssien jakoluku allaolevan taulukon mukaan. 31

CS12 CS11 CS10 Kellon valinta 0 0 0 Stop, Timer 1 stopped 0 0 1 Järjestelmän kello, CK 0 1 0 Järjestelmän kello/8, CK/8 0 1 1 Järjestelmän kello/64, CK/64 1 0 0 Järjestelmän kello/256, CK/256 1 0 1 Järjestelmän kello/1024, CK/1024 1 1 0 Ulkoinen T1-pinni, laskee laskevasta reunasta 1 1 1 Ulkoinen T1-pinni, laskee nousevasta reunasta Timeriin menevien kellopulssien jakoluku valitaan CS12, CS11 ja CS10 biteillä ylläolevan taulukon mukaan. PWM voidaan asettaa resoluutiolla 8, 9 tai 10 bittiseksi. Resoluutiolla on suora vaikutus pwm-taajuuteen eli aikaan PWM cyclien välillä ja se valitaan pwm11 ja pwm10 biteillä TCCR1A-rekisterissä. PWM resoluutio Timer TOP value Frequency 8-bit 0xFF (255) ftc1/510 9-bit 0x1FF (511) ftc1/1022 10-bit 0x3FF (1023) ftc1/2046 PWM on eräässä mielessä Output Compare Moden laajennus. Kun TCNT1 saavuttaa OCR1 arvon, lähtöpinni OC1A asetetaan tai nollataan riippuen mikä on PWM-mode. Voit valita normal tai inverting. Se tehdään COM1A1 ja COM1A0 biteillä TCCR1A-rekisterissä. COM1A1 COM1A0 Toiminne 1 0 non-inverting PWM 1 1 inverting PWM Non-inverting PWM tarkoittaa, että Output Compare Pin nollataan, kun timer laskee ylös ja saavuttaa OCR1-arvon. Kun timer saavuttaa TOP-arvon 0xFFFF, sen laskentasuunta kääntyy ja Output Compare Pin asetetaan, kun timer matsaa OCR1- arvon kanssa alas laskettaessa. Inverted toimii päinvastoin. Kumpi mode valitaan riippuu ohjattavasta elektroniikasta. Jos PWM-taajuus on suuri ja se viedään sopivasti mitoitetun suotimen läpi, saadaan kanttiaallon sijasta vakiona pysyvä jännite. Se edustaa jännitteen keskiarvoa, eli toiminne on simppeli DAC, digitaali-analogia-muunnin. Toinen mahdollisuus on muuttaa kanttiaalto vastaavaksi siniaalloksi suotamalla pois suuret taajuudet. 32

Mallikoodit Tutkitaan ensiksi miten PWM-signaalilla ohjataan LEDin kirkkautta. /********************************************************** Project : pwm_t1_eka.c Hardware: PV-M32 + PV-LEDIT on PORTD Software: WinAVR-20070525 Date : 04.11.2007 Author : pva Comments: OC1A-PD.5 LEDin kirkkaus himmenee PWM:n ohjaamana. Sama uudelleen... PWM-taajuus = (fosc/(2*n*top) = n. 30 Hz N jakoluku TOP = 1023 (10-bitin moden maksimiarvo) PWM-freq = 4000000/(2*64*1023) = n. 30 **********************************************************/ #include <avr/io.h> #include <util/delay.h> #define WAIT(time) for(uint16_t i=0;i<2000;i++)_delay_loop_2(time); int main(void) DDRD = 0xFF; // uint16_t luku = 0x03; // pienin sallittu vertoarvo PORTD = 1<<7; // loistaa jatkuvasti kirkkaana TCCR1A = (1<<WGM11) (1<<WGM10); // 10-bitin pwm, phase correct mode TCCR1A = (1<<COM1A1) (1<<COM1A0); /* Set OC1A/OC1B on compare match when upcounting. Clear OC1A/OC1B on compare match when downcounting.*/ TCCR1B = (1<<CS11) (1<<CS10); // jakoluku 64 while (1) OCR1A = luku++; // vertailurekisterin arvoa // kasvatetaan 1-> 1023, alussa kirkas LED if(luku > 1023) luku = 3; // ettei ajeta "yli" // 10-bitin mode = 0x03FF = 1024des WAIT(10); Analysointi Tutki kommentit. Tähän tulee Fast PWM Mode Phase Correct PWM Mode Phase and Frequency Correct PWM Mode 33

Timer 2 tästä esitetään toistaiseksi vain async-toiminta Timer2 on 8-bittinen, joten sen resoluutio on pienempi, eli se osaa laskea vain nollasta 255, eli 0x00 -> 0xFF. Timer2 voidaan käyttää synkronisena laskurina aivan kuten timer1. Mutta sillä on lisäksi oma erikoinen käyttötarkoitus, sitä voidaan kellottaa asynkronisesti. Asynkroninen oskillaattori on optimoitu toimimaan 32,768 khz:n kellokiteen taajuudella. Sama kide joka tahdittaa PC:n kelloja. Tästä taajuudesta on helppo tehdä RTC, Real Time Clock. Tälle kiteelle on PV-M32-kortilla kiinnitysreiät valmiina. Jos haluat todella tarkkoja sekunteja, kiteen valintaan on kiinnitettävä huomiota. Siitä myöhemmin lisää. ASSR Bit 7 6 5 4 3 2 1 0 - - - - AS2 TCN2UB OCR2UB TCR2UB Read/write R R R R R/W R R R Init. Value 0 0 0 0 0 0 0 0 Asynchronous Status Register Määritetään normal operation tai Bitti 3 AS2 Kun 0: T/C2 kellotetaan systeemin kellosta Kun 1: T/C2 kellotetaan 32,768 khz kideoskillaattorista, TOSC1 Bitti 2 TCN2UB Timer/Counter2 Update Busy When Timer/Counter2 operates asynchronously and TCNT2 is written, this bit becomes set. When TCNT2 has been updated from the temporary storage register, this bit is cleared by hardware. A logical zero in this bit indicates that TCNT2 is ready to be updated with a new value. Bitti 1 OCR2UB Output Compare Register2 Update Busy When Timer/Counter2 operates asynchronously and OCR2 is written, this bit becomes set. When OCR2 has been updated from the temporary storage register, this bit is cleared by hardware. A logical zero in this bit indicates that OCR2 is ready to be updated with a new value. Bitti 0 TCR2UB Timer/Counter Control Register2Update Busy When Timer/Counter2 operates asynchronously and TCCR2 is written, this bit becomes set. When TCCR2 has been updated from the temporary storage register, this bit is cleared by hardware. A logical zero in this bit indicates that TCCR2 is ready to be updated with a new value. If a write is performed to any of the three Timer/Counter2 Registers while its update busy flag is set, the updated value might get corrupted and cause an unintentional interrupt to occur. Käännös tulee seuraavaan versioon. 34

Aloitetaan tämäkin tutkailemalla LEDin kirkkautta. Timer 2 async, Phase Correct PWM Mode, mallikoodi /******************************************************************** Project : pwm_t2_eka.c Hardware: PV-M32 + PV-TINT on D-port Sofware: WinAVR-20070525 Date : 04.11.2007 Author : pva Comments: Timer/Counter2, Phase corret mode PWM mode. 32768 Hz operation OC2:n = PD7, PWM muuttuu PD.7 RED-LED ON, kun tila on "1" PD.7 GREEN-LED ON, kun tila on "0" ********************************************************************/ #include <avr/io.h> #include <util/delay.h> #define WAIT(time) for(uint16_t i=0;i<2000;i++)_delay_loop_2(time); // funktion esittely, eli prototyyppi void Timer2_init(void); int main(void) DDRD = 0xFF; uint8_t pwm = 0x00; Timer2_init(); while(1) OCR2 = ++pwm; // OCR2 = pwm + 1 WAIT(100); // ** Timer2 rekisterien asetukset ********************************** void Timer2_init(void) ASSR = 1<<AS2; // 32,768 khz operation TCCR2 = 1<<WGM20; // Phase corret mode PWM mode TCCR2 = 1<<COM21; // Clear OC2 on compare match when up-counting. // Set OC2 on compare match when downcounting. // OC2 = PD.7 TCCR2 = (1<<CS20) (1<<CS21); // clk/32, clk=32768 Hz 35

RTC, Real Time Clock 1. rtc_tero koodaaja: Tero Ilenius, Turkuamk, 2006 syksy Tämä on hyvin monipuolinen kello, joka on toteutettu timer 2:lla ja sen 32 khz kiteellä. Tulostaa LCD-näyttöön. Koska koodi on aika pitkä, en tulosta sitä tähän, vaan voit etsiä koodipaketin rtc_tero, siinä on kaikki. (lcd-näytön ajurit ovat vanhaa versiota, joten uudista.) 2. Toinen mallikoodi, tulostaa ajan ledeillä. /******************************************************************** Project : rtc_1.c Date : 17.10.2006 Hardware: PV-M32 (4 MHz) + PV-TINT Software: AVRStudio + WinAVR 20060421 Author : pva Comments: Timer2, jossa 32768 Hz kide ********************************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> Loppuosa koodista on USB-muistitikulla, koska se on liian pitkä tulostettavaksi tässä. 36