Čítače a časovače

Z MAM wiki

Verze z 11. 3. 2014, 11:58; Horcik (diskuse | příspěvky)
(rozdíl) ← Starší verze | zobrazit aktuální verzi (rozdíl) | Novější verze → (rozdíl)
Přejít na: navigace, hledání

V minulé úloze jsme regulaci otáček motoru ventilátoru řešili pomocí softwarově časované pulsně šířkové modulace. Nevýhody jsou zřejmé - procesor stále běží a je zatěžován nepřetržitým "nicneděláním", doba trvání pulsů je obtížně nastavitelná a ovlivněná vyvoláváním přerušení apod. Přitom se nabízí využít další část logiky zabudované do mikroprocesoru, blok čítačů a časovačů. Ten obsahuje dva 8-bitové a jeden 16-bitový čítač/časovač s předděliči kmitočtu a komparátory hodnot, na ně je navázáno celkem 6 kanálů PWM. Jednotlivé kanály se v možnostech mírně liší, princip popisovaný dále pro 8-bitový kanál 0 je ale stejný.

[editovat] Základní vlastnosti

Hlavní částí každého čítače/časovače je jednotka programovatelného čítače TCNTn, taktovaná buď hodinovým signálem procesoru vyděleným nastavitelným předděličem, nebo externím zdrojem hodinového signálu. Výstup čítače je nepřetržitě porovnáván s hodnotou uloženou v Output Compare Register (OCRnx, např. OCR0A, OCR0B, 1A...). Výsledek porovnání lze použít pro PWM na výstupech Output Compare (OCnx, např. OC0A, OC0B, ...). V okamžiku shody stavu čítače a registru OCRnx je také nastavován příznak Compare Flag (OCFnx, tj. OCF0A až OCF2B), to lze využít pro vytváření požadavku na přerušení.


Čítač/časovač múže být nastaven pomocí nastavení registrů WGMn a COMnx, Waveform Generation mode a Compare Output mode na jeden za 4 módů, detaily je třeba hledat v datasheetu v sekcích Counter/Timer0, 1, 2:

Normal Mode, (WGM02:0 = 0) Je nejjednodušší mód, čítač čítá vždy nahoru, po přetečení přes 0xFF pokračuje opět od 0x00 a při přetečení do nuly nastaví příznak přetečení Timer/Counter Overflow Flag (TOV0). Přerušení může vyvolávat i výstupní komparátor při shodě hlídané hodnoty se stavem čítače Output Compare Flag (OCFnx).

Clear Timer on Compare Match (CTC) Mode, (WGM02:0 = 2) V tomto módu je registr OCR0A použit ke změně počtu stavů čítače, nastavuje koncovou hodnotu, po jejímž dosažení je nastaven příznak Output Compare Flag (OCFnx) a čítač je vynulován a znovu čítá od nuly, v tu chvíli také nastaví příznak přetečení Timer/Counter Overflow Flag (TOV0). Oba příznaky mohou vyvolat přerušení.

Fast PWM Mode, (WGM02:0 = 3 nebo 7) Tento mód dovoluje generovat PWM výstup, čítač čítá od nuly do maxima (0xFF pro WGM2:0 = 3, a OCR0A pron WGM2:0 = 7) a potom přejde opět do stavu 0x00, porovnávací jednotka umožňuje generovat na výstupech OC0x PWM signály. Přerušení může vyvolávat TOV2 při přetečení.

Phase Correct PWM Mode, (WGM02:0 = 1 nebo 5) Mód je podobný předchozímu, liší se tím, že čítač po dosažení nejvyšší hodnoty čítá zpět ke své nejnižší hodnotě, tím vytváří přesně symetrický výstup. Přerušení lze vyvolávat příznakem TOV2 při nejnižší hodnotě čítače.

[editovat] Příklad

Pro náš účel regulace ventilátoru využijeme mód Fast PWM, při kterém čítač čítá od nuly do maxima (0xFF pro WGM2:0 = 3, a OCR0A pro WGM2:0 = 7), nabízí se časovač 0 s výstupem OC0B, ten sdílí pin č. 11 s momentálně nepotřebným portem PD5 (výstup OC0A není možno použít, jeho komparátor se stará o zkrácení cyklu čítače). S maximem čítače nastaveném na 0xFF bychom získali rozlišení 256 stupňů regulace, to je pro tyto účely zcela zbytečné, navíc při hodinovém kmitočtu mikroprocesoru 1 MHz by byla frekvence PWM signálu zhruba 6x nižší než požadovaných 25 kHz, při předděliči nastaveném na 1 dostaneme 1 MHz/256=3,9 kHz. Pokud ale nastavíme mód s WGM2:0 = 7, můžeme zapsat koncovou hodnotu čítače do OCR0A a její volbou nastavíme požadovaný kmitočet zhruba 25-30 kHz pro PWM, 1 MHz/25 kHz=40. K dispozici máme rozlišení 40 stupňů regulace, to bohatě stačí. Jeden mírný problém nastane pouze s požadavkem na nulovou hodnotu výstupu, dle datasheetu se na výstupu při nastavení střídy na nulu bude objevovat úzká špička. Pokud by to vadilo, lze pro tento případ odpojit od vývodu procesoru časovač a nulu nastavit na patřičném bitu paralelního portu PD5. Druhý problém je rozsah 0-100 % otáček při vstupu z klávesnice s rozsahem 0-9, tedy v 9 krocích. Hodnotu OCR0A proto zvolíme jako násobek 9, např. 45 nebo 36, frekvence PWM bude 1 MHz/36=27,28 kHz, stále v požadovaném rozsahu. Hodnotu klávesy lze vynásobit 4 a máme přímo počet hodinových taktů, po které má být PWM výstup v log. 1, tedy hodnotu registru OCR0B.

; 
; example fan program for ATmega168 with Timer controlled PWM&Interrupt&Sleep
;
; Rotation speed  is controlled by keyboard, 
; keys 0-9 represent the speed between 0 and 100 %
;
; Fan starts to rotate with the first valid key press
;
; To do: *** Catch only the key press, not key release
;
; To do: *** Set higher value of PWM (=higher fan rpm) for 
; a few first periods to start the fan reliably
;
;
; P4 CPU fan Ucc pin is supposed to be connected 
; to +12 V, GND pin is supposed to be connected 
; to NMOS Drain,, Source on GND, Gate on 
; pin 11 (OC0B, PD5). Fan runs when pin 11 is high.


.INCLUDE "m168def.inc"

.EQU PWM_PULSES = 36	; value for 27.8 kHz PWM
;.EQU PWM_PULSES = 45	; value for 22.2 kHz PWM


.ORG 0x0000 
	jmp Main ; Reset Handler

.ORG 0x0008 
	jmp isr1 ; PCINT1 Handler



; Main program start

Main: 

; Stack pointer init:
	ldi r16,high(RAMEND); Main program start
	out SPH,r16 ; Set Stack Pointer to top of RAM
	ldi r16,low(RAMEND)
	out SPL,r16


; Hardware initialization

; Keyboard init:
	cbi DDRC, 2 ; set inputs for keyboard (COL1-3)
	cbi DDRC, 3
	cbi DDRC, 4

	sbi PORTC, 2 ; set internal Pull-Ups for keyboard
	sbi PORTC, 3
	sbi PORTC, 4

	sbi DDRD, 0 ; set driving outputs for keyboard
	sbi DDRD, 1 ; (ROW1-ROW4)
	sbi DDRD, 2
	sbi DDRD, 3

	cbi PORTD, 0	; log. 0 on all rows
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3


; Timer controlled PWM init:
;
; There are registers TCCR0A and TCCR0B for config, DDRD for output bit
; enabling, OCR0A for counter lenght and OCR0B for pulse "high" lenght.
; Register TIMSK0 controlls interrupts - not used, 0x00 by default 

PWM_INIT:
	ldi R17, 0b00100011	; Fast PWM Mode, out on OC0B, non Inverting
	out TCCR0A, R17			; 
	ldi R17, 0b00001001	; WGM2:1 (Fast PWM), CS2..0:001 (internal clock, prescale=1)
	out TCCR0B, R17
	ldi R17, PWM_PULSES	; load number of clock pulses for 1 PWM period
	out OCR0A, R17   

	sbi DDRD, 5	; set pin 11 as PWM output OC0B (PD5 pin)


; Keyboard interrupt setup
;
; Activation of pin change interrupt - PROBLEM!!! PCICR and PCIMSK are 
; extended I/O registers (0x68 and 0x6C), and must be handled as 
; a memory location

	ldi r26, PCICR ; load address of PCICR in X low
	clr r27 ; load high byte with 0
	ldi r16,0b00000010 ; activate PCINT1
	st X, r16 ; store new PCINT1

	ldi r26, PCMSK1 ; load address of PCMSK1 in X low
	clr r27 ; load high byte with 0
	ldi r16,0b00011100 ; allow pin change interrupt on portC bits 2,3,4
	st X, r16 ; store new PCMSK1

	sei ; Enable interrupts


; Set sleep mode of the CPU
; SMCR: 0,0,0,0,SM2,SM1,SM0,SE   SM2..0: Sleep Mode Select Bits, SE: Sleep enabled)

	ldi r16,0b00000001 ; Idle mode 
	out SMCR,r16 ; Sleep mode set


; Sleep loop, wake up by the Interrupt, return with RETI back to sleep loop

loop:
	sleep ; now AVR sleeps
	nop ; return from Interrupt to this instruction
	rjmp loop ; and sleep again


; PCINT0 Service Routine:
;
; To do: *** rpm reading, regulation, etc.


isr1:
	rcall KEYPRESS

	mov R17, R16
	lsl R17
	lsl R17	; multiply key number by 4 for 10 steps in 40 clock pulses of PWM
	out OCR0B, R17  ; output pulse "high" lenght to PWM compare unit 

	reti ; return from Interrupt


; Keyboard decoding :

KEYPRESS:
KEY0:
	sbi 	PORTD, 0
	sbi 	PORTD, 1
	sbi 	PORTD, 2
	cbi 	PORTD, 3	;log. 0 to the row with *, 0, #, D	
	sbic	PINC, 3
	rjmp	KEY1
	ldi	R16, 0		;pressed key 0
	rjmp	KEYRET
KEY1:
	cbi 	PORTD, 0	;log. 0 to the row with 1, 2, 3, A
	sbi 	PORTD, 1	;log. 1 on another three
	sbi 	PORTD, 2
	sbi 	PORTD, 3	
	sbic	PINC, 2
	rjmp	KEY2
	ldi	R16, 1		;pressed key 1
	rjmp	KEYRET
KEY2:
	sbic	PINC, 3
	rjmp	KEY3
	ldi	R16, 2
	rjmp	KEYRET
KEY3:
	sbic	PINC, 4
	rjmp	KEY4
	ldi	R16, 3
	rjmp	KEYRET

KEY4:
	sbi 	PORTD, 0
	cbi 	PORTD, 1	;log. 0 to the row with 4, 5, 6, B
	sbi 	PORTD, 2
	sbi 	PORTD, 3	
	sbic	PINC, 2
	rjmp	KEY5
	ldi	R16, 4		;pressed key 4
	rjmp	KEYRET
KEY5:
	sbic	PINC, 3
	rjmp	KEY6
	ldi	R16, 5
	rjmp	KEYRET
KEY6:
	sbic	PINC, 4
	rjmp	KEY7
	ldi	R16, 6
	rjmp	KEYRET

KEY7:
	sbi 	PORTD, 0
	sbi 	PORTD, 1
	cbi 	PORTD, 2	;log. 0 to the row with 7, 8, 9, C
	sbi 	PORTD, 3	
	sbic	PINC, 2
	rjmp	KEY8
	ldi	R16, 7		;pressed key 7
	rjmp	KEYRET
KEY8:
	sbic	PINC, 3
	rjmp	KEY9
	ldi	R16, 8
	rjmp	KEYRET
KEY9:
	sbic	PINC, 4
	rjmp	KEYRET
	ldi	R16, 9

KEYRET:
	cbi PORTD, 0	; log. 0 on all rows for next key press catch
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3
	ret


[editovat] Odkazy

Osobní nástroje