Forum: Compiler & IDEs atoi oder char zu integer - Anfängerfrage


von Henri G. (hene42)


Lesenswert?

Hallo, ich habe folgenden Code auf einem Atmega8 (Ausschnitt):
1
unsigned int empfi;
2
3
empfi = uart_getc();
4
 if ( empfi & UART_NO_DATA )
5
  {
6
   // keine Daten erhalten
7
  }
8
 else
9
  {
10
   uart_putc( (unsigned char)empfi );

an meinem PC wird jetzt eine Zahl zwischen 0-255 ausgegeben.

jetzt möchte ich mit dem Wert "empfi" auf meinem Atmega8 Berechnungen
durchführen (z.B.: empfi=empfi-10).
Wie/oder Was muss ich mit "empfi" machen damit ich solche Berechnungen 
durchführen kann?

Danke.

von Max H. (hartl192)


Lesenswert?

Henri Großmann schrieb:
> Wie/oder Was muss ich mit "empfi" machen damit ich solche Berechnungen
> durchführen kann?
1
empfi=empfi-10;

von 16 Bit oder mehr (Gast)


Lesenswert?

Besser aus empfi einen empfuint8_t machen. 8 Bit reichen.

von Chris L. (kingkernel)


Lesenswert?

Wenn uart_getc aber 16 bit zurück gibt, wobei die oberen 8 bit als 
Statusbits verwendet werden, dann reichen 8 bit nicht. UART_NO_DATA ist 
so ein Statusbit, das man verwendet, um zu erkennen ob überhaupt Daten 
empfangen wurden!

von 16 Bit oder mehr (Gast)


Lesenswert?

Dann sollte man mit Wert nicht einfach rechnen. Ist irgendwie ein 
Widerspruch.

von Henri Großmann (Gast)


Lesenswert?

Hallo,  das mit einfach rechnen wie z.b. empfi = empfi-10 funktioniert 
nicht.
Kommt immer mist raus.

von Kaj (Gast)


Lesenswert?

Chris L. schrieb:
> Wenn uart_getc aber 16 bit zurück gibt, wobei die oberen 8 bit als
> Statusbits verwendet werden, dann reichen 8 bit nicht.

16 Bit oder mehr schrieb:
> Dann sollte man mit Wert nicht einfach rechnen.

Henri Großmann schrieb:
> Hallo,  das mit einfach rechnen wie z.b. empfi = empfi-10 funktioniert
> nicht.
> Kommt immer mist raus.
Statusbits loeschen...
1
uint16_t empfi;
2
3
empfi = uart_getc();
4
5
// statusbits loeschen
6
empfi = empfi & 0x00FF; // wenn die statusbits im oberen Byte stehen, sonst
7
                        // mit 0xFF00 verunden
8
empfi = empfi - 10;

von 16 Bit oder mehr (Gast)


Lesenswert?

Henri Großmann schrieb:
> Hallo,  das mit einfach rechnen wie z.b. empfi = empfi-10
> funktioniert nicht.
> Kommt immer mist raus.

Pack den cast mit rein
 empfi = (unsigned char)empfi - 10;

von Karl H. (kbuchegg)


Lesenswert?

'Kaj' schrieb:

> empfi = empfi & 0x00FF; // wenn die statusbits im oberen Byte stehen,
> sonst

sie stehen im oberen Byte und man braucht sie nicht löschen, da sie 0 
sind, solange UART_NO_DATA nicht gesetzt ist. Abgesehen davon strippt 
uart_putc sowieso das High-Byte raus.

'16 Bit oder mehr' schrieb

> Pack den cast mit rein
Man braucht auch nichts casten. Du bellst den völlig falschen Baum an.

@Henri
> Kommt immer mist raus.

Definiere 'Mist'.

Was sendest du dem µC und was erwartest du?
Dir ist hoffentlich klar, dass du hier eine Binärübertragung hast. D.h. 
du sendest Bytes.
Wenn du vor einem Terminal sitzt und dort auf der Tastatur 173 tippst, 
dann wird nicht 1 Byte mit dem Wert 173 übertragen, sondern es werden 3 
Bytes übertragen: eines mit dem ASCII Code für '1', eines mit dem ASCII 
Code für '7' und eines mit dem ASCII Code für '3'. Und ein 4.tes Byte 
wirst du dann auch noch brauchen, denn der µC kann ja nicht riechen, 
dass du nach den Tasten 1 und 7 noch die 3 drücken wirst. Das 4.te Byte 
brauchst du also um anzuzeigen: jetzt ist alles übertragen.
Auf dem µC musst du die Bytes wieder zusammensetzen, daraus eine Zahl 
machen, davon 10 abziehen und dann aus der neuen Zahl wieder einen Text 
machen, den du dann zurück schickst, damit im Terminal die 'Zahl' (die 
eigentlich auch nur ein Text ist) aufleuchtet und dein Gehirn 163 liest.

Wenn das nicht das ist, was du machen willst, dann definiere 'Mist'; wie 
du feststellst, das Mist rauskommt und ob du eigentlich deine UART 
insofern schon getestet hast, dass die Übertragung (Taktfrequenz, 
Baudrate) überhaupt korrekt funktioniert.

: Bearbeitet durch User
von Henri G. (hene42)


Lesenswert?

@Karl Heinz

Hallo, erst einmal Danke für deinen langen Text...
Hier nochmal eine etwas genauere Angabe von mir.

Ich sende von einem Visual Basic Programm auf meine PC einen Wert an den 
µC,
und zwar so...
1
Dim data As Integer
2
data = 128
3
SerialPort1.Write(data)

im µC Empfange ich die Daten (über USB -> UART) und gebe die Daten 
danach zurück...
1
while (1) 
2
{
3
empfi = uart_getc();   // Daten empfangen
4
if ( empfi & UART_NO_DATA )
5
{
6
// keine Daten erhalten
7
}
8
else
9
{
10
uart_putc( (unsigned char)empfi );   // Daten zurück senden
11
}

jetzt empfange ich die Daten wieder mit meinem Visual Basic Programm auf 
dem PC...
1
PufferString = SerialPort1.ReadExisting()
2
RichTextBox1.AppendText(PufferString)

Jetzt wird auf meinem PC GENAU die Zahl angezeigt welche ich vom PC zu 
µC gesendet habe.
Das sagt mir die Übertragung von PC zu µC und zurück Funktioniert.
Jetzt möchte ich jedoch auf dem µC mit dieser Zahl (z.B.: 128) 
verschieden Port's schalten...
1
if (empfi > 127)
2
{
3
PORTB |= (1<<PB5);  // Port B5 ein
4
empfi = empfi -128;   // rest von empfi
5
}
6
else
7
{
8
PORTB &= ~(1<<PB5);   // Port B5 aus
9
}

So wo ist nun mein Denkfehler, lass mich gerne belehren beschäftige mich 
ja
auch erst ca. 2 Wochen mit µC.

Danke an alle die mir weiterhelfen können, und dies auch machen...

von Karl H. (kbuchegg)


Lesenswert?

> RichTextBox1.AppendText(PufferString)

Text?

Sobald Text im Spiel ist, funktioniert alles ein wenig anders.

Du musst dir erst mal klar machen, dass es einen UNterschied zwischen 
binärer Übertragung und textueller Übertragung gibt.

Klar. Texte werden ebenfalls übertragen, in dem Bytes auf die Reise 
gehen. Der UNterschied ist dann eben der, dass bei einer rein binären 
Übertragung ein Byte-WErt von zb 32 für die Zahl 32 steht, während er 
bei einer Text-Übertragung nach ASCII für ein Leerzeichen steht (weil 
der ASCII COde für ein Leerzeichen nun mal 0x20 oder eben dezimal 32 
ist).

Sobald Texte im Spiel sind, gibt es keinen prinzipiellen UNterschied 
zwischen dem Text "168" und "Hugo". Beides sind auf der 
Übertragungsebene einfach nur Texte, die Buchstabe für Buchstabe 
übertragen werden.
Dass das Programm, welches am jeweils anderen Ende der Leitung mit 
diesem Text etwas spezielles macht, ist eine andere Sache - betrifft 
aber die reine Textübertragung nicht.

> Jetzt wird auf meinem PC GENAU die Zahl angezeigt welche ich vom PC zu µC 
gesendet habe.

Nein. Es wird nicht die Zahl angezeigt. Es wird der Text (bestehend aus 
mehreren 'Buchstaben') angezeigt. Das das mal eine Zahl war, das 
entsteht erst in deinem Gehirn, welches dem Text "168" eine besondere 
Bedeutung (nämlich den einer Zahl) zuweist. Aus Sicht der UART 
unterscheidet sich der Text "168" vom Text 
"Supercalifragilisticexpialidocious" nur in der Anzahl der Buchstaben 
und der Auswahl der verwendeten Buchstaben. Aber Text ist Text und der 
hat als solcher keine Bedeutung. Vor allen Dingen nicht den, eine Zahl 
zu sein, mit der man rechnen könnte. Man kann natürlich auf µC Seite aus 
dem Text "168" wieder eine Zahl machen und dann mit der rechnen. Kann 
man, aber erst mal ist das einfach nur Text und sonst nichts.

: Bearbeitet durch User
von Henri G. (hene42)


Lesenswert?

Danke, aber hättest du eventuell noch einen kleinen Tipp wie ich
das am besten mache mit dem Text zu Zahl?

Habe schon viel mit atoi probiert will aber irgendwie nicht so wie 
ich...
Und wäre dann so eine Abfrage möglich/richtig?
1
if (empfi > 127)
2
{
3
PORTB |= (1<<PB5);
4
empfi = empfi -128;
5
}
6
else
7
{
8
PORTB &= ~(1<<PB5);
9
}

Danke.

von Karl H. (kbuchegg)


Lesenswert?

Henri Großmann schrieb:
> Danke, aber hättest du eventuell noch einen kleinen Tipp wie ich
> das am besten mache mit dem Text zu Zahl?

zuallererst brauchst du eine Kennung, mit der du feststellen kannst: 
hier ist der Text zu Ende.

D.h. der PC kann nicht einfach nur den Text "12" senden. Denn niemand 
kann (auch der µC nicht) wissen, ob nach den Zeichen '1' und '2' noch 
etwas kommt, oder ob das schon der ganze Text war. Kann ja sein, dass 
der PC den Text "12" wegschicken wollte. Kann aber auch sein, dass da 
noch eine 4 kommt, und der ganze Text in WIrklichkeit "124" darstellen 
soll.

Auf der anderen Seite des Kabels kann man nun mal nicht mehr 
unterscheiden, ob diesseits
1
  SerialPort1.Write( "123" );
stattgefunden hat, oder
1
  SerialPort1.Write( "1" );
2
  SerialPort1.Write( "2" );
3
  SerialPort1.Write( "3" );

In beiden Fällen wird dasselbe übertragen. Nämlich nacheinander die 
Zeichen '1', '2' und '3'.

Fazit: Ohne Zusatzinformation geht das nicht.
Dein VB Programm muss also nachdem es den
1
  SerialPort1.Write(data)
noch etwas nachschieben. Ein Zeichen, welches in den Daten selbst nicht 
vorkommt, woran aber der µC erkennen kann 'Huch: jetzt ist der Text zu 
Ende, da kommt nichts mehr'

zb könnte dein VB Programm irgendein Sonderzeichen nachschieben. Ich 
nehm man einen ';'
1
  SerialPort1.Write(data)
2
  SerialPort1.Write(";")

so. Damit ist klar, dass (in deinem Fall), die Zeichen '1', '2', '8' und 
dann eben noch ein ';' über die Leitung geschoben werden.

Und die musst du eben wieder zusammensetzen.
Das kann man jetzt natürlich machen, in dem man die Zeichen in einem 
char-Array sammelt. Kann man, muss man aber in deinem speziellen Fall 
nicht. Denn in deinem Fall wissen wir, das (abgesehen vom ';') das ganze 
eine Zahl darstellen soll. Und bei Zahlen geht das ganz einfach.
Ausgehend von zb 8, wie hängst du da die nächste Ziffer (sagen wir mal 
eine '3' ran), so dass aus den 8 die 83 entstehen? Na, ganz einfach: 
wenn du das nächste Zeichen hast, dann nimmst du die 8 einfach mal 10 
und addierst noch den Zahlenwert für 3. So werden aus den 8 durch 8 * 10 
+ 3 die 83. Und aus den 83 werden mit der nächsten Ziffern 4 die 834, 
indem du die 83 mal 10 nimmst und noch 4 addierst.

D.h. deine Strategie lautet:
Hole das nächste Zeichen von der UART, falls eines vorhanden ist
Ist dieses nächste Zeichen ein ';', dann bedeutet das, das die 'Zahl' 
(in Textform) komplett übertragen wurde. D.h. man kann die Zahl 
bearbeiten und damit irgendwas machen (zb 10 subtrahieren und zurück 
schicken)
Ist das nächste Zeichen kein ';' dann geht die Zahl weiter und dieses 
Zeichen muss in die Zahl eingerechnet werden.
1
int main()
2
{
3
  char buffer[10];
4
5
  .....
6
7
  zahl = 0;
8
9
  while( 1 )
10
  {
11
    empfi = uart_getc();
12
13
    if ( !( empfi & UART_NO_DATA ) )     // gibt es ein Zeichen?
14
    {
15
      char c = empfi;          // High Byte loswerden und nur den char übrig lassen
16
      if( c == ';' )
17
      {
18
        // mach was mit der Zahl
19
        zahl = zahl - 10
20
        itoa( zahl, buffer, 10 );
21
        uart_puts( buffer );
22
        uart_puts( ';' );
23
        zahl = 0;
24
      }
25
      else
26
      {
27
         // sicherheitshalber, auch wenn es nie vorkommen sollte
28
        if( isdigit( c ) )
29
          zahl = zahl * 10 + ( c - '0' );
30
      }
31
    }
32
  }


und teste das Ganze erst mal mit einem gewöhnlichen Termninalprogramm 
anstelle einem VB Programm. Du beginnst gerade einen 2-Fronten Krieg, in 
dem du nicht weißt ob deine Programmfehler auf µC-Seite oder auf 
VB-Seite zu suchen sind. Soweit bist du noch nicht, dass du das in einem 
Aufwasch handhaben könntest. In derartigen 2-Fronten Kriege sind schon 
ganz andere Kapazunder als von deinem Kaliber gnadenlos untergegangen.
Also. Entwickle erst mal so, dass du auf PC Seite ein Terminal-Programm 
hast und du deine Eingaben mit der Hand machst. Dann weißt du auch, was 
tatsächlich über die Schnittstelle rausgeht bzw. zurück kommt und musst 
nicht raten, ob dein VB Programm das alles tatsächlich so erzeugt, wie 
es das sollte, bzw. was tatsächlich über die Schnittstelle rausgeht 
(dafür wäre auch zb die Installation eines Serial Port Monitors eine 
ausgesprochen gute Idee)

: Bearbeitet durch User
von Henri G. (hene42)


Lesenswert?

Hallo, soweit versteh ich das jetzt ein wenig.
Der Code von dir funktioniert auch soweit, aber wie zum Teufel bekomme 
ich jetzt den Wert (Zahl) welche sich im char c befindet zu einem 
Integer (genau wie Zahl in deinem Beispiel).


Danke.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was vermustest Du, macht dieser Codeabschnitt hier?

> if( isdigit( c ) )
>           zahl = zahl * 10 + ( c - '0' );

von Henri G. (hene42)


Lesenswert?

NEIN, NEIN, NEIN bin ich blöd....

Alles klar ich hab jetzt den Durchblick, alles funktioniert wie es soll.

Ich bedanke mich sehr bei

Karl Heinz

sowie

Rufus Τ. Firefly (für den letzten Tipp zum verstehen)

Danke, mein Problem ist gelöst.

P.S.: warum steht da "zahl * 10", versteh ich nicht

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Henri Großmann schrieb:
> warum steht da "zahl * 10", versteh ich nicht

Damit du alle Ziffern deiner Zahl mit einrechnest.
Dezimalzahl hat was mit 10 zu tun.

Probier es doch mal aus mit 123
Du bekomst erst die Ziffer '1' und zahl = 0

zahl =  0 * 10 + ('1' - '0') =   0 + 1 = 1
zahl =  1 * 10 + ('2' - '0') =  10 + 2 = 12
zahl = 12 * 10 + ('3' - '0') = 120 + 3 = 123

fertig

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.