Forum: Mikrocontroller und Digitale Elektronik AtMega16 Uart empfangen


von e3onjz (Gast)


Lesenswert?

Hey Profis,

ich benutze einen Mikrocontroller um ein Gerät über RS232 anzusteuern.

Wenn ich auf einen Taster drücke wird ein Befehl gesendet, - was auch 
funktioniert.
Allerdings soll pro Durchgang der endless-Schleife ein zusätzlicher 
Befehl gesendet werden, und die Antwort darauf ausgewertet werden.

Das Senden funktioniert wieder ohne Probleme, allerdings tut sich nach 
dem ersten Empfangen gar nichts mehr.
1
.include  "m16def.inc"
2
3
.def  tmp   = r16
4
.def  tmp2  = r17
5
.def  tmp3  = r18
6
.def  sign  = r19
7
.def  state = r20
8
9
; Bit-Names for Register "state"
10
.equ  statePower    = 0
11
12
.equ  systemClock = 18432000    ; System clock in Hz
13
.equ  rs232Baud   = 9600    ; BAUD for RS232 Signal
14
.equ  ubbr_value  = ((systemClock+rs232Baud*8)/(rs232Baud*16)-1)
15
16
/********************************************************************************/
17
; initialize Stackpointer
18
ldi    tmp, HIGH(RAMEND)
19
out    SPH, tmp
20
ldi    tmp, LOW(RAMEND)
21
out    SPL, tmp
22
23
; set BAUD
24
ldi    tmp,   high(ubbr_value)
25
out    UBRRH, tmp
26
ldi    tmp,   low(ubbr_value)
27
out    UBRRL, tmp
28
29
; set 8 Bit - Frame format
30
ldi    tmp,   (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0)
31
out    UCSRC, tmp
32
33
; activate transmit and receive in USART-Register
34
sbi    UCSRB, TXEN
35
sbi    UCSRB, RXEN
36
37
ldi    tmp,   0x00    ; Port B as input
38
out    DDRB,  tmp
39
ldi    tmp,   0xFF    ; Port B, activate PullUp Resistor 
40
out    PORTB, tmp
41
out    DDRA,  tmp    ; Port A as output
42
/********************************************************************************/
43
44
endless: 
45
  
46
  sbic  PINB, 0
47
  rcall  power
48
  /*hier werden später der reihe nach noch weiterer Pins (Taster) abgefragt*/
49
  
50
  rcall  receiveInformation
51
52
  rjmp  endless
53
54
55
; transmit content of register sign via rs232
56
transmitSign:
57
  sbis  UCSRA, UDRE    ; wait until UDR is ready to transmit
58
  rjmp  transmitSign
59
  out    UDR,   sign
60
ret
61
62
63
; pause
64
wait:
65
  ldi    tmp, 0xFF
66
  loop_1:
67
    ldi    tmp2, 0xFF
68
    loop_2:
69
      ldi    tmp3, 0x20
70
      loop_3:
71
        dec    tmp3
72
        brbc  1,   loop_3
73
      dec    tmp2
74
      brbc  1,   loop_2
75
    dec    tmp
76
    brbc  1,   loop_1
77
ret
78
79
; if power is pressed
80
power:
81
  sbrs  state, statePower
82
  rjmp    transmitPowerOn
83
84
  transmitPowerOff:
85
    ldi    sign, 0x02
86
    rcall  transmitSign
87
    ldi    sign, 0x00
88
    rcall  transmitSign
89
    ldi    sign, 0x00
90
    rcall  transmitSign
91
    ldi    sign, 0x00
92
    rcall  transmitSign
93
    ldi    sign, 0x00
94
    rcall  transmitSign
95
    ldi    sign, 0x02
96
    rcall  transmitSign
97
    rjmp  powerEnd
98
99
  transmitPowerOn:
100
    ldi    sign, 0x02
101
    rcall  transmitSign
102
    ldi    sign, 0x01
103
    rcall  transmitSign
104
    ldi    sign, 0x00
105
    rcall  transmitSign
106
    ldi    sign, 0x00
107
    rcall  transmitSign
108
    ldi    sign, 0x00
109
    rcall  transmitSign
110
    ldi    sign, 0x03
111
    rcall  transmitSign
112
113
  powerEnd:
114
  ldi    tmp,   (1<<statePower)
115
  eor    state, tmp
116
  rcall  wait
117
ret
118
119
receiveInformation:
120
121
  ldi    tmp2, 0x80
122
123
  transmitRequest:
124
    ldi    sign, 0x00
125
    rcall  transmitSign
126
    ldi    sign, 0xC0
127
    rcall  transmitSign
128
    ldi    sign, 0x00
129
    rcall  transmitSign
130
    ldi    sign, 0x00
131
    rcall  transmitSign
132
    ldi    sign, 0x00
133
    rcall  transmitSign
134
    ldi    sign, 0xC0
135
    rcall  transmitSign
136
137
  receiveWait:
138
    sbis    UCSRA, RXC
139
      rjmp    receiveWait
140
    receive:
141
      dec    tmp2
142
      brbs  1,     receiveEnd
143
      in      sign,  UDR    
144
      out     PORTA, sign                  
145
      rjmp    receiveWait
146
147
  receiveEnd:
148
149
ret

In der endless-Schleife wird praktisch gewartet ob ein Taster gedrückt 
wird. Pro Durchgang wird ein zusätzlicher Befehl durch aufrufen des 
Unterprogramms "receiveInformation" gesendet, nach dem Senden, soll 
jedes empfangene Byte an Port A ausgegeben werden... Es werden genau 128 
(0x80) Bytes empfangen.

Jetzt funktioniert das ganze genau einmal, - ich sehe das sich an PortA 
was tut, aber danach passiert gar nichts mehr...

Versteht ihr was ich will und wo's hängt?

Vielen Dank jetzt schon mal!!! :)

von chris (Gast)


Lesenswert?

Hallo,

e3onjz schrieb:
> ldi    tmp,   0x00    ; Port B as input
> out    DDRB,  tmp
> ldi    tmp,   0xFF    ; Port B, activate PullUp Resistor

hier werden die internen pulls aktiviert ok.

/*********************************************************************** 
*********/
>
> endless:
>
>   sbic  PINB, 0
>   rcall  power

der SBIC-Befehl tut folgendes:

"SKIP IF BIT IS CLEARED" = nachfolgenden Befehl überspringen wenn der 
PIN 0 ist.

Und jetzt kommts da du die Pulls aktiviert hast ist dein PIN immer 1 und 
bei 1 wird der folgende Befehl ausgeführt >>>>>> heist dein Programm 
wird immer ausgeführt.

sbis    Pinb,0
rcall   power

wäre eine von mehreren Möglichkeiten

von e3onjz (Gast)


Lesenswert?

Hey Chris - danke für deine Antwort!!

Aber daran liegts nicht, weil ich die Schaltung so aufgebaut habe, dass 
bei Tasterdruck ein High-Pegel anliegt, und somit stimmt der Befehl dann 
auch...

Ohne Aufruf des Unterprogramms "receiveInformation" funktioniert das 
ganze auch wunderbar - also muss der Fehler iwo dort liegen...

von chris (Gast)


Lesenswert?

mal so neben bei gefragt du willst in dem Unterprogramm

receiveInformation

das die UP erst Daten sendet und dann auf Eingaben von dir wartet um 
dann wieder herauszuspringen aus dem UP ?

von der alte Hanns (Gast)


Lesenswert?

Was ist, wenn nur 127 Bytes empfangen werden?


Hat zwar nichts mit dem Problem zu tun, aber das Nachfolgende verstehe 
ich nicht:
>.equ  ubbr_value  = ((systemClock+rs232Baud*8)/(rs232Baud*16)-1)

von e3onjz (Gast)


Lesenswert?

Ja genau das war der Plan...
Bin total neu auf diesem Gebiet, - wie würdest du es machen?

Also die Antwort auf den Befehl der gesendet wurde, kommt relativ 
unmittelbar...

von der alte Hanns (Gast)


Lesenswert?

Und, bitte: ist es nötig zu wissen, an welcher Stelle im SREG welches 
Flag sitzt? Also, statt 'brbs 1' 'breq' etc. verwenden. Hilft allen 
Beteiligten.

von chris (Gast)


Lesenswert?

e3onjz schrieb:
> Ja genau das war der Plan...

receiveWait:
      sbis    UCSRA, RXC
      rjmp    receiveWait
      in      sign,  UDR     ;A wie Antwort von deinem PC gesendet
      cpi     sign, 'A'      ; Vergleich auf A
      brne    receiveWait    ;und wenn !=A springe zu label
receiveWaitEnd
      ; hier dein Code für Visualisierungen
      ret

achso und führe dir für die bedingten Verzweigungen mal das DB zu Gemüte

von der alte Hanns (Gast)


Lesenswert?

Die Variable state mit dem Bit/Flag statePower wird zu Beginn nicht 
gesetzt. Es kann also sein, dass nach dem Senden von PowerOff auf eine 
Kommunikation gewartet wird - ist das so korrekt?

von e3onjz (Gast)


Lesenswert?

Hey Chris, das sieht ziemlich vielversprechend aus - werd mal ein 
bisschen mit experimentieren.

>achso und führe dir für die bedingten Verzweigungen mal das DB zu Gemüte

Meinst du mit DB die Direktive zum Speichern? Was hat das mit 
Verzweigungen zu tun? Sry bin noch beim Reinlesen in das alles ;)


Und ich bitte auch beim alten Hanns um Entschuldigung, ich kenne bis 
jetzt nur eine handvoll Befehle - wollte niemanden verwirren...

von chris (Gast)


Lesenswert?

DB = DatenBlatt sorry mein Fehler ;)

von e3onjz (Gast)


Lesenswert?

Oh sry, hab da ein paar Antworten übersehen...

Yapp stimmt, im Register 'state' wird am Anfang kein Wert gesetzt, was 
bedeutet, dass er je nach Inhalt "zufälig" An- bzw Ausschalten will...

Aber das dürfte für dieses Problem nicht relevant sein, da pro Durchlauf 
der endless-Schleife immer auf eine Kommunikation gewartet wird, damit 
das Gerät auch immer auf dem neuesten Stand ist.

>Hat zwar nichts mit dem Problem zu tun, aber das Nachfolgende verstehe
ich nicht:
>>.equ  ubbr_value  = ((systemClock+rs232Baud*8)/(rs232Baud*16)-1)

ähm da muss ich passen, - das habe ich von 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART#UART_konfigurieren 
abgeschrieben...

von der alte Hanns (Gast)


Lesenswert?

Kann das Gerät nach dem 'Ausschalten' noch auf andere Befehle als 
'Einschalten' reagieren?
Und es ist sicher, dass als Antwort genau 128 Zeichen kommen? Sonst 
hängt die Empfangsschleife.

Es ist zwar nur ein Schönheitsfehler, aber die Baudrate liegt um 0.4 % 
daneben.

von der alte Hanns (Gast)


Lesenswert?

Der Hinweis auf die Baudrate ist ein Irrtum meinerseits - 
Entschuldigung.

von e3onjz (Gast)


Lesenswert?

Also erstmal auch dir vielen Dank für deine Mühe!!

Ah verdammt, vll ist das nicht klar rübergekommen:
Das oben gezeigt Programm bildet zsm mit dem Controller und ein paar 
Bedienelementen eine eingenständige Steuerung, welche ein Gerät X 
steuert.

Der Befehl "Ausschalten" schaltet also das Gerät X aus. In diesem 
"ausgeschaltetem Zustand (StandBy)" reagiert das Gerät X nur auf den 
"Einschalt" Befehl.

>Und es ist sicher, dass als Antwort genau 128 Zeichen kommen?
>Sonst hängt die Empfangsschleife.
Yapp das hab ich erstmal wieder zur Fehlersuche weggenommen, - aber ich 
wollte diesen Teil (während er auf ein neues Byte im 
UART-Empfangs-Register wartet):
1
sbis    UCSRA, RXC
2
rjmp    receiveWait
einfach auf ein paar Zyklen beschränken...
Das würde ja dann das Problem beheben, oder?

von chris (Gast)


Lesenswert?

e3onjz schrieb:
> sbis    UCSRA, RXC
> rjmp    receiveWait
> einfach auf ein paar Zyklen beschränken...
> Das würde ja dann das Problem beheben, oder?

vom prinzip her ja, wenn du denn auf alles weitere erstmal verzichten 
willst um den Fehler zu finden aber wie weit bist du denn?

von der alte Hanns (Gast)


Lesenswert?

>Der Befehl "Ausschalten" schaltet also das Gerät X aus. In diesem
>"ausgeschaltetem Zustand (StandBy)" reagiert das Gerät X nur auf den
>"Einschalt" Befehl.

Liegt nicht genau hier das Problem? Spätestens beim zweiten Durchlauf 
vom Unterprogramm 'power' wird ausgeschaltet, anschließend aber in 
'receiveInformation' auf die Antwort einer Frage gewartet, die der 
'Ausgeschaltete' verschlafen hat.

von e3onjz (Gast)


Lesenswert?

So hab das ganze jetzt bissle erweitert:
1
receiveInformation:
2
3
  ldi    tmp2, 0x86  ; Counter2 - damit nur 134 Bytes empfangen werden
4
5
  transmitRequest:  ; Sende Befehl um Informationen zu bekommen
6
    ldi    sign, 0x00
7
    rcall  transmitSign
8
    ldi    sign, 0xC0
9
    rcall  transmitSign
10
    ldi    sign, 0x00
11
    rcall  transmitSign
12
    ldi    sign, 0x00
13
    rcall  transmitSign
14
    ldi    sign, 0x00
15
    rcall  transmitSign
16
    ldi    sign, 0xC0
17
    rcall  transmitSign
18
19
  receiveStart:
20
    ldi      tmp,  0xFF  ; Counter1 damit empfangsschleife abbricht, wenn keine Bytes mehr empfangen werden
21
    receiveWait:
22
      dec    tmp      ; dekrementiere Counter1
23
      cpi    tmp, 0x00  ; vergleíche ob COunter1 abgelaufen ist
24
      breq  receiveEnd  ; breche empfangsschleife ab, wenn Counter1 abgelaufen ist
25
      sbis    UCSRA, RXC  ; überspringe nächsten Befehl, wenn kein Zeichen empfangen wurde
26
      rjmp    receiveWait  ; springe zum anfang der empfangsschlefe
27
      receive:
28
        in      sign,  UDR   ; lese empfangenes Byte ein
29
        out     PORTA, sign   ; gib Byte an PortA aus (Nur zur überprüfung - später wird hier ausgewertet)
30
        dec    tmp2     ; decrementiere Counter2
31
        cpi    tmp2, 0x00   ; vergleiche ob Countr2 abgelaufen ist (alle 134 Bytes empfangen wurden)
32
        breq  receiveEnd   ; breche schleife ab, wenn counter2 abgelaufen ist
33
        rjmp    receiveStart ; springe wieder zm Anfangspunkt wo der Counter2 initialisiert wird
34
  receiveEnd: ; Punkt zum abbrechen der schleifen
35
ret

>Liegt nicht genau hier das Problem? Spätestens beim zweiten Durchlauf
>vom Unterprogramm 'power' wird ausgeschaltet, anschließend aber in
>'receiveInformation' auf die Antwort einer Frage gewartet, die der
>'Ausgeschaltete' verschlafen hat.
Yappt stimmt, hab jetzt beim testen einen anderen Befehl eingesetzt, - 
allerdings konnte ich trotzdem noch an der LED sehn, dass sich nach 
einer weile nichts mehr tat...

Und mit dem aktualisierten Unterprogramm ist es genau das gleiche. - 
Kann es sein, dass nicht gesendet werden darf, während im 
Empfangsregister noch Bytes sind?

von der alte Hanns (Gast)


Lesenswert?

>Kann es sein, dass nicht gesendet werden darf, während im
>Empfangsregister noch Bytes sind?
Nein, senden und empfangen sind getrennt.

Das Grundproblem von gestern abend besteht doch nach wie vor, ich sehe 
nicht, dass daran etwas geändert wurde.

Allgemein: Sie sollten etwas mehr in Ihre Grundlagen investieren, z.B. 
setzt 'dec' das Z-Flag bereits, ein 'cpi .,0' ist also überflüssig. Und 
das timeout in receiveWait wird in 255*6* 54.25 ns = 83 us durchlaufen, 
ein Byte benötigt bei 9600 Bd aber 1042 us.

von e3onjz (Gast)


Lesenswert?

Meinst du mit Grundproblem, dass nach dem Ausschalten des Gerätes X 
keine Antwort mehr kommt?
Das ist auch so erwünscht, in dem Fall sollte die Empfangsschleife 
abbrechen und (noch nicht implementiert) eine z.b. LED anschalten die 
anzeigt, dass das Gerät ausgeschaltet ist. Wird das Gerät wieder 
eingeschaltet, sendet es auch wieder eine Antwort ergo sollte die 
Empfangsschleife nicht abgebrochen werden - die beispielhafte LED wird 
wieder ausgeschaltet und andere LEDs können je nach Antwort 
eingeschaltet werden...

Ja das mit dem Timeout hab ich nicht bedacht bzw. falsch eingeschätzt, 
werde es morgen gleich mal mit einem längeren probieren.

Danke auf jedenfall für deine Hilfe!! :)

von chris (Gast)


Lesenswert?

e3onjz schrieb:
> in dem Fall sollte die Empfangsschleife abbrechen

dann nutze einen timer dazu in dessen ISR das T-Flag gesetzt wird, in 
der empfangsroutine das T-Flag löschen und danach abfragen ob gesetzt.

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.