Jan Marek: Generátor signálů

Z MAM wiki

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

Obsah

[editovat] Úvod

V rámci semestrální práce byl zhotoven generátor signálů s mikroprocesorem Atmega 168. Procesor na výstupu generuje postupně pravoúhlý, pilovitý/trojúhelníkový a harmonický signál s možností nastavení kmitočtu, amplitudy a stejnosměrné složky (offset). Kmitočet zvoleného průběhu lze regulovat hrubě pomocí tlačítka a jemně potenciometrem.


[editovat] Schéma zapojení a popis funkce

Soubor:Schema_gen.png

Jádrem celého zapojení je již zmíněný mikroprocesor ATmega 168. Celé zapojení je uvedeno do chodu po stisknutí tlačítka POWER (signalizuje LED LD1). Procesor generuje na výstupní bráně PB0 až PB7 čtyři typy průběhů v digitální formě. Jednotlivé průběhy (sinus, pila, trojúhelník a obdélník) lze přepínat tlačítky tl1 až tl3. Zapojení má programově implementovánu děličku kmitočtu 1:1, 1:2, 1:8 a tzv. ,,synchronizační“ režim f_s (viz dále). Příslušný dělící poměr můžeme nastavit tlačítkem tl4. Nastavení děličky funguje cyklicky, což znamená, že po stisknutí tlačítka v synchronizačním módu se opět nastaví dělící poměr 1:1. Nastavený mód děličky signalizují LED diody LD2-LD5 zapojené na výstupní bráně PDx. Pro jemné nastavení kmitočtu slouží potenciometr P2, jehož běžec je připojen na vstup interního A/D převodníku (kanál 0). Převodník je sice desetibitový, my však pracujeme pouze s horními osmi bity (ADCH), takže máme k dispozici celkem 256 stupňů regulace. A/D převodník pracuje s vnější referencí 5V (AREF), jenž je na stejném potenciálu jako potenciometr P2 (z téhož napětí je celý procesor také napájen). Výstupní signál je převeden do analogové formy D/A převodníkem a dále upraven zesilovacím stupněm. V zapojení je použit D/A převodník AD7524 od firmy Analog Devices. Jedná se o paralelní osmibitový převodník, jenž je kompatibilní s většinou typů používaných mikroprocesorů; doba převodu je maximálně 500 ns. Stejně jako u ostatních číslicových obvodů, i tento je vybaven aktivačním vstupem CS a vstupem povolující zápis WR. Oba vstupy jsou řízeny mikroprocesorem a pro nás budou mít význam především z hlediska spotřeby celého zapojení. Převodník pracuje na principu součtu váhovaných proudů, jenž jsou odvozeny z napěťové reference a vnitřní žebříčkové sítě R, 2R. Součet proudů je vyveden na komplementární výstup OUT1 a OUT2. Na výstupu OUT1 je vnitřně připojen rezistor 10k, jehož druhý konec je vyveden (Rfb) a může být využit pro nastavení zesílení navazujícího zesilovače A2, jako v našem případě. Výstupní napětí je navíc stejnosměrně posunuto tak, abychom na výstupu A2 získali bipolární úroveň napětí (hodnotě 128d odpovídá 0V). Úroveň výstupního napětí (amplitudu) regulujeme potenciometrem P1, jehož běžec je připojen na vstup zesilovače A3. Zpětnovazební obvod zesilovače A3 v neinvertujícím zapojení není připojen na zem, ale má zavedeno předpětí, odvozené z ±Uref a připojené přes zesilovač A4 (opět v neinvertujícím zapojení). Takto je možné pomocí potenciometru P2 regulovat stejnosměrnou složku na výstupu téměř nezávisle na amplitudě signálu. Lze dokázat, že amplitudu i offset můžeme regulovat v rozsahu -2Uref až +2Uref, tj. -10V až +10V (regulačně jsme samozřejmě omezeni saturačním napětím operačních zesilovačů).

[editovat] Algoritmus programu

Soubor:Alg_main.jpg Po resetu mikroprocesoru proběhne základní inicializace proměnných, nastaví se A/D převodník a časovač a program odchází do režimu spánku, ve kterém očekává stisk tlačítka POWER. Stisk tohoto (a žádného jiného!) tlačítka se vyvolá přerušení, ve kterém se aktivuje časovač, D/A převodník, A/D převodník (CS, WR) a povolí se přerušení i pro ostatní tlačítka. Pokud nedojde ke stisku jiného tlačítka, procesor implicitně nastaví na svém výstupu generaci pilovitého průběhu s frekvenčním dělícím poměrem 1:1, všechna nastavení signalizují příslušné LED diody. A/D převodník pracuje ve volně běžícím módu a jeho činnost nevyvolává přerušení z důvodu časové úspory, ale obsah registru ADCH je průběžně kontrolován ve smyčce SEND (viz dále). Časovač pracuje v režimu Clear timer on compare match (CTC) mode, tzn, že poté co časovač dosáhne nastavené komparační úrovně, dojde k jeho vynulování a nastaví se příznak přetečení. Přetečení časovače nevyvolává přerušení ze stejného důvodu jako v případě A/D převodníku. Časovač ve spolupráci s časovačem slouží k nastavení požadované frekvence zvoleného průběhu. Komparační úroveň časovače je nastavena pro každý průběh zvlášť v obsluze přerušení.

Obsluha přerušení tedy provádí: aktivaci časovače, A/D převodníku a D/A převodníku (pouze po zapnutí), aktivaci ostatních tlačítek, výběr požadovaného průběhu, výběr frekvenčního dělícího poměru (= komparační úroveň časovače), při opětovném stisku tlačítka POWER provede deaktivaci zmíněných periférií a nastaví přechod do režimu spánku.


Soubor:Alg_gen.jpg

Po nastavení potřebných kroků běží hlavní smyčka programu, která generuje na výstup funkčního hodnoty vybraného průběhu. V prvé řadě, program čeká na přetečení časovače (test příznaku. Po přetečení je nutné vymazat příznak přetečení (k automatickému vymazání příznaku dochází jen v případě přerušení, to my však nechceme). Poté se inkrementuje hodnota registru, ve které je uložena hodnota z A/D převodníku, tato hodnota udává počet průchodů čekací smyčkou - počítadlo. V případě, že hodnota počítadla není nulová, program se vrátí na čekací smyčku, kde opět čeká na vypršení hodnoty časovače. Následně se zapíše hodnota na výstupní bránu (po návratu z přerušení je první hodnota vždy nula) a opětmusíme vymazat příznak přetečení a vynulovat časovač. Časovač čítá od nuly a program je připraven vygenerovat další hodnotu. V tomto čase je zkontrolována hodnota registru ADCH. V případě, že není převod dokončen, nemůžeme z registru číst a hodnota našeho počítadla zůstane stejná (počkáme na převod do dalšího průchodu smyčkou). Pokud je převod hotov, hodnota počítadla se přepíše, proběhne test zvoleného průběhu a z podprogramu, jenž přísluší danému průběhu, se vyzvedne nová funkční hodnota a celý děj se opakuje. V programu by nám mohlo vadit, že frekvence všech průběhů nejsou stejné. To je způsobené různými časy průchodu celou smyčkou vznikající v důsledku odlišného počtu funkčních hodnot potřebných k vygenerování jedné periody signálu (například k vygenerování jedné periody obdélníkového průběhu nám postačí dvě hodnoty, zatímco u pilovitého průběhu potřebujeme 256 hodnot). Pro tento účel je programově implementován, již zmíněný, ,,synchronizační režim“, který podle typu zvoleného průběhu zvolí příslušný komparační čas přetečení časovače (určeno ze simulace, lze i vypočítat), a to takový, aby se frekvence všech průběhů sjednotili (budou synchronizovány). Za uvedené opatření zaplatíme výrazným snížením maximálního dosažitelného kmitočtu, které se nejvíce projeví právě u pravoúhlého průběhu.

[editovat] Zdrojový kód

.INCLUDE "m168def.inc"


 .ORG 0x0000 
	jmp Main ; Reset Handler

.ORG 0x0008 
	jmp keys ; PCINT1 Handler


 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

 ; zapojeni nozicek
 
 .EQU RANGE = 2
 .EQU POWER = 1
 .EQU OBD = 3
 .EQU PILA = 4
 .EQU SIN = 5
 .EQU LED_pow = 0
 .EQU LED_f1 = 2
 .EQU LED_f2 = 3
 .EQU LED_f8 = 4
 .EQU LED_syn = 5

 .EQU WR = 6
 .EQU CS = 1


 ;***********nazvy registru***************************

 ; vstupy
 ldi r16,0b11000000 ;tlacitka, potenciometr
 out DDRC,r16
 
 ldi r16,0b00111110 ;pull-up
 out PORTC,r16


 ;vystupy
 ldi r16,0xFF
 out DDRB,r16 ;pripojeni A/D

 ldi r16, 0b01111111 ; pripojeni WR,CS, LED
 out DDRD,r16

 ldi r16,0b01000010 ;WR, CS neaktivni, LED zhasnuty
 out PORTD,r16


 ;*********************************************
 ;**************nastaveni sleep modu***********
 ;*********************************************

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


 ;*********************************************
 ;************nastaveni AD prevodniku**********
 ;*********************************************

 ldi r28,ADMUX ;Y pointer
 clr r29 
 ldi r16,0b01100000 ;vnitrni reference vstup na ADC0
 st Y,r16

 ldi r28,ADCSRA
 clr r29
 ldi r16,0b11100000 ;povoleni prevodniku,zakazano preruseni
 st Y,r16

 ldi r28,ADCSRB ;free running mod
 clr r29
 ldi r16,0x00
 st Y,r16

 ldi r28,ADCH ;nastav ukazatel Y na registr ADCH
 clr r29

 ;******Ukazatel Y zabran!*************************



 ;********************************
 ;******nastaveni casovace********
 ;********************************

 ldi R18,0b00000001 ;nastaveni frekvence, fIO
 out TCCR0B, R18

 ldi R24,0b00000010 ;mod citace, 
 out TCCR0A, R24

 ldi R23,0x0F; konecna hodnota citace - synchronizace
 out OCR0A, R23

 ldi r19,0x01
 clr r24
 clr r22
 ldi r21,0x01 ; priznak zapnuti



 ;*********************************************
 ;************Nastaveni preruseni**************
 ;*********************************************

 ldi r26, PCICR 
	clr r27 
	ldi r16,0b00000010 ; activate PCINT1
	st X, r16 

	ldi r26, PCMSK1 
	clr r27 
	ldi r16,0b00000010 ;povol preruseni pouze na probuzeni
	st X, r16 ; store new PCMSK1

	;ukazatel X je na PCMSK1

	sei ; Enable interrupts

 ;*********************************
 ;**************spani**************
 ;*********************************

	spani:
	sleep
	nop 
	jmp send
	rjmp spani


 ;******************************************************
 ;*******************Zapis funkcni hodnoty na vystup****
 ;******************************************************

 send:
 sbis  TIFR0,1 ;testuj priznak komparace
 rjmp send
 sbi TIFR0,1
 inc r25
 BRNE send
 out portb,r22 ;posli na vystup funkcni hodnotu
 out TCNT0,r24 ;vynuluj  prvni citac
 sbi TIFR0,1 ;vymaze priznak komparace
 ;nahraj hodnotu z A/D prevodniku
 ld r25,Y ; ADCH je v registru R25
 out OCR0A,r23 ; vrat synchronizacni cas
 cpi r20,1
 breq gen_pila
 cpi r20,0
 breq gen_obd
 cpi r20,2
 breq gen_sin
 jmp spani

 ; vrat se zpet a vyber novou funkcni hodnotu

 ;*****************************************************
 ;********************Prubehy**************************
 ;*****************************************************

 gen_pila:
 inc r22
 rjmp send

 gen_sin:
 lpm r22,Z+
 CPI ZL, 32
 brne send
 ldi ZL,0
 rjmp send

 gen_obd:
 ldi r22,0xFF
 sbic pinb,0
 ldi r22,0x00
 rjmp send

 tab_sin:
 .DB 64,76,88,99,109,117,123,126
 .DB 127,126,123,117,109,99,88,76
 .DB 64,51,39,28,19,11,5,1
 .DB 0,1,5,11,19,28,39,51


 ldi ZL,low(2*tab_sin)
 ldi ZH,high(2*tab_sin)



 ;******************************************************************
 ;**************************obsluha preruseni***********************
 ;******************************************************************

 keys:

 sbis PINC,POWER
 rjmp  zapni
 sbis PINC,RANGE
 rjmp rozsah
 sbis PINC,OBD
 rjmp init_obd
 sbis PINC,PILA
 rjmp init_pila
 sbis PINC,SIN
 rjmp init_sin
 rjmp default

 zapni:
 inc r21 
 BRNE zapnuto

 ;***********zde zacina vypnuto*****************
 vypnuto:
 clr r21
 sbi PORTD,WR ; A/D vypnuto
 sbi PORTD,CS
 cbi PORTD,LED_pow
 cbi PORTD,LED_f1
 cbi PORTD,LED_f2
 cbi PORTD,LED_f8
 cbi PORTD,LED_syn

 ldi R20,3
 ldi R25,0xFC
 ldi R18,0x06
 ldi r16,0b00000010 ;povol preruseni pouze na PC1 - zapnuti
 st X,r16
 ldi R16,0b00000001 ;nastaveni frekvence, fIO/8
 out TCCR0B, R16	;hotovo
 rjmp default

 zapnuto:
 ldi r21,0xFF
 cbi PORTD,WR ;aktivni A/D prevodnik
 cbi PORTD,CS
 sbi PORTD,LED_pow ;rozsvit LED
 ldi r16,0b00101110  ;povol preruseni na vsech C pinech
 st X,r16

 ;*****************************************************
 ;******************Vychozi nastaveni******************
 ;*****************************************************

 ldi r23,0x0C ; ;synchro
 ldi r25,0xFF ;hodnota z A/D prevodniku nastavena na nejvyssi kmitocet
 ldi r20,1 ;pila
 sbi PORTD,LED_f1 ;rozsvit LED

 rjmp default

 ;***************************************
 rozsah:
 inc r19
 init:
 ldi R16,0b00000001 ;nastaveni frekvence, fIO/1
 out TCCR0B, R16
 cpi r19,1
 breq rozsah_a ;f/1
 cpi r19,2
 breq rozsah_b ;f/2
 cpi r19,3
 breq rozsah_c ;f/8
 cpi r19,4
 breq rozsah_synchr ;synchronizace
 clr r19 ;vynuluje rozsah
 rjmp rozsah

 rozsah_a:
 sbi PORTD,LED_f1 ; rozsvit LED
 cbi PORTD,LED_f2 ; zhasni LED
 cbi PORTD,LED_f8 ; zhasni LED
 cbi PORTD,LED_syn ;zhasni LED
 ldi r23,0x05 ;nastaveno
 rjmp default

 rozsah_b:
 sbi PORTD,LED_f2 ; rozsvit LED
 cbi PORTD,LED_f1 ; zhasni LED
 cbi PORTD,LED_f8 ; zhasni LED
 cbi PORTD,LED_syn ; zhasni LED

 cpi r20,1
 breq range_pila
 cpi r20,0
 breq range_obd

 range_sin:
 ldi r23,0x31 ;hotovo
 rjmp default

 range_pila:
 ldi r23,0x24 ;hotovo
 rjmp default

 range_obd:
 ldi r23,0x22 ;hotovo
 rjmp default

 ;f/8
 rozsah_c:
 sbi PORTD,LED_f8 ; rozsvit LED
 cbi PORTD,LED_f1 ; zhasni LED
 cbi PORTD,LED_f2 ; zhasni LED
 cbi PORTD,LED_syn ; zhasni LED

 ldi R16,0b00000010 ;nastaveni frekvence, fIO/8
 out TCCR0B, R16	;hotovo
 rjmp default

 rozsah_synchr:
 sbi PORTD,LED_syn ; rozsvit LED
 cbi PORTD,LED_f1 ; zhasni LED
 cbi PORTD,LED_f2 ; zhasni LED
 cbi PORTD,LED_f8 ; zhasni LED

 cpi r20,1
 breq synchr_pila
 cpi r20,0
 breq synchr_obd

 synchr_sin:
 ldi r23,0xB7 ;hotovo
 rjmp default
 
 synchr_pila:
 ldi r23,0x05 ;hotovo
 rjmp default

 synchr_obd:
 ldi r16,0b00000011 ;nastaveni frekvence, fIO/64
 out TCCR0B,r16
 ldi r23,0x2E ;hotovo
 rjmp default

 ;************************************

 init_obd:
 ldi r23,0x0D ;1d=24us , fmax = 20,8kHz
 ldi R20,0
 ldi r16,0b00110110  ;zakaz preruseni na pinu obd
 st X,r16
 jmp init

 init_pila:
 ldi r23,0x0C ;nastaveno! 1d=23us fmax=170 Hz
 ldi r20,1
 ldi r16,0b00101110  ;zakaz preruseni na pinu pila
 st X,r16
 jmp init

 init_sin:
 ldi r23,0x13 ;1d=32 resp 30us, f=960Hz
 ldi r20,2
 ldi ZL,0 ;nastavi ukazatel Z na prvni hodnotu
 ldi r16,0b00011110  ;zakaz preruseni na pinu sinus
 jmp init

 default:
 out TCNT0,r24 ;vynuluj casovac
 sbi TIFR0,1 ;vymaz priznak komparace
 clr r22 ;vymaz funkcni hodnotu

 reti
 ; r14 kontrolni registr
 ; r20 vyber prubehu
 ; r19 volba rozsahu
 ; r21 priznak zapnuti
 ; r18 frekvencni cas
 ; r22 funkcni hodnota
 ; r24 nulovani casovace
 ; r25 vystup AD pr
 ; r23 synchronizace
 ; X ukazatel na PCMSK1
 ; Y ukazatel na ADCH
 ; Z ukazatel na sinus


[editovat] Závěr

Domnívám se, že uvedená práce slouží spíše jako demonstrační, neboť pro některé aplikace může být nevyhovující. Problémem je zejména nízký kmitočet, způsobený jednak nízkým taktem oscilátoru a jednak instrukcemi v hlavní smyčce, které generování ještě více brzdí. Největším úskalím hlavní smyčky je především fakt, že musíme pokaždé testovat, jaký průběh vlastně generujeme. Jedním z řešení by bylo nahrát do programové paměti adresy návěští na zvolené průběhy a v přerušení si pak pouze vybrat adresu skoku příslušného průběhu, čímž bychom několik instrukcí ušetřili. Tato operace je však poměrně dosti složitá.

[editovat] Práce ze semestru

[editovat] blikání LEDkami

; example LED-show program for ATtiny 2313
;
; 2-color LED with 300 Ohm resistor in series is supposed to be
; connected between pins 12 (PB0, LED_X) and 13 (PB1, LED_Y).
;
; Color1 shines when LED_X is high and LED_Y is low
; Color2 shines when LED_Y is high and LED_X is low
; LED is off when LED_Y and LED_X are both low or both high


	.EQU DDRB = $17		; DDRB address
	.EQU PORTB = $18	; PORTB address
	.EQU PINB = $16
	.EQU PIND = $10
	.EQU DDRD = $11
	.EQU PORTD = $12


	.EQU LED_X = 0		; LED_X is on PB0, pin 12 of ATtiny2313
	.EQU LED_Y = 1		; LED_Y is on PB1, pin 13 of ATtiny2313

; Pins connected to LED are outputs, DDRx=1 (set):

	SBI	DDRB, LED_X	; SBI - Set Bit in I/O Register
	SBI	DDRB, LED_Y


	; Tady klavesnice

    SBI DDRB,2
    SBI PORTB,2

	STISK:
    
	 SBIS PINB,2
	 RCALL SHOW
     RJMP STISK




SHOW:	
	RCALL	COLOR1	; RCALL - Relative Call to Subroutine
	RCALL	WAIT
	
	RCALL	DARK
	RCALL	WAIT
	
	RCALL	COLOR1
	RCALL	WAIT
	
	RCALL	DARK
	RCALL	WAIT
	
	RCALL	COLOR2
	RCALL	WAIT

	RCALL	DARK
	RCALL	WAIT
	
	RCALL	COLOR2
	RCALL	WAIT

	RCALL	DARK
	RCALL	WAIT

	RCALL	COL3W

	RCALL	DARK
	RCALL	WAIT

	RCALL	COL3W

	RCALL	DARK
	RCALL	WAIT
	
	RET		; RJMP - Relative Jump 

;;;
;;;
;;; P R O C E D U R E S
;;;
;;;
	
SMALLWAIT:
	INC	R1				; INC - Increment
	BRNE	SMALLWAIT	; BRNE - Branch if Not Equal (Z flag) 
	RET					; RET - Return from Subroutine

WAIT:
	LDI	R16, 2			; LDI - Load Immediate
WAIT1:	INC	R1
	BRNE	WAIT1
	INC	R2
	BRNE	WAIT1
	DEC	R16
	BRNE	WAIT1
	RET
	
COLOR1:
    SBI	PORTB, LED_X
	CBI	PORTB, LED_Y	; CBI - Clear Bit in I/O Register
	RET

COLOR2:
    SBI	PORTB, LED_Y
	CBI	PORTB, LED_X
	RET

COL3W:
	LDI	R16, 1
COL3X:
 	RCALL	COLOR1
	RCALL	SMALLWAIT
	RCALL	COLOR2
	RCALL	SMALLWAIT
	INC	R2
	BRNE	COL3X
	DEC	R16
	BRNE	COL3X

DARK:
    CBI	PORTB, LED_X
	CBI	PORTB, LED_Y
	RET

[editovat] Ovládání ventilátoru klávesnicí

Tyden 5
; 
; example fan program for ATmega88
;
; P4 CPU fan Ucc pin is supposed to be connected 
; to +12 V, GND pin is supposed to be connected 
; to FET Drain, Source on GND, Gate on 
; pin 16 (PB2, FAN). Fan runs when FAN output is log. H.
;
; FAN is switched ON with switch between PC2 and PD2


	.EQU DDRB = $04
	.EQU PORTB = $05

	.EQU DDRC = $07
	.EQU PORTC = $08
	.EQU PINC = $06

	.EQU DDRD = $0A
	.EQU PORTD = $0B
	.EQU PIND = $09

;	.INCLUDE "m168def.inc"  ; replaces previous lines of the program

	.EQU FAN = 2


; Pin driving FAN is set as output:

	SBI	DDRB, FAN

; Basic keyboard init:

; One switch of matrix keyboard is connected between PINC 2 a PIND 2
; Zero values of DDRC, 2 and PORTB, 2 are implicit

	SBI DDRD, 2
	SBI PORTC, 2

    SBI DDRC,3
	SBI PORTC,3


; Init:
	RCALL   FAN_OFF

GO:	SBIS	PINC, 2
	RCALL	FAN3W   ; Simple PWM control of the FAN, if the key is pressed
	RJMP	GO


;;;
;;;
;;; P R O C E D U R E S
;;;
;;;
	
VERYSMALLWAIT:
	LDI R20, 0xFC
	MOV R1, R20
SMALLWAIT:
	INC	R1
	BRNE	SMALLWAIT
	RET

WAIT:
	LDI	R21, 4
WAIT1:
	INC	R1
	BRNE	WAIT1
	INC	R2
	BRNE	WAIT1
	DEC	R21
	BRNE	WAIT1
	RET
	
FAN_ON:
	SBI	PORTB, FAN
	RET

FAN_OFF:
	CBI	PORTB, FAN
	RET

FAN3W:
	LDI	R16, 0x20
FAN3X:
 	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  ; pulse ratio controlled by number of waits
	RCALL	VERYSMALLWAIT  ; 4:1 in this case
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
    
  
    

	RCALL	VERYSMALLWAIT 


	INC	R2
	BRNE	FAN3X
	DEC	R16
	BRNE	FAN3X
	RET




           Ovladani ventilatoru klavesnici

.EQU DDRC = $07	 ; DDRB address 
.EQU PORTC = $08	; PORTB address 
.EQU PINC = $06 
.EQU DDRD = $0A 
.EQU PORTD = $0B

; Tady klavesnice
KEY:
SBI DDRC,0 ; VÝSTUP PRO VENTILÁTOR

CBI DDRC,2	;BUDÍCÍ ČÁST
CBI DDRC,3
CBI DDRC,4
CBI DDRC,5

SBI PORTC,2	; PULL UP REZISTORY
SBI PORTC,3
SBI PORTC,4
SBI PORTC,5

CBI DDRD,2	;VSTUPNÍ ČÁST
CBI DDRD,3
CBI DDRD,4
CBI DDRD,5

SBI DDRD,2
CBI PORTD,2;TEST PRVNÍHO SLOUPCE
SBI PORTD,3
SBI PORTD,4
SBI PORTD,5

SBIS PINC,2
RCALL TLAC1
SBIS PINC,3
RCALL TLAC4
SBIS PINC,4
RCALL TLAC7
SBIS PINC,5
RCALL TLACHV


CBI DDRD,2
SBI DDRD,3
SBI PORTD,2;TEST 2 SLOUPCE
CBI PORTD,3

	SBIS PINC,2
	RCALL TLAC2
	SBIS PINC,3
	RCALL TLAC5
	SBIS PINC,4
	RCALL TLAC8
	SBIS PINC,5
	RCALL TLAC0

CBI DDRD,3
SBI DDRD,4
SBI PORTD,3;TEST 3 SLOUPCE
CBI PORTD,4

	SBIS PINC,2
	RCALL TLAC3
	SBIS PINC,3
	RCALL TLAC6
	SBIS PINC,4
	RCALL TLAC9
	SBIS PINC,5
	RCALL TLACKR

CBI DDRD,4
SBI DDRD,5
SBI PORTD,4;TEST 4 SLOUPCE
CBI PORTD,5

	SBIS PINC,2
	RCALL TLACA
	SBIS PINC,3
	RCALL TLACB
	SBIS PINC,4
	RCALL TLACC
	SBIS PINC,5
	RCALL TLACD

JMP KEY



TLAC0:
	RCALL	FAN_OFF
RET

TLAC1:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC2:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC3:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC4:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC5:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC6:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC7:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC8:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
RET

TLAC9:
	RCALL	FAN_ON
	RCALL	VERYSMALLWAIT  
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	VERYSMALLWAIT
	RCALL	FAN_OFF
	RCALL	VERYSMALLWAIT
RET

TLACA:
RCALL	FAN_ON
RET

TLACB:
RET
TLACC:
RET
TLACD:
RET
TLACHV:
RET
TLACKR:
RET



VERYSMALLWAIT:
	LDI R20, 0xFC
	MOV R1, R20
SMALLWAIT:
	INC	R1
	BRNE	SMALLWAIT
	RET

FAN_ON:
	SBI	PORTC, 0
	RET

FAN_OFF:
	CBI	PORTC, 0
	RET

;
;
;
;
;DALSI VARIANTA REGULACE

;
;
;Nastaveni adres
;Zapojeni klaves:



.EQU PORTD = $0B ;nastaveni hodnoty na portu D
.EQU DDRD = $0A
.EQU PIND = $09

.EQU PORTC=$08
.EQU DDRC=$07
.EQU PINC=$06


.EQU PORTB=$05
.EQU DDRB=$04
.EQU PINB=$03

SBI DDRD,0
SBI DDRD,1
SBI DDRD,2  ;pripojeni radku jako vystup
SBI DDRD,3
SBI DDRD,4

;CBI DDRC,2
;CBI DDRC,3  ;pripojeni sloupcu jako vstup
;CBI DDRC,4
;CBI DDRC,5

SBI PORTC,2
SBI PORTC,3
SBI PORTC,4 ;pripojeni pull up rezistoru
SBI PORTC,5


;ovladani ventilatoru
;vystup je na PC0
.EQU FAN=0
SBI DDRC,FAN ;vystup
CBI PORTC,FAN; ventilator vypnut

KEY:
; prvni radek
CBI PORTD,0
SBI PORTD,1
SBI PORTD,2
SBI PORTD,3

SBIS PINC,2
RCALL KEY1
SBIS PINC,3
RCALL KEY2

SBIS PINC,4
RCALL KEY3

SBIS PINC,5
RCALL KEYA

;druhy radek
SBI PORTD,0
CBI PORTD,1


SBIS PINC,2
RCALL KEY4
SBIS PINC,3
RCALL KEY5

SBIS PINC,4
RCALL KEY6

SBIS PINC,5
RCALL KEYB

;treti radek
SBI PORTD,1
CBI PORTD,2


SBIS PINC,2
RCALL KEY7
SBIS PINC,3
RCALL KEY8

SBIS PINC,4
RCALL KEY9

SBIS PINC,5
RCALL KEYD

;ctvrty radek
SBI PORTD,2
CBI PORTD,3

SBIS PINC,2
RCALL KEYKR
SBIS PINC,3
RCALL KEY0

SBIS PINC,4
RCALL KEYHV

SBIS PINC,5
RCALL KEYD

JMP KEY


;procedury

KEY1:
CALL FANON
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT

SBIS PINC,2
RJMP KEY1

RET

KEY2:
CALL FANON
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT

SBIS PINC,3
RJMP KEY2
RET


KEY3:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT


SBIS PINC,4
RJMP KEY3
RET

KEY4:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT

SBIS PINC,2
RJMP KEY4
RET

KEY5:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT

SBIS PINC,3
RJMP KEY5
RET

KEY6:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT

SBIS PINC,4
RJMP KEY6
RET

KEY7:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT
CALL WAIT

SBIS PINC,2
RJMP KEY7
RET

KEY8:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT
CALL WAIT

SBIS PINC,3
RJMP KEY8
RET

KEY9:
CALL FANON
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL WAIT
CALL FANOFF
CALL WAIT

SBIS PINC,4
RJMP KEY9
RET

KEY0:
CALL FANOFF
RET

KEYHV:
RET

KEYKR:
RET

KEYA:
CALL FANON
RET

KEYB:
RET

KEYC:
RET

KEYD:
RET


FANOFF:
CBI PORTC,FAN; ventilator vypnut
RET

FANON:
SBI PORTC,FAN
RET

WAIT:
LDI R20,0xFF
SWAIT:
DEC R20
BRNE SWAIT
RET


;Ovladani ventilatoru klavesnici - pouziti hardwarove PWM
;ventilator - PWM,sleep
           ;Ovladani ventilatoru klavesnici

.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 OCR0A 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)

	ldi r26, PCICR ; load address of PCICR in Y 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 Y 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
;******verze s upravenou klavesnici******************
;Vypracovali: Jan Marek, Jan Nemazal


.INCLUDE "m168def.inc"

.EQU PWM_PULSES = 36	; value for 27.8 kHz PWM


;vektory preruseni
.ORG 0x0000 
	jmp Main ; Reset Handler

.ORG 0x0008 
	jmp isr1 ; PCINT1 Handler



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



 ;nastaveni klavesnice
 cbi DDRC,2
 cbi DDRC,3  ;nastaveni sloupcu jako vstupy
 cbi DDRC,4
 cbi DDRC,5

 sbi PORTC,2 ;pull-up resistor
 sbi PORTC,3
 sbi PORTC,4
 sbi PORTC,5


 sbi DDRD,0
 sbi DDRD,1
 sbi DDRD,2	 ;nastaveni radku jako vystupu
 sbi DDRD,3

 cbi PORTD,0 ;vsechny radky jsou v logicke nule
 cbi PORTD,1
 cbi PORTD,2
 cbi PORTD,3


;Hlavni program

PWM_INIT:
	ldi R17, 0b00100011	; mod FAST PWM
	out TCCR0A, R17			; 
	ldi R17, 0b00001001	; mod FAST PWM, interni hodiny
	out TCCR0B, R17
	ldi R17, PWM_PULSES	; load number of clock pulses for 1 PWM period
	out OCR0A, R17   

	sbi DDRD, 5	; vystup ventilatoru na PD5


	ldi r26, PCICR ; load address of PCICR in Y 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 Y low
	clr r27 ; load high byte with 0
	ldi r16,0b00011100 ; vymaskovani - nastaveni preruseni na pinech PC2-PC4
	st X, r16 ; store new PCMSK1
	sei ; povoleni globalniho preruseni



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


spi:
	sleep 
	nop 
	rjmp spi 


;vyvolani preruseni

isr1:
	rcall KLAVESNICE
	mov R17, R16
	lsl R17
	lsl R17	
	out OCR0B, R17 
	reti ; navrat z preruseni


; Ovladani klavesnice


KLAVESNICE:
;vsechny radky jako vstupy
cbi DDRD,0
cbi DDRD,1
cbi DDRD,2
cbi DDRD,3

;pripojeni pull-up resistoru
sbi PORTD,0
sbi PORTD,1
sbi PORTD,2
sbi PORTD,3


;aktivace prvniho radku

sbi DDRD,0 ;prvni radek jako vystup
cbi PORTD,0 ;logicka nula

SBIS PINC,2
RJMP KEY1
SBIS PINC,3	;test prvniho sloupce
RJMP KEY2
SBIS PINC,4
RJMP KEY3
;SBIS PINC,5
;RJMP KEYA


;aktivace druheho radku
cbi DDRD,0 ;prvni radek je opet vstup
sbi PORTD,0 ;pull-up

sbi DDRD,1 ;druhy radek je vystup
cbi PORTD,1 ;na druhem radku je nula

SBIS PINC,2
RJMP KEY4
SBIS PINC,3
RJMP KEY5		;test druheho sloupce
SBIS PINC,4
RJMP KEY6
;SBIS PINC,5
;RJMP KEYB

;aktivace 3 radku
cbi DDRD,1 ;druhy radek je opet vstup
sbi PORTD,1; pull-up

sbi DDRD,2 ;treti radek je vystup
cbi PORTD,2 ;na tretim radku je nula

SBIS PINC,2
RJMP KEY7
SBIS PINC,3
RJMP KEY8		;test tretiho sloupce
SBIS PINC,4
RJMP KEY9
;SBIS PINC,5
;RJMP KEYC

;aktivace 4 radku
cbi DDRD,2 ;treti radek je opet vstup
sbi PORTD,2 ;pull-up

sbi DDRD,3 ;ctvrty radek je vystup
cbi PORTD,3	;nula na ctvrtem radku

;SBIS PINC,2
;RJMP KEYHV
SBIS PINC,3
RJMP KEY0	;testovani ctvrteho sloupce
;SBIS PINC,4
;RJMP KEYKR
SBIS PINC,5
RJMP KEYD

RET


KEY0:
ldi R16,0
cbi DDRD, 5 ;nastaveni ventilatoru jako vstupu-vypnuti
RJMP DEFAULT

KEY1:
ldi R16,1
RJMP DEFAULT

KEY2:
ldi R16,2
RJMP DEFAULT

KEY3:
ldi R16,3
RJMP DEFAULT

KEY4:
ldi R16,4
RJMP DEFAULT

KEY5:
ldi R16,5
RJMP DEFAULT

KEY6:
ldi R16,6
RJMP DEFAULT

KEY7:
ldi R16,7
RJMP DEFAULT

KEY8:
ldi R16,8
RJMP DEFAULT

KEY9:
ldi R16,9
RJMP DEFAULT

KEYA:
NOP
RJMP DEFAULT

KEYB:
NOP
RJMP DEFAULT

KEYC:
NOP
RJMP DEFAULT

KEYD:
NOP
RJMP DEFAULT

KEYHV:
NOP
RJMP DEFAULT


KEYKR:
NOP
RJMP DEFAULT


DEFAULT:
sbi DDRD, 5
sbi DDRD,0
sbi DDRD,1  ;vsechny radky jsou vystupy
sbi DDRD,2
sbi DDRD,3

cbi PORTD,0
cbi PORTD,1 ;na vsech radcich je nula pro vyvolani dalsiho preruseni
cbi PORTD,2
cbi PORTD,3
RET

;
;
;

[editovat] Ovládání segmentovky posuvným registrem

;Posuvny registr

.INCLUDE "m168def.inc"

.EQU key = 0
.EQU MR = 1
.EQU SH_CP = 2
.EQU ST_CP = 3
.EQU OE = 4
.EQU DS = 5


;vektory preruseni
.ORG 0x0000 
	;jmp Main ; Reset Handler

.ORG 0x0008 
	;jmp isr1 ; PCINT1 Handler

;nastaveni vstupu a vystupu

CBI DDRC,key
;SBI PORTC,key 	;tlacitko jako vstup, pripojen pull-up

;nastaveni vystupni brany

SBI DDRC,MR	;MRnon
SBI DDRC,SH_CP	;SH_CP - hodinu posuv.reg.
SBI DDRC,ST_CP	;ST_CP - hodiny latch 
SBI DDRC,OE	;OEnon - uvolnovaci vstup
SBI DDRC,DS	;DS	- seriovy vstup

LDI R24,0b10000010  ; prvni cislo segmentovky
LDI R25,0b10000001  ; druhe cislo segmentovky
LDI R18,0x01	;maska pro seriovy prenos

CLR R26
CLR R28
;pomocne registry R26-key H
                 ;R28 - key L


;  Hlavni program
STBY:
;nech zobrazeno a nic nedelej
SBIC PINC,key
RJMP KEY_H
;KEY_L
MOV R22,R24
CLR R26
SBRC R28,0
RJMP STBY
RJMP INIT_L

KEY_H:
MOV R22,R25
CLR R28
SBRC R26,0
RJMP STBY
RJMP INIT_H

INIT_H:
LDI R26,0x01
RJMP WR_INIT

INIT_L:
LDI R28,0x01

;------------------------------------------
WR_INIT:
LDI R18, 0b00000001	;maska
CBI PORTC,OE
SBI PORTC,MR
CBI PORTC,ST_CP

WR_SEND:
CBI PORTC,DS
MOVW R20,R18 ;R20 je pomocny registr
AND R20,R22		;R22 - hodnota, kterou chci poslat na vystup
BREQ CLK_SH
SBI PORTC,DS ;data = 1

CLK_SH:
SBI PORTC,SH_CP
NOP
CBI PORTC, SH_CP	;vzestupna hrana

LSL R18
BRNE WR_SEND
;-----------------

ZOBRAZ:
;CBI PORTC,OE
;SBI PORTC,MR
CBI PORTC,DS

CBI PORTC,SH_CP
SBI PORTC,ST_CP
NOP
CBI PORTC,ST_CP
CBI PORTC,MR
JMP STBY

[editovat] 1.Domácí úkol

;****************************************************************
;**************************1. Domaci ukol ***********************
;****************************************************************

.INCLUDE "m168def.inc"

.EQU potenc = 0 ;poteciometr na PC0
.EQU key=5 ;tlacitko na PC5
.EQU LED_AD = 2 ;LED na PB2
.EQU LED_INT = 5 ;LED2 na PB5

.EQU STMIVANI=0xFF
.EQU PWM_pulz = 0xF0


;vektory preruseni
.ORG 0x0000 
	jmp Main ; Reset Handler

.ORG 0x0008 
	jmp keypress ; PCINT1 Handler pro tlacitko

.ORG 0x002A 
	jmp ADCon ; ADC Conversion Complete Handler



Main: 
sei ;povol preruseni
clr r24

ldi r16,high(RAMEND)	; Main program start
out SPH,r16 			;nastaveni zasobniku na konec RAM
ldi r16,low(RAMEND)
out SPL,r16

sei ;povol preruseni

; vstupy a vystupy
CBI DDRC,key
CBI DDRC,potenc

SBI DDRB,LED_AD
SBI DDRB,LED_INT



;**************nastaveni preruseni pro dverni kontakt

	ldi r26, PCICR ; Aktivuj PCINT1
	clr r27 
	ldi r16,0b00000010 
	st X, r16 

	ldi r26, PCMSK1 ;nastaveni masky
	clr r27 
	ldi r16,0b00100000 ;povol preruseni na pinu PC5 - tlacitko
	st X, r16

;*************************************************************





;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
; nastaveni AD prevodniku


ldi r26,ADMUX
	ldi r16,0b00000000 ;nastaveni registru ADMUX-vnejsi reference
	st X,r16

ldi r26, ADCSRA 
	ldi r16,0b10001111 ;povoleni preruseni od AD prevodniku, volny beh prevodniku
	st X, r16 

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

; nastaveni HW_PWM pro regulaci LED

HW_INIT:
ldi R17,0b00100011
out	TCCR0A, R17
ldi	R17,0b00001001	; 
out	TCCR0B, R17
ldi	R17, PWM_pulz	; pocet pulsu na periodu
out	OCR0A, R17   
sbi	DDRB, LED_AD	; PWM output - LED


;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


;nastaveni PWM pro stmivani LED

PWM_INIT:
ldi r26,TCCR1A ;v r26 je adresa TCCR1A, ukazatel X=adresa TCCR1A
clr r27
ldi r16,0b00000011 ;Fast PWM
st X,r16

ldi r26,TCCR1B
clr r27
ldi r16,0b00001001
st X,r16

;ldi r26,TCCR1C
;ldi r16,0x00
;st X,r16

ldi r26,OCR1AL
clr r27
ldi r16,STMIVANI
st X,r16
nop


;*********************Cekaci smycka a stmivani*************************


ori r24,0x00
BREQ LOOP


CEKEJ5SEC:			; cekaci smycka pred stmivanim
clr r24				; vymaz priznak otevreni
ldi R25,20
ldi R26,0xFF
ldi R27,0xFF


WAIT:
DEC	R1
BRNE	WAIT
DEC	R2
BRNE	WAIT
DEC	R3
BRNE	WAIT

ldi r17,STMIVANI
ldi r16,TCCR1A		;povol citac
clr r27
ldi r16,0b00100000
st X,r16
nop

SNIZUJ_PWM:
ldi r26, OCR1BL	; nacte do PWM aktualni hodnotu pomeru
clr r27
mov r16,r17
st X,r16

SMALLWAIT:
	INC	R1	
	BRNE	SMALLWAIT	

	DEC	R17		
	LDI	R18, 0x0 
	CPSE	R18, R17 	;
	RJMP	SNIZUJ_PWM	

ZHASNI:
cbi PORTB,LED_INT
ldi r16,TCCR1A		;vypni citac
clr r27
ldi r16,0b00000000
st X,r16


LOOP:
sbi PORTB,LED_INT 
nop
RJMP main




;%%%%%%%%%%%%%%%%%%%%%%%obsluha preruseni%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

ADcon:			;preruseni od AD prevodniku
ldi R26,ADCH ; v X je adresa 0x79
clr r27
ld r16,X
mov r22,r16 ;ADCH v r22
ldi r26,ADCL
clr r27
ld r16,X ; ADCL v r16

lsr r16
lsr r16
lsl r22
lsl r22
lsl r22
lsl r22
lsl r22
lsl r22

or r22,r16
out OCR0B,R22  ; AD prevodnik na vystup PWM
reti



;**************obsluha spinace********************

; v preruseni se zapne LED 
keypress:
sbis pinc,5
ldi r24,0x01           ;priznak cekaci smycky
nop
reti

[editovat] Posuvný registr v jazyce C


; registr v C - funkcni

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

#define SER		PD5
#define SRCLK	PD6
#define RCLK	PD7
#define SRCLR	PB0

// global constants and variables
// static code table used for 7-segment led display decoding (common anode)
/*unsigned char code [] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x9B, 0x92, 0x93, 0xF8, 0x80, 0x98,
				 		  0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E };*/
unsigned char code [] = { 0x3F, 0x06, 0x5B, 0x4F, 0b01100110, 0x6D, 0xFD, 0x07, 0x7F, 0x67,
				 		  0xF7, 0x7C, 0x39, 0b01011110, 0x79, 0x71 };

// character to show on display
static volatile unsigned char anumber = 0;
// Interrupt vector table is created by compiler
// the ISR macro defines interrupt service handlers

// Pin change interrupt 1
// keyboard handler
ISR(PCINT1_vect)
{
	unsigned char keys[10];
	unsigned char nkeys = 0;
	register unsigned char column;

//    DDRD 	&= 0b00000001;
	DDRD	&= 0b11110001;
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 1;
	if (!(PINC & 8))
		keys[nkeys++] = 2;
	if (!(PINC & 16))
		keys[nkeys++] = 3;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD1);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 4;
	if (!(PINC & 8))
		keys[nkeys++] = 5;
	if (!(PINC & 16))
		keys[nkeys++] = 6;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD2);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 7;
	if (!(PINC & 8))
		keys[nkeys++] = 8;
	if (!(PINC & 16))
		keys[nkeys++] = 9;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD3);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 8))
		keys[nkeys++] = 0;

	DDRD 	|= 0b00001111;		// configure rows as outputs
	PORTD 	&= 0b11110000;		// set keyboard rows at port D to zero

	if (nkeys > 0) {
		OCR1A = keys[0] * 100;
		TCNT1 = 0;
	}
}

// Timer/Counter1 Compare Match A
// the value shown on the display will be updated here
ISR(TIMER1_COMPA_vect)
{
	unsigned char tmp = code[anumber];
	volatile char loopcounter = 8;

	do {
		PORTD &= ~(1 << SRCLK);			// assert 0 on serial clock line
		if (tmp & 0x80)					// test LSB
			PORTD |= (1 << SER);		// if 1, assert 1 on serial data line
		else
			PORTD &= ~(1 << SER);		// assert 0 otherwise
		PORTD |= (1 << SRCLK);			// assert 1 on serial clock line - rising edge writes bit into the serial shift register
		tmp <<=  1;					// shift right to proceed next bit
		loopcounter--;
	} while (loopcounter > 0); 
	PORTD &= ~(1 << RCLK);				// toggle parallel register clock 0-1 to make a rising edge
	PORTD |= (1 << RCLK);
	
	// update value to display for next time
	if (anumber < 15)
	    anumber++;
	else
		anumber = 0;
}

void main(void)
{
	// keyboard (and serial shift register connection) ports init
	DDRD 	|= 0b11101111;		// configure rows as outputs (PD0 ... PD3), serial shift register pins PD5 .. PD7
	PORTD 	= 0;				// set port D to zero
	DDRC	= 0;				// configure port C as input port
	PORTC	|= 0b00011100;		// activate pul-up resistors on three columns

	DDRB	|= (1 << SRCLR);	// configure PB0 as output - serial shoft register clear
	PORTB	|= (1 << SRCLR);	// toggle PB0 1-0-1 to clear the serial shift register
	PORTB	&= ~(1 << SRCLR);
	PORTB	|= (1 << SRCLR);

	// an interrupt masking must be here
	// keyboard interrupt
	PCICR 	= (1 << PCIE1);		// Pin change interrupt control register, Pin change interrupt enable 1
	PCMSK1 	= 0b00011100;		// allow pin change interrupt on portC bits 2,3,4

	// timer configuration
	TCCR1A	= 0;				// OC1A/OC1B disconnected, CTC bits WGM11, WGM10
	TCCR1B 	= (1 << CS12) | (1 << CS10) | (1 << WGM12);
								// CTC mode, prescaler division factor 1024
	OCR1A 	=  976;				// timer compare value

	TIMSK1 = (1 << OCIE1A);		// enable timer interrupt

	set_sleep_mode(SLEEP_MODE_IDLE);
	sei();						// set Global Interrupt Enable!!!

	while (1) {
		sleep_cpu();
	}
}
;**********************************************************************************************


[editovat] Posuvný registr - kombinace jazyka C a assembleru


;****************registr C + asm *************************************************************

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

#define SER		PD5
#define SRCLK	PD6
#define RCLK	PD7
#define SRCLR	PB0


// toto je hlavní soubor s kódem v jazyce C
extern void send595(unsigned char posuv595){
volatile int x;
	x = eeprom_diff_val (posuv595);  // volání funkce v asembleru

}
// global constants and variables
// static code table used for 7-segment led display decoding (common anode)
/*unsigned char code [] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x9B, 0x92, 0x93, 0xF8, 0x80, 0x98,
				 		  0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E };*/
unsigned char code [] = { 0x3F, 0x06, 0x5B, 0x4F, 0x64, 0x6D, 0xFC, 0x07, 0x7F, 0x67,
				 		  0xF7, 0x7F, 0x39, 0x3F, 0x79, 0x71 };

// character to show on display
static volatile unsigned char anumber = 0;
// Interrupt vector table is created by compiler
// the ISR macro defines interrupt service handlers

// Pin change interrupt 1
// keyboard handler
ISR(PCINT1_vect)
{
	unsigned char keys[10];
	unsigned char nkeys = 0;
	register unsigned char column;

//    DDRD 	&= 0b00000001;
	DDRD	&= 0b11110001;
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 1;
	if (!(PINC & 8))
		keys[nkeys++] = 2;
	if (!(PINC & 16))
		keys[nkeys++] = 3;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD1);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 4;
	if (!(PINC & 8))
		keys[nkeys++] = 5;
	if (!(PINC & 16))
		keys[nkeys++] = 6;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD2);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 7;
	if (!(PINC & 8))
		keys[nkeys++] = 8;
	if (!(PINC & 16))
		keys[nkeys++] = 9;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD3);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 8))
		keys[nkeys++] = 0;

	DDRD 	|= 0b00001111;		// configure rows as outputs
	PORTD 	&= 0b11110000;		// set keyboard rows at port D to zero

	if (nkeys > 0) {
		OCR1A = keys[0] * 100;
		TCNT1 = 0;
	}
}

// Timer/Counter1 Compare Match A
// the value shown on the display will be updated here
ISR(TIMER1_COMPA_vect)
{
/*	unsigned char tmp = code[anumber];
	volatile char loopcounter = 8;

	do {
		PORTD &= ~(1 << SRCLK);			// assert 0 on serial clock line
		if (tmp & 0x80)					// test LSB
			PORTD |= (1 << SER);		// if 1, assert 1 on serial data line
		else
			PORTD &= ~(1 << SER);		// assert 0 otherwise
		PORTD |= (1 << SRCLK);			// assert 1 on serial clock line - rising edge writes bit into the serial shift register
		tmp <<=  1;					// shift right to proceed next bit
		loopcounter--;
	} while (loopcounter > 0); 
	PORTD &= ~(1 << RCLK);				// toggle parallel register clock 0-1 to make a rising edge
	PORTD |= (1 << RCLK); */

	send595(code[anumber]);
	
	// update value to display for next time
	if (anumber < 15)
	    anumber++;
	else
		anumber = 0;
}

void main(void)
{
	// keyboard (and serial shift register connection) ports init
	DDRD 	|= 0b11101111;		// configure rows as outputs (PD0 ... PD3), serial shift register pins PD5 .. PD7
	PORTD 	= 0;				// set port D to zero
	DDRC	= 0;				// configure port C as input port
	PORTC	|= 0b00011100;		// activate pul-up resistors on three columns

	DDRB	|= (1 << SRCLR);	// configure PB0 as output - serial shoft register clear
	PORTB	|= (1 << SRCLR);	// toggle PB0 1-0-1 to clear the serial shift register
	PORTB	&= ~(1 << SRCLR);
	PORTB	|= (1 << SRCLR);

	// an interrupt masking must be here
	// keyboard interrupt
	PCICR 	= (1 << PCIE1);		// Pin change interrupt control register, Pin change interrupt enable 1
	PCMSK1 	= 0b00011100;		// allow pin change interrupt on portC bits 2,3,4

	// timer configuration
	TCCR1A	= 0;				// OC1A/OC1B disconnected, CTC bits WGM11, WGM10
	TCCR1B 	= (1 << CS12) | (1 << CS10) | (1 << WGM12);
								// CTC mode, prescaler division factor 1024
	OCR1A 	=  976;				// timer compare value

	TIMSK1 = (1 << OCIE1A);		// enable timer interrupt

	set_sleep_mode(SLEEP_MODE_IDLE);
	sei();						// set Global Interrupt Enable!!!

	while (1) {
		sleep_cpu();
	}



}

;**************************************************************************************************
Osobní nástroje