Forum: Mikrocontroller und Digitale Elektronik Punkt wird als ASCII gesendet, lesbar nur als dezimal Zahl. Zahlen und Buchstaben funktionieren!


von Arne (Gast)


Lesenswert?

Hallo,

ich möchte ein paar Zeichen mittels UART an eine andere Steuerung 
senden. Das Protokoll ist ASCII.

Ich habe folgendes definiert:
1
volatile unsigned int Wert;   // Ausgabewert
2
volatile unsigned char ASCII[15] = {0,1,2,3,4,5,6,7,8,9,'.',',',':','+','-'};
3
// ASCII[0]  = 0              
4
// ASCII[1]  = 1
5
// ASCII[2]  = 2
6
// ASCII[3]  = 3
7
// ASCII[4]  = 4
8
// ASCII[5]  = 5
9
// ASCII[6]  = 6
10
// ASCII[7]  = 7
11
// ASCII[8]  = 8
12
// ASCII[9]  = 9
13
// ASCII[10] = .
14
// ASCII[11] = ,
15
// ASCII[12] = :
16
// ASCII[13] = +
17
// ASCII[14] = -

Die Main sieht so aus:
1
Wert = ASCII[1];  ausgabe_wert();
2
Wert = ASCII[2];  ausgabe_wert();
3
Wert = ASCII[3];  ausgabe_wert();
4
Wert = ASCII[4];  ausgabe_wert();
5
ausgabe_stop();
An der Steuerung kommen folgende ASCII-Zeichen an: 1234<CR>.
Soweit funktioniert das wie gewollt.
Jetzt möchte ich aber ein Punkt mitsenden und habe die Main wie folgt 
geschrieben:
1
Wert = ASCII[1];  ausgabe_wert();
2
Wert = ASCII[10]; ausgabe_wert();
3
Wert = ASCII[2];  ausgabe_wert();
4
Wert = ASCII[3];  ausgabe_wert();
5
Wert = ASCII[4];  ausgabe_wert();
6
ausgabe_stop();
Ich erwarte folgendes: 1.234<CR>
In der Steuerung kommt aber folgendes an: 1 46 234<CR> (ohne 
Leerzeichen).
Hierbei fällt auf, dass der Punkt nicht als Punkt lesbar gemacht wird, 
sondern als dezimale Zahl 46.
Ist in meiner Routine etwas falsch oder versteht die Steuerung den Punkt 
nicht?

Grüße,
Arne

von gascht (Gast)


Lesenswert?

Arne schrieb:
> Ist in meiner Routine etwas falsch oder versteht die Steuerung den Punkt
> nicht?

Weder die Routine, noch die Steuerung ist benannt bzw. angegeben.
Glaskugelraten mögen hier einige nicht.

von Floh (Gast)


Lesenswert?

Arne schrieb:
> volatile unsigned char ASCII[15] = {0,1,2,3,4,5,6,7,8,9,'.',',',':','+','-'};

Ascii geht so:

> volatile unsigned char ASCII[15] = 
{'0','1','2','3','4','5','6','7','8','9','.',',',':','+','-'};

und dann muss die Gegenstelle natürlich die ankommenden Bytes als 
Charakter deuten.

von Karl H. (kbuchegg)


Lesenswert?

Arne schrieb:

> Ist in meiner Routine etwas falsch

Deine Ausgaberoutine wird höchst wahrscheinlich kein Zeichen versenden, 
sondern eine Zahl, wobei sich die Funktion selber eine ASCII 
Repräsentierung der Zahl baut.

Deine Versendefunktion macht zuviel.

von Arne (Gast)


Lesenswert?

Hallo.

So sieht die Senderoutine aus:
1
void UART_SendByte(uint8_t data)
2
{
3
  while (!(UCSRA & (1<<UDRE)));
4
  UCSRA|=(1<<TXC);
5
  UDR = data;
6
}
7
8
void uart_puts(char *s) {  
9
  while (*s)
10
  {
11
    UART_SendByte(*s++);         
12
  }
13
  while (!(UCSRA & (1<<TXC)));
14
}

Der Empfänger ist ein Computer.
Folgende dezimale Zahlen stehen im Empfänger bei der Zahl 1234
1
CHAR[0] = 49 -> 1 in ASCII
2
CHAR[1] = 50 -> 2 in ASCII
3
CHAR[2] = 51 -> 3 in ASCII
4
CHAR[3] = 52 -> 4 in ASCII

Die dezimalen Zahlen bei 1.234 sehen so aus:
1
CHAR[0] = 49 -> 1 in ASCII
2
CHAR[1] = 52
3
CHAR[2] = 54
4
CHAR[3] = 50 -> 2 in ASCII
5
CHAR[4] = 51 -> 3 in ASCII
6
CHAR[5] = 52 -> 4 in ASCII

CHAR[1] und CHAR[2] sollen ein Punkt darstellen, aber meine Senderoutine 
macht da wohl etwas anderes draus?!

von Arne (Gast)


Lesenswert?

Ach, die Funktion ausgabe_wert() macht folgendes:
1
void ausgabe_wert (void)
2
{
3
  utoa(Wert, Sendestring, 10);
4
  uart_puts(Sendestring);
5
}

Wenn ich als Stoppzeichen eine Raute angebe, wird diese auch korrekt 
übertragen.
Ein Punkt, ein Komma, ein Minus, ein Plus und ein Doppelpunkt, die in 
ASCII[..] gespeichert sind, werden falsch gesendet.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nun, Du gibst also den Zahlenwert aus, der in "Wert" steht.

Was also passiert?

   Wert = ASCII[1];  ausgabe_wert();

Wert wird hier auf 0 gesetzt. Folglich wird auch ein String mit dem 
Inhalt "0" gesendet.


   Wert = ASCII[10]; ausgabe_wert();

Das hier setzt Wert auf '.', das ist dezimal 46.

Folglich wird ein String mit dem Inhalt "46" gesendet.

> Ein Punkt, ein Komma, ein Minus, ein Plus und ein Doppelpunkt, die in
> ASCII[..] gespeichert sind, werden falsch gesendet.

Nein. JEDES Zeichen, das in ASCII[] nicht als Zahl, sondern als 
Zeichenkonstante gespeichert ist, wird falsch gesendet.

von gascht (Gast)


Lesenswert?

Arne schrieb:
> Ach, die Funktion ausgabe_wert() macht folgendes

Na das ist ja mal ein Anfang...
Deswegen hast du auch die Zahlen als Zahlen in deinem Array und nicht 
als ASCII Zeichen. Das einfachste wäre du schmeißt die Funktion 
ausgabe_wert() raus und nimmst nur noch uart_puts(Sendestring). Dann 
aber in deinem Array die Zahlen als ASCII Zeichen einfügen also statt 1 
eben '1'. Zudem stellt sich bei der Funktion noch die Frage was Wert und 
Sendestring sollen. Sind das globale Variablen? Warum hast du das nicht 
als Übergabeparameter gemacht?

von mano (Gast)


Lesenswert?

schau nochmal nach was ascii ist!!!! vvlt. findest Du auch eine 
ascii-Tabelle und rat mal was der Punkt als hex bez. dezimal ist... 
(auch wenn es schon beantwortet worden ist)

von Floh (Gast)


Lesenswert?

Zunächst würde ich das Terminal (welches?) auf der PC-Seite auf Ascii 
einstellen.
Dann wird der Punkt richtig übertragen, die Zahlen allerdings nicht, da 
deine Initialisierung von ASCII[] falsch ist:

Floh schrieb:
> Arne schrieb:
>> volatile unsigned char ASCII[15] = {0,1,2,3,4,5,6,7,8,9,'.',',',':','+','-'};
>
> Ascii geht so:
>
>> volatile unsigned char ASCII[15] =
> {'0','1','2','3','4','5','6','7','8','9','.',',',':','+','-'};

:-)

von Arne (Gast)


Lesenswert?

mano schrieb:
> vvlt. findest Du auch eine
> ascii-Tabelle und rat mal was der Punkt als hex bez. dezimal ist...
Ein Punkt ist dezimal 46, diese Antwort habe ich mir ja selbst 
gegeben... ;)

gascht schrieb:
> Dann
> aber in deinem Array die Zahlen als ASCII Zeichen einfügen also statt 1
> eben '1'. Zudem stellt sich bei der Funktion noch die Frage was Wert und
> Sendestring sollen. Sind das globale Variablen? Warum hast du das nicht
> als Übergabeparameter gemacht?
  volatile unsigned int Wert;
Damit weise ich einem Int das Zeichen zu...
Ach shit, kann es sein, dass ich statt INT CHAR schreiben muss?

  utoa(Wert, Sendestring, 10);
Das ist in der ausgabe_wert() zu finden.
Hhm, unnütz, oder?
Ich werde das mal direkt mit der Zuweisung '0','1','2', usw. versuchen.

Der Grund, warum ich das mache, ist Speicherplatzmangel im Attiny2313.

Floh schrieb:
> Zunächst würde ich das Terminal (welches?) auf der PC-Seite auf Ascii
> einstellen.
Der Empfänger steht auf ASCII, Terminal ist wxTerm.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du könntest Dir das Leben erheblich einfacher machen, wenn Du auf die 
Funktion ausgabe_wert komplett verzichtest. Die brauchst Du gar nicht.

Schreib' einfach anstelle von
1
Wert = ASCII[1];  ausgabe_wert();
2
Wert = ASCII[10]; ausgabe_wert();
3
Wert = ASCII[2];  ausgabe_wert();
4
Wert = ASCII[3];  ausgabe_wert();
5
Wert = ASCII[4];  ausgabe_wert();

das hier:
1
UART_SendByte('1');
2
UART_SendByte('.');
3
UART_SendByte('2');
4
UART_SendByte('3');
5
UART_SendByte('4');

von Arne (Gast)


Lesenswert?

Rufus t. Firefly schrieb:
> Du könntest Dir das Leben erheblich einfacher machen, wenn Du auf die
> Funktion ausgabe_wert komplett verzichtest.

Bei aber 30 Senderoutinen ist der Speicher des Attiny2313 total voll.
Darum wollte ich mir ein Array generieren und den Inhalt des Arrays 
"fast" dynamisch zuweisen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hä? Welche 30 Senderoutinen?

von Arne (Gast)


Lesenswert?

Rufus t. Firefly schrieb:
> Hä? Welche 30 Senderoutinen?
Der Mikrocontroller hört auf Zeichen.
Je nachdem, welches Zeichen an ihn gesendet wird, gibt der einen Wert 
aus.
Übrigens, seit der Umstellung auf '0','1', usw. funktioniert gar nichts 
mehr. ;(

von Grrrr (Gast)


Lesenswert?

Rufus t. Firefly schrieb:
>> Hä? Welche 30 Senderoutinen?
>Der Mikrocontroller hört auf Zeichen.
>Je nachdem, welches Zeichen an ihn gesendet wird, gibt der einen Wert
>aus.

Das mag ja sein, aber was hat das mit der Frage nach den 30 
Senderoutinen zu tun?

Eine Senderoutine sendet Zeichen. Eine Routine, die Eingabezeichen 
verarbeitet und abhängig davon jeweils eine bestimme Ausgabe erzeugt ist 
keine Senderoutine.

Auch ist mir die Begründung nicht klar. Es ist Speichermäßig (RAM) 
völlig egal, ob Du nun mit Index einen Wert aus einem Array lädst und 
dann sendest oder direkt den Wert angibst.

Abgesehen davon, ist es eher unwahrscheinlich, das ein uC auf eine 
Anfrage mit einen konstanten String antwortet. Die Antwort könnte sich 
dann der PC nämlich selbst geben ohne den uC zu bemühen, weil sie 
konstant ist.
Vermutlich willst Du also etwas ganz anderes tun und hast das nur nicht 
geschrieben.

Die übliche Antwort darauf ist: "Ich wollte nur mal was ausprobieren. 
Das ist noch nicht das richtige Programm". OK. Aber dann hast Du das 
eigentliche Problem noch garnicht erkannt oder Dich bei der Analyse 
geirrt und auf ein irrelevantes Detail konzentriert.

Wozu also genau, willst Du den auszugebenden Wert aus einem Array holen?

von mano (Gast)


Lesenswert?

Arne schrieb:
> Rufus t. Firefly schrieb:
>> Hä? Welche 30 Senderoutinen?
> Der Mikrocontroller hört auf Zeichen.
> Je nachdem, welches Zeichen an ihn gesendet wird, gibt der einen Wert
> aus.
> Übrigens, seit der Umstellung auf '0','1', usw. funktioniert gar nichts
> mehr. ;(

schau dir mal die uart echo Beispiele an. Eine geringfügige Änderung 
macht wahrscheinlich das, das Du möchtest.

von Arne (Gast)


Lesenswert?

Rufus t. Firefly schrieb:
> Nun, Du gibst also den Zahlenwert aus, der in "Wert" steht.
>
> Was also passiert?
>
>    Wert = ASCII[1];  ausgabe_wert();
>
> Wert wird hier auf 0 gesetzt. Folglich wird auch ein String mit dem
>
> Inhalt "0" gesendet.
>
>    Wert = ASCII[10]; ausgabe_wert();
>
> Das hier setzt Wert auf '.', das ist dezimal 46.
>
> Folglich wird ein String mit dem Inhalt "46" gesendet.

Uuups, habe diesen Beitrag komplett überlesen.
Dann ist auch einiges klar.
Der Punkt wird dezimal übertragen: 46
Und da bei ASCII jedes Zeichen einzeln übertragen wird, bekomme ich auch 
erst eine 4 und dann eine 6.

Grrrr schrieb:
> Wozu also genau, willst Du den auszugebenden Wert aus einem Array holen?
Ich hatte am Anfang Werte dem INT Wert direkt zugewiesen.
Also:
Wert = 1234;
Wert = 1.234;
Wenn der Mikrocontroller ein Zeichen empfangen hat, soll dieser einen 
dazugehörigen Wert ausgeben. Wenn beispielsweise ein 'a' empfangen wird, 
soll 1234 ausgegeben werden, bei 'b' 1.234 usw.
Macht bei einem Alphabet mindestens 26 Wertzuweisungen.
Bei direkter Zuweisung ist der Programmspeicher im Attiny2313 über 100% 
voll, der Datenspeicher bei etwas mehr als 15%.
Mit der Zuweisung mittels Array ist der Programmspeicher deutlich 
gesunken ca. 40%, der Datenspeicher auf ca. 17% gewachsen.
Darum halt die Zuweisung mittels Array.

Kann ich denn irgendwie ein Punkt als "Punkt" per ASCII übertragen, ohne 
dass der Punkt dezimal beim Empfänger landet?
Ich glaub, meine Senderoutine macht murks.

von Karl H. (kbuchegg)


Lesenswert?

Arne schrieb:

> Ich glaub, meine Senderoutine macht murks.

Du hast noch nicht verinnerlicht, dass
1234
und
"1234"
2 voneinander grundverschiedene Dinge sind.

Das eine ist die Zahl 1234. Mit der kann man rechnen, die ist entweder 
gerade oder ungerade usw. Eine richtige Zahl eben.
Das andere ist ein String. So wie "Herbert Müller" ein String ist. 
Zusammengesetzt aus einzelnen Zeichen. Nur das bei dir die Zeichen 
zufällig die Zeichen '1' '2' '3' '4' sind.

Jedes Zeichen ist aber selber wieder eine Zahl. In einem Computer ist 
alles eine Zahl! Für jedes Zeichen wurde eine Zahl definiert, die für 
dieses Zeichen steht. Das ist der ASCII Code.

Will Computer 1 das Zeichen 'A' an Computer 2 schicken, so schickt er 
ihm die Zahl 65. Dies deswegen, weil im ASCII Code definiert ist, dass 
65 für 'A' steht. Computer 2 ist nun so programmiert, dass er wenn er 65 
empfängt, dafür ein 'A' auf den Bildschirm malt.
Für einen Aussenstehenden sieht es daher so aus, als ob Computer 1 an 
Computer 2 ein 'A' gesendet hätte. Tatsächlich sind aber Zahlen hin und 
her gegangen und nur deswegen, weil sich beide Parteien darüber einig 
sind, dass jede Zahl laut ASCII Code für ein Zeichen steht, gibt es 
keine Probleme.

Im Moment versuchst du den Spaghat:
Du möchtest Zahlen als Zahlen senden und empfangen aber andere Zeichen 
in ihrem ASCII Code. Und damit beginnt dann der Tragödie erster Teil.

von mano (Gast)


Lesenswert?

Arne schrieb:
> Dann ist auch einiges klar.
> Der Punkt wird dezimal übertragen: 46
> Und da bei ASCII jedes Zeichen einzeln übertragen wird, bekomme ich auch
> erst eine 4 und dann eine 6

Nein, dir ist nichts klar!!!

Schau dir C-Strings (Arrays, Pointer usw., also C-Grundlagen), was es 
mit ASCII auf sich hat und hier das AVR-GCC-Tutorial/Der UART an.

von Arne (Gast)


Lesenswert?

mano schrieb:
> Nein, dir ist nichts klar!!!

Bleib mal locker.
Ich habe NICHT geschrieben, dass MIR etwas klar geworden ist!



Karl heinz Buchegger schrieb:
> Du möchtest Zahlen als Zahlen senden und empfangen aber andere Zeichen
>
> in ihrem ASCII Code. Und damit beginnt dann der Tragödie erster Teil.

Sende ich 0,1,2,3 usw., kommen die Zahlen im Empfänger an. Schalte ich 
auf dezimale Sicht beim Empfänger, sehe ich für die 0 eine 48, für eine 
1 eine 49 usw.
Sende ich '0','1','2','3', usw. wird die Zahl dezimal übertragen, also 
für eine 0 erst die 4, dann die 8 usw.

von Karl H. (kbuchegg)


Lesenswert?

Arne schrieb:

> Sende ich 0,1,2,3 usw., kommen die Zahlen im Empfänger an.

Ja. Aber nur deshalb, weil du senderseitig noch ein utoa dazwischen 
hast. utoa macht genau die Transformation.
Aus 1234 macht es "1234"
Also aus einer Zahlendarstellung eine Textdarstellung. Du hast aber bei 
'.' schon die Textdarstellung! Also darfst du '.' nicht mehr durch den 
utoa durchschicken!

von Arne (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ja. Aber nur deshalb, weil du senderseitig noch ein utoa dazwischen
> hast. utoa macht genau die Transformation.
> Aus 1234 macht es "1234"
> Also aus einer Zahlendarstellung eine Textdarstellung. Du hast aber bei
> '.' schon die Textdarstellung! Also darfst du '.' nicht mehr durch den
> utoa durchschicken!

Vielen Dank! Mit dieser Information kann ich weiter arbeiten!
Das, was utoa macht, werde ich mir für die Zukunft merken!

von Karl H. (kbuchegg)


Lesenswert?

Arne schrieb:

> Vielen Dank! Mit dieser Information kann ich weiter arbeiten!
> Das, was utoa macht, werde ich mir für die Zukunft merken!

Du solltest lieber mit einem C-Buch die Dinge systematisch am PC 
erkunden.

von P. S. (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:

> Du solltest lieber mit einem C-Buch die Dinge systematisch am PC
> erkunden.

Du ueberraschst mich, du nimmst dir gerade den ganzen Spass :-/

von Arne (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du solltest lieber mit einem C-Buch die Dinge systematisch am PC
> erkunden.

Manche Bücher sind aber genau so schlecht wie viele Antworten hier im 
Forum.

von mano (Gast)


Lesenswert?

Arne schrieb:
> mano schrieb:
>> Nein, dir ist nichts klar!!!
>
> Bleib mal locker.
> Ich habe NICHT geschrieben, dass MIR etwas klar geworden ist!

Sorry, wenn das für dich bissl krass rüber kam. Und Du hast Recht, ich 
habe gedanklich irgendwie noch ein "mir" in den Satz gebaazt.


Trotzdem ändert das nicht daran, dass dir C-Grundlagen fehlen.

von Karl H. (kbuchegg)


Lesenswert?

Arne schrieb:
> Karl heinz Buchegger schrieb:
>> Du solltest lieber mit einem C-Buch die Dinge systematisch am PC
>> erkunden.
>
> Manche Bücher sind aber genau so schlecht wie viele Antworten hier im
> Forum.

Mag sein.
Wenn aber jemand Code präsentiert, den man dann des langen und breiten 
durchkauen muss und am Ende steht dann die Aussage "Ach, dazu ist diese 
Funktion gut!", dann ist ziemlich klar, dass er noch nicht einmal ein 
schlechtes Buch durchgekaut hat.

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.