Uživatel:Stolcala

Z MAM wiki

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

[editovat] Semestrální práce

Generování signálu robotickému klavíristovi

Generujeme impulsy pro elektromagnetické "prsty" nad jednotlivými klávesy, ze vstupního signálu využíváme pouze dvou informací: Výšku tónu a její sílu, délku určíme podle toho, kdy pustíme klávesu. Jako sériový vstupní signál využijeme MIDI. Každá MIDI informace je rozdělena do 2-3 bytů ve formátu na obrázku níže (reversní, tzn. nejvyšší bit je na konci). Byty jsou ohlášeny logickou 1 a ukončeny logickou 0, nejvyšší bit bytu je vždy buďto v 1 při tzv. stavovém bytu, který nám říká, co bude v datech, a nebo 0 při datových bytech, ty nesou informaci o výšce tónu a o jeho síle. Máme tak pro přenos informace tedy pouze 7 bitů, proto máme i 128 informací o výšce (11 oktáv) a 128 o síle tónu.

Soubor:midi.png

V první bytu se mohou nacházet informace v tabulce níže, první tři bity nesou informaci o kanálu, nejvyšší poslední bity (vysílá se reversivně) pak informaci o čísle kanálu. V mé práci budu používat pouze jeden kanál a informaci o stisknutí klásvesy a puštění klávesy (Note On, Note Off), výška tónu se nalézá v datovém bytu spolu s její sílou. Zajímají nás tedy pouze stavové byty 0x80 a 0x90, všechny ostatní můžeme vesele ignorovat. Pro jednoduchost však předpokládáme pouze tyto dva.

Soubor:Status.png

Proto je u vstupní části potřeba zajistit detekci těchto bytů. Frekvence vysílání MIDI je 31250 Hz, celý byte i s ohlášením a ukončením (10 bitů) se nám přenese za 320us. Je tedy nejdříve nutné ideálně synchronizovat AVR s touto frekvencí. Nejvhodnější by teoreticky bylo využít módu UART, který zajišťuje synchronizovaný sériový vstup při zachování frekvence. Jednodušší řešení představuje nastavit celý CLK procesoru na stejnou frekvenci jako frekvenci signálu MIDI. Nastavení procesor do synchronního slave modu pro využití externího CLK z MIDI signálu by probíhalo jednoduchým příkazem

Soubor:Spcr.png

SPCR = 0b01000000;

V registru SPCR nastavujeme hlavně hodnotu SPE (SPI Enable) a MSTR (Master/Slave Select). Poté bychom mohli data jednoduše vyčítat

for (i=0,i=9,i++)
 if (i>0&&i<9) přijatý byte[i-1]=input;

Toto by fungovalo, pokud by každá operace trvala jeden cyklus. To však nehrozí a musela by se využít ještě menší slave CLK. Je tedy lepší využít synchroní sériové rozhraní USART. Toto rozhraní mají některé mikrokontrolery řady PICmicro MCU a většina MCU firmy Atmel. Jedná se vlastně o analogii RS-232, start bit, přenášený byte a stop bit. Při použití správné knihovny můžeme toto rozhraní aktivovat v SPI slave módu pomocí příkazu

usart_init(slave,spi);

Díky tomu nám zůstave frekvence procesoru nezměněná a data se ukládají do paměťového registru USARTu UBRR. Posléze je s nimi libovolně pracovat, ideálně někam překopírovat, než přijde na sériový port další informace. Po přečtení bytu je důležité vědět, zdali se jedná o stavový či datový byte. Jak jsem uvedl výše, to zjistme pomocí nejvyššího bitu (posledního). Již v prvním odstavci jsem zmiňoval, že jedna MIDI informace může mít dva až tři byty. Je to z toho důvodu, že nemusíme uvádět stavový byte, pokud je stejný jako v předchozím případě a tak zvýšíme rychlost tím, že přeneseme pouze informaci o výšce a síle tónu.

if (přijatý_byte[7]==1)
 if (přijatý_byte[]==note_on[]) note=true;
 if (přijatý_byte[]==note_off[]) note=false;
 pořadí_byte=1;
else
 if (pořadí_byte==1||pořadí_byte==3) 
 výška_tónu[]=lrshift(přijatý_byte[]);
 pořadí_byte=2;
 else
 síla_tónu[]=lrshift(přijatý_byte[]);
 pořadí_byte=3;

Nyní máme uloženou informaci o výšce, síle a zdali tón vypínáme či zapínáme. Nyní potřebujeme tuto informaci nějakým způsobem předat na výstup. Standardní klaviatura má 88 kláves, my máme k dispozici 128 výšek tónů, což nám klavír bohatě pokryje.

Soubor:Piano.jpg

Potřebujeme tedy minimálně 88 výstupů a pokud bychom neuvažovali sílu tónu, stačilo by je na elektromagnety připojit. Tu ale vzít v úvahu chceme a proto musíme nějakým způsobem řídit napětí na každém z elektromotorků na výstupu. V následujícím zapojení vidíme možnost řízení síly tónu pomocí PWM, druhý výstup slouží pouze k indikaci toho, že byla klávesa spuštěna.

Soubor:Zapojeni.png

Toto zapojení je nutné zopakovat pro každou klávesu zvlášť, tj. 88 kláves znamená 176 výstupů. Dva výstupy proto, že při použití PWM nemůžeme klávesu s danou hodnotou držet, klávesa by nám skákala do nuly. Posléze jí chceme pouze stisknout, což se již děje okamžitě. Každá klávesa má tento výstup, neboť pokud bychom použili multiplexor, nemohli bychom hrát polyfonní melodie.

for (i=0,i=počet_kláves_ovládaných_procesorem,i++);
 if (note_on==1) 
  casovac_pwm_klavesy[i]=síla_tónu[i];
  out_klavesa[i]=1;
 else
  out_klavesa[i]=0;

Problém je, že nám zcela určitě jeden procesor (pokud budeme vybírat nějaký z cenově dostupných) nevystačí, potřebujeme minimálně 88 analogových výstupů pro každou klávesu. Je tedy zcela na výběru procesoru, jak bude celý program a komunikace mezi jednotlivými procesory vypadat, kód by mohl vypadat následovně.

if (výška_tónu>max_výška_tónu_chipu)
 out_next_procesor(note,výška_tónu,sóla_tónu);
else
 main















8 týden, kód pro sedmisegmentovku, přepínání číslic 1 a 2 pomocí portu D0.

.INCLUDE "m168def.inc"


.ORG 0x0000 
	rjmp Main ; Reset Handler

.ORG 0x0008 
	rjmp cteni ; PCINT1 Handler



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


	cbi DDRC, 0 ;¨vstup
	sbi PORTC, 0 ; set internal Pull-Ups for keyboard
	sbi DDRD, 5 ; výstup

	


	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, 0b11111111
	out OCR0A,R17  


    ldi r16,0b00100000
	sts ADMUX,r16
	ldi r16, 0b11000000
	sts ADCSRA, r16

cteni:
	lds r16, ADCL
	lds r16, ADCH
	ldi r17, 0b11110000
	and r16,r17
	out OCR0B,R16
	rjmp cteni


1.domácí úkol, 1 část

.INCLUDE "m168def.inc"


.ORG 0x0000 
	rjmp Main ; Reset Handler

.ORG 0x0008 
	rjmp dvere ; PCINT1 Handler



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


	cbi DDRC, 2 ;¨vstup
	sbi PORTC, 2 ; set internal Pull-Ups for keyboard
	sbi DDRD, 5 ; výstup


	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



	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, 0b11111111
	out ocr0a, r17

	ldi r17,0

	


; 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,0b00000000 ; 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



dvere:
zavrene:
	sbrs r17, 0
	rjmp otevrene
	rcall WAITaSEC
dosvit:
	out OCR0B, R17
	rcall waitamsec
	dec R17
	breq 0
	rjmp dosvit
	cbi PORTD,5	
	ldi r17, 0b00000000
	out OCR0B, R17
	reti

otevrene:
	ldi r17,0b11111111
	out OCR0B,R17  ; output pulse "high" lenght to PWM compare unit 
	reti ; return from Interrupt





WAITaSEC:
	ldi  r18, 102
    ldi  r19, 118
    ldi  r20, 193
L1: dec  r20
    brne L1
    dec  r19
    brne L1
    dec  r18
    brne L1
    ret

WAITamSEC:
     ldi  r18, 41
    ldi  r19, 148
L2: dec  r19
    brne L2
    dec  r18
    brne L2
    ret



1.domácí úkol 2.část


.INCLUDE "m168def.inc"


.ORG 0x0000 
	rjmp Main ; Reset Handler

.ORG 0x0008 
	rjmp osvetleni ; PCINT1 Handler



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


	cbi DDRC, 0 ;¨vstup
	sbi PORTC, 0 ; set internal Pull-Ups for keyboard
	sbi DDRD, 5 ; výstup

	


	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, 0b00000000



    ldi r16,0b00100000
	sts ADMUX,r16
	ldi r16, 0b11000000
	sts ADCSRA, r16

cteni:
	lds r16, ADCL
	lds r16, ADCH
	lsr r16
	lsr r16
	lsr r16
	lsr r16
	neg r16
	ldi r17, 0b00001111
	and r16,r17
	out OCR0A,R16  
	rjmp cteni





Cvičení 7.3.2013


; 
; 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 DDRD = $0A
	.EQU PORTD = $0B
        .EQU PIND = $09

	.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	DDRD, 2  ; PD2 is output - ROW
;       CBI PORTD, 2  ; PD2=0
;       CBI DDRB, 2   ; PB2 is input - COLUMN
	SBI	PORTB, 2 ; enables pull-up resistor on this pin

	SBIS	PINC, 2
	RJMP 	SVIT	

	
	RCALL	DARK
	RCALL	WAIT

		; RJMP - Relative Jump 

;;;
;;;
;;; P R O C E D U R E S
;;;
;;;
	
SVIT:
	RCALL	COLOR1
	RCALL	WAIT
	RET
	

SMALLWAIT:
	INC	R1				; INC - Increment
	BRNE	SMALLWAIT	; BRNE - Branch if Not Equal (Z flag) 
	RET					; RET - Return from Subroutine

WAIT:
	LDI	R16, 1			; 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, 2
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

Cvičení 14.3.2013


; 
; 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 "m88def.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


; Init:
	RCALL   FAN_OFF

GO:	SBIS	PINC, 2
	RCALL	FAN_PWM   ; 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

	
FAN_ON:
	SBI	PORTB, FAN
	RET

FAN_OFF:
	CBI	PORTB, FAN
	RET

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

	RET

; 
; 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 +15 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 "m88def.inc"

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


.ORG 0x0000 ;
	rjmp Main ; Reset Handler

.ORG 0x0008 
	rjmp 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	; rezim PWM, 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 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

--- Domácí příprava

- Oprava chyby klávesnice pro tlačítka A,B,C,D (tlačítko D spouštělo prakticky podprogram tlačítka A - při ručním krokování se ale program choval správně) + reakce na každou klávesu jiným signálem LED diody, ochrana proti zkratu při stisku více tlačítek současně




	.EQU DDRB = $17		; DDRB address
	.EQU PORTB = $18	; PORTB address
	.EQU PINB = $16
	
	.EQU PB7 = 7		
	.EQU PB6 = 6
	.EQU PB5 = 5		
	.EQU PB4 = 4

	.EQU PB1 = 1		;pro LED diodu		
	.EQU PB0 = 0
	
	.EQU DDRD = $11		; DDRD address
	.EQU PORTD = $12	; PORTD address
	.EQU PIND = $10		; PIND address

	.EQU PD2 = 2		
	.EQU PD3 = 3
	.EQU PD4 = 4		
	.EQU PD5 = 5
	

START:

;PB nastavime na vstupni
	CBI DDRB, PB7
	CBI DDRB, PB6
	CBI DDRB, PB5
	CBI DDRB, PB4

;PB push-pull rezistor

	SBI PORTB, PB7
	SBI PORTB, PB6
	SBI PORTB, PB5
	SBI PORTB, PB4


;PD nastavime na vystupnni
	SBI DDRD, PD2
	SBI DDRD, PD3
	SBI DDRD, PD4
	SBI DDRD, PD5
	

;PD nastavime na log. nulu
	CBI PORTD, PD2
	CBI PORTD, PD3
	CBI PORTD, PD4
	CBI PORTD, PD5
	


SLOUPEC1:	
	
	SBIS PINB, PB7	;pokud je nula, tak provede nasledujici
	RJMP VYHODNOT1	;
	RJMP SLOUPEC2	;

VYHODNOT1:
	RCALL PDvstupy
	SBI DDRD, PD2	;PD2 vystupni 
	CBI PORTD, PD2	;log 0
	
 	SBIS PINB, PB7
	RJMP A

	RCALL PDvstupy
	SBI DDRD, PD3	;vystupni
	CBI PORTD, PD3	;log 0
		
	SBIS PINB, PB7
	RJMP B

	RCALL PDvstupy
	SBI DDRD, PD4	;vystupni
	CBI PORTD, PD4	;log 0

	SBIS PINB, PB7
	RJMP C

	RCALL PDvstupy
	SBI DDRD, PD5	;vystupni
	CBI PORTD, PD5	;log 0

	SBIS PINB, PB7
	RJMP D

	RJMP START


SLOUPEC2:
	nop
	RJMP START

A:

			SBI DDRB, PB0	;Nastav PB0 brany B na vystupni (ddrb nastavime na 1 pomoci SBI)
			SBI DDRB, PB1	;Nastav PB1 brany B na vystupni (SBI)
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAIT
			RJMP START

B:

			SBI DDRB, PB0	;Nastav PB0 brany B na vystupni (ddrb nastavime na 1 pomoci SBI)
			SBI DDRB, PB1	;Nastav PB1 brany B na vystupni (SBI)
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAIT
			RJMP START
C:

			SBI DDRB, PB0	;Nastav PB0 brany B na vystupni (ddrb nastavime na 1 pomoci SBI)
			SBI DDRB, PB1	;Nastav PB1 brany B na vystupni (SBI)
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAIT
			RJMP START


D:

			SBI DDRB, PB0	;Nastav PB0 brany B na vystupni (ddrb nastavime na 1 pomoci SBI)
			SBI DDRB, PB1	;Nastav PB1 brany B na vystupni (SBI)
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Rozsvitim diodu
			SBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAITkratky
			CBI PORTB, PB0	;Nastav port B vystup PB0 do log. 0 Zhasnu diodu
			CBI PORTB, PB1	;Nastav port B vystup PB1 do log. 1
			RCALL WAIT
			RJMP START


PDvstupy:

	CBI DDRD, PD2	;vstupni
	CBI DDRD, PD3	;vstupni
	CBI DDRD, PD4	;vstupni
	CBI DDRD, PD5	;vstupni
	RET


WAIT:
	LDI	R16, 4			; LDI - Load Immediate
WAIT1:	
	INC	R1
	BRNE	WAIT1
	INC	R2
	BRNE	WAIT1
	DEC	R16
	BRNE	WAIT1
	RET


WAITkratky:
	LDI	R17, 1			; LDI - Load Immediate
WAITkratky1:	
	INC	R3
	BRNE	WAITkratky1
	INC	R4
	BRNE	WAITkratky1
	DEC	R17
	BRNE	WAITkratky1
	RET



--- 6. Cviceni

; 
; 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 +15 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 "m88def.inc"

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


.ORG 0x0000 ;
	rjmp Main ; Reset Handler

.ORG 0x0004 
	rjmp isr1 ; PCINT1 Handler



; Main program start

Main: 

; Stack pointer init:
	ldi r16,high(RAMEND); posledni adresa pameti - je ulozena  Main program start
	out SPH,r16 ; SPH je registr (adresa v hlavickovem souboru) v IO prostoru 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	; rezim PWM, 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 ; aktivace preruseni reknu ktery port budu aktivovat. kdyz spadne do log nuly, preruseni load address of PCICR in Y low
	clr r27 ; load high byte with 0
	ldi r16,0b00000010 ; port C 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 ; ktere piny budou aktivovat - sloupce (2.3.4) allow pin change interrupt on portC bits 2,3,4
	st X, r16 ; store new PCMSK1

	sei ; globalni preruseni - 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 ; navrat z preruseni 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


Osobní nástroje