Mérés laboratórium 2. - 3. mérés

A VIK Wikiből
A lap korábbi változatát látod, amilyen Unknown user (vitalap) 2012. október 21., 21:03-kor történt szerkesztése után volt. (Új oldal, tartalma: „{{GlobalTemplate|Infoalap|MeresLabor2Meres3}} vissza a Mérés 2 tárgyhoz ---- __TOC__ A második mérés végen a laborvezetővel kitaláltok egy …”)
(eltér) ← Régebbi változat | Aktuális változat (eltér) | Újabb változat→ (eltér)

Ez az oldal a korábbi SCH wikiről lett áthozva.

Ha úgy érzed, hogy bármilyen formázási vagy tartalmi probléma van vele, akkor, kérlek, javíts rajta egy rövid szerkesztéssel!

Ha nem tudod, hogyan indulj el, olvasd el a migrálási útmutatót.


vissza a Mérés 2 tárgyhoz



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

Eredeti forrás: <a href="http://www.mit.bme.hu/oktatas/targyak/vimm3226/jegyzet/doc2467.pdf" target="_blank">ATmega128 doksi</a> 87-89. oldal

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 <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 :)

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:

Szoftveres PWM ADC és Poti

Terkó - 2011.05.26