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


von Pascal C. (passi)


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

von Uhu U. (uhu)


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?

von Pascal C. (passi)


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..

von Uhu U. (uhu)


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?

von Axel R. (Gast)


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.

von Pascal C. (passi)


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)

von Uhu U. (uhu)


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.

von Axel R. (Gast)


Lesenswert?

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

von spess53 (Gast)


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

von Uhu U. (uhu)


Lesenswert?

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

von Stefan W. (wswbln)


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)?

von Pascal C. (passi)


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

von Uhu U. (uhu)


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.

von spess53 (Gast)


Lesenswert?

@ Nachtvogel

Gewusst oder geraten?

MfG Spess

von Uhu U. (uhu)


Lesenswert?

Na ja, hab schon ein paar Flugstunden in ASM auf dem Buckel...

von Pascal C. (passi)


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

von spess53 (Gast)


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

von Alexander H. (c_type)


Lesenswert?

Und noch was,

wie Stefan weite oben bereits angemerkt hat:

Im Interrupt zuerst Statusregister sichern !!

Gruß
Alexander

von spess53 (Gast)


Lesenswert?

Hi

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

MfG Spess

von Kai S. (Firma: ZeuSWarE GmbH) (zeusosc)


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

von Pascal C. (passi)


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

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.