UART s přerušením atmega8

Diskuze a poradna o programátorech a programování různých obvodů

Moderátor: Moderátoři

Odpovědět
Zpráva
Autor
Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

UART s přerušením atmega8

#1 Příspěvek od DavidChlup »

Ahoj,

už nevím kudy kam, mám tu úplně triviální program pro příjem po UARTu a někde mám něco blbě.

Když mám verzi bez přerušení a volání rutiny pro výpis z UDR do registru provozuji v hlavní smyčce, vše funguje. Vlastně to čte UDR pořád za běhu programu hlavní smyčky.

ALE jak to udělám systémem přerušení, tj že při příjmu Rx vyvolám přerušení, které mě odkáže na výčet UDR do registru a zpět do hlavní smyčky, tak mi to přečte data jen jednou a při dalším příjmu dat to absolutně nic nedělá. Jako by se mi UDR nevyprázdnilo a tak nepřijme další hodnoty.

Už nevím co a jak, tak prosím o radu. Ti, co mne chtějí odkázat na datasheet, tak z toho jsem to prostě nepochopil, nejsem znalec AJ a google překladač to jako vždy kazí.

Kód: Vybrat vše

.NOLIST
.INCLUDE "m8def.inc"
.LIST




.def	reg=R16
.def	reg2=r17

.EQU DATAIND=DDRD
.EQU LEDD=DDRC

.EQU DATAIN=PORTD	;RX DATA
.EQU LED=PORTC		;PC0-PC4 LED


.cseg 
.org $0		  		

		rjmp ini
.org $00b
		rjmp USART_Receive


Ini:	ldi reg, 0b00000000
		out DATAIND, REG

		ldi reg, 0b11111111
		out LEDD, reg
		out LED, reg

		ldi reg, 0b00000000
		out DATAIN, REG

	 	ldi reg,LOW(RAMEND)
		out SPL,reg 
		ldi reg,HIGH(RAMEND) 
		out SPH,reg 


; Set baud rate
		ldi reg, 51
		ldi reg2, 0
		out UBRRH, reg2
		out UBRRL, reg

; Enable receiver and transmitter
		ldi reg, (1<<RXEN)|(1<<RXCIE)
		out UCSRB, reg

; Set frame format: 8data, 1stop bit
		ldi reg, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
		out UCSRC, reg

		ldi reg, 0b00000000
		out led, reg
		rcall time2s
		ldi reg, 0b11111111
		out led, reg
		sei

;----------------- Vektory přerušení ----------------------





START:

		out led, reg

		rjmp start 


USART_Receive:
		
					
		sbis UCSRA, RXC
		rjmp USART_Receive
						
		in reg, UDR
		rjmp start





time2s:
; ============================= 
;    delay loop generator 
;     16000000 cycles:
; ----------------------------- 
; delaying 15999993 cycles:
          ldi  R20, $53
WGLOOP0:  ldi  R21, $FB
WGLOOP1:  ldi  R22, $FF
WGLOOP2:  dec  R22
          brne WGLOOP2
          dec  R21
          brne WGLOOP1
          dec  R20
          brne WGLOOP0
; ----------------------------- 
; delaying 6 cycles:
          ldi  R20, $02
WGLOOP3:  dec  R20
          brne WGLOOP3
; ----------------------------- 
; delaying 1 cycle:
          nop
; ============================= 
ret

Uživatelský avatar
Zmije
Příspěvky: 1513
Registrován: 30 čer 2005, 02:00
Bydliště: Pardubický kraj

#2 Příspěvek od Zmije »

Jak tak na to koukám, zatím si nepochopil princip přerušení. Na tvém místě bych si dopřát trošek luxusu, který nabízí jazyk C. Amega je na to uzpůsobená, najdeš na to více tutoriálů, zdarma kvalitní překladač atd...

Obsluha přerušení se nikdy neukončuje rjmp ale příkazem reti.

viz. https://www.avrfreaks.net/forum/externa ... g-assembly

Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

#3 Příspěvek od DavidChlup »

Dobrý postřeh, to jsem přehlídl. Přerušení jsem nepoužíval dost dlouho, resp jsem dlouho nic nepsal :D nicméně to problém nevyřešilo.

Uživatelský avatar
Zmije
Příspěvky: 1513
Registrován: 30 čer 2005, 02:00
Bydliště: Pardubický kraj

#4 Příspěvek od Zmije »

pokud to máš upravené na

Kód: Vybrat vše

USART_Receive:
      
               
      sbis UCSRA, RXC
      rjmp USART_Receive
                  
      in reg, UDR
      reti
Tak je tam nekonečná smyčka.

edit:
zjistil jsem, že instrukce sbis je podmínková. Nekonečnou smyčku beru zpět.
http://www.avrbeginners.net/architectur ... instr.html
sbic/sbis (skip if bit in I/O register is cleared/set) skips the next instruction depending on the I/O bit's state. In the example above I added a relative jump (rjmp) to show you how you could use this instruction. In this case, the mcu will jump to bit_is_set if bit 7 of PortD is not cleared (->set) and proceed with the instruction following the relative jump if that bit is cleared.
Naposledy upravil(a) Zmije dne 03 kvě 2020, 13:55, celkem upraveno 1 x.

Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

#5 Příspěvek od DavidChlup »

Nahoře na adrese už mám:

Kód: Vybrat vše

.org $00b
		rcall USART_Receive
		rjmp start
dole pak to, co píšeš, jen podle datasheetu s instrukcí RET:

Kód: Vybrat vše

USART_Receive:
		
					
		sbis UCSRA, RXC
		rjmp USART_Receive
						
		in reg, UDR
		ret
Naposledy upravil(a) DavidChlup dne 03 kvě 2020, 13:15, celkem upraveno 1 x.

Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

#6 Příspěvek od DavidChlup »

AHA, tak datasheet píše "ret" a to nejde, ale s instrukcí "reti" to funguje...

Kód: Vybrat vše

.NOLIST
.INCLUDE "m8def.inc"
.LIST




.def	reg=R16
.def	reg2=r17

.EQU DATAIND=DDRD
.EQU LEDD=DDRC

.EQU DATAIN=PORTD	;RX DATA
.EQU LED=PORTC		;PC0-PC4 LED


.cseg 
.org $0	
	  		
;----------------- Vektory přerušení ----------------------

		rjmp ini
.org $00b
		rcall USART_Receive
		rjmp start

;------------------- Inicializace -------------------------


Ini:	ldi reg, 0b00000000
		out DATAIND, REG

		ldi reg, 0b11111111
		out LEDD, reg
		out LED, reg

		ldi reg, 0b00000000
		out DATAIN, REG

	 	ldi reg,LOW(RAMEND)
		out SPL,reg 
		ldi reg,HIGH(RAMEND) 
		out SPH,reg 


; Set baud rate
		ldi reg, 51
		ldi reg2, 0
		out UBRRH, reg2
		out UBRRL, reg
; Enable receiver and transmitter
		ldi reg, (1<<RXEN)|(1<<RXCIE)
		out UCSRB, reg
; Set frame format: 8data, 1stop bit
		ldi reg, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
		out UCSRC, reg

		ldi reg, 0b00000000
		out led, reg
		rcall time2s
		ldi reg, 0b11111111
		out led, reg

		sei

;------------------- Hlavní smyčka ------------------------


START:

		out led, reg

		rjmp start 
;---------------- Podprogram přerušení --------------------


USART_Receive:
		
					
		sbis UCSRA, RXC
		rjmp USART_Receive
						
		in reg, UDR
		reti


;----------------- Podprogram časování --------------------


time2s:
; ============================= 
;    delay loop generator 
;     16000000 cycles:
; ----------------------------- 
; delaying 15999993 cycles:
          ldi  R20, $53
WGLOOP0:  ldi  R21, $FB
WGLOOP1:  ldi  R22, $FF
WGLOOP2:  dec  R22
          brne WGLOOP2
          dec  R21
          brne WGLOOP1
          dec  R20
          brne WGLOOP0
; ----------------------------- 
; delaying 6 cycles:
          ldi  R20, $02
WGLOOP3:  dec  R20
          brne WGLOOP3
; ----------------------------- 
; delaying 1 cycle:
          nop
; ============================= 

reti

Uživatelský avatar
lesana87
Příspěvky: 3296
Registrován: 20 zář 2014, 02:00

#7 Příspěvek od lesana87 »

To

Kód: Vybrat vše

sbis UCSRA, RXC 
rjmp USART_Receive
je tam samozřejmě nesmyslné. V přerušení se žádné čekací cykly zásadně nedělají, princip přerušení je, že se automaticky vyvolá v okamžiku, kdy událost nastala, tak nemá smysl na ní čekat.
Stejně tak

Kód: Vybrat vše

.org $00b 
      rcall USART_Receive 
      rjmp start
je nesmysl, má tam být jen

Kód: Vybrat vše

.org $00b 
      rjmp USART_Receive
Procesor se instrukcí reti automaticky vrací na místo, kde k přerušení došlo, s tím rcall se pokaždé vrací na start, což je blbost. Že to teď jako fuguje, je jen proto, že to nic jiného než skákání na start stejně nedělá a že přetéká zásobník se asi taky nepozná.

Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

#8 Příspěvek od DavidChlup »

Takže to má být takhle?

Kód: Vybrat vše

.NOLIST
.INCLUDE "m8def.inc"
.LIST




.def	reg=R16
.def	reg2=r17

.EQU DATAIND=DDRD
.EQU LEDD=DDRC

.EQU DATAIN=PORTD	;RX DATA
.EQU LED=PORTC		;PC0-PC4 LED


.cseg 
.org $0	
		rjmp ini
	  		
;----------------- Vektory přerušení ----------------------

.org $00b
		rjmp USART_Receive

;------------------- Inicializace -------------------------


Ini:	ldi reg, 0b00000000
		out DATAIND, REG

		ldi reg, 0b11111111
		out LEDD, reg
		out LED, reg

		ldi reg, 0b00000000
		out DATAIN, REG

	 	ldi reg,LOW(RAMEND)
		out SPL,reg 
		ldi reg,HIGH(RAMEND) 
		out SPH,reg 


; Set baud rate
		ldi reg, 51
		ldi reg2, 0
		out UBRRH, reg2
		out UBRRL, reg
; Enable receiver and transmitter
		ldi reg, (1<<RXEN)|(1<<RXCIE)
		out UCSRB, reg
; Set frame format: 8data, 1stop bit
		ldi reg, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
		out UCSRC, reg

		ldi reg, 0b00000000
		out led, reg
		rcall time2s
		ldi reg, 0b11111111
		out led, reg

		sei

;------------------- Hlavní smyčka ------------------------


START:

		out led, reg
		rjmp start 

;---------------- Podprogram přerušení --------------------


USART_Receive:
						
		in reg, UDR
		reti


;----------------- Podprogram časování --------------------


time2s:
; ============================= 
;    delay loop generator 
;     16000000 cycles:
; ----------------------------- 
; delaying 15999993 cycles:
          ldi  R20, $53
WGLOOP0:  ldi  R21, $FB
WGLOOP1:  ldi  R22, $FF
WGLOOP2:  dec  R22
          brne WGLOOP2
          dec  R21
          brne WGLOOP1
          dec  R20
          brne WGLOOP0
; ----------------------------- 
; delaying 6 cycles:
          ldi  R20, $02
WGLOOP3:  dec  R20
          brne WGLOOP3
; ----------------------------- 
; delaying 1 cycle:
          nop
; ============================= 

reti

Uživatelský avatar
lesana87
Příspěvky: 3296
Registrován: 20 zář 2014, 02:00

#9 Příspěvek od lesana87 »

Až na to reti úplně na konci :D to jako demonstrace, že funguje přerušení, může posloužit. Ale do reálného použití to má ještě daleko. :)

Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

#10 Příspěvek od DavidChlup »

Takhle to generuje delay loop generátor i s tím reti na konci. Co by se tedy mělo zlepšit? Stačí jen bodovitě vyjmenovat, nějak to snad dohledám. Tohle bylo jen pro pochopení uartu, takže nečekám, že to bude hned použitelné 😁

Uživatelský avatar
lesana87
Příspěvky: 3296
Registrován: 20 zář 2014, 02:00

#11 Příspěvek od lesana87 »

RETI patří na konec obsluhy přerušení. Na konec podprogramu patří RET.

Uživatelský avatar
DavidChlup
Příspěvky: 69
Registrován: 03 zář 2019, 02:00
Bydliště: Karlovy Vary

#12 Příspěvek od DavidChlup »

Výborně, děkuji :)

Odpovědět

Zpět na „Programování PIC, ATMEL, EEPROM a dalších obvodů“