mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik µC führt Reset bei UART Aktivität aus


Autor: Pascal Christian (passi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

mein Programm sendet bei einem Reset Daten aus 6 Registern an den PC. 
Beim Empfang von Daten vom PC werden diese Register entsprechend der 
empfangenen Werte geändert, oder aber die aktuellen Werte wieder an den 
Rechner zurückgesendet wenn der Rechner diese durch Senden von 255 
anfordert.

Nun zum Problem: Der µC führt anscheinend bei jeder UART Aktivität einen 
Reset aus. Jedenfalls bekomme ich immer, wenn ich Daten an den µC sende, 
die aktuellen Daten zurück. Egal was ich sende. Der Inahlt der 
LED-Register lässt sich auch nicht ändern, was wohl daran liegt, dass 
sie im Reset Handler initialisiert werden und mit Werten vorgeladen 
werden.

Hier der Code:
.include "m8def.inc"
.device Atmega8
 
.def temp = r16
.def LED1 = r17
.def LED2 = r18
.def LED3 = r19
.def LED4 = r20
.def LED5 = r21
.def LED6 = r22
.def LEDAdd = r23
.def RSinCount = r24

.equ CLOCK = 8000000
.equ BAUD = 38400
.equ UBRRVAL = CLOCK/(BAUD*16)-1

.org 0x00
        rjmp main

.org URXCaddr                             ; Interruptvektor für UART-Empfang
        rjmp int_rxc


main:
 
        ; 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
 
        sbi UCSRB,TXEN                    ; TX aktivieren

        sbi UCSRB, RXCIE                  ; Interrupt bei Empfang
        sbi UCSRB, RXEN                   ; RX (Empfang) aktivieren
        
        sei                               ; Interrupts global aktivieren

    ldi LED1, 20            ; Werte initialisieren
    ldi LED2, 40
    ldi LED3, 60
    ldi LED4, 80
    ldi LED5, 100
    ldi LED6, 120
    ldi RSinCount, 0
    rcall senddata            ; Bei Reset: Daten senden
 
loop:                     ; Endlosschleife

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


SendData:
    push temp

    mov temp, LED1
        rcall serout                      ; Daten senden
        mov temp, LED2
        rcall serout                      
        mov temp, LED3
        rcall serout                      
        mov temp, LED4
        rcall serout
        mov temp, LED5
        rcall serout
        mov temp, LED6
        rcall serout
        ldi temp, 254
        rcall serout
        ldi temp, 255
        rcall serout

    pop temp
    ret


; Interruptroutine: wird ausgeführt sobald ein Byte über das UART empfangen wurde
int_rxc:
        push temp                         ; temp auf dem Stack sichern

     sbis USR,RXC    ;exit if no new word is received
    rjmp extrsin

        in temp, UDR

        sbic USR, FE    ; exit if no stop bit in word
        rjmp extrsin 

    cpi temp, 255    ; Empfang=255? Dann Daten senden
    breq SendData

    cpi RSinCount, 1  ; 2. RS232 Input? Dann Wert setzen
    breq setLED

    cpi RSinCount, 0  ; 1. RS232 Input? Dann Adresse speichern, für die Wert gesetzt werden soll
    breq storeLEDAdd 

        pop temp                          ; temp wiederherstellen
        reti                              ; Interrupt beenden 

extrsin:
        pop temp                          ; temp wiederherstellen
        reti                              ; Interrupt beenden 

storeLEDAdd:

    mov LEDAdd, temp  ; Adresse speichern
    inc RSinCount    ; RS232 Input Zähler erhöhen
    ret

setLED:
    
    cpi LEDadd, 1    ; Je nach Adresse Werte für LED Register setzen
    breq setLED1
    cpi LEDadd, 2
    breq setLED2
    ret

setLED1:
    mov LED1, temp    ; Unterprogramme zum Setzen der LED Werte
    ret

setLED2:
    mov LED2, temp
    ret



Ich hab den Code nun schon ein paar mal umstrukturiert und sogar alles 
neu geschrieben - aber ich finde den Fehler einfach nicht :(

Ich höffe, ihr könnt mir helfen.

Danke + Grüße
Passi

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte es sein, daß das ein Hardwareproblem ist? daß der Resetpin in der 
Luft hängt, oder von irgendwelchen Störsignalen umgeschaltet wird?

Autor: Pascal Christian (passi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also der Resetpin ist mit nem Taster verbunden, da hängt nichts in der 
Luft.. Störsignale sollte es auch nicht geben, die Platine ist quasi 
komplett leer, mal vom Atmega8 und dem Max232 mit serieller 
Schnittstelle und ein paar LEDs abgesehen..

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo hängt denn der Reset elektrisch, wenn der Taster offen ist?

Kannst Du die LED aus dem Hauptprogramm blinken lassen, wenn der UART 
nicht läuft?

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und der Taster geht an Masse?

Muss man das SREG im Interrupt sichern?

sonst kann ich auch erstmal nichts verdächtiges finden.

Viel Erfolg

AxelR.

Autor: Pascal Christian (passi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Danke für Eure Antworten.

Also, ich gehe davon aus das der Reset Taster richtig verlötet ist, ist 
ein fertig gekauftes Entwicklerboard..

Eine LED im Hauptprogramm blinken lassen funktioniert ohne Probleme.. er 
wird also tatsächlich nur resettet, wenn der UART aktiv ist..

Edit:
Die LED bleibt einfach aus, wenn ich dann noch UART aktiviere und was 
senden lasse. D.h. er wird tatsächlich resettet (da ich mein 
Warte-Zähl-Register im Reset Handler auf Null setze)

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist ein Programmfehler:

    breq SendData

Das heißt doch wohl 'branch on equal'.

Das heißt, Du springst aus der ISR in SendData und die terminiert mit 
einem einfachen ret.

Da sie nicht per call aufgerufen wurde, popt ret den Wert von temp - das 
wurde am Eingang der ISR gepusht - vom Stack und interpretiert es als 
Rückkehradresse. D.h., der µC springt in die Wüste und setzt sich 
womöglich selbst zurück.

Interrupts mußt Du immer mit reti abschließen.

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hätt' ich auch sehen müssen gräm (na iss ja schon spät) ;-)))

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Kein Wunder. Du springst z.B. aus der IR-Routine nach setLed. Am Ende 
ist weder ein 'pop temp' noch ein 'reti'. Der Stackpointer lässt sich 
nicht
verarsch...!
Abgesehen davon: Woher kommt eigentlich diese komische Manie, irgend-
welche allgemeingültigen Register mit 'tmp/temp/tempxx' zu bezeichnen?
Für z.B. 'r16' brauche ich nur 3 Zeichen einzutippen und jeder(selbst 
ich in 10 Jahren) weiß was gemeint ist. Ich tippe auf C-Programmierer.

MfG Spess

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na dann hab' ich ja als Nichtkenner des Atmega8-ASM richtig geraten ;-)

Autor: Stefan Wimmer (wswbln)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...habe ich das richtig in Erinnerung, dass man sich ausserdem in ASM in 
Interruptroutinen beim AVR selber noch um das Statusregister kümmern 
muss (mach' wohl schon zu lange nur noch C)?

Autor: Pascal Christian (passi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

naja eigentlich bin ich ein Delphi Programmierer xD.. Keine Ahnung wieso 
ich das Temp nenne ^^..

Aber auch egal.
Ich versteh das nicht so recht. Bedeutet das, dass ich in einem 
Interrupt Handler kein Unterprogramm aufrufen kann? Also ich hab in der 
Schule gelernt, dass der ret Befehl aus Unterprogrammen dafür sorgt, 
dass im Programmcode wieder hinter dem rcall Befehl weitergemacht wird.

Das bedeutet für mich, dass wenn ich im Interrupt Handler per rcall 
SetLED das UP aufrufe, und dieses dann mit ret beende, dass der µC dann 
wieder in den Interrupt Handler springt und mit dem dortigen Code weiter 
macht und somit auch popt und den Interrupt mit reti abschließt.. ist 
das ein Denkfehler? ^^

Ich kann mir grad auch nicht vorstellen, wie das richtig gehen soll. 
Kann mir jemand ein Beispiel geben wie ich ein Unterprogramm korrekt 
innerhalb einer Interrupt Service Routine aufrufe?

Danke + Grüße
Passi

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich versteh das nicht so recht. Bedeutet das, dass ich in einem
> Interrupt Handler kein Unterprogramm aufrufen kann?

Doch, das kannst Du - aber nur mit rcall, nicht mit einem branch.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Nachtvogel

Gewusst oder geraten?

MfG Spess

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Na ja, hab schon ein paar Flugstunden in ASM auf dem Buckel...

Autor: Pascal Christian (passi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aahh jetzt hat's Klick gemacht. Dann muss ich das mit CPSE und einem 
dahinterfolgenden rcall machen.. denk ich mal ^^.

Also vielen Dank, werds morgen ausprobieren und dann berichten!

Grüße
Passi

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Mit Br../jmp... rufst du kei Unterprogramm auf, sondern du verzweigst
dorthin,d.h. es erfolgt kein Rücksprung.
Wenn du das willst, musst du Call/Rcall benutzen.
Bin übrigens Delphiprogrammierer(für PC).

MfG Spess

Autor: Alexander Heckmayr (c_type)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und noch was,

wie Stefan weite oben bereits angemerkt hat:

Im Interrupt zuerst Statusregister sichern !!

Gruß
Alexander

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Biete etwas mehr als 20 Flugjahre dagegen. (Ist meine letzte Aussage zu
diesem Thema).

MfG Spess

Autor: Kai Scheddin (zeusosc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
öhmmmm, ich hätts so gemacht....
SendData:
    push temp
.
.
.
    andi r25,0b11111110    
    pop temp
    ret

loop:                     ; Endlosschleife
        sbrc r25,0
        rcall SendData
        sbrc r25,1
        rcall setLED
        sbrc r25,2
        rcall storeLEDAdd
        rjmp loop
.
.
.
int_rxc:
        in r26,SREG
        push r26
        push temp                         ; temp auf dem Stack sichern

     sbis USR,RXC    ;exit if no new word is received
    rjmp extrsin

        in temp, UDR

        sbic USR, FE    ; exit if no stop bit in word
        rjmp extrsin 

    cpi temp, 255    ; Empfang=255? Dann Daten senden
    brne d1
    ori r25,0b00000001    
    rjmp extrsin

d1: cpi RSinCount, 1  ; 2. RS232 Input? Dann Wert setzen
    brne d2
    ori r25,0b00000010
    rjmp extrsin

d2: cpi RSinCount, 0  ;.... 
    brne extrsin
    ori r25,0b00000100

extrsin:
        pop temp                          ; temp wiederherstellen
        pop r26
        out SREG,r26
        reti                              ; Interrupt beenden 

storeLEDAdd:

    mov LEDAdd, temp  ; Adresse speichern
    inc RSinCount    ; RS232 Input Zähler erhöhen
    andi r25,0b11111011
    ret

setLED:
    andi r25,0b11111101
    cpi LEDadd, 1    ; Je nach Adresse Werte für LED Register setzen
    .
    .
    ret

grüüüße da Kai
______________________________
>Das ist kein sinnfreier Beitrag

Autor: Pascal Christian (passi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

vielen Dank für Eure Hilfe. Es funktioniert jetzt wunderbar mit rcall 
und Statusregister sichern :)

Kai, Deinen Code schau ich mir auch mal an. Sieht etwas eleganter aus 
^^..

Also Danke nochmal!

Grüße
Passi

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.