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