µC führt Reset bei UART Aktivität aus

OP #557877
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:
1
.include "m8def.inc"
2
.device Atmega8
3
 
4
.def temp = r16
5
.def LED1 = r17
6
.def LED2 = r18
7
.def LED3 = r19
8
.def LED4 = r20
9
.def LED5 = r21
10
.def LED6 = r22
11
.def LEDAdd = r23
12
.def RSinCount = r24
13

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

18
.org 0x00
19
        rjmp main
20

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

24

25
main:
26
 
27
        ; Stackpointer initialisieren
28
        ldi temp, LOW(RAMEND)
29
        out SPL, temp
30
        ldi temp, HIGH(RAMEND)
31
        out SPH, temp
32
 
33
        ; Baudrate einstellen
34
        ldi temp, LOW(UBRRVAL)
35
        out UBRRL, temp
36
        ldi temp, HIGH(UBRRVAL)
37
        out UBRRH, temp
38
 
39
        ; Frame-Format: 8 Bit
40
        ldi temp, (1<<URSEL)|(3<<UCSZ0)
41
        out UCSRC, temp
42
 
43
        sbi UCSRB,TXEN                    ; TX aktivieren
44

45
        sbi UCSRB, RXCIE                  ; Interrupt bei Empfang
46
        sbi UCSRB, RXEN                   ; RX (Empfang) aktivieren
47
        
48
        sei                               ; Interrupts global aktivieren
49

50
    ldi LED1, 20            ; Werte initialisieren
51
    ldi LED2, 40
52
    ldi LED3, 60
53
    ldi LED4, 80
54
    ldi LED5, 100
55
    ldi LED6, 120
56
    ldi RSinCount, 0
57
    rcall senddata            ; Bei Reset: Daten senden
58
 
59
loop:                     ; Endlosschleife
60

61
        rjmp loop
62
 
63
serout:
64
        sbis UCSRA,UDRE                   ; Warten bis UDR für das nächste
65
                                          ; Byte bereit ist
66
        rjmp serout
67
        out UDR, temp
68
        ret                               ; zurück zum Hauptprogramm 
69

70

71
SendData:
72
    push temp
73

74
    mov temp, LED1
75
        rcall serout                      ; Daten senden
76
        mov temp, LED2
77
        rcall serout                      
78
        mov temp, LED3
79
        rcall serout                      
80
        mov temp, LED4
81
        rcall serout
82
        mov temp, LED5
83
        rcall serout
84
        mov temp, LED6
85
        rcall serout
86
        ldi temp, 254
87
        rcall serout
88
        ldi temp, 255
89
        rcall serout
90

91
    pop temp
92
    ret
93

94

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

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

102
        in temp, UDR
103

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

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

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

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

116
        pop temp                          ; temp wiederherstellen
117
        reti                              ; Interrupt beenden 
118

119
extrsin:
120
        pop temp                          ; temp wiederherstellen
121
        reti                              ; Interrupt beenden 
122

123
storeLEDAdd:
124

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

129
setLED:
130
    
131
    cpi LEDadd, 1    ; Je nach Adresse Werte für LED Register setzen
132
    breq setLED1
133
    cpi LEDadd, 2
134
    breq setLED2
135
    ret
136

137
setLED1:
138
    mov LED1, temp    ; Unterprogramme zum Setzen der LED Werte
139
    ret
140

141
setLED2:
142
    mov LED2, temp
143
    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
OP #557916
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)
#557924
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.
Gast #557928
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
OP #557932
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
Gast #557939
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
(Firma: ZeuSWarE GmbH) #558233
Lesenswert?

öhmmmm, ich hätts so gemacht....
1
SendData:
2
    push temp
3
.
4
.
5
.
6
    andi r25,0b11111110    
7
    pop temp
8
    ret
9

10
loop:                     ; Endlosschleife
11
        sbrc r25,0
12
        rcall SendData
13
        sbrc r25,1
14
        rcall setLED
15
        sbrc r25,2
16
        rcall storeLEDAdd
17
        rjmp loop
18
.
19
.
20
.
21
int_rxc:
22
        in r26,SREG
23
        push r26
24
        push temp                         ; temp auf dem Stack sichern
25

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

29
        in temp, UDR
30

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

34
    cpi temp, 255    ; Empfang=255? Dann Daten senden
35
    brne d1
36
    ori r25,0b00000001    
37
    rjmp extrsin
38

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

44
d2: cpi RSinCount, 0  ;.... 
45
    brne extrsin
46
    ori r25,0b00000100
47

48
extrsin:
49
        pop temp                          ; temp wiederherstellen
50
        pop r26
51
        out SREG,r26
52
        reti                              ; Interrupt beenden 
53

54
storeLEDAdd:
55

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

61
setLED:
62
    andi r25,0b11111101
63
    cpi LEDadd, 1    ; Je nach Adresse Werte für LED Register setzen
64
    .
65
    .
66
    ret

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren