The modular mitmót system Ismerkedés a fejlesztő eszközökkel Hardver közeli programozás API készítés (példa) Egyszerű mintaalkalmazás Dokumentációkód: 2006. szeptember Budapesti Műszaki és Gazdaságtudományi Egyetem Méréstechnika és Információs Rendszerek Tanszék Beágyazott Információs Rendszerek csoport 2006. szeptember BME MIT 2006. -D02a 1
Tartalom A mitmót honlap 3 A fejlesztői környezet 4 Telepítés 4 WinAVR 4 Fordítás 4 Segédprogramok, make 4 AVR Libc standard C könyvtár 5 Az Eclipse 6 Workspace és perspektíva választás 6 Meglévő project megnyitása és másolása 7 Fordítás és letöltés 7 Hardver közeli programozás 8 A forrástól a letölthető állományig egyszerű mintaprogram 8 A makefile-ról 8 Alacsony szintű programozás 9 Bevezető feladat: kis módosítás 9 Információk a fordítás után keletkező gépi kódról 10 Megszakítás kezelés 11 API készítés 11 Komplex feladat 12 Mitmót API 12 mcu avr atmega128 api 12 Magas szintű IO kezelés 12 Specifikáció: 14 A program megtervezése 14 Függelék megoldások 16 Bevezető feladat: kis módosítás 16 Időzítő API 17 Reflexidő mérése (reflex.c) 19 BME MIT 2006. -D02a 2
A mitmót honlap A mitmót honlap webcíme: http://bri.mit.bme.hu, ez elérhető a MIT portál Hallagtói információk pontja alól is. Itt belépés után - bal oldalt a mitmót linket választva kapunk egy bővebb menüsort. Az e laborhoz kapcsolódó dokumentumok folyamatosan felkerülnek a Documents menü alá. A fejlesztői környezet telepíthető fájljai és a telepítési útmutató a Software/Eclipse és WinAVR linkre kattintva tölthetők le. A modulok leírásánál (Modules) a hardver dokumentációja mellett megtaláljuk a modulhoz készült C API dokumentációját és forráskódját. A laborok során bemutatott minta-projektek az MCU modul oldalára kerülnek fel. BME MIT 2006. -D02a 3
Telepítés WinAVR Fordítás Segédprogramok, make A fejlesztői környezet A laborban használt rendszer komponensei ingyenesen letölthetőek. Ezek egymástól függetlenül is folyamatos fejlesztés alatt állnak, így a mindenkori legújabb változatot használva kisebb-nagyobb eltéréseket tapasztalhatunk az itt leírtakhoz képest. Egy tesztelt, működő telepítő csomag (Windows rendszerhez) letölthető a mitmót honlapról, ahol részletes telepítési útmutatást is adunk. E mellett itt megadjuk az egyes szoftverek legfrissebb változatának elérhetőségét, illetve egy rövid leírást a programokról. Letölthető: http://winavr.sourceforge.net/download.html A laborban használt változat: 20060421 Fordítást, linkelést, debugolást, futtatható állomány letöltését ( ) szolgáló programok [\bin]. Ezek mindegyike parancssorból hívható és paraméterezhető, így tetszőleges grafikus front-end alól is használhatjuk őket, megfelelő beállítások után. avr-gcc: fordítás, assembler, linkelés avr-as: assembler avr-ld: linker avr-objdump: elemző avr-gdb: GNU debugger ( ) A WinAVR csomag tartalmaz néhány, a Unix/Linux rendszerekből ismert segédprogramot. Ezek közül számunkra legfontosabb a fordítás, letöltés lépéseinek automatizálását szolgáló make parancs, amiről később még szólunk. BME MIT 2006. -D02a 4
AVR Libc standard C könyvtár Megjegyzés: Hasznos tudni, hogy a teljes toolchain Linux környezetben fut, amit Windows alatt cygwin segítségével emulál. (Ez egy Windows-hoz készült Linux API, bővebben lásd: www.cygwin.com ) Az általános C függvények, a legfontosabb hardver specifikus funkciók (IO műveletek, megszakításkezelés ) implementációja, illetve néhány segédfüggvény. (Részletesen lásd [doc\avr-libc\avr-libc-user-manual- 1.4.4.pdf] Module Index fejezetét) Ezek mellé, fölé adhatunk még egyéb API függvényeket, és így biztosítható egy egységes, hardverfüggetlen interfész a felhasználó felé. Megjegyzés: A gyakorlatban sajnos ez az egységesség csak korlátozottan biztosítható: az AVR libc könyvtár folyamatos fejlesztés alatt áll, és különböző változatai nem feltétlenül kompatibilisek (pl. egy-egy függvény paraméterezése változhat). Ekkor a fordításkor figyelmeztető/hibaüzeneteket kapunk, amik alapján a hiba javítható. E mellett javasoljuk, hogy minden projekt/forráskód esetén tüntessük fel az általunk használt könyvtár vagy WinAVR verziószámát. (Ez történhet egyszerű komment, vagy define előfordító direktíva formájában) Feladat: A könyvtár assembly és C forráskódokból fordított tárgykódú állományok (obj fájlok) gyűjteménye, lehetőségünk van arra, hogy belenézzünk. Ehhez a WinAVR avr\lib könyvtárában indítsunk parancssort, és adjuk ki a következő utasítást: avr-ar -t libc.a Ezzel kilistázzuk a könyvtárban lévő tárgykódú állományokat. Látható, hogy szinte minden függvényt külön object fájlban valósítottak meg, noha tudjuk, hogy egy-egy C modul több függvényt is tartalmazhat. Erre a minimális kódméret eléréséhez van szükség: a futtatható fájl készítésekor a linker a main függvényből indulva feltérképezi, mely függvényeket használja a programunk, és az ezeket tartalmazó tárgykódú állományokból áll elő a végeredmény. Ez azt jelenti, hogy ha egy object fájlból használunk egy függvényt, a teljes fájl (az esetleges nem használt függvényekkel együtt) bekerül a futtatható állományba. BME MIT 2006. -D02a 5
Feladat: Vizsgáljuk meg, mi alapján tudja a fordító ami alapvetően magas szintű, hardverfüggetlen programozást szolgál értelmezni a hardver közeli parancsokat, például: DDRA=0xf0; A DDRA rövidítés az IO definíciók alapján oldható fel, amit a következő sorral adunk meg: #include <avr/io.h> //register defines Ennek hatására kódunk elejére fordítás előtt bemásolódik a C:\WinAVR\avr\include\avr\io.h állomány, ami pedig a makefile-ban megadott processzortípus alapján az iom128.h fájlra hivatkozik. Ebben találjuk a következő sorokat: / Data Direction Register, Port A / #define DDRA _SFR_IO8(0x1A) Az Atmega128 kontroller dokumentációjában megtalálhatjuk, hogy az A port irányregiszterének memóriacíme 0x1A. A fordítóhoz definiált _SFR_IO8(x) makró segítségével pedig közvetlenül írhatunk x memóriacímre egy 8 bites változót. Az Eclipse Letölthető: http://www.eclipse.org/downloads http://www.eclipse.org/cdt/downloads.php A laborban használt változat: Eclipse SDK 3.2, CDT 3.0.2 Workspace és perspektíva választás Az Eclipse indítása után meg kell adnunk azt a könyvtárat, ahol a project-einket tárolni fogjuk. Ez tetszőleges lehet, a laborba telepített gépeken az d:\student\eclipse\avrlab könyvtárat használjuk. A File/Switch Workspace menüpont kiválasztásával ez a beállítás bármikor megváltoztatható. A felhasználói felület, ún. perspektívákból áll. A C/C++ fejlesztéshez nekünk ki kell választani a a megfelelő perspektívát, amit a Window/Open Perspective/Other... almenüpont, majd az újonnan megjelenő kis ablakban a C/C++ perspektíva kiválasztásával tehetünk meg. Ennek hatására átalakul kicsit a felhasználói képernyő. Az Eclipse emlékezni fog a következő indításkor a kiválasztott perspektívára. BME MIT 2006. -D02a 6
Meglévő project megnyitása és másolása Fordítás és letöltés Ha egy előre elkészített projectet szeretnénk megnyitni, akkor az azt tartalmazó könyvtárat célszerű a workspace alá másolni. Ezután a baloldali project navigatorban a jobb gomb megnyomására legördülő menüből, vagy a File menü alól az Import... pontot, majd innen értelemszerűen az General / Existing Projects into Workspace lehetőséget kell választani. A következő ablak Browse pontjára kattintva ki tudjuk választani az importálandó projectet tartalmazó könyvtárat. A megnyíló project leíró fájljai több olyan beállítást is tartalmaznak (például a Build parancsok, lásd később), amiket a szoftvercsomag installálása után csak egyszer kell helyesen beállítanunk, mert gyakorlatilag nem változnak. Újabb project létrehozásakor a Makefile-t (lásd később) is csak kis mértékben kell változtatni. Ezért célszerű az új projectet egy már meglévő másolásával létrehozni (a Navigator ablakban a meglévő projekt gyökerére kattintva használhatjuk a szokásos Copy-Paste parancsokat). Az Eclipse egy általánosan használható integrált fejlesztői felület (IDE, front-end ), ami legtöbbször valamilyen specifikus tool-cahin fölé épül. Esetünkben ez a WinAVR. Fordításhoz és letöltéshez a Project Navigatorban jobb gombbal kattintsunk a projekt gyökerére, majd válasszuk a Build Make Target pontot. A felugró ablakból az all pontot választva lefordíthatjuk a programot, a program pontot választva pedig fordítás után az ISP interfészen keresztül le is tölthetjük. Az Edit gombra kattintva láthatjuk, hogy ilyenkor a háttérben annyi történik, hogy a WinAVR make parancsát meghívjuk a megfelelő bemeneti paraméterrel. A parancs kimenetét az Eclipse Console ablakjában olvashatjuk. A fordításhoz, letöltéshez szükséges összes információt a projekt részét képző Makefile szkript tartalmazza. BME MIT 2006. -D02a 7
Hardver közeli programozás A forrástól a letölthető állományig egyszerű mintaprogram A makefile-ról A Makefile egy olyan szkript amiben megadhatjuk a fordításhoz, letöltéshez szükséges programokat a megfelelő paraméterezéssel, a fordítás menetét és a forrásfájlokat. Ezután a make parancs meghívásával készíthetjük el programunkat. Importáljuk az avrlab06_1 nevű projektet, és nyissuk meg a hozzá tartozó Makefile-t. Azokat a részeket, amik egy-egy új projekt létrehozásakor valószínűleg változhatnak, kiemeltük a fájl elejére: ilyen például a main függvényt tartalmazó forrás modul neve, illetve az egyéb forrás állományok. Később megadjuk a processzor típusát, a fordító különböző beállításait, a fordító (avr-gcc) és letöltő program ( avrdude ) nevét A fordítás menetét lépésenként adjuk meg: definiáljuk, mely paranccsal állítható elő a C forrásfájlból a tárgykódú állomány (%.o : %.c szakasz), majd ebből elf (Executable and Linkable format) állomány (%.elf : $(OBJ) szakasz), végül például a letölthető bináris fájl (%.hex : %.elf). Ezek után a források megadása után már csak annyit kell közölni a fájlban egy parancs például all definiálásakor, hogy készítsd el a bináris állományt. Ez adja ennek a struktúrának egy nagy előnyét: a megfelelő részlépések megadása után könnyen definiálhatunk új parancsokat. Így, ha például gépi kódú forrásfájlokat is hozzá szeretnénk adni a projektünkhöz, csupán annyit kell tenni, hogy a makefile-hoz, hozzáadjuk a gépi kódú fájlok fordítási szabályát (%.o : %.S). Ezután a korábban megírt all parancs minden további nélkül használható. BME MIT 2006. -D02a 8
Alacsony szintű programozás Az első mintaprogram a kijelző modul LED-jeit gyújtja ki egymás után (leds.c) : #include <avr/io.h> //register defines int main(void) DDRA=0xf0; unsigned char i=0x10; while(1) PORTA=i; //MCU specific! i<<=1; if(!i) i=0x10; for(unsigned long int k=0 ;k<30000000; ++k); Ez a program alacsony szinten valósítja meg funkcióját: a C nyelv gyakorlatilag csupán szintaktikai könnyítést jelent a gépi kódú programhoz képest. Ilyen típusú programozásra lehet szükség az API-k megírásakor, illetve egyes idő vagy kódméret kritikus alkalmazásoknál, amikor fontos, hogy az adott program(rész) minimális idő alatt lefusson, és/vagy kevés memóriát foglaljon. Hátránya, hogy természetesen hardverfüggő: nem hordozható és értelmezéséhez szükséges a hardver pontos ismerete. A fenti programot például csak akkor értelmezhetjük, ha tudjuk, hogy a kijlző modul LED-jei és gombjai az alábbi módon kapcsolódnak a mikrokontrollerhez: PORTA L4 L3 L2 L1 B3 B2 B1 x Bevezető feladat: kis módosítás A PORTA regiszter 0-s bitje a jobbszélső, a B az egyes nyomógombokat (Button), míg az L az egyes LED-eket jelenti. Változtassuk meg a mintaprogramot úgy, hogy csak egy adott gomb megnyomásakor léptessük a világító LED-et. Ehhez tudni kell, hogy a gombok low active -ak, azaz értékük lenyomott állapotban nulla. BME MIT 2006. -D02a 9
Információk a fordítás után keletkező gépi kódról A jelenleg alapértelmezett Makefile használata esetén a program fordításakor az elf (Executable and linking format) fájlból automatikusan generálódik az lss listafájl, ami két fő részből tevődik össze: A különféle memóriaszekciók felsorolása, amelyek leírják, hogy a program fizikailag hol helyezkedik el az adat- és programmemóriában. Mindegyik szekcióhoz a nevén és sorszámán kívül a következő paramétereket tünteti fel a lista: size a szekció mérete VMA (Virtual Memory Address) a szekció virtuális memóriacíme LMA (Load Memory Address) a tényleges fizikai címe a szekciónak, ide fog letöltődni. (Beágyazott rendszerek esetén a VMA szinte mindig megegyezik az LMA-val, kivéve az inicializált adatmemória részt). File off a szekció file-ban lévő offset-címről ad információt Algn a minimális blokkméretet definiálja a szekcióhoz A fontosabb szekciók:.text: a programkód a FLASH memóriában.data: inicializált statikus adat, az SRAM memóriában (Az SRAM memória virtuális címe 0x800000).bss: inicializálatlan statikus és globális változók SRAM-ban. Ezeket a fordító automatikusan 0 értékre inicializálja. Ha ezt el akarjuk kerülni, a változót explicit módon.bss alszekciójába (.noinit) kell helyezni, ehhez deklarációnál a változó neve után attribute ((section (".noinit"))) írandó..eeprom: az EEPROM memóriába írt adat A debug kezdetű szekciók a hibakeresés támogatására csak az.elf fájlban találhatók meg, a bináris kimenetben nem. A memória szekciók leírása az avr-libc dokumentáció Memory Sections fejezetében található. A szekciók leírása után a.text szekció kommentezett visszafejtett gépi kódját találjuk: az IT ugrótáblát, néhány segédfüggvényt, végül a fő programunkat. BME MIT 2006. -D02a 10
Megszakítás kezelés API készítés Az IT kezelés tipikus példája a hardver közeli feladatoknak. Erre a C nyelv nem kínál szabványos megoldást, minden fejlesztői környezet, fordító esetében eltérő lehet. Az AVR libc különböző verzióiban sem egységes (a kompatibilitás érdekében a régebbi változatokban definiált függvények továbbra is használhatók, de a fordító figyelmeztet, hogy elavult módszert használunk.) Az IT kezelése egy speciális makró (ISR()) segítségével történik, ami a felhasználó elől rejtve biztosítja egyrészt az IT ugrótábla kitöltését, másrészt megszakítás esetén a kontextus váltást (azaz a regiszterek elmentését / visszatöltését.). Részletes leírás: [doc\avrlibc\avr-libc-user-manual-1.4.4.pdf p. 120] Példát a következő fejezetben adunk. Az API-k (Application Program Interface) egyrészt a programkód hardverfüggő részeinek elfedésére, másrészt gyakran használt funkciók megvalósítását szolgálják. Szerencsés esetben ezek már rendelkezésre állnak, és a fejlesztőnek elég magas szinten (akár hardver független kód formájában) implementálnia az alkalmazást. Beágyazott rendszer fejlesztése esetén azonban bármikor szükség lehet a hardvert közvetlenül kezelő modulok megírására. Célunk ennek segítése, egy Időzítő API megírásával. Ehhez szükségünk lesz a kontroller dokumentációjára, és az AVR libc dokumentációra. Segítségként elkészítettük az API fejlécét, illetve vázát (timer_api.c, timer_api.h). A header fájlban kommentben megadtuk az egyes függvények leírását, ami alapján a kód megírható. Ez a leírás szükséges, hisz az API felhasználója sok esetben például ha a forrás fájlt könyvtárba rejtjük csak a header fájlt látja. Ha a forrás elkészült, a Makefile SRC változójában meg kell adnunk, hogy ezt is le szeretnénk fordítani. Tesztelésként készítsük el a futófény program időzítő API-t használó változatát. Segítségként ennek törzsét is megadtuk (leds2.c). A fordításhoz természetesen be kell állítani a Makefile TARGET változóját. BME MIT 2006. -D02a 11
Komplex feladat Mitmót API A mitmót rendszer processzor moduljaihoz (AVR/ARM) készített API-k lehetővé teszik, hogy használatukkal valóban hordozható kódot írjunk. Az API-k és dokumentációjuk letölthetők a mitmót honlapról. A függvények részletes dokumentációját kérjük, itt olvassátok el. Az API jelenlegi változatát a használt Eclipse workspace avr_mitmot_api könyvtárában, könyvtárként (.a fájl) helyeztük el. Ezt a makefile-ban már megadtuk: LDFLAGS = -L.../avr_mitmot_api/libmcu_avr_atmega128_api.a Használatához csak az alábbi sort kell megadni a forrás fájlban: #include "../avr_mitmot_api/mcu_avr_atmega128_api.h" mcu avr atmega128 api Magas szintű IO kezelés Az AVR processzor modulhoz készült API jelenlegi verziója a következő támogatásokat tartakmazza: Gyakran használt standard könyvtárak (pl. stdio) importálása. Általános célú segédmakrók A mitmót busz GPIO lábainak kezelése, System LED kezelése UART, SPI és I2C kommunikáció Mint tudjuk, C nyelven az IO eszközöket magas szinten fájlként kezeljük, amibe írhatunk, és ahonnan olvashatunk. Az stdio interfész is amit pl. a printf és egyéb jól ismert C BME MIT 2006. -D02a 12
függvények használnak egy ilyen fájlhoz rendelhető. Az általunk használt fordító sajátossága, hogy az elsőként megnyitott FILE struktúrát értelmezi stdio interfészként. A FILE struktúra megnyitásánál meg kell adnunk hogyan valósul meg az elemi (egy bájtnyi) írási és olvasási művelet a használt eszköz esetében. Ezt az API-ban tesszük meg. Írás: írás a diagnosztikai soros portra: int UART1_put(char c, FILE f); loop_until_flag_is_set(ucsr1a, UDRE); UDR1 = c; return 0; Olvasás: olvasás a diagnosztikai soros portról. A fogadott karakter visszaküldése, illetve ENTER fogadása esetén korrekció (ENTER esetén a PC \r\n karaktereket küld, de ebből a könyvtári függvények pl. a gets a \n-t levágja. Echo esetén azonban ezt is vissza kell küldeni). char UART1_get(void) loop_until_flag_is_set(ucsr1a, RXC); return UDR1; int UART1_get_echo(FILE f); //stdio handler uses this one int i=uart1_get(); if(i=='\r') UART1_put(i); i='\n'; //gets cuts \n UART1_put(i); return i; Ezek után a soros port inicializálásakor létrehozhatjuk a FILE struktúrát: FILE UART1_handler; //device handler for stdio - set in UART1_Init void UART1_Init(unsigned long baud_rate, void (handler)(void)) if(uart1_handler)fclose(uart1_handler); UART1_handler=0; //if already opened (reinit): close dev. handler UART1_handler=fdevopen(&UART1_put,&UART1_get_echo,0); //open device handler BME MIT 2006. -D02a 13
Specifikáció: Készítsen programot, ami alkalmas az 1 másodpercnél rövidebb reflex idő ezredmásodperc felbontású mérésére. Az eredményt a soros portra írja ki. 5 másodpercenként gyújtsa ki véletlenszerűen az 1-3 LED-ek egyikét. Ha a felhasználó 1 másodpercen belül megnyomja a kigyújtott LED-nek megfelelő (1-3) gombot, a soros portra írja ki a LED kigyújtása és a gombnyomás közt eltelt időt (ezred másodpercben). Időtúllépés, illetve rossz gomb megnyomása esetén 999-et írjon ki. A program megtervezése Ehhez a programhoz már nem adunk vázat, csak egy lehetséges megvalósítás tervét. Adjunk a projecthez egy új, reflex.c nevű forrásfájlt (jobb kattintás a project nevén a project navigátorban New Source file), és ebben valósítsuk meg az alábbiakat. Az ezredmásodpercek számolásához és az 5 másodpercenkénti LED kigyújtásához használjuk az elkészített időzítő API-t, a soros port kezeléséhez a mitmót MCU API-t! Ezeken kívül véletlenszám generáláshoz még szükségünk lesz az stdlib.h-ban definiált rand() függvényre. Az IT rutinban (void ms_elapsed(void)) elvégzendő feladatok: sw_cntr1 szoftveres számláló növelése. Ebben számoljuk az eltelt időt ms-ban. Ha eltelt 5 másodperc (sw_cntr1==5000) sw_cntr1 nullázása, és a fő ciklusban előállított (lsd. később) 0-2 közti véletlenszám (randnum) alapján véletlenszerűen egy LED kigyújtása. A LED-ek állapotát célszerű egy külön változóban (flags) is tárolni. A LED-ek beállítása megoldható az alábbi módon: flags=_bv(4+randnum); PORTA=flags; Itt _BV(x) makró egy olyan maszkot állít elő, aminek x bitje egy, azaz a klasszikus (1<<x) utasításnak felel meg. BME MIT 2006. -D02a 14
Időtúllépés, jó/rossz gomb megnyomása esetén hasonló műveleteket kell elvégeznünk, így ezeket érdemes egy segédfüggvénybe foglalni (void Done(int num)): flags=0 jelezzük, hogy a reflex-idő mérés megtörtént írjuk ki a soros portra az eredményt Oltsuk el a LED-eket Generáljunk új (ál)véletlenszámot: randnum=(unsigned char)rand()%3; A főprogramban: Inicializáljuk a globális változókat, az A portot, a soros portot és az időzítő API-t. Végtelen ciklusban: ha még nem történt meg a mérés (flags) a. Időtullépés Done(999); b. Gombnyomás történt: i. Jó gomb Done(sw_cntr1); ii. Rossz gomb Done(999); A gombok állapotának lekérése: unsigned char btns=0xf1 PINA; btns=(~btns)<<3; Ezután btns és flags változók összehasonlíthatók. BME MIT 2006. -D02a 15
Függelék megoldások Bevezető feladat: kis módosítás A for ciklusban megvalósított szoftveres késleltetés után végtelen ciklusban várakozzunk B1 gomb megnyomására. (A késleltetést nem hagyhatjuk el, hisz ekkor a LED egy gombnyomásra többször is lépne, mert a ciklus többször is lefut, miközben a gombot nyomva tartjuk): for(unsigned long int k=0 ;k<30000000; ++k); while(pina&0x02); BME MIT 2006. -D02a 16
Időzítő API timer_api.h //Toolchain: WinAVR 20060421 #ifndef TIMER_API_H_ #define TIMER_API_H_ / Function: TickInit(unsigned int period_ms, void (handler)(void)) PreCondition: Input: period_ms: desired IT period in ms //TODO: max. value? handler: pointer to the IT handler function Output: none Side Effects: uses TIMER1 compare A Overview: Calls the handler function periodically Note: To start timing call TickStart / void TickInit(unsigned int period_ms, void (handler)(void)); / Function: TickStart PreCondition: Call to TickInit Input: none Output: none Side Effects: uses TIMER1 compare A Overview: Enables TIMER1 capture IT Note: / void TickStart(void); BME MIT 2006. -D02a 17
/ Function: TickStop PreCondition: Call to TickInit Input: none Output: none Side Effects: uses TIMER1 compare A Overview: Disables TIMER1 capture IT Note: / void TickStop(void); #endif /TIMER_API_H_/ timer_api.c #include "timer_api.h" #include <avr/interrupt.h> #include <avr/io.h> void (Tick_IT_Handler)(void)=0; //pointer to IT handler function - set in TickInit ISR(TIMER1_COMPA_vect) if(tick_it_handler) Tick_IT_Handler(); //TODO: ISR vector? void TickInit(unsigned int period_ms, void (handler)(void)) Tick_IT_Handler=handler; //TODO TCCR1A=0; //Normal port operation (IO pins not connected) TCCR1B=0x0b; //CTC mode prescale 64 --> T=8 us if cclk=8 MHz OCR1A=F_CPU/64000period_ms; //Period of ITs sei(); //Enable global ITs //TODO end void TickStart(void) //TODO TIMSK=0x10; //Output Compare IT TIMER1/A enabled //TODO end void TickStop(void) //TODO TIMSK=0x00; //Output Compare IT TIMER1/A disabled //TODO end BME MIT 2006. -D02a 18
Reflexidő mérése (reflex.c) //Toolchain: WinAVR 20060421 #include "../avr_mitmot_api/mcu_avr_atmega128_api.h" #include "timer_api.h" #include <stdlib.h> //global variables unsigned int sw_cntr1; unsigned char randnum=0; unsigned char flags=0; //The IT handler function void ms_elapsed(void) ++sw_cntr1; if(sw_cntr1==5000) sw_cntr1=0; flags=_bv(4+randnum); PORTA=flags; void Done(int num) flags=0; printf("ido: %d\r\n",num); PORTA=0; randnum=(unsigned char)rand()%3; int main(void) //init sw_cntr1=0; Done(0); DDRA=0xf0; UART1_Init(9600,NULL); TickInit(1, ms_elapsed); TickStart(); while(1) if(flags) //not done if(sw_cntr1>999) Done(999); else unsigned char btns=0xf1 PINA; btns=(~btns)<<3; if(btns) //button pressed if(btns==flags) Done(sw_cntr1); else Done(999); //else //while BME MIT 2006. -D02a 19