Forum: Mikrocontroller und Digitale Elektronik interrupt uart


von ralph (Gast)


Lesenswert?

hi!

habe ein problem mit dem interrupt.
bei mir soll er bei einer änderung an dem uart eingangspins des atmega
8 eine inerrupt rutine durchlaufen.
welchen inerrupt nimmt man denn dazu????

irgendwie geht das bei mir nämlich nicht. habe den
12 0x00B USART, RX USART-Empfang abgeschlossen
genommen. aber damit funzt es irgendwie nicht.

bei einem reset macht er das was er soll aber dann nicht mehr!!!

kann mir da bitte einer helfen?

von crazy horse (Gast)


Lesenswert?

kann man nehmen, allerdings musst du in der Rx-ISR vor reti das
UDR-Register lesen, damit das entsprechende flag zurückgesetzt wird.
Sonst wird direkt ein neuer int ausgelöst, obwohl nichts passiert ist.
Aber, wie immer, ein paar Zelen Code sagen mehr als eine umständliche,
unvollständige Beschreibung.

von ralph (Gast)


Lesenswert?

na gut, wenn du meinst! werd ich den code mal posten. aber der ist etwas
wirr. da ich nun mal ein anfänger bin.

.include "m8def.inc"

.def temp = r16
.equ CLOCK = 4000000
.equ BAUD = 37000
.equ UBRRVAL = CLOCK/(BAUD*16)-1

.org 0x000
    rjmp main0
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    rjmp int_rxc
    reti
    reti
    reti
    reti
    reti
    reti
    reti



main0:
      ; Stackpointer initialisieren
        ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

        ; Baudrate einstellen
        ldi temp, LOW(UBRRVAL)
        out UBRRL, temp
        ldi temp, HIGH(UBRRVAL)
        out UBRRH, temp

        ; Frame-Format: 8 Bit
        ldi temp, (1<<URSEL)|(3<<UCSZ0)
        out UCSRC, temp
weiter:
  sbi UCSRB,TXEN                    ; TX aktivieren

        sbi UCSRB, RXCIE
  sbi UCSRB, RXEN

  sei

loop:   rjmp weiter

main1:  rcall zeit
        rcall zeit
  rcall zeit
  rcall zeit
  rcall zeit
  rcall zeit
        ldi temp, 8
        rcall serout                      ; Unterprogramm aufrufen
  rcall zeit
  ldi temp, 0
        rcall serout
  rcall zeit                        ; Unterprogramm aufrufen
  .
  .
        .
        .
        rjmp loop

serout:
        sbis UCSRA,UDRE                   ; Warten bis UDR für das
        rjmp serout
        out UDR, temp
  ret                               ; zurück zum Hauptprogramm

; =============================
;   Warteschleifen-Generator
;     800 Zyklen:
; -----------------------------
; warte 798 Zyklen:
zeit:
    ldi  R17, $03
WGLOOP0:  ldi  R18, $84
WGLOOP1:  dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP0
          ret

int_rxc:
    push temp
    rjmp main1
    in temp, UDR
    pop temp
    reti

von ralph (Gast)


Lesenswert?

jetzt habe ich das programm gepostet aber keiner schreibt meht etwas.

ist es denn so schlecht???

von crazy horse (Gast)


Lesenswert?

au weia!
loop: rjmp weiter //Schwachsinn, aber nicht tragisch

der Hund lauert hier:
int_rxc:
    push temp
    rjmp main1     // ganz schlecht, eine ISR mit jmp verlassen
                   // da dadurch reti nicht erreicht wird
                   // und damit die ints nicht wieder freigegeben
werden
//nebenbei bekonmmst du damit ein stackproblem
    in temp, UDR
    pop temp
    reti

von ralph (Gast)


Lesenswert?

das verstehe ich nicht ganz!

der Hund lauert hier:
int_rxc:
    push temp
    rjmp main1     // ganz schlecht, eine ISR mit jmp verlassen
                   // da dadurch reti nicht erreicht wird
                   // und damit die ints nicht wieder freigegeben
werden

komme doch nach dem jump befehl wieder zurück in die interruptroutine
und dann kommt der reti.... oder ist das nicht so?

was meinst du mit stackproblem???

//nebenbei bekonmmst du damit ein stackproblem
    in temp, UDR
    pop temp
    reti

von crazy horse (Gast)


Lesenswert?

wo steht, dass du zurückkommst?
Zurück kämst du, wenn du irgendwas anderes mit call aufrufst, und dort
dann irgendwann ein return steht, bei jmp ist die Rückkehradresse
futsch.
Machs doch nicht komplizierter, als es ist. Setz dir in der ISR ein
flag, welches anzeigt, dass ein Zeichen empfangen wurde, kann ein
einzelnes Bit sein oder du benutzt ein komplettes Register. Hier mal
ein Beispiel mit Register, hat einen kleinen Schönheitsfehler, dass es
auf empfangenes Zeichen 0 nicht reagiert, aber das Prinzip wird klar

clr  rec_byte

main_loop: tst rec_byte
           breq main_loop   //warte bis rec_byte >0
           dein_kram
           rjmp main_loop

int_rxc: push r2
         in r2, sreg     //sollte man (fast) immer sichern
         in rec_byte, UDR
         out sreg, r2
         pop r2
         reti

von ralph (Gast)


Lesenswert?

also das was du da geschrieben hast habe ich noch nicht ganz verstanden.
weis noch icht ganz was das macht.

habe jetzt mein programm so geändert:

.include "m8def.inc"

.def temp = r16
.equ CLOCK = 4000000
.equ BAUD = 37000
.equ UBRRVAL = CLOCK/(BAUD*16)-1

.org 0x000
    rjmp main0
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    reti
    rjmp int_rxc
    reti
    reti
    reti
    reti
    reti
    reti
    reti



main0:
  ; Stackpointer initialisieren
        ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

        ; Baudrate einstellen
        ldi temp, LOW(UBRRVAL)
        out UBRRL, temp
        ldi temp, HIGH(UBRRVAL)
        out UBRRH, temp

        ; Frame-Format: 8 Bit
        ldi temp, (1<<URSEL)|(3<<UCSZ0)
        out UCSRC, temp
weiter:
  sbi UCSRB,TXEN                    ; TX aktivieren

        sbi UCSRB, RXCIE
  sbi UCSRB, RXEN

  sei

loop:   rjmp loop



serout:
        sbis UCSRA,UDRE                   ; Warten bis UDR für das
nächste
        rjmp serout
        out UDR, temp
  ret                               ; zurück zum Hauptprogramm

; =============================
;   Warteschleifen-Generator
;     800 Zyklen:
; -----------------------------
; warte 798 Zyklen:
zeit:
    ldi  R17, $03
WGLOOP0:  ldi  R18, $84
WGLOOP1:  dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP0
          ret


int_rxc:
  push temp
        rcall zeit
        rcall zeit
  rcall zeit
  rcall zeit
  rcall zeit
  rcall zeit
        ldi temp, 8
        rcall serout                      ; Unterprogramm aufrufen
  rcall zeit
  ldi temp, 0
        rcall serout
  rcall zeit                        ; Unterprogramm aufrufen
  ldi temp, 0
        rcall serout
  rcall zeit                    ; ...
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 17
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 40
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 70
        rcall serout
  rcall zeit
        ldi temp, 118
        rcall serout
  rcall zeit
        ldi temp, 60
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 25
        rcall serout
  rcall zeit
        ldi temp, 1
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
        ldi temp, 0
        rcall serout
  rcall zeit
  in temp, UDR
  out portd, temp
  pop temp
  reti

irgedwie funktioniert das auch, nur schickt er mir die ausgabe die ich
mache zweimal. der läuft die interruptrotine zweimal durch. aber
wieso????
ich versteh das irgendwie nicht???
hast du dazu eine idee?

von Michael (Gast)


Lesenswert?

Ein bißchen viel Code - aber wo wird eigentlich das Statusregister in
der INT-Routine gerettet ?

von ralph (Gast)


Lesenswert?

jetzt raff ich gar nichts mehr mit den doofen interrupts....

wie ist das jetzt?

mit sei aktiviere ich alle
mit cli kann ich sie deaktivieren.

wenn ich einen interrupt hatte, muss ich aber kein flag zurücksetzen
oder? macht er automatisch!?

was ist wenn ich noch einen interrupt bekomme wenn gerade einer
ausgeführt wird? merkt er sich den und macht es dann später?

habe versucht mit cli die interrupts dann während des ausführen eine
interrupts zu unterdrücken. bewirkt aber nichts...

schrott... bei mir führt er die interruptroutine so wie es aussieht
immer zweimal hintereinander aus. ich raffs nich mehr...*flenn*

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.