Uživatel:Tulacjir

Z MAM wiki

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

Semestralni prace

Semestralni práce má jednoduché zadání-stisknutí tlačítka na maticové klávesnici a následné zobrazení na sedmisegmentovém display.Použil jsem 2 μP ATmega16,z nichž jeden slouží jako vysílač, druhý jako přijímač. Vysílač vysílá u určitých intervalech jeden byte, který se mění v rozsahu 0-255. Vysílání je zahájeno sestupnou hranou přerušení. Přijímač tento byte načte a má za úkol ho zobrazit na sedmisegmentovém display. K vzájemné komunikaci používám jednotku USART.

Atmega16

Čerpal jsem z této literatury.


Vysilac

   
        
 ;ATIKBD.ASM:inteligentní klávesnice
    .nolist
	.INCLUDE "m16def.inc"
	.list 
;	.cseg ;kódový segment   
      .equ baud = 103    ;9600 Bd
	  .def reg0=r16
	  .def reg1=r17
	  .def reg2=r18
	  .def ACC =r19
	  .equ cekani=250
	  ldi reg0,0xff
;	  ldi r26,0xff 
      ldi r16,low(ramend);nastav zásobník
	  out spl,r16
	  ldi r16,high(ramend)	  
	  out sph,r16

	  ldi r16,0x00
      out ddra,r16
	  ldi r16,0xff  ;pull up pro tlačítka
	  out porta,r16
;inicializace usart pro vysílání
      
      sbi ddrd,1                 ;TxD je výstup
      ldi r16,high(baud)         ;nastavení
	  out ubrrh,r16              ;přenosové 
	  ldi r16,low(baud)          ;rychlosti 
	  out ubrrl,r16
	  ldi r16,(1<<txen);povol vysílání
	  out ucsrb,r16
	  ldi r16,(1<<ursel)|(3<<ucsz0);8dat bitů + 1 stop bit
	  out ucsrc,r16
      sbi ddrd,2
      sbi portd,2
	  sbi portd,1
	        

smycka0:
      rcall klav
      
     cbi portd,2       ;sestupná hrana přerušení int0	                   
     out udr,r16       ;vysílání přes usart

    
     cekej1:              ;čekání na 
     sbis ucsra,udre   ;vyprázněný bufer
     rjmp cekej1
     cbi ucsra,udre    ;nulování příznaku
     sbi portd,2       ;konec vysílání vzestupná hrana


rjmp smycka0
 
;klavesnice 4x4 na portb, v acc je pozice, v r0 je kod znaku,r2-docasny vysledek,r1-pomoc.promenna
;reg r16,r17,r18,r19,r0      
klav: 
	
smycka:	RCALL CKLAV	;čti znak

	TST ACC	;nula bez stisku klávesy
	breq smycka ;Z=1(acc=0), chyba
	
;k adrese tabulky přičítám 0 až 15
	DEC ACC	;sniž kód
	LDI R30,LOW(ADRTAB)	;Z ukazuje
	LDI R31,HIGH(ADRTAB)	;na tabulku
	ADD R30,ACC	;posuň
	CLR REG0	;na načtený znak
	ADC R31,REG0	
	LPM	r16,z;přečti kód z tabulky

	ret

;na spodní řádek klavesnice se dá jednička v inverzi nula
;tato jednička(nula) se bude posouvat a tím se postupně budou nulovat
;další řádky a hledat nulu ve sloupcích		
CKLAV:	LDI REG0,$01	;maska na první řádek

;v reg2 se utváří číslo 1 až 16 což odpovídá nějaké klávese
	CLR REG2	;nuluj dočasný výsledek

;obsah si dám do pomocné proměnné
CTIRAD:	MOV REG1,REG0

;reg0 použiji na definici výstupu a vstupu-bude tam vždy jeden výstup
;ostatní vstup(bude to čteno)
;znegovaný reg1 se použije na aktivací nuly pro daný řádek	
	COM REG1	
	OUT DDRa,REG0	;aktivuj jeden řádek
	OUT PORTa,REG1	;log. 0

;čtu jaký je stav na portu kde je připojena klávesnice, zda je propojen vynulovaný
;řádek s nějakým sloupcem
	IN ACC,PINa	;čti stav do ACC
;počkám neboť při stisku jsem mohl stisknout nechtěně vícekrát, což je takzvaný zákmit
;tlačítka 
	LDI REG1,CEKANI	;počkej
CTICEK:	DEC REG1	
	BRNE CTICEK	

;čtu znova aby se dala tato hodnota v REG1 porovnat s minulou v ACC
	IN REG1,PINa	;čti stav do REG1
	CP ACC,REG1	;porovnej

;pokud se nerovnají tak  znova od CTIRAD
	BRNE CTIRAD	;A=REG1->jdi dál

;neguji acc aby se dalo pracovat s jedničkou
	COM ACC	;neguj

;bude mě zajímat zda ve sloupcových bitech je jednička tzn. zda je zmáčknuta
;nějaká klávesa
	ANDI ACC,$F0	;vymaskuj sloupce

;pokud není tak se připraví na nulování dalšího řádku
	BREQ CDALR	;Z=1->nic není, čti další řádek
	LDI REG1,1	;nastaveni pozice

;posouvám jedničku v horních sloupcových bitech do leva až se mně objeví
;ve stavovém registru sreg v příznaku přetečení bitu C
CSLOUP:	LSL ACC	;posuň do C
	BRCS CTEST	;C=1->proveď test

;každý posun načítám do reg1
	INC REG1	;jinak zvyš pozici
	RJMP CSLOUP	;a znovu

;provádím další ošetření zákmitu
;v acc nula jinak se zmáčkly najednou 2 tlačítka
CTEST:	BRNE CCHYBA	;ACC musí být 0
;reg2 musí být vynulován jinak dostanu hodnotu větší než 1 až 16
	TST REG2	;REG2 musí být 0
	BRNE CCHYBA

;pozici sloupce dám do reg2 a k tomu přičítám pozici řádku + 4
;tím každému tlačítku přiřadím číslo 1 až 16		
	MOV REG2,REG1	;pozice je výsledek
	MOV REG1,REG0	;zjisti řádek
	LDI ACC,4

;zde zjišťuji pozici řádku rotací do prava ve spodních 4 řádkových bitech
;až se mě objeví v příznaku přetečení C
CRADI:	LSR REG1	;posouvej masku
	BRCS CDALR	;C=1->konec
	ADD REG2,ACC	;přičti k pozici 4
	RJMP CRADI	;a znovu

;zde nahazuji jedničku(nulu) na další řádek a testuji zda není v příznaku přetečení
CDALR:	LSL REG0	;příprava na další řádek
	CPI REG0,$10	;test konce
	BREQ CKON		
	RJMP CTIRAD	;jinak na další řádek

;načtený hodnoty 1 až 16 dám do acc
CKON:	MOV ACC,REG2	;ulož výsledek do ACC
	RET
CCHYBA:	CLR ACC	;vynuluj ACC
	RET
		;tabulka znaků
;k adrtab přičítám hodnotu 0 až 15
		;tabulka znaků          ;klavesa
TAB:	.DB 0b00011001,0b00000100	;hvezdicka,0
	.DB 0b11110100,0b11110110	;hash,D
	.DB 0b00110110,0b00000000	;7,8
	.DB 0b00010000,0b00010000	;9,C
	.DB 0b11010010,0b00011000	;4,5
	.DB 0b00001000,0b11111110	;6,B
        .DB 0b11110110,0b00100001	;1,2
	.DB 0b00110000,0b00010000	;3,A
	.EQU ADRTAB=(2*TAB)	;adresa tabulky

přijímač


	.NOLIST	
	.INCLUDE "m16def.inc"	
	.LIST	

	.EQU BAUD=103	;tj. 9600 Bd
		
	.CSEG
	RJMP RESET	;inicializace
	.ORG URXCaddr
	RJMP PRIJEM	;obsluha RXC
	
	;inicializace:	
RESET:	LDI R16,LOW(RAMEND)	;nastav
	OUT SPL,R16	;SPL
	LDI R16,HIGH(RAMEND)	;nastav
	OUT SPH,R16	;SPH
	
	LDI R16,255	;port a
	OUT DDRa,R16	;je výstupní
	OUT PORTa,R16	;zhasne LED
	OUT PORTA,R16	;A má pull-upy    
	cBI DDRD,0	;rXD je vstup
	cbi ddrd,2  ;přerušení int0
	LDI R16,HIGH(BAUD)	;nastavení
	OUT UBRRH,R16	;přenosové
	LDI R16,LOW(BAUD)	;rychlosti
	OUT UBRRL,R16	;do UBRR
	
	LDI R16,(1<<RXEN)|(1<<RXCIE)|(1<<TXEN)	;povol příjem+vysílání
	OUT UCSRB,R16	;a RXC přerušení

	LDI R16,(1<<URSEL)|(3<<UCSZ0)	;8 datových bitů
	OUT UCSRC,R16	;+1 stop-bit

	SEI	;I=0
	RJMP PC	;čekej


	;obsluha URXC:	
PRIJEM: IN R16,UDR	;načti bajt1
	OUT PORTa,R16	;na LED	  	
;	OUT UDR,R16	;odešli bajt
	RETI	;konec


 

Ukol na klavesnici

.INCLUDE "2313def.inc"

 

 // Nastavení vstupù a výstupù pro klávesnici
    cbi     DDRD, 2      // nastavení vstupů pro klávesnici (sloupec 1 - 3)
    cbi     DDRD, 3
    cbi     DDRD, 4

    sbi     PORTD, 2     // nastavení pull-upù
    sbi     PORTD, 3
    sbi     PORTD, 4

    sbi     DDRB, 7     // nastavení výstupù pro klávesnici (øádek 1 - 4)
    sbi     DDRB, 6
    sbi     DDRB, 5
    sbi     DDRB, 4

    cbi     PORTB, 7    // nastavení log. nuly na všech rádcích
    cbi     PORTB, 6
    cbi     PORTB, 5
    cbi     PORTB, 4


// Ètení klávesnice


// Stisknutí klávesy 0
KL0:
    ;sbi R17, 2
    ;cp R16, R17
   
    sbi    PORTB, 7    // nastavení jednièky pro první øádek
    sbi    PORTB, 6    // nastavení jednièky pro druhý øádek
    sbi    PORTB, 5    // nastavení jednièky pro tøetí øedek
    cbi    PORTB, 4    // nastavení nuly pro ètvrtý øádek (* 0 # D)
   
    sbic    PIND, 3        // pokud je na druhém sloupci (2 5 8 0) nula, pøeskoè následující instrukci
    rjmp    KL1        // pokraèuj na KL1 (testuj, jestli je zmáèknutá 1)
    ldi    R16, 0
    RCALL COLOR2    // zapiš do registru R16, že byla stisknuta 0
    rjmp     STISK        // pokraèuj na èást STISK, kde dojde k vypnutí výstupù

// Stisknutí klávesy 1
KL1:
    cbi    PORTB, 7    // log. nula na prvním øádku (1 2 3 A)
    sbi    PORTB, 6    // log. jednièka na ostatních øádcích
    sbi    PORTB, 5
    sbi    PORTB, 4

    sbic    PIND, 2        // pokud je na prvním sloupci (1 4 7 *) nula, pøeskoè následující instrukci
    rjmp    KL2        // pokraèuj na KL2 (testuj, jestli je zmáèknutá 2)
    ldi    R16, 1        // zapiš do R16, že byla stisknuta 1
    rjmp    STISK        // pokraèuj na èást STISK

// Stisknutí klávesy 2
// Výstupy máme nastavené od KL1, pouze testujeme vstup
KL2:
    sbic     PIND, 3     // pokud je na druhém sloupci (2 5 8 0) nula, preskoc následující instrukci
    rjmp     KL3        // pokraèuj na KL3 (testuj, jestli je zmáèknutá 3)
    ldi    R16, 2        // zapiš do R16, že byla stisknuta 2
    rjmp     STISK        // pokraèuj na STISK

// Stisknutí klávesy 3
// Výstupy máme nastavené od KL1, pouze testujeme vstup
KL3:
    sbic    PIND, 4        // pokud je na tøetím sloupci (3 6 9 #) nula, pøeskoè následující instrukci
    rjmp    KL4        // pokraèuj na KL4 (testuj jestli je zmácknutá 4)
    ldi     R16, 3        // zapiš 3 do R16
    rjmp    STISK        // pokraèuj na STISK
   
// Stisknutí klávesy 4
KL4:
    sbi        PORTB, 7    // log. jednièka na prvním øádku
    cbi        PORTB, 6    // log. nula na druhém øádku (4 5 6 B)
    sbi     PORTB, 5    // log. jednièka na tøetím a ètvrtém øádku
    sbi     PORTB, 4

    sbic    PIND, 2        // jestli je na prvním sloupci (1 4 7 *) nula
    rjmp    KL5
    ldi    R16, 4        // zapiš 4 do R16
    rjmp    STISK

// Stisknutí klávesy 5
KL5:
    sbic     PIND, 3        // jestli je na druhém sloupci (2 5 8 0) nula
    rjmp    KL6
    ldi     R16, 5        // zapiš 5 do R16
    rjmp    STISK

// Stisknutí klávesy 6
KL6:
    sbic     PIND, 4        // jestli je na tøetím sloupci (3 6 9 #) nula
    rjmp    KL7
    ldi     R16, 6        // zapiš 6 do R16
    rjmp     STISK

// Stisknutí klávesy 7
KL7:
    sbi     PORTB, 7    // log. jednièka na prvním, druhém a ètvrtém rádku
    sbi    PORTB, 6
    cbi    PORTB, 5    // log. nula na tøetím øádku (7 8 9 C)
    sbi    PORTB, 4

    sbic    PIND, 2        // jestli je na prvním sloupci (1 4 7 *) nula
    rjmp    KL8
    ldi    R16, 7        // zapiš 7 do R16
    rjmp    STISK

// Stisknutí klávesy 8
KL8:
    sbic    PIND, 3        // jestli je na druhém sloupci (2 5 8 0) nula
    rjmp     KL9
    ldi    R16, 8        // zapiš 8 do R16
    rjmp    STISK

// Stisknutí klávesy 9
KL9:
    sbic     PIND, 4        // jestli je na tøetím sloupci (3 6 9 #) nula
    rjmp    STISK
    ldi    R16, 9        // zapiš 9 do R16

// část STISK, která vynuluje výstupy
STISK:
    cbi PORTB, 7    // log. nula na všech øádcích
    cbi    PORTB, 6
    cbi    PORTB, 5
    cbi    PORTB, 4
    ret



COLOR2:
    SBI PORTB, 0
    CBI PORTB, 1
    RET
 

1.domaci ukol

.NOLIST	
	.INCLUDE "m16def.inc"	
	.LIST	
	.CSEG	                ;kódový segment
	RJMP RESET           	
	.ORG $000C	
	RJMP palubka         	;vektor $000C
		
reset:	ldi r16,low(ramend)	;nastav zasobnik
    	out spl,r16	          
    	ldi r16,high(ramend)
    	out sph,r16
    ;nastavení portd
   
	ldi r16,0b00110001      ;pull-up na pinu 0,4,5
    out portd,r16
	ldi r16,0b00110000      ;PORTD.5(0C1A),portd.4(0C1B),portd.0(dveře)
	out ddrd,r16

	                	
	;čítač/časovač 1
	LDI r16,$10         	;povol přerušení OCIE1A
	OUT TIMSK,r16       	;při přetečení č/č 1

	ldi r16,0b00001100      ;řídící registr B
	out tccr1b,r16          ;8bitový, předdělička 256 
	SEI                     ;povol přerušení
	ldi r16,0b00000001      ;řídící registr A č/č 1
	out tccr1a,r16

	;adc převodník
	ldi r16,0b00100000;zarovnání do leva v adch
	out admux,r16
	ldi r16,0b00000000;volný běh
	out sfior,r16
   
smycka:

    sbic pind,0 ;dveře otevřené 
    rjmp konec

    ldi r18,12  ;vyloučení zákmitu dveřního spínače cca 150ms
	rcall cekej
	ldi r17,0b00110001 ;zapni pwm
	out tccr1a,r17
    ldi r17,0xff
    out ocr1bl,r17     ;rozsvícení stropu pwm B
smycka3:	
    sbis pind,0
	rjmp smycka3

    ldi r18,200 ;cekej 5s
    rcall cekej
	ldi r18,200
    rcall cekej 
    ldi r17,0xff
cekej2:

    out ocr1bl,r17                    
    ldi r18,4           ;stmívání 2s
    rcall cekej    
    subi r17,5
    	
    brsh cekej2         ;cekej 2s, větší nebo shoda
    ldi r17,0b00000001
	out tccr1a,r17      ;vypni pwm B
	   
konec:
             
rjmp smycka

    ;čekací smyčka
cekej:    
	ldi r19,0
	ldi r20,0
cekej1:
    dec r20
    brne cekej1
    dec r19
    brne cekej1
    dec r18
    brne cekej1
	ret

    ;obsluha přetečení č/č 1	
palubka:
    ldi r16,0b11100011 ;zapnutí a start adc převodu
                       ;hodinový kmitočet 2 MHz,autospouštění
	out adcsra,r16
    in r16,adch        ;načtení změřené hodnoty z adc

	cpi r16,1          ;nastavení minimální hodnoty
	brsh zapni
	in r21,tccr1a      ;vypni pwm A
	andi r21,0b00111111
	ori r21,0b00000000
	out tccr1a,r21
	rjmp konec1
zapni: 
     in r21,tccr1a
	 andi r21,0b00111111
     ori r21,0b11000000
     out tccr1a,r21
     out ocr1al,r16 ;vložení do porovnávacího registru č/č 1;
konec1:
     RETI	;konec obsluhy
 
Osobní nástroje