„Mérés laboratórium 2. - 3. mérés” változatai közötti eltérés
61. sor: | 61. sor: | ||
===Gombok kezelése IT-vel=== | ===Gombok kezelése IT-vel=== | ||
Először az EICRB (External Interrupt Control Register B – INT7:4) regiszterben 2-2 biten kell beállítani, hogy szintérzékeny, felfutóél érzékeny, stb. módban működjön: | Először az EICRB (External Interrupt Control Register B – INT7:4) regiszterben 2-2 biten kell beállítani, hogy szintérzékeny, felfutóél érzékeny, stb. módban működjön: |
A lap 2013. január 28., 20:05-kori változata
Ez a lap elavult adatokat tartalmazhat. Segíts felfrissíteni
Ha nem tudod, hogy állj neki, olvasd el a tutorialt.
A második mérés végen a laborvezetővel kitaláltok egy komolyabb progit, amit otthon megírsz a társaddal együtt, és a helyszínen belövitek. Hasonlóan a mérés1 5-ös méréséhez. Tipikusan valamilyen játékról van szó, vagy valamelyik egzotikus periféria (potméter, fényérzékelő) kezeléséről.
Ha játék, akkor érdemes valóban a folyamatábrával kezdeni, és akkor nekiugrani a kódolásnak, ha kész a blokkvázlat, meg átgondoltátok, hogy milyen változókat használtok, illetve hogyan tároltok a memóriában adatokat.
A programot megírhatod otthon, átrághatod (a kódot olvasva), hogy azt csinálja-e, amit terveztél, és leellenőrizheted, hogy szintaktiakilag helyes-e, de a perifériák működését kipróbálni csak on the spot tudod. Ha alaposan terveztél, az utóbbira elég lesz a négy óra.
Ellenőrző mérés során nem használható a magyar nyelvű AVR jegyzet, csak a hivatalos, angol nyelvű ATMega128 datasheet (és az utasításkészlet, illetve az ASM vázfájl). Emiatt már házi írásakor érdemes megbarátkozni a doksival, hogy ne EM-en lássátok először!
Házi írás alatt kerüljétek a magyar nyelvű AVR jegyzetből való copy-paste-elést, inkább gépeljétek be, azzal is gyakoroltok.
Perifériák és beépített hardveregységek
Regiszterek
Csak a 16 feletti regiszterekbe tölthető be érték közvetlenül, tehát egy 0-20 terjedő értéket tároló változót csak ilyenben lesz kényelmes kezelni. Az utolsó 6 regiszter indirekt címzéshez használatos, szóval marad 10, amiből az LCD rutingyűjtemény lefoglal magának 8-at - ha használjuk az LCD-t, akkor legyünk körültekintőek, hogy mikor mi változik.
LED-ek kezelése
A LED-ek kezelése egyszerű: be kell őket állítani kimenetként, ezt követően a PORTC bitjeinek állapota megjelenik rajtuk.
; inicializáció ldi temp, 0xff out DDRC, temp ; írás out PORTC, temp ; PORTC n. bitje 1-es => balról az n. LED világít, 0<=n<=7
Gombok kezelése
A gombok a PINE 5, 6, 7. bitjein érhetőek el; az INT feliratú különálló gomb a 4. biten; BT3 pedig a PINB 7. bitjére van kötve. Lenyomva 0, felengedve 1 értékűek. Az elején ne felejtsd el bemenetnek beállítnani őket! A gombnyomás után érdemes 4ms-et várni a pergés elkerülésére. Ha egy gomb egymás utáni többszöri lenyomásának van értelme, akkor egy lenyomás után vagy várd meg a gomb felengesését, vagy várj 200msec-et. Ellenkező esetben mindig több ezer (millió) lenyomást fog lekezelni a progi ;)
; inicializáció ldi temp, 0xff ; BTN0-BTN2 és az IT gomb engedélyezése out PORTB, temp ldi temp, 0x80 out DDRB, temp ldi temp, 0xff ; BTN3 engedényezése out PORTE, temp ldi temp, 0x01 out DDRE, temp ; olvasás in temp, PinE ; BTN0 andi temp, 0x20 in temp, PinE ; BTN1 andi temp, 0x40 in temp, PinE ; BTN2 andi temp, 0x80 in temp, PinB ; BTN3 andi temp, 0x80 in temp, PinE ; IT andi temp, 0x10
Gombok kezelése IT-vel
Először az EICRB (External Interrupt Control Register B – INT7:4) regiszterben 2-2 biten kell beállítani, hogy szintérzékeny, felfutóél érzékeny, stb. módban működjön:
- 00 - mindig interruptol
- 01 - lenyomásra es felengedésre interruptol
- 10 - magas-alacsony átmenetnél interruptol, tehát a gomb benyomásakor
- 11 - az alacsony-magas átementnél interruptol
Az egyes gombok az alábbi biteken állíthatóak:
- INT - 0-1-es bitek,
- BT0 - 2-3-as bitek,
- BT1 - 4-5-ös bitek, végül
- BT2 - 6-7-es bitek.
- A BT3 a B portra van kötve, külső interruptra nem használható.
Az esemény bekövetkeztekor a következő interrupt hívódik meg, az elején e szerint kell az IT vektortáblát beállítani:
- INT - INT4
- BT0 - INT5
- BT1 - INT6
- BT2 - INT7
Az EICRB regiszter beállítása után az EIMSK regiszterben az adott IT sorszámával megegyező bitet 1-be állítva lehet az adott IT vonalat engedélyezni. Az IT-ket globálisan SEI ill. CLI utasításokkal lehet engedélyezni/tiltani. (Megszakításkor ez a bit törlődik, az IT rutin elején SEI-vel engedélyezve oldható meg, hogy az IT kiszolgálását másik IT megszakíthassa. Ekkor már figyelni kell az egyes IT vonalak prioritására is.)
Természetesen ahhoz, hogy működjön, az E I/O port DDR regiszterét is be kell állítani - a gombokat bemeneti I/O-ként kell beállítani.
Pl. BT2 megszakításának engedélyezése:
; interrupt kiszolgáló rutin
A =reti ; INT7 Handler= és az utána következő =nop= sort cseréljük ki
jmp BT2_HANDLER
-re.
; BT2 megszakítás engedélyezése ldi wreg, 0b10000000 ; interrupt lenyomásra out EICRB, wreg ldi wreg, 0b10000000 ; BT2 interruptolhat out EIMSK, wreg sei ; interruptok engedélyezése .... BT2_HANDLER: ; megszakításkezelő rutin ; Interrupt beérkezésekor a globális megszakításengedélyező bit automatikusan törlődik ... ; interrupt-kezelő utasítások ; reti hatására a globális megszakításengedélyező bit automatikusan engedélyeződik reti ; interrupt vége, vezérlés visszaadása a hívó szubrutinnak BT2_HANDLER: ; Interrupt beérkezésekor a globális megszakításengedélyező bit automatikusan törlődik ... ; interrupt-kezelő utasítások ; reti hatására a globális megszakításengedélyező bit automatikusan engedélyeződik reti ; interrupt vége, vezérlés visszaadása a hívó szubrutinnak
Pl.: INT gomb kezelése interrupttal, ha benyomják
;*** PORTE.4: INT button *** ldi temp,0b11111111 ; INT engedelyezese out PORTE,temp ldi temp,0b00000001 out DDRE, temp ;****** INT intterrupt ***** ldi temp, 0b00000010 ; interrupt lenyomasra out EICRB, temp ldi temp, 0b00010000 ; INT interruptolhat out EIMSK, temp sei ; interruptok engedelyezese
Kapcsolók kezelése
; inicializáció ldi temp, 0xff sts PORTG, temp ldi temp, 0x00 sts DDRG, temp ; olvasás lds r20, PING ;kapcsolók beolvasása r20 regiszterbe sbrc r20, 4 ;SW2 kapcsoló miatt kell, rejtélyes okokból a PING4-re van kötve ori r20, 0x04 ;ha SW2 1-ben van, akkor hozzáadok 4-et (1x0xx -> 1x1xx) sbrc r20, 4 subi r20, 0x10 ;és kivonom az 5. helyen lévő 1-et (1x1xx -> 0x1xx)
Szám kiírása
A !Bin2ToAsc5 szubrutingyűjtemény: MeresLabor2Meres3Bin2Ascii A KiirandoH:L regiszterpárban van a kiírandó érték, ezt a 0x0601 memóriacímtől kezdődően 5 ASCII karakterbe írjuk, majd ezeket kirakjuk az LCDre.
mov rBin1H, KiirandoH ; ezt mov rBin1L, KiirandoL ; konvertáljuk ldi ZH, 6 ; itt lesz ldi ZL, 6 ; a string vége call Bin2ToAsc5 ; konverzió ; öt karakter kiírása ld DataReg, Z+ call LCD_Data ld DataReg, Z+ call LCD_Data ld DataReg, Z+ call LCD_Data ld DataReg, Z+ call LCD_Data ld DataReg, Z+ call LCD_Data
-- SzaMa - 2005.10.11.
LCD kijelző
A stamp2.asm a barátod. (Egy egy terminal-t valósít meg, a soros portról olvas, és a képernyőre ír ki. Ebből a soros port kezelése, és a spéci karakterek nyomtatása nem fog kelleni neked.) A kódot másold át a saját progidba, a definíciók és a szubrutinok mind mehetnek, az inicializáló részből az üdvözlő képernyőt hagyd ki, meg a program törzsét is. A következő szubrutinokat fogod felhasználni:
- LCD_cls: törli a képernyőt, a kurzort a bal felső sarokba teszi
- LCD_GotoXY: az LCD_X és LCD_Y regiszterbe betöltöd a koordinátákat, majd meghívod szubritunt, ami áthelyezi a kurzort az adott pozícióba.
- LCD_Data: a DataReg regiszterbe betöltöd a kiírandó karakter ASCII kódját, és meghívod a szubrutint, amely kiírja a karaktert, és lépteti a kurzort.
"Grat!" kiírása: <Verbatim> call LCD_Cls ; törlés ldi DataReg, 'G' call LCD_Data ldi DataReg, 'r' call LCD_Data ldi DataReg, 'a' call LCD_Data ldi DataReg, 't' call LCD_Data ldi DataReg, '!' call LCD_Data </verbatim>
Érdemes megnézni az EEPROM-kezelő részeket is, mert oda sokkal kényelmesebb hosszabb szövegeket pakolni.
Megjegyzés: (by zslevi) Az első és legfontosabb dolog, hogy a soros port kezelést vedd ki a programodból, mert ez végtelen ciklusban várakozik a soros port-ról érkező info-ra. (A main loop-ból kiveszed az UART-os dolgokat, és beírod helyére a saját progid.) A többi dologról meg úgyis meglátod, hogy mit csinál (villognak a ledek és megjelenik az üdvözlő szöveg.)
Ha Flash-be írod (legalábbis a stamp2.asm flashnek hívja) a kiírandó szöveget egyszerűbb lesz a dolgod, mintha EEPROM-ba írnál, ugyanis az EEPROM-ot mindig újra kell programozni, ahányszor a futtatható kódot kicseréled. Be lehet valahol állítani, hogy ezt csinálja meg automatikusan a fejlesztőkörnyezet, de nekem nem sikerült. (A stamp2.asm végén a "demo_text" illetve a "www_text" van Flash-ben.)
www_text: .db "http://www.mscbp.hu",0x0d .db "http://www.pyxys.hu",0x0d .db "http://www.puzsar.hu",20,19 .db 0xc,"Wait character from RS232" .db " 9600,n,8,2",0,0
A "0x0d" az enter ASCII kódja, a "20,19" szintén lehetnének ASCII kódok, de nem azok, mert "stamp2.asm" felüldefiniálja őket (lásd a stamp2.asm fejlécét; a "19,20" Delay100ms-t ill. Dealay1s-t jelentenek esetünkben). A fenti öt sor egy stringnek számít, a string végét a két "0" jelzi. Az LCD_Flash_str az LCD_Write_Chr szubrutint használja. Ez ugyanazt csinálja, mint az LCD_Data, csak kiírja a vezérlőkaraktereket is, mint pl. az enter, tab stb.
A/D konverzió
A félelmetesnek tűnő művelet félelmetesen egyszerű. Az F port 3. pinjére van kötve a potméter, a 2. pinre a fényérzékelő, ezen kívül pl. hőmérő is található a panelen. A konverzió nem az jelenti, hogy az F megfelelő pinjének értékét beolvassuk, hanem hogy A/D konverziót indítunk, a megfelelő F pinről mintavételezve.
Az A/D konverzió két lényeges regisztere az ADMUX és az ADCSR (244-245. oldal az <a href="http://www.mit.bme.hu/oktatas/targyak/vimm3226/jegyzet/doc2467.pdf" target="_blank">ATmega128 doksiban</a>), ezek megfelelő beállításával választható ki, melyik csatornát akarjuk digitalizálni, a digitalizálás mennyi ideig tartson (pontosság), hova kerüljön az eredménye, és interruptot akarunk-e kapni elkészültéről (ADIE == 1-re ADC Conversion Complete Handler nevezetű interrupt fog kiváltódni).
A konverzió 10 bites eredménye az ADCH és ADCL regiszterekbe kerül, állítható, hogy jobbra vagy balra legyen igazítva (ADLAR bit).
Fényérzékelő
Mintakód, mely folyamatosan olvassa a fényérzékelő értékét, és visszajelzi a ledeken. A bitek nevére (lásd komment) rá tudsz keresni a doksiban.
ldi temp, 0b11100010 ; 11......... Az összehasonlításhoz a belső 2.56V referenciaérték lesz használva ; ..1........ Balra igazított bitek az ADC dupla regiszterben. Lásd man 246. oldal alja. ; ...00010... 2. pin, vagyis fényérzékelő kiválasztva out ADMUX, temp ldi temp, 0b11100111 ; 1.......... ADEN: ADC Enable ; .1......... ADSC: ADC Start Conversion ; ..1........ ADFR: ADC Free Running Select ; ...0....... ADIF: ADC Interrupt Flag ; ....0...... ADIE: ADC Interrupt Enable (akarsz -e interrupot) ; .....111... ADPS2:0: ADC Prescaler Select Bits (128-as osztó) out ADCSR, temp ldi temp,0b11111111 ; LED kimenet out DDRC,temp M_LOOP: in temp,ADCH out PORTC,temp jmp M_LOOP
-- Bandita - 2005.10.24.
Potméter
Úgy láttam, hogy a potméter a !PortF3-ra van kötve, legalábbis az Experiment Board leírása ezt mondja. Ez azt jelenti, hogy a 3-as AD csatornára kell beállítani az AD-t:
ldi r18, 0b11000011 ;// az utolsó két bit 11=belső 2.5voltos komperátor fesz. out ADMUX, r18
Ahhoz, hogy folyamatosan működjön az AD, Free Running módba kell tenni, engedélyezni és indítani kell. Interrupt nem kell, az előosztó 2 legyen:
ldi r18, 0b11100000 out ADCSR, r18
A bitek leírása az ATMega128.pdf 245-246. oldala körül van, a többi regiszterrel együtt. A fenti beállításokkal a 3. csatorna feszültségszintje fog folyamatosan megjelenni az ADCL és ADCH regiszterekben, az alsó 8 bit az ADCLben, a felső 2 az ADCH alsó 2 bitjén (10 bites az AD).
Időzítéshez érdemes a TMR1-et használni, mert az 16bites, és 1024-es előosztóval már lehet pár Hz-es jelet csinálni. FastPWM módba kell kapcsolni (a CTC móddal sok a szívás, főleg ha állítod az OCRxx regisztereket...).
8 bites timer
Ez a 8 bites TIMER/COUNTER0 egy lehetséges beállítása
ldi r18, 108 ; a compare regisztert beállítjuk pl. 108-ra, out OCR0, r18 ; így lesz a belső órajelünk majdnem pontosan 100 Hz ldi r18, 0x00 out TCNT0, r18 ; számláló nulláz ldi r18, 0b00001111 ; .....111 ; prescaler=1024 ; .0..1... ; mode=CTC out TCCR0, r18 ; TCCR0 beállítása sem hagyható el ldi r18, 0b00000010 ; ......1. ; compare match IT enable out TIMSK, r18 ; TIMSK 2. bitje engedélyezi az interruptot, ha elszámoltunk OCR0-ig sei ; global interrupt enable
Az inicializálás után 10 ms-enként meghívódik a Timer0 Compare Match interrupt
pepov levele alapján
16 bites timer
Egy kicsit részletezve, hogy is kell egy 16bites időzítőt elindítani :) csak elvetemülteknek, akik nem akarják a milliszekundumokat külön számolgatni.
Először kivonatolva, hogy ne tűnjön bonyinak :)
A két control registerben (TCCR1A, TCCR1B) be kell állítani az üzemmódot (WGM=0100), az előskálázót CS=101).
Aztán be kell állítani a periódust (OCR1AH, OCR1AL), nullázni kell a számlálót (TCNT1H, TCNT1L) és engedélyezni az interuptkérést (TIMSK regiszter OCIE1A=1). + sei
S itt a kommentezett kód:
.equ c1max = 00 ; counter1 mikor nullázódjon? ; úgy tudom, a laborban a clock az 12MHz, de megkérded -> megmondják ; 1 sec => c1max = clock/1024 = 12*1024 = 00 .def temp = r16 ; temporary register (...) ; TCCR1B: Timer/Counter1 Control Register B ; 4-3. bit: WGM1[3]-WGM1[2] = 01 ; a WGM a számláló pontos működését határozza meg ; 2-0. bit: előskálázó választása = 101 => clock/1024 ldi temp, 0b01101 out TCCR1B, temp ; TCCR1A: Timer/Counter1 Control Register A ; 1-0. bit: WGM1[1]-WGM1[0] = 00 ldi temp, 0 out TCCR1A, temp ; WGM1[3]-WGM1[0] = 0100 -> clear timer on compare match ldi temp, HIGH(c1max) ; számláló periódusának beállítása: out OCR1AH, temp ldi temp, LOW(c1max) ; felső - alsó byte, sorrend fontos! out OCR1AL, temp clr temp out TCNT1H, temp ; számláló nullázása out TCNT1L, temp ldi temp, 0b10000 ; timer1 match A interrupt enable out TIMSK, temp ; visszaírás sei
Egyéb assembly programrészletek
Véletlen szám
A legegyszerűbb módja a véletlenszám generálásnak a gombnyomás hossza: végtelen ciklusban növeled egy regiszter értékét (255 után túlcsordul), amíg le nem nyomják a gombot. Mivel az órajel 16 MHz, tényleg teljesen véletlenszerű, hogy a 256 állapot közül melyikben nyomták le a gombot. A második véletlenszámodat egyből ugyanígy megkaphatod a gomb felengedésére várva (de előtte tegyél be egy 4ms-es várakozást, hogy a pergés ne rontsa el - még az után is egy csomó ideig le lesz nyomva a gomb).
Ha még sok-sok véletlen számra van szükséged, akkor az előző számokból kiindulva a digitből ismert XOR-ral visszacsatolt shiftregisztert alkalmazhatod.
Többszörös elágazások
Ha a programban több egymásba ágyazott if szerkezetet vagyis egy switch - case-t kell létrehoznod, akkor figyelj arra, hogy a branch utasítások csak korlátos nagyságú ugrást képesek végrehajtani a kódban. Ezért ha pl. cpi - breq utasításpárt használsz az elágaztatás megvalósítására, akkor a breq mögött álló címke legfeljebb 64 utasítás sorral később állhat a programkódban. Ennek megkerülésére egy a feltétel ágba ágyazott call-t lehet használni, mely ugyan szintén korlátos nagyságú távolságra levő programrészlet hívására képes, azonban a 64k már általában elegendő a mi céljainkra. Ha ez sem lenne elég, akkor jmp-vel lehet megoldani (4M már mindenképp elég lesz), előtte viszont gondoskodni kell a PC stack-re mentéséről, feltéve, hogy a szubrutin hívás után vissza is szeretnénk térni a hívási ponthoz.
;*** Fő program (részlet) *** M_LOOP: cpi temp,{feltétel_1 konstans} ; konstans, amely feltétel teljesülése esetén a szubrutint meg akarjuk hívni breq callSubRoutine1 ; ha nem használnánk a szubrutinokat és itt sok kód szerepelne, a breq nem tudná megcímezni callSubRoutine1-t cpi temp,{feltétel_2 konstans} breq callSubRoutine2 ; ha nem használnánk a szubrutinokat és itt sok kód szerepelne, a breq nem tudná megcímezni callSubRoutine2-t call SubRoutine3 jmp M_LOOP callSubRoutine1: call SubRoutine1 jmp M_LOOP callSubRoutine2: call SubRoutine2 jmp M_LOOP ;*** Szubrutinok *** SubRoutine1: {ide kerülnek a feltétel_1 teljesülése esetén végrehajtandó utasítások} ret SubRoutine2: {ide kerülnek a feltétel_2 teljesülése esetén végrehajtandó utasítások} ret SubRoutine3: {ide kerülnek az else ág esetén végrehajtandó utasítások} ret
stb.
-- NeoXon - 2005.10.13.
Osztás és maradék képzés
Ha az a feladat, hogy jelenítsük meg egy regiszter tartalmát decimális formában, jól jön, ha tudunk 10-zel osztani, illetve 10-es maradékot képezni. Sajnos a =div= és =mod= utasítások lemaradtak az ATMega128 mikrovezérlő utasításkészletéből, ezért külön kell őket megvalósítani.
Az itt leírtnál sokkal egyszerűbben meg lehet oldani a kérdést, úgy, hogy a mérésvezető is értse. Ha ezt a kódot használod, tudni fogják hogy nem saját kútfőből dolgoztál. -- Bandita - 2007.02.08.
Íme a kód:
.def temp=r16 ; az osztás egy iterációs lépését végzi el .macro DivIter lsl @4 ; hányados*=2 lsr @1 ; osztó/=2 ror @0 cp @3, @1 ; maradék >=? osztó*2^x brne notequal cp @2, @0 notequal: brlo lo ; ha nem, a hányados x. bitje 0 ori @4, 1 ; különben 1 sub @2, @0 ; és a maradékból levonunk osztó*2^x-et sbc @3, @1 lo: .endmacro ; hányados és maradék számolása ; pre: r1=osztandó/256, r0=osztandó%256, temp=osztó ; post: r1=hányados, r0=maradék, temp=osztó DivMod: push YH push YL mov YH, temp ; Y = osztó shl 8 ldi YL, 0 ldi temp, 0 ; hányados = 0 DivIter YL,YH,r0,r1,temp ; hányados legfelső bitjének számítása DivIter YL,YH,r0,r1,temp DivIter YL,YH,r0,r1,temp DivIter YL,YH,r0,r1,temp DivIter YL,YH,r0,r1,temp DivIter YL,YH,r0,r1,temp DivIter YL,YH,r0,r1,temp DivIter YL,YH,r0,r1,temp ; hányados legalsó bitjének számítása mov r1, temp ; hányados r1-be kerül mov temp, YL ; osztó visszakerül temp-be pop YL pop YH ret ; példa a kód használatára ldi temp, 0 mov r1, temp ldi temp, 82 mov r0, temp ldi temp, 10 call DivMod ; r1=8, r0=2, temp=10
-- Peti - 2005.12.17.
Kész házi feladatok
Kidolgozott, kész házi feladatok, amelyek a 3. mérésre készültek.
Kifutó fények(OPTO,PWM)
A PWM-nek az a lényege, hogy nem folyamatosan adod a jelet a LED-nek, hanem fogsz egy alapfrekvenciát (szemnek láthatatlan -> nagyobb, mint 25 Hz -> például 100 Hz), és ezzel a frekvenciával változtatod a kitöltési tényezőket.
Azaz 100% esetén mind a 100 db századmásodperces blokkban 1 értéket adsz ki. 99% esetén a 100 blokkból 99-ben 1-et, 1 blokkban 0-t. És így tovább, pl 45% esetén 100 blokkból 45-ben 1, a maradék 55-ben 0 a kiadott érték. Majd ezt a 100 blokkot ismételgeted egymás után folyamatosan.
Ez azonban néha villogni látszik, főleg a végértékeknél. A még jobb hatás érdekében vegyél mondjuk 10KHz-es frekvenciát, így másodpercenként 10000 blokkod lesz, ezt felosztod 100×100 blokkra. A fenti módszer szerint rakod össze a 100 blokkból álló századmásodperceket, és ezekből a 100 blokkos, századmásodperc időtartamú mintákból raksz egymás után 100 darabot minden másodpercben.
Ezzel gyönyörűen lehet fokozatokat létrehozni digitális vezérlések mellett.
Egy pszeudokódú program, mely 10 másodperc alatt, fokozatosan csökkenti a fényerőt 100%-ról 0%-ra PWM segítségével:
ciklus i=100-tól 0-ig //ez lesz egy % ugrás, 1/10 sec alatt: ismételd 10-szer: //ez lesz egy db PWM blokk, 1/100 sec alatt: ismételd i-szer: //az egyes bitek adj ki 1-est és várj 1/10000 sec-ot ismételd 100-i-szer: //a nullás bitek adj ki 0-t és várj 1/10000 sec-ot ciklus vége
Így a PWM blokkokból 10 egyforma jön egymás után mindig, és minden 10. után eggyel kevesebb 1-es lesz bennük. Az elején még csupa 1 lesz, aztán elkezdenek beszivárogni a 0-k, majd a vége felé már azok dominálnak, a legvégén meg csupa 0 lesz. Persze közben az is fontos, hogy kb egyenletesen jöjjenek az egyesek és nullák, ezért van egy % lépéshez 10 PWM blokk. Ha nagyon villog, akkor meg lehet próbálni lépésenként 100 blokkal is, ekkor értelemszerűen az idők ehhez igazítandóak.
Feladat
Írni kellett egy kódot, ami a ledeket egy kifutópálya fényeihez hasonlóan működteti, illetve a külső fény függvényébel változtatja a ledek fényerejét. A fényerőt pulse width modulation (PWM) segítségével kellett megoldani. A rendszert le lehet állítani, majd újraindítani az INT gombbal. INT-et pergésmentesíteni nem kell.
Az assembly fájl letöltése
Megjegyzések
A kódban próbáltam a lehető legtöbbet kommentezni. Akinek ez sem segít, az böngéssze át a teljes használati útmutatót :) A szimulátoron nem akart jól műküdni a PWM, így saját módszerrel kellett megvalósítani. A megoldás kicsit bugos, amikor leáll, majd beindul a rendszer: a fényerő "értékelése" néha az ellenkezőjére vált, azaz sötétben lesznek világosabb a ledek. Beépített PWM-mel valószínűleg helyesen működik. Ha a komment eltér a kód valódi jelentésétől, akkor a kód a mérvadó. Elvileg (sőt gyakorlatilag is) működött.
(Azoknak, akik nem tudják, mi az a PWM: A led fényerejét úgy változtathatjuk, hogy ki-bekapcsolgatjuk gyorsan. Hosszabb szünet két bekapcsolás között-->halványabb fény.)
-- Bertram - 2006.11.28.
Kígyó játék
Feladat
A Nokia telefonokból megismert kígyójáték reprodukálása ATmega128-ra. A 3 nehézségi szint három különböző pályának felel meg, melyek több belső fallal is rendelkeznek. A kígyó hossza nem nő miután felveszi a kaját, de a program fel van készítve a növekedésre :)
Megjegyzések
A kódban szinte minden sor kommentezve van, így a makrók, a megszakítások, a pergésmentesítés, a memória kezelés és a funkcióhívások tanulásának forrása is lehet. Azokban a kódokban hiányos a dokumentáció, amit helyben az implementáláskor illesztettünk bele. AVR Studio-s szimulációban elég nehézkesen tesztelhető, mert nem tud megszakítást generálni és LCD plugin sincs erre a hardverre. A tesztelést tehát memória képben kell végezni, úgyis azt rajzolja ki a program a kijelzőre. Sok sikert!
-- Majdi - 2006.12.12.
Betörés érzékelő
Feladat
A baloldali LED soron alapesetben a zöld LED világít. Ha valaki elhalad az optikai érzékelő előtt, akkor gyulladjanak ki a piros LED-ek és 2 Hz-es frekvenciával kezdjenek el villogni. Egészen addig villogjanak, amíg a kezelőszemélyzet a BT0 gomb megnyomásával nem nyugtázta, hogy észrevették a jelzést. A villogás időzítése hardver időzítővel történjen. A gomb pergésmentesítésével nem kell foglalkoznia, viszont kezelését megszakítás segítségével valósítsa meg.
HW: timer, LED-ek, fényérzékelő, nyomógomb
Egy hasonló feladat, csak itt az INT gombbal kell leállítani a jelzést. Másfajta hardver timert használtam szoftveressel egyetemben. Tökéletesen működött.
Megjegyzések
Működik, bár néhol kicsit nem logikus, néhol kicsit redundáns. Nemhiába, a végefelé locsolgatásos módszerrel fejlesztgettem, de végülis elfogadta a mérésvezető, működött prímán.
-- Csaba - 2008.03.18.
Futófény potméteres szabályzással
Feladat
Futófény megvalósítása LED eken: sorban felgyullad az összes LED, majd az elsőtöl kezdve egyenként kialszanak.A léptetés sebessége és iránya a potenciométer állásól függjön, 100 msec-ként növelhető/csökkenthető legyen 2x15 lépésben, ha a potenciométer a középállásnál kisebb értéken van akkor a fény "előre" lépked ha nagyobb az érték akkor "hátrafelé". A lámpák időzítése hardver időzítővel történjen.
HW: timer. LED-ek,potméter.
Megoldás:
by Pöri
Liftvezérlés
Feladat
3 emeletes (+földszint) épületben lift vezérlésének szimulálása. Egyik LED-sor jelzi a lift helyét, másik a liftajtó nyitását; nyomógombokkal lehet megnyitni a liftet. Hívás irányát a gombhoz tartozó kapcsoló mutatja. Az ajtó kinyitását mindig azon a szinten kell mutatni, ahol a lift éppen jár. A lift gyorsasága saját belátás szerint állítható, körülbelül egy szinte való megállás ideje: 0,25 sec - 1 sec (Timer egység használata). A program egyetlen hívást tárol, amíg ki nem szolgálja, nem fogad újat.
mayer - 2010.04.10
2x4 bites számológép (LED-es)
Feladat
A számológép a 0..15 számokon végzi el a 4 alapműveletet. Az első operandust a kapcsolókon lehet beállítani (SW0 a legkisebb, SW3 a legnagyobb helyiérték), a nyomógombok valamelyikének megnyomása állítja be az operandust és a műveletet, ekkor az operandus a bal oldali LED-soron, a műveletnek megfelelő LED pedig a jobb oldalon jelenik meg. Ezt követően beállítható a második érték a kapcsolókon, és az INT gomb megnyomására a művelet eredménye a LED-ekre kerül 5 másodpercre, majd törlődik a kijelző.
Hw: timer, LED-ek, nyomógombok, kapcsolók
Megoldás:
LED céllövölde potméterrel
Feladat
A baloldali LED oszlopon véletlenszerűen LEDek gyulladnak fel. A felgyulladások közötti időt(n*100 ms) a potméter állásával lehet szabályozni, 16 lépésben. A nyomógombokkal el kell találnunk, hogy melyik LED világít. A megnyomás pillanatában a LED-ek állapota kimerevedik, a baloldali oszlopon pedig az a LED világít, amelyhez tartozó gombot lenyomtuk. Minél kisebb az időalap ( hw időzítés) annál nehezebben lehet eltalálni az állapotot. Találat esetén a jelző jobboldali LED 4 Hz frekvenciával villogjon. Az INT gomb megnyomásával lehet a mérést folytatni. A pergésmentesítéssel nem kell foglalkozni.
Hw: timer, LED, kapcsoló, potméter
Megoldás:
Szoftveres PWM ami fényérzékelőről vagy Potiról veszi a jelet.
Feladat
A feladat szoftveres pwm volt, ami az ADCről vette az értéket, minnél sötétebb van annál jobban világítanak a ledek. Kiegészítettük, hogy kapcsoló segítségével lehessen állítani az ADC és a Poti között. Mivel a mintavételezett jel baromi zajos volt ezért átlagoljuk az ADC értékét. Levágjuk az alsó biteket, mert azok értéke használhatatlan.
Használjátok egészséggel.
Megoldás:
- Ezen a helyen volt linkelve a(z) sw.asm nevű fájl ("sw.asm" link szöveggel) a régi wiki http://wiki-old.sch.bme.hu/bin/view/Infoalap/MeresLabor2Meres3 oldaláról. (Ha szükséged lenne a fájlra, akkor a pontos oldalmegnevezéssel együtt küldd el a wiki sch.bme.hu címre a kérésedet)
- Szoftveres PWM ADC és Poti
Terkó - 2011.05.26