Forum: Mikrocontroller und Digitale Elektronik Zeichenkette vom UART auswerten AVR Assembler


von pacer (Gast)


Lesenswert?

Hallo Leute,

ich möchte eine Zeichenkette (3 Zeichen) die über die serielle 
Schnittstelle kommt auswerten und hab mir auch ein kurze Routine 
geschrieben.
Leider nimmt der MC die Zeichenkette nicht an. Die Schnittstelle selbst 
funktioniert, weil die Initialisierungsroutine eine Zeichenkette an das 
Terminal schickt.
Im ersten Teil hab ich sowas wie ein Blinkprogramm eingefügt, damit ich 
sehen kann ob der MC irgendwo hängen leibt, was nicht der Fall ist.
Den Empfang hab ich freigeschalten:   sbi UCSRB,RXEN

Kann mir vielleicht jemand sagen warum, das Programm nicht so wie ich 
will?
Ich komm nicht von allein drauf
1
main:
2
        ldi r16, 0xf0
3
  out portb, r16
4
  rcall warte_1s
5
6
  ldi r16, 0x0f
7
  out portb, r16
8
  rcall warte_1s
9
10
  in r16, UDR    ; Zeichen auslesen
11
  cpi r16,0x74    ; prüfen ob t gedrückt wurde
12
  brne no_enter  
13
  out UDR, r16
14
 wait_RX1:
15
  sbis UCSRA,RXC
16
  rjmp wait_RX1
17
18
no_m:
19
  in r16, UDR    ; Zeichen auslesen
20
  cpi r16,0x6D    ; prüfen ob m gedrückt wurde
21
  brne no_m
22
  out UDR, r16
23
 wait_RX2:
24
  sbis UCSRA,RXC
25
  rjmp wait_RX2
26
27
no_p:
28
  in r16, UDR    ; Zeichen auslesen
29
  cpi r16,0x70    ; prüfen ob p gedrückt wurde
30
  brne no_p
31
  out UDR, r16
32
 wait_RX3:
33
 
34
  rcall get_temp
35
no_enter:
36
rjmp main

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Wird denn die Datadirection des UART-Ports richtig initialisiert, ich 
kann im Code keine Initialisierung finden. Standardmäßig ist nach dem 
Einschalten jeder Pin ein Eingang, das musst du aber geändert haben, 
sonst würde der AVR keine Zeichen senden können. Rxd muss als Eingang 
konfiguriert sein, vielleicht ist da ein Fehler passiert.

Man kann als Konstanten auch character schreiben, das wäre besser 
lesbar:

  cpi r16,'t'    ; prüfen ob t gedrückt wurde

Hast du mal eine einfache Loopback-Schleife getestet oder zumindest ein 
Hardwareloopback ausprobiert?

Grüße,

Peter

von pacer (Gast)


Lesenswert?

Hallo Peter,

ich wüsste nicht, dass RX und TX extra als Eingang bzw. Ausgang 
geschalten werden müssen, ich nutze die eingebaute serielle 
Schnittstelle.
Hier meine Initalisierungsroutine:
1
UART_INIT:
2
.equ BAUD = 38400
3
.equ UBRRVAL = F_CPU/(BAUD*16)-1
4
; Baudrate einstellen
5
  ldi r16, LOW(UBRRVAL)
6
  out UBRRL, r16
7
  ldi r16, HIGH(UBRRVAL)
8
  out UBRRH, r16
9
; Frame-Format: 8 Bit
10
  ldi r16, (1<<URSEL)|(3<<UCSZ0)
11
  out UCSRC, r16
12
  sbi UCSRB,TXEN    ; TX aktivieren
13
  sbi UCSRB,RXEN    ; RX aktivieren

Das mit dem Charater ist ein guter Hinweis...
Was meinst du mit Hardwareloopback?
Ich habe auch schon versucht, gleich nach dem Auslesen des Zeichens es 
wieder an die UART zurückzusenden, leider ohne Erfolg.
Das Senden an das Terminal funktioniert aber definitiv

von pacer (Gast)


Lesenswert?

Hab nochmal ein altes Prgramm ausprobiert, ich vermute fast mal dass ein 
Hardwaredefekt vorliegt oder irgendwas mit meinem Windows nicht stimmt.

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Hardwareloopback bedeutet, dass man den Mikrocontroller aus der 
Schaltung entfernt und am Sockel Rxd mit Txd verbindet. EIn 
angeschlossenes Terminal muss dann genau die gesendeten Zeichen 
empfangen. Damit hat man die Hardware bis zum Controller gestestet.

Grüße,

Peter

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Du solltest außerdem besser warten bis ein Zeichen angekommen ist, bevor 
du es ausließt, also etwa so:

getChar:
sbis   UCSRA,RXC   ; wait for incoming data (until RXC==1)
rjmp   getChar
in   R16,UDR   ; store received data in R16
ret

Grüße,

Peter

von pacer (Gast)


Lesenswert?

Der Hardwareloop funktioniert. Trotz Einfügen der Warteschleife aber 
immernoch kein Ergebnis. :-(

von eProfi (Gast)


Lesenswert?

Dann erweitere die Loop ein wenig:
sende das empfangene Byte wieder zurück (evtl. auch im Klartext, d.h. 
für ein empfangenes A sendest Du 41 oder A41 zurück).

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Ich kann mich wage daran erinnern, dass es beim ATMEGA wichtig ist, in 
welcher Reihenfolge die Register geschrieben werden.

Ich denke, es muss hier UBRRH zuerst geschrieben werden:

  ldi r16, LOW(UBRRVAL)
  out UBRRL, r16
  ldi r16, HIGH(UBRRVAL)
  out UBRRH, r16

Um welchen Prozessor geht es denn eigentlich genau?

Peter

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Hast du dir eigentlich genau überlegt, was diese Zeile macht?
ldi r16, (1<<URSEL)|(3<<UCSZ0)

Vor allem das mit der 3 in 3<<UCSZ0?

Ich habe das jetzt nicht nachgeprüft, aber die vordefinierten Bits (z.B. 
UCSZ0) sind eine Zahl von 0 bis 7 und geben die Stelle des jeweiligen 
Bits im Register an. Normalerweise verwendet man sie um den Code 
lesbarer zu machen und shiftet um eben die damit definierte Konstante 
eine 1 in das Register. Aber eine 3 setzt ja zwei Bits. Damit ist die 
Lesbarkeit verloren gegangen und zudem größere Verwirrung erzeugt, denn 
wer weiß dadurch intuitiv eindeutig, welches das zweite gesetzte Bit 
ist?

Also sollte man es entweder so machen:

ldi r16, (1<<URSEL)|(1<<UCSZ0)|(1<< das andere, was gemeint war)

Oder gleich ohne lesbare Konstanten:

ldi r16, 0xirgendwas

Grüße,

Peter

von pacer (Gast)


Lesenswert?

Hallo Peter,

ich muss natürlich gestehen, dass viele Codeteile nicht von mir sind.
Ich hatte ursprünglich begonnen einen Temperatursensor (DS1632) per TWI 
auszulesen.
Da ohne Vorkenntnisse habe ich mir den Code von Metaller geschnappt, 
siehe Blutrausch I2C. Nach einigen Wochen rumgefrickel und 
Datenblätterlesen hab ich es doch noch hinbekommen den Code entsprechend 
anzupassen.

Da die Ausgabe über den UART immer funktioniert hat, habe ich mir keine 
Gedanken drum gemacht. Erst als ich versucht habe den Code dahingehend 
zu erweitern, dass ich auch Befehle an den Temperatursensor schicken 
kann.
Wie wieder mal unschwer zu erkennen, spart man mit copy and paste 
mitnichten Zeit :-(

Um zurückzukommen zum Thema, das mit 3<<UCSZ0 ist mir gestern auch 
aufgefallen. Das hatte den Vorteil, dass mir einige Unstimmigkeiten in 
meinen alten selbstgeschriebenen Programmen aufgefallen sind.
Grundsätzlich kommt ja nach UCSZ0 gleich UCSZ1. wird jetzt eine 3 
reingeschoben, werden beide Bits gesetzt.

Ich werde mir das heute alles nochmal anschauen, kann ja nicht sein, 
dass ich für dieses Fuzelchen an Programmcode 2 Wochen brauche.

Nun werde ich wohl nochmal einen Schritt zurückgehen und die 
Befehlserkennung separat programmieren, das macht das debuggen dann 
hoffentlich einfacher.

Mein Controller ist übrigens der Mega8

Ich melde mich dann wieder,
Gruß, Jürgen

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.