„Mérés laboratórium 2. - 3. mérés” változatai közötti eltérés

A VIK Wikiből
Ugrás a navigációhoz Ugrás a kereséshez
(legyen vissza-link a tárgyoldalra!)
1. sor: 1. sor:
 
{{Elavult}}
 
{{Elavult}}
 +
 +
{{Vissza|Mérés_laboratórium_2.}}
  
 
__TOC__
 
__TOC__

A lap 2013. június 24., 14:39-kori változata

Hiba a bélyegkép létrehozásakor: Nem lehet a bélyegképet a célhelyre menteni
Ez a lap elavult adatokat tartalmazhat. Segíts felfrissíteni
Hiba a bélyegkép létrehozásakor: Nem lehet a bélyegképet a célhelyre menteni

Ha nem tudod, hogy állj neki, olvasd el a tutorialt.


← Vissza az előző oldalra – Mérés_laboratórium_2.


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.

További LCD-s hasznosságok


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 ATmega128 doksiban), 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 :)

A kígyó játék letöltése

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

Kód letöltése (UTF8)

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.

Forráskód

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:

futofeny.asm

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.

Liftvezerlo.zip

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:

szamologep.asm

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:

i108cdu23_1.doc

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:

  • sw.asm: Szoftveres PWM ADC és Poti

Terkó - 2011.05.26