Řešení

Z MAM wiki

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

Toto je řešení prvního domácího úkolu - Stmívač do automobilu.

Zadání nebudu zbytečně opisovat, najdete jej na stránce 1. domácí úkol. Jedná se o ukázku možného řešení, která má sloužit k inspiraci. Zneužití je na vlastní nebezpečí :-)

Použitý procesor je ATmega328P. Hodiny pro procesor jsou získávány z interního 8 MHz oscilátoru a nejsou vydělené. CKDIV8 (Fuses) je odpojen. Pin VREF je přes kondenzátor přiveden na zem. Napájecí napětí je použito jako referenční napětí pro ADC.


; *************************************************************************************************
;
;  Program stmivani svetel v automobilu / 1. domaci ukol 
;  Hlida napeti na vstupu PC0(ADC0) a podle nej nastavuje parametry PWM vystupu PD5(OC0B)
;  Logicka uroven 0 na vstupu PD2 spousti vystup PD6 a drzi jej 5 vterin. 
;  Pote postupne PWMkem ztlumi na minimum a vypne PD2 uplne.
;
; 	Autor: Pavel Vitvar	 	
; 	Pro ATmega328P 
;
; *************************************************************************************************
.include "m328pdef.inc"

.equ	panelak		=	0x100	;je plny bitu
.equ	dimm		=	0	;povoleni stmivani
.equ	wait		=	1	;povoleni cekani a sviceni
.equ	strop		=	5	;OC0B
.equ	palubka		=	6	;OC0A
.equ	dvere		=	2	;vstup (log. 0 = otevrene dvere)

.equ	vin_min		=	6	;5V/256*x (x=6)

.equ	wait_ticks	=	255	;pocet useku pro zpozdeni po zavreni dveri
.equ	wait_speed	=	4	;rychlost odecitani zpozdeni
.equ	dimm_ticks	=	255	;pocatecni uroven ztlumeni
.equ	dimm_speed	=	4	;rychlost ztlumeni na nulu


.cseg
; Interrupt Vectore Table	
.org	0x00				; Reset-Address
	rjmp	start
.org	INT0addr			; External Interrupt Request 0
.org	INT1addr			; External Interrupt Request 1
.org	PCI0addr			; Pin Change Interrupt Request 0
.org	PCI1addr			; Pin Change Interrupt Request 0
.org	PCI2addr			; Pin Change Interrupt Request 1
.org	WDTaddr				; Watchdog Time-out Interrupt
.org	OC2Aaddr			; Timer/Counter2 Compare Match A
.org	OC2Baddr			; Timer/Counter2 Compare Match A
.org	OVF2addr			; Timer/Counter2 Overflow
.org	ICP1addr			; Timer/Counter1 Capture Event
.org	OC1Aaddr			; Timer/Counter1 Compare Match A
	rjmp	OC1A
.org	OC1Baddr			; Timer/Counter1 Compare Match B
.org	OVF1addr			; Timer/Counter1 Overflow
.org	OC0Aaddr			; TimerCounter0 Compare Match A
.org	OC0Baddr			; TimerCounter0 Compare Match B
.org	OVF0addr			; Timer/Couner0 Overflow
.org	SPIaddr				; SPI Serial Transfer Complete
.org	URXCaddr			; USART Rx Complete
.org	UDREaddr			; USART, Data Register Empty
.org	UTXCaddr			; USART Tx Complete
.org	ADCCaddr			; ADC Conversion Complete
.org	ERDYaddr			; EEPROM Ready
.org	ACIaddr				; Analog Comparator
.org	TWIaddr				; Two-wire Serial Interface
.org	SPMRaddr			; Store Program Memory Read

;---------------------------------------------------------------------------
;	Hlavni program
;---------------------------------------------------------------------------
start:	ldi	r16,low(RAMEND)	;inicializace stack pointeru
	out	SPL,r16
	ldi	r16,high(RAMEND);na konec ramky (RAMEND)
	out 	SPH,r16

	;Predpokladam 8MHz oscilator bez vydeleni


	rcall	Pinout_init
	rcall	ADC_init
	rcall	ADC_start
	rcall	T0_init
	rcall	T1_init


	ldi	r16,255
	out	ocr0a,r16
	out	ocr0b,r16
	ldi	r17,0
	sts	panelak,r17


	sei				; Global Interrupts enabled
	
;----- hlavni smycka --------------------------
main:	sbic	pind,dvere		;kontrola stavu dveri
	rjmp	m0			;pokud je na vstupu 1 tak neni sepnuto
	
	sbi	portd,strop		;rozsviceni svetel na stropu		
	ldi	r18,wait_ticks		;prednastaveni doby cekani
	ldi	r16,0b00000010		;spusteni waitu
	sts	panelak,r16		
	

m0:	lds	r16,ADCSRA		;nacteni konfigurace z ADC
	sbrs	r16,(ADIF)		;kontrola hotoveho prevodu
	rjmp	main	

	lds	r16,ADCH		;nacteni zmerene hodnoty
	cpi	r16,vin_min		;porovnani s minimalni hodnotou osvetleni palubky
	brsh	m1			;pokud je stejne nebo vyssi tak zapneme pwm
	rcall	stop_osv		;pokud je nizsi tak vypnem osvetleni
	rjmp	m_end

m1:	rcall	start_osv
	
m_end:	rcall	ADC_start		;spusteni noveho mereni ADC
	rjmp	main

;---------------------------------------------------------------------------
;	spusteni PWM na OCR0B
;---------------------------------------------------------------------------
start_osv:
	out	ocr0a,r16

	in	r16,TCCR0A
	ori	r16,0b10000000	;vlozeni jednicky
	andi	r16,0b10111111	;vlozeni nuly
	out	TCCR0A,r16	;Timer mode = FAST PWM, OCR0A outputed
	ret
;---------------------------------------------------------------------------
;	vypnuti PWM na OCR0B
;---------------------------------------------------------------------------
stop_osv:
	in	r16,TCCR0A
	andi	r16,0b00111111	;vlozeni dvou nul
	out	TCCR0A,r16	;Timer mode = FAST PWM, OCR0A suppressed
	cbi	portd,palubka
	ret
;---------------------------------------------------------------------------
;	Zpozdovaci smycka
;---------------------------------------------------------------------------
delay:	
	ldi	r16,3
delay1:	inc	r1
	brne	delay1
	inc	r2
	brne	delay1
	dec	r16
	brne	delay1
	ret
;---------------------------------------------------------------------------
;	Obsluha preruseni od Timeru 1
;---------------------------------------------------------------------------
OC1A:

	lds	r17,panelak
	sbrs	r17,wait
	rjmp	oc1a2		;pokud wait = 0 skoc dal

	subi	r18,wait_speed	;odecitani casu
	cpi	r18,wait_speed+1
	brsh	oc1a_end	;kontrola uplynuleho casu

	lds	r17,panelak
	andi	r17,0b11111101	;vynulovani wait
	ori	r17,0b00000001	;nastaveni dimm
	sts	panelak,r17	

	ldi	r18,dimm_ticks	;prednastaveni r18 pro stmivani
	out	ocr0b,r18

	in	r17,TCCR0A	;zapnuti stmivani
	ori	r17,0b00100000	;vlozeni jednicky
	andi	r17,0b11101111	;vlozeni nuly
	out	TCCR0A,r17	;Timer mode = FAST PWM, OCR0A outputed
	rjmp	oc1a_end


oc1a2:	lds	r17,panelak	;pokud dimm=0 jdi pryc
	sbrs	r17,dimm
	rjmp	oc1a_end	
	
	subi	r18,dimm_speed
	out	ocr0b,r18
	cpi	r18,dimm_speed+1
	brsh	oc1a_end

	lds	r17,panelak
	andi	r17,0b11111110	;vynulovani dimm
	sts	panelak,r17

	in	r17,TCCR0A
	andi	r17,0b11001111	;vlozeni dvou nul
	out	TCCR0A,r17	;Timer mode = FAST PWM, OCR0B suppressed
	cbi	portd,strop

oc1a_end:
	reti

;---------------------------------------------------------------------------
;	Nastaveni vstupu a vystupu
;---------------------------------------------------------------------------
Pinout_init:
; Define pull-ups and set outputs high
; Define directions for port pins
	in	r16,MCUCR
	ori	r16,0x00	;0x40=>PullUp=disabled, 0x00=>PullUp=enabled	
	out	MCUCR,r16
				;DDxn	PUD
				;  0	 0	Bidirectional	
				;  0	 1	Input only = Open collector
				;  1	 x	Push - Pull
				
	;ldi 	r16,0xff	;(1<<PA7)|(1<<PA6)|(1<<PA1)|(1<<PA0)
	;ldi 	r17,0xff	;(1<<DDA3)|(1<<DDA2)|(1<<DDA1)|(1<<DDA0)
	;out 	PORTA,r16
	;out 	DDRA,r17
	
	ldi 	r16,0b11111111	
	ldi 	r17,0b00000000
	out 	PORTB,r16
	out 	DDRB,r17
	
	ldi 	r16,0b11111111	
	ldi 	r17,0		
	out 	PORTC,r16
	out 	DDRC,r17
	
	ldi 	r16,0b10011111
	ldi 	r17,(1<<DDD5)|(1<<DDD6)	;PD5 a PD6 jsou vystupy 
	out 	PORTD,r16
	out 	DDRD,r17
	; Insert nop for synchronization
	nop
	ret
;---------------------------------------------------------------------------
;	Nastaveni timeru 1
;---------------------------------------------------------------------------
T1_init: 			;16 bit
	ldi	r16,4		;
	sts	OCR1AH,r16	;Timer 1 Compare Value
	ldi	r16,0		;
	sts	OCR1AL,r16	;

	ldi	r16,0
	sts	TCCR1A,r16	;Timer mode = CTC (Clear Time on Compare Match)
	
	ldi 	r16,0b00001100
	sts 	TCCR1B,r16 	;Timer clock = system clock / 256

	ldi 	r16,0
	sts 	TCCR1C,r16 	

	ldi 	r16,0
	out 	TIFR1,r16 	;Clear match pending interrupts

	ldi 	r16,(1<<OCIE1A)
	sts 	TIMSK1,r16 	;Enable Timer/Counter1 Compare Match A Interrupt
	ret

;---------------------------------------------------------------------------
;	Nastaveni timeru 0
;---------------------------------------------------------------------------
T0_init:
	ldi	r16,0b10000011
	out	TCCR0A,r16	;Timer mode = FAST PWM, oc1a spusteno, oc1b vypnuto (zapina se v preruseni)
	ldi 	r16,0b00000001
	out 	TCCR0B,r16 	;Timer clock = system clock/1
	ldi	r16,0b00000000
	sts	TIMSK0,r16	;no interrupt
	ldi 	r16,0b00000000
	out 	TIFR0,r16 	;Clear pending interrupts
	ret

;---------------------------------------------------------------------------
;	Nastaveni ADC
;---------------------------------------------------------------------------
ADC_init:
	ldi	r16,0b10000011	;Enable ADC system clk/8
	sts	ADCSRA,r16
	ldi	r16,0b01100000	;Input PC0 selected and Vcc as reference and data left alignment
	sts	ADMUX,r16
	ldi	r16,0b00000000	;Free running mode
	sts	ADCSRB,r16		
	ldi	r16,0b00000001	;Digital input ADC0 disable
	sts	DIDR0,r16
	;ldi	r16,0b11000000	;Enable ADC + prescaler setup + Start conversion
	;out	ADCSRA,r16
	ret

;---------------------------------------------------------------------------
;	Spusteni konverze ADC
;---------------------------------------------------------------------------
ADC_start:
	lds	r16,ADCSRA
	ori	r16,0b01000000	;Start conversion
	sts	ADCSRA,r16
	ret

;---------------- konec programu ------------

--Vitvapav 29. 3. 2012, 11:24 (UTC)


Další řešení je zde: Úkol 1--Havraale 8. 4. 2012, 18:54 (UTC)

Osobní nástroje