Forum: Mikrocontroller und Digitale Elektronik ASM, mit UART ein Byte binär ausgeben


von Bruno M. (brumay)


Lesenswert?

Hallo,

ich weiß, die Frage wurde schon gestellt, aber alles in C :-)

Mein Problem: Ich versuche über UART eine Kombination aus Text und 
Binärzahlen auszugeben. Z.B. Modus: 01010101

Gibt es dafür einen eleganten Weg? Ich habe bis jetzt versucht das 
Problem mit rotieren und Carry zu lösen, aber da scheint es ein Problem 
zu geben, das ich bisher nicht lösen konnte.
1
BIN_AUS:  
2
  push  R16
3
  ldi  R16, 8
4
BIN_AUS_LOOP:  
5
  lsl  TEMP_0
6
  mov  TEMP_1, TEMP_0
7
  clr  TEMP_0
8
  adc  TEMP_0, NULL
9
  subi  TEMP_0, -48
10
  rcall  uart_send_byte
11
  mov  TEMP_0, TEMP_1
12
  dec  R16
13
  breq  BIN_AUS_EXIT
14
  rjmp  BIN_AUS_LOOP
15
BIN_AUS_EXIT:
16
  pop  R16
17
  ret
Das Problem zeigt sich darin, daß es manchmal funktioniert, manchmal 
aber auch Müll ausgegeben wird.

Mod: Wenn du für AVR-Assemblercode die [avrasm]- statt der [c]-Tags 
nimmst, wird die Darstellung viel bunter :)

Beitrag #4993173 wurde von einem Moderator gelöscht.
von Thomas F. (igel)


Lesenswert?

Bruno M. schrieb:
> Ich habe bis jetzt versucht das
> Problem mit rotieren und Carry zu lösen

Klingt nicht schlecht.

Schau doch mal den Beispielcode aus dem Tutorial für die Ausgabe auf 
einem LCD an. Der Code sollte sich leicht auf UART ändern lassen.

https://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD#Bin.C3.A4r_ausgeben

von Holger74 (Gast)


Lesenswert?

BIN_AUS:
  push  R16
  ldi  R16, 8
  mov TEMP_1, TEMP_0

BIN_AUS_LOOP:
  ldi  TEMP_0,'1'
  sbrs TEMP1,7
  ldi  TEMP_0,'0'

  rcall  uart_send_byte

  lsl  TEMP_1
  dec  R16
  brne BIN_AUS_LOOP

BIN_AUS_EXIT:
  pop  R16
  ret

So mal schnell überlegt. Vielleicht gehts ja?!
Viel Spaß! :)

von Yalu X. (yalu) (Moderator)


Lesenswert?

Einen Fehler kann ich in deinem Code nicht direkt erkennen, aber könnte
es sein, dass uart_send_byte das Register TEMP_1 überschreibt? Das würde
evtl. auch erkären, dass der Fehler nicht immer auftritt.

Außerdem kann man den Code etwas eleganter formulieren:

1
BIN_AUS:  
2
  push  R16
3
  ldi  R16, 8
4
BIN_AUS_LOOP:  
5
  lsl  TEMP_0
6
  ldi  TEMP_1, '0'
7
  adc  TEMP_1, NULL
8
  rcall  uart_send_byte
9
  dec  R16
10
  brne BIN_AUS_LOOP
11
BIN_AUS_EXIT:
12
  pop  R16
13
  ret

Edit: In dieser Variante darf uart_send_byte auch gerne TEMP_1
überschreiben.

von c-hater (Gast)


Lesenswert?

Bruno M. schrieb:

> ich weiß, die Frage wurde schon gestellt, aber alles in C :-)
>
> Mein Problem: Ich versuche über UART eine Kombination aus Text und
> Binärzahlen auszugeben. Z.B. Modus: 01010101

Naja, das trifft die Sache nicht ganz. Was du versuchst, ist schlicht: 
Gib eine ASCII-codierte Zeichenkette aus, die zum Teil aus 
Repräsentation einer Zahl in Binärdarstellung besteht.

> Gibt es dafür einen eleganten Weg? Ich habe bis jetzt versucht das
> Problem mit rotieren und Carry zu lösen

Das ist definitiv ein guter Ansatz.

> aber da scheint es ein Problem
> zu geben, das ich bisher nicht lösen konnte.
[...]

Das Problem dürfte in dem Teil des Codes stecken, den du nicht gezeigt 
hast. Wie so oft...

Vermutlich werden in der Ausgaberoutine Registerinhalte geändert, die du 
für deine Zahlenkonversion benötigst und die folglich nicht irgendwo 
anders geändert werden dürfen, bis alle 8 Zeichen raus sind.

Im Simulator kannst du ganz hervorragend verfolgen, was da passiert. 
Warum benutzt du ihn nicht einfach?

von Bruno M. (brumay)


Lesenswert?

Erst mal herzlichen Dank für die vielen Hinweise und Anregungen. Die muß 
ich erst verdauen.

c-hater:

> Im Simulator kannst du ganz hervorragend verfolgen, was da passiert.
> Warum benutzt du ihn nicht einfach?

Das habe ich natürlich gemacht. Das Resultat war allerdings auch da 
nicht durchgängig. Mal lief der Debugger durch ohne auch nur ein Problem 
zu zeigen. Dann landete er nach einem ret im Nirwana. Wobei ich 
zwischendurch natürlich immer wieder andere Varianten probiert habe.

von Bruno M. (brumay)


Lesenswert?

Das ist übrigens die send_byte Routine:
1
uart_send_byte:
2
  push  TEMP_1
3
4
uart_send_byte_loop:
5
  lds  TEMP_1,UCSR0A
6
  sbrs    TEMP_1,UDRE0               ; Send-Register leer ?
7
        rjmp    uart_send_byte_loop        ; nein
8
9
  pop  TEMP_1
10
        sts     UDR0,TEMP_0
11
    ret

von c-hater (Gast)


Lesenswert?

Bruno M. schrieb:

>> Im Simulator kannst du ganz hervorragend verfolgen, was da passiert.
>> Warum benutzt du ihn nicht einfach?
>
> Das habe ich natürlich gemacht. Das Resultat war allerdings auch da
> nicht durchgängig. Mal lief der Debugger durch ohne auch nur ein Problem
> zu zeigen. Dann landete er nach einem ret im Nirwana.

Simulator != Debugger

Im Debugger hast du mit zusätzlich zu den Fehlern der Software auch noch 
mit den Fehlern in der Hardware zu kämpfen. Beim Simulator hingegen nur 
mit den Fehlern und Unzulänglichkeiten der Simulation. Diese allerdings 
sind weitestgehend bekannt und spielen in deinem Fall keine Rolle.

D.h.: Wenn's auch im Simulator nicht korrekt läuft, hast du erstmal den 
direkten Nachweis, dass in deiner Software ein Fehler steckt. Und mit 
kluger Nutzung des Simulators ist es dann auch relativ leicht, 
herauszufinden, wo er steckt.

Läuft es hingegen im Simulator, aber nicht auf realer Hardware, steckt 
das Problem in der realen Hardware. Da wären dann Probleme bezüglich 
unzureichender Stromversorgung bzw. unzureichender Pufferung selbiger 
die ersten Kandidaten. Wichtig: Solche Probleme kann man nicht dadurch 
finden, dass man stundenlang auf den Quelltext starrt. Und übrigens auch 
nicht dadurch, dass man das Problem bei µC.net postet...

von c-hater (Gast)


Lesenswert?

Bruno M. schrieb:
> Das ist übrigens die send_byte Routine:
>
>
1
> uart_send_byte:
2
>   push  TEMP_1
3
> 
4
> uart_send_byte_loop:
5
>   lds  TEMP_1,UCSR0A
6
>   sbrs    TEMP_1,UDRE0               ; Send-Register leer ?
7
>         rjmp    uart_send_byte_loop        ; nein
8
> 
9
>   pop  TEMP_1
10
>         sts     UDR0,TEMP_0
11
>     ret
12
>

Ich seh' den Fehler.

Wenn du den Simulator sinnvoll benutzen könntest, hättest du ihn auch 
längst gefunden...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Bruno M. schrieb:
> Gibt es dafür einen eleganten Weg?

 Probieren:
1
BIN_AUS:  
2
        push    R16
3
        ldi     R16, 8
4
BA_LOOP:  
5
        ldi     TEMP_1, '0'
6
        lsl     TEMP_0
7
        brcc    Uart_Snd
8
        ldi     TEMP_1, '1'
9
Uart_Snd:
10
        push   TEMP_0
11
uart_wt:
12
        lds    TEMP_0, UCSR0A
13
        sbrs   TEMP_0, UDRE0               ; Send-Register leer ?
14
        rjmp   uart_wt                     ; nein
15
        sts    UDR0,TEMP_1
16
        pop    TEMP_0
17
18
        dec     R16
19
        brne    BA_LOOP
20
        pop     R16
21
        ret

von Bruno M. (brumay)


Lesenswert?

c-hater schrieb:

>
> Ich seh' den Fehler.
>
> Wenn du den Simulator sinnvoll benutzen könntest, hättest du ihn auch
> längst gefunden...

Du sprichst wie immer in Rätseln!

von Bruno M. (brumay)


Lesenswert?

Dank Eurer Hinweise bin ich ein großes Stück weiter. Ich hatte an einer 
Stelle tatsächlich TEMP_1 überschrieben. Außerdem habe ich den super Tip 
von Yalu X.

>   ldi  TEMP_1, '0'

übernommen.

von c-hater (Gast)


Lesenswert?

c-hater schrieb:

> Ich seh' den Fehler.

Ergänzung: das ist nur einer der Fehler in "deinem" Code.

Mit dem nunmehr gezeigten Codeumfang war es mir möglich, die Herkunft 
des Codes (fast) zweifelsfrei zu ermitteln.

D.h.: ich bin 'raus. Mach deine Hausaufgaben gefälligst alleine...

Bei der Hausaufgabe geht es gerade darum, dass der Delinquent (also du) 
die Fehlersuche alleine gebacken bekommt, als Nachweis seines gewonnen 
Verständnisses der Assemblerprogrammierung...

Also solltest du das eigentlich sogar nur durch reine Analyse des 
Quelltextes herausbekommen, ohne Zuhilfenahme von Debugger oder 
Simulator. Aber ich denke, dass es durchaus noch fair ist, solche 
Werkzeuge zu benutzen, schließlich werden die auch im RL regelmäßig 
benutzt. Aber auch die Beherrschung dieser Werkzeuge will halt gelernt 
sein...

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.