Uživatel:Vitvamar

Z MAM wiki

Přejít na: navigace, hledání

Obsah

[editovat] Stopky

[editovat] Obvodové řešení:

PD2 - tlačítko START/STOP/RESET

PD3 - tlačítko MEZIČAS

displej ve formátu: MM:SS:mS (celkem 5 segmentů)

Na PORTB navěšená sběrnice pro 7 segmentové displaye.

PC0, PC1, PC2, PC3, PC4 spínají LE vstup latche 74AC373N.

[editovat] Popis časovače

Soubor:Ctc1.png
Soubor:Ctc2.png

Procesor má nastavený TIMER1 do CTC režimu, který generuje signál o kmitočtu 1kHz, tedy přerušuje po 1ms a to je časovou základnou. Když se dosadí frekvence oscilátoru 1000000, předdělička=8 a OCR1A=124, vyjde f=1 kHz.

[editovat] Schéma

Soubor:Stopky.png

[editovat] Kód

#include <avr/io.h>
#include <avr/interrupt.h>

// pocet moznych ulozeni mezicasu
#define MEZICASU 5


// casove promenne
unsigned char milisekundy_T, milisekundy_Z;
unsigned char sekundy_J, sekundy_D;
unsigned char minuty_J, minuty_D;

// mezicas
unsigned short mezicas_milisekundy[MEZICASU];
unsigned char mezicas_sekundy[MEZICASU];
unsigned short mezicas_minuty[MEZICASU];

// mezicasy
unsigned char mezicas;

// prave multiplexovany segment
unsigned char segment;


enum stav_stopek {
 resetovany = 0, stopuji, zastaveny
} stav;


// rozsvecovani segmentu
const unsigned char segmenty[10]={0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};




ISR(TIMER0_OVF_vect, ISR_NOBLOCK)
{
	// odpojeni vystupu
	DDRB = 0x00;
	// nasledujici segment
	PORTC = 1 << segment;
	
	switch(segment){
		case 0:
			PORTB = segmenty[minuty_D];
		break;
		case 1:
			PORTB = segmenty[minuty_J];
		break;
		case 2:
			PORTB = segmenty[sekundy_D];
		break;
		case 3:
			PORTB = segmenty[sekundy_J];
		break;
		case 4:
			PORTB = segmenty[milisekundy_T];
		break;	
	}
	
	
	// pripojeni vystupu
	DDRB = 0xFF;
	
	if(++segment == 5)
		segment = 0;
}



//compare - ovf

ISR(TIMER1_COMPA_vect , ISR_BLOCK)
{
	
	if(++milisekundy_Z == 100){
		milisekundy_Z = 0;

		if(++milisekundy_T == 10){
			milisekundy_T = 0;

		if(++sekundy_J == 10){
			sekundy_J = 0;
			
			if(++sekundy_D==6){
				sekundy_D=0;
			
				if(++minuty_J == 10){
					minuty_J=0;
				
					if(++minuty_D==10){
						minuty_D=0;
					}
				}		
			}
		}
	}	
}
}

// START/STOP/RESET
ISR(INT0_vect, ISR_BLOCK)
{
	switch(stav){
		
		case resetovany: // START
			stav = stopuji;
			TCCR1B = 0x0A;
		break;
		
		case stopuji: // STOP
			stav = zastaveny;
			TCCR1B = 0x08;
			TIFR1 = 0x00;
		break;
		
		case zastaveny: // RESET
			stav = resetovany;
			milisekundy_T = 0;
			milisekundy_Z = 0;
			sekundy_J = 0;
			sekundy_D = 0;
			minuty_J = 0;
			minuty_D = 0;
		
			mezicas = 0;
		
			unsigned char i;
		
			for(i = 0; i < MEZICASU; i++){
				mezicas_milisekundy[i] = 0;
				mezicas_sekundy[i] = 0;
				mezicas_minuty[i] = 0;
			}
		
		break;
	}
}


// ulozeni mezicasu
ISR(INT1_vect, ISR_BLOCK)
{
	if(mezicas<MEZICASU){
		
		mezicas_milisekundy[mezicas] = 1000*milisekundy_T + milisekundy_Z;
		mezicas_sekundy[mezicas] = 10*sekundy_D + sekundy_J;
		mezicas_minuty[mezicas] = 10*minuty_D + minuty_J;
		
		mezicas++;
	}
}





int main(void)
{
	// TIMER0 s delickou 8, plne preteceni
	TCCR0B = (1 << CS00);
	TIMSK0 = (1 << TOIE0);
	
	// nastaveni TIMER1 do CTC modu
	TCCR1B = 0x08;
	// preruseni pri compareA
	TIMSK1 = 0x02;
	
	// kmitocet preruseni 1 kHz
	OCR1A = 124;
	
	// ext. preruseni - sestupna hrana na INT0
	EICRA = (1<<ISC01) | (1<<ISC11);
	EIMSK = (1<<INT0) | (1<<INT1);

	// sedmisegmentovka
	DDRB = 0xFF;
	
	// multiplex segmentu
	DDRC = 0x1F;

	PORTD = (1<<PD2) | (1<<PD3);

	sei();
	
	
	while(1);
}

[editovat] Domácí úkoly

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                    ;;
;;  Regulace otacek ventilatoru PWM modulem s Timer0                  ;;
;;  a pripojenou maticovou klavesnici na ATMega88.                    ;;
;;  ---------------------------------------------------------------   ;;
;;  Regulace jest mozna stiskem klaves '1'-'9' s postupnou zmenou     ;;
;;  otacek. Stiskem '0' dojde k odpojeni ventilatoru.                 ;;
;;  ---------------------------------------------------------------   ;;
;;  Radky maticove klavesnice pripojeny jsou na PORTD0-3,             ;;
;;  sloupce pripojeny jsou na PORTB0-3.                               ;;
;;  Modul PWM(A) vyveden na PORTD6.                                   ;;
;;                                                                    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


.include "m88def.inc"

.org $0000
	rjmp reset

.org $000E
	rjmp timer0_compareA

.org $000F
	rjmp timer0_compareB

.org $0010
	rjmp timer0_ovf


; preteceni TIMER0, nepouzite
timer0_ovf:
	reti

; pripravene obsluhy preruseni pro obe jednotky PWM, nepouzite
timer0_compareA:
	reti

timer0_compareB:
	reti




reset:


; nastaveni timer0 na Fast PWM
	ldi r20, 0b11110011
	out TCCR0A, r20

	ldi r20, 0x01
	out TCCR0B, r20

; nastaveni OCR0A + 0x20
	ldi r20, 200
	sts 0x47, r20

; nastaveni OCR0B + 0x20
	ldi r20, 20
	sts 0x48, r20

	ldi r20, 0x07
	sts TIMSK0, r20

; nastaveni vystupu PWM
	sbi DDRD, 5 ;jednotka A
	;sbi DDRD, 6 ;jednotka B

; sloupce maticove klavesnice, jako vstup s pull-up resistory
	cbi DDRB, 0
	cbi DDRB, 1
	cbi DDRB, 2
	cbi DDRB, 3

	sbi PORTB, 0
	sbi PORTB, 1
	sbi PORTB, 2	
	sbi PORTB, 3


; radky maticove klavesnice na PD0-3, vystupem ve vysoke impedanci s PORTD v 0
	cbi DDRD, 0
	cbi DDRD, 1
	cbi DDRD, 2
	cbi DDRD, 3
	
	cbi PORTD, 0
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3


; povoleni preruseni
	;sei

smycka:

;radka 1

	sbi DDRD, 0 ; prvni radka jako vystup v log. 0
	
	sbis PINB, 0
	rcall rychlost1

	sbis PINB, 1
	rcall rychlost2

	sbis PINB, 2
	rcall rychlost3

	cbi DDRD, 0 ; prvni radka zpet do vysoke impedance

; radka 2

	sbi DDRD, 1 ; druha radka do log. 0

	sbis PINB, 0
	rcall rychlost4

	sbis PINB, 1
	rcall rychlost5

	sbis PINB, 2
	rcall rychlost6

	cbi DDRD, 1 ; druha radka do vysoke impedance

; radka 3

	sbi DDRD, 2 ; treti radka do log. 0

	sbis PINB, 0
	rcall rychlost7

	sbis PINB, 1
	rcall rychlost8

	sbis PINB, 2
	rcall rychlost9

	cbi DDRD, 2 ; treti radka do vysoke impedance

; radka 4

	sbi DDRD, 3 ; ctvrta radka do log. 0

	sbis PINB, 1
	rcall rychlost0

	cbi DDRD, 3 ; ctvrta radka do vysoke impedance





	rjmp smycka






rychlost1:
	ldi r30, 0b11110011 ; znovu zapnuti PWM vystupu 
	out TCCR0A, r30
	ldi r20, 0 ; zmena komparacni urovne
	sts 0x47, r20
	ret

rychlost2:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 30
	sts 0x47, r20
	ret

rychlost3:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 60
	sts 0x47, r20
	ret

rychlost4:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 90
	sts 0x47, r20
	ret

rychlost5:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 120
	sts 0x47, r20
	ret

rychlost6:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 150
	sts 0x47, r20
	ret

rychlost7:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 180
	sts 0x47, r20
	ret

rychlost8:
	ldi r30, 0b11110011 
	out TCCR0A, r30
	ldi r20, 210
	sts 0x47, r20
	ret

rychlost9:
	ldi r30, 0b11110011
	out TCCR0A, r30
	ldi r20, 240
	sts 0x47, r20
	ret

; odpojeni PWM
rychlost0:
	ldi r30, 0b00110011 ; odpojeni PWM modulu
	out TCCR0A, r30
	cbi PORTD, 6 ; log. 0 na vystup
	ret



;  Obě světla jsou připojená na hw pwm jednotku timer/counter0.
;  Ovládací potenciometr je připojen na ADC0, zdrojem referenčního napětí je AVCC.
;  Timer0, který je zdrojem pwm zároveň přerušuje po 1ms a je tak časovou základnou,
;  která po cca 100ms spouští adc převod. Převod signalizuje připravená data přerušením.
;  ADC využívá rozlišení jen 8 bitů, které rovnou odpovídají hodnotě komparace pwm -
;  OCR0B. Tlačítko je připojené k INT0 - externímu přerušení, v klidu jest nastavená log. 1.
;  Po dobu stisku tlačítka je výstup OC0A trvale v log. 1, při uvolnění (detekována náběžná hrana)
;  je nastaven čítač timer1 na přerušení po 5s. Po vyvolaném přerušení jsou čítací registry přenastaveny
;  na hodnotu doby přerušení odpovídající 2000/255=7,8ms - každé přerušení poté inkrementuje registr OCR0A.
;  To má za následek pozvolné pohasínání po dobu 2s. Při případném opětovném stisku před dokončením je celý
;  cyklus opakován.
;  Celý kód je psán událostně - využívá zdroje přerušení a šetří procesorový čas. Po dobu nečinnosti program vysí
;  v nekonečné smyčce, kde by mohl případně vykonávat jinou činnost.






.include "m88def.inc"



.org $0000
	rjmp reset

.org $0001
	rjmp ext_preruseni

.org $000D
	rjmp timer1_ovf

.org $000E
	rjmp timer0_compareA

.org $000F
	rjmp timer0_compareB

.org $0010
	rjmp timer0_ovf

.org $0015
	rjmp prevodnik




.equ milivterinovy_citac = 0x0100





ext_preruseni:

	push r22

	lds r22, 0x69 ; EICRA - nastaveni ext preruseni
	cpi r22, 0x00 ; reaguje na log. 0
	breq nula


	; dalsi preruseni bude pri log. 0
	ldi r22, 0x00
	sts 0x69, r22 ;EICRA



	; spusteni TIMER1
	;;;;;
	ldi r22, 0x04
	sts 0x81, r22 ;TCCR1B

	clr r22
	out TIFR1, r22

	; preruseni odpovida cca 5 s
	ldi r22, 0xB3 ;TCNT1H
	sts 0x85, r22

	ldi r22, 0xB4 ;TCNT1L
	sts 0x84, r22

	ldi r22, 0x01
	sts 0x6F, r22 ;TIMSK1
	;;;;;

	clr r22
	sts 0x47, r22 ; znulovat OCR0A

	rcall odpojit_pwmA
	sbi PORTD, 5

	rjmp konec


	nula:
	; dalsi preruseni se nastavi na nabeznou hranu
	ldi r22, 0x03
	sts 0x69, r22 ;EICRA
	sbi PORTD, 5 ;rozsvitime svetlo

	rcall zakaz_timer1
	

	konec:

	pop r22

	reti


timer1_ovf:

	push r22
	push r23


	ldi r22, 0xFF ;TCNT1H
	sts 0x85, r22

	ldi r22, 225 ;TCNT1L
	sts 0x84, r22





	; zmena nastaveni PWM
	lds r23, 0x47 ; OCR0A


	

	cpi r23, 0x00 ; prvotni prubeh - musi se povolit PWM modul
	brne rien1
	rcall pripojit_pwmA

	rien1:

	cpi r23, 0xFF ; posledni prubeh - musi se zakazat PWM modul
	brne rien2
	rcall zakaz_timer1
	rcall odpojit_pwmA

	rien2:


	inc r23 ; na samem konci po 0xFF opet nastavi vychozi stav 0x00
	sts 0x47, r23


	pop r23
	pop r22
	

	reti



; preteceni TIMER0, po cca 1ms 
timer0_ovf:

	push r22
	push r23
	push r24
	push r25


	ldi r23, 134
	out TCNT0, r23



	lds r25, milivterinovy_citac


	; spusti AD prevod kazdych cca 100ms

	cpi  r25, 100 

	brne preskoc_prevod
	
	rcall spustit_adc_prevod
	clr r25
	


	
	preskoc_prevod:

	inc r25 ; inkrementuje milivterinovy citac
	sts milivterinovy_citac, r25


	pop r25
	pop r24
	pop r23
	pop r22

	reti

; pripravene obsluhy preruseni pro obe jednotky PWM, nepouzite
timer0_compareA:
	reti

timer0_compareB:
	reti



; obsluha ADC predvodu
prevodnik:

	push r22

	ldi r22, 0x79 ; precte ADCH
	; nastaveni OCR0B
	sts 0x48, r22

	pop r22

	reti


reset:


	; vynulovani milivterinoveho citace
	clr r0 ; pomocny vzdy nulovy registr
	sts milivterinovy_citac, r0




; nastaveni timer0 na Fast PWM
	ldi r20, 0b11110011
	out TCCR0A, r20

	ldi r20, 0x02
	out TCCR0B, r20

; nastaveni OCR0A + 0x20
	ldi r20, 200
	sts 0x47, r20

; nastaveni OCR0B + 0x20
	ldi r20, 20
	sts 0x48, r20

	ldi r20, 0x07
	sts TIMSK0, r20

; nastaveni vystupu PWM
	sbi DDRD, 5 ;jednotka A
	sbi DDRD, 6 ;jednotka B


; nastaveni externiho preruseni
	clr r20
	sts 0x69, r20 ; EICRA, reaguje na log. 0
	ldi r20, 0x01
	sts 0x3D, r20


; nastaveni prevodniku
	ldi r20, 0x20
	sts 0x7C, r20 ; nastaveni ADMUX

	ldi r20, 0b10001000
	sts 0x7A, r20



; odpojeni PWM modulu A
	rcall odpojit_pwmA

; povoleni preruseni
	sei

smycka:
	rjmp smycka






spustit_adc_prevod:

	lds r24, 0x7A
	ldi r25, 0b01000000
	or r24, r25	
	sts 0x7A, r24

	ret


pripojit_pwmA:
	
	in r20, TCCR0A
	ori r20, 0b11000000
	out TCCR0A, r20

	ret


odpojit_pwmA:

	in r20, TCCR0A
	andi r20, 0b00111111
	out TCCR0A, r20

	cbi PORTD, 5

	ret


zakaz_timer1:

	clr r22
	sts 0x6F, r22 ;TIMSK1
	sts 0x36, r22 ;TIFR1
	ret


;$$$$&&&&&#### POSUVNÝ REGISTR ####&&&&$$$$

.include "m88def.inc"


.equ PORT_REGISTR = PORTB
.equ DDR_REGISTR = DDRB

.equ OE    = 0 ; output enable (active LOW)
.equ DS    = 1 ; serial data input
.equ SH_CP = 2 ; shift register clock input
.equ ST_CP = 3 ; storage register clock input
.equ MR    = 4 ; master reset (active LOW)






.org $0000
	rjmp reset








zapis_do_registru:

	;sbi PORT_REGISTR, OE ; vystup ve vysoke impedanci
	sbi PORT_REGISTR, MR ; neni reset
	cbi PORT_REGISTR, SH_CP ; hodiny na nulu
	cbi PORT_REGISTR, ST_CP ; hodiny na nulu


	ldi r21, 0x08 ; promenna na cykleni


	cyklus:


	cbi PORT_REGISTR, SH_CP ; hodiny na 0
	rcall cekej

	
	sbrs r20, 7
	sbi PORT_REGISTR, DS ; DS na 1
	sbrc r20, 7
	cbi PORT_REGISTR, DS ; DS na 0
	
	
	

	lsl r20 ; posunu vysilane data
	nop
	nop
	nop


	sbi PORT_REGISTR, SH_CP ; hodiny na 1
	rcall cekej
	


	dec r21
	breq konec
	rjmp cyklus


	konec:


	sbi PORT_REGISTR, ST_CP ; nabezna hrana k zapisu dat
	cbi PORT_REGISTR, OE ; povoleni vystupu

	rcall cekej

	ret







reset:

	sbi DDR_REGISTR, OE
	sbi DDR_REGISTR, DS
	sbi DDR_REGISTR, SH_CP
	sbi DDR_REGISTR, ST_CP
	sbi DDR_REGISTR, MR

	sbi PORT_REGISTR, OE ; vystup ve vysoke impedanci



	ldi r20, 0b00101010 ; data k zapisu
	rcall zapis_do_registru ; zapise data do registru




smycka:
	rjmp smycka





; kratke cekani
cekej:
	ldi r25, 20

	cekej_tu:

	dec r25
	breq fin
	rjmp cekej_tu

	fin:

	ret
Osobní nástroje