-         

Ergebnis 1 bis 9 von 9

Thema: atoi() Probleme - String in Integer wandeln

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19

    atoi() Probleme - String in Integer wandeln

    Anzeige

    Hallo,

    ich möchte eine Zeichenkette die in dem Char Array "pc_data" enthalten ist in eine Integer Zahl umwandeln, die ich beispielweise einem Register (in diesem Fall PortB=i_value) zuweisen möchte. Ich sende vom Pc aus einen String, der Zahlen von 0-255 enhält: z.B. "7" oder "132".

    Für Zahlen von 0-9 funktioniert das auch ganz gut. Die Zahlen werden mit atoi() umgewandelt und PortB=i_value zugewiesen. Sind die Zahlen aber größer als 9 erzeugt atoi() irgendwie nix brauchbares. Bei der Zahl 10 wird scheinbar in 1 und 0 aufgeteilt. Die Zahl 123 wird scheinbar in 1 und 23 aufgeteilt.

    Das Programm ist im Moment zunächst erst eine Vorstufe zu einer einfachen Protokollimplementation. Ich will zunächst erst einmal testen, wie ich denn aus Strings Integer-Werte erzeugen kann.

    Wie müßte ich denn mein Porgramm verändern damit es richtig funktioniert. Es wäre schön wenn mir da jemand helfen könnte.

    Hier mein Quelltext:
    Code:
    #include <stdio.h>
    #include <stdlib.h> 
    #include <ctype.h>
    #include <avr/io.h>
    #include <avr/delay.h>
    #include <avr/interrupt.h>
    #include <avr/signal.h>
    
    char pc_data[3];
    char *pointer=pc_data;
    unsigned char receive_char;
    unsigned char sendflag;
    
    // Initialisierung UART
    void uart_init (void)
    {
    /* USART-Init 38400 Baud bei 8MHz für Mega32 */
      UCSRB = ( (1<<RXCIE) | (1<<RXEN) | (1<<TXEN) );
    /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
      UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
      UBRRH  = 0;                                   // Highbyte ist 0
      UBRRL  = 12;                                  // Lowbyte ist 51 ( dezimal )
    }
    
    // Zeichen senden
    int uart_putc(unsigned char c)
    {
        while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich */
        UDR = c;                      /* sende Zeichen */
        return 0;
    }
    
    // String senden 
    void uart_puts (char *s)
    {
        while (*s)
        {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
            uart_putc(*s);
            s++;
        }
    }
    
    //Zeichen empfangen 
    uint8_t uart_getc (void)
    {
        while (!(UCSRA & (1<<RXC)));  // warten bis Zeichen verfuegbar
        return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
    }
    
    SIGNAL (SIG_UART_RECV)
    {
      receive_char=1;
    }
    
    // Erzeugt ASCII-Werte und sendet diese and den PC
    void toascii_8 (uint8_t uvalue)
    {
    char pos1=0;
    char rest1=0;
    char pos2=0;
    char pos3=0;
    
    pos1=uvalue/100;
    uart_putc(pos1+48);
    rest1=uvalue%100;
    pos2=rest1/10;
    uart_putc(pos2+48);
    pos3=rest1%10;
    uart_putc(pos3+48);
    uart_putc(' ');
    }
    
    
    int main()
    {
      
      uint8_t var;
      uint8_t i;
      uint8_t i_value;
      
      DDRB=255;
      PORTB=0;
      
      uart_init();
      sei(); 
      i=0;
       
        while (1)
        {
        	if(receive_char==1)
        	{
        	while (!(UCSRA & (1<<RXC)));
        	{
        		pc_data[i]=UDR;
        		i++;
        		if(i>2)
        		{
        			i=0;
        		}    		
        	}
        	receive_char=0;
        	sendflag=0;
        	}
        	
        	if(receive_char==0&&sendflag==0)
        	{
        		//uart_puts(pc_data);
        		//i_value=atoi(pointer);  //Funktioniert auch nicht richtig
    		
    		i_value=atoi(pc_data); 
        		PORTB=i_value;
        		toascii_8(i_value); //Ausgabe als ASCII
        		i=0;
        		sendflag=1;
        	}
        }  
    }

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    17.01.2005
    Ort
    Obertraun
    Alter
    29
    Beiträge
    194
    Kann es sein, dass du im String pc_data die null-Terminierung vergessen hast??

    Es kann auch sein, dass ich es überlesen habe, aber aufgefallen ist es mir eigentlich nicht ...

  3. #3
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    pc_data ist auf jeden falls zu kurz mit 3 Elementen.
    Die Zahlen können 3-Stellig sein und die Ende-Null muss reinpassen.

    Was die Null angeht hat skilli schon gesagt.

    receive_char muss hier als volatile (flüchtig) definiert werden.
    Disclaimer: none. Sue me.

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    18.03.2005
    Beiträge
    52
    Hi

    Also ich weiß nicht genau wie es auf einem microcontroller ist,
    aber in "normalem" c ist atoi so implementiert:

    string=atoi(zahl,string,int);

    string : ist ein Pointer auf char
    zahl: ist die Zahl die du umwandeln willst
    int: ist das zahlensystem in das du wandeln willst, also in deinem fall 10


    Mfg Reinhold Fischer

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19
    Hallo,

    danke für Eure schnell Hilfe. An eine Null-Terminierung habe ich natürlich nicht gedacht. Was muss ich denn da genau machen? Muss ich bei meinem String ein Terminierungszeichen mitsenden? Wenn ja, muss ich dieses Terminierungszeichen wieder entfernen, bevor ich atoi() anwende?
    Also ich müßte auf jeden Fall das pc_data Feld mit mindestens 5 Elementen ausstatten.

    @Crash32
    Vielen Dank für Deine Hilfe, aber Du verwechselst die Syntax wahrscheinlich mit itao().

  6. #6
    Benutzer Stammmitglied
    Registriert seit
    18.03.2005
    Beiträge
    52
    Hi

    Ja, hast recht, hab das was verwechselt, lag vielleicht an der Uhrzeit.
    Ich mußte gestern mal wieder einen Marathon einlegen, ging noch bis halb 4

    Wegen der Null-Terminierung:

    Ja, du mußt ein Terminierungszeichen mitsenden.

    Oder du sendest jeden String ohne terminierungszeichen, und hängst es dann manuell an jeden String den du empfangen hast.Ist vielleicht besser, bei niedriger Bandbreite, man "spart" sich quasi bei jedem senden ein Zeichen.

    Am besten ist es wenn du jeden String immer nullterminierst, z.b du hängst "\0" al letztes zeichen hintendran. So übergibst du den String auch an atoi.
    Wenn du z.b itoa benutzt, bekommst du auch einen Null-terminierten String zurück.

    Mfg Reinhold Fischer

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19
    Hallo,

    ich habe die Nullterminierung jetzt meines Wissens nach richtig eingebaut, aber habe trotzdem weiterhin das gleiche Problem, dass die Zahlen ausgeteilt werden. Es wird am Ende immer nur die letzte Stelle zugewiesen. Schicke ich "10" so ist i_value=0, bei einer "11" ist i_value=1, bei einer "110" ist komischerweise i_value=10.
    Ich bin nun echt ratlos woran das liegt und wie ich dsa Porblem beheben kann.

    Meine Änderungen:
    char pc_data[5];
    volatile unsigned char receive_char;

    Meine main() sieht jetzt so aus:
    Code:
    int main()
    {
      
      uint8_t var;
      uint8_t i;
      uint8_t i_value;
      
      DDRB=255;
      PORTB=0;
      
      uart_init();
      sei(); 
      i=0;
       
        while (1)
        {
        	if(receive_char==1)
        	{
        	while (!(UCSRA & (1<<RXC)));
        	{
        		pc_data[i]=UDR;
        		i++;
        		if(i>2)
        		{
        			i=0;
        		}    		
        	}
        	//pc_data[3]='\0';
        	receive_char=0;
        	sendflag=0;
        	}
        	
        	if(receive_char==0&&sendflag==0)
        	{
        		//uart_puts(pc_data);
        		//i_value=atoi(pointer);  //Funktioniert auch nicht richtig
    		pc_data[3]='\0';
    		i_value=atoi(pc_data); 
        		PORTB=i_value;
        		toascii_8(i_value); //Ausgabe als ASCII
        		i=0;
        		sendflag=1;
        	}
        }  
    }

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    17.01.2005
    Ort
    Obertraun
    Alter
    29
    Beiträge
    194
    Ich glaube ich weiß jetzt was dein Problem ist

    [Code]
    while (!(UCSRA & (1<<RXC)));
    [\Code]
    Ist der Strichpunkt am Ende der Zeile Absichtlich?


    Mir kommt vor, dass dein Programm eher kompliziert/Umständlich geschriben ist... zumindest ist das meine Ansicht.

    Wieso fragst du überhaupt das bit RXC aus??? das Bit braucht man doch normalerweise gar nicht wenn man den UART_RECV Interrupt verwendet, oder täusche ich mich da?

    Wieso liest du das UDR nicht in der Interrupt-Routine aus(z.B. könntest du es in das Array pc_data speichern) und setzt dir ein Flag, wenn du 3 Zeichen empfangen hast.
    Wenn dieses Flag gesetzt ist wertest du das Array pc_data im Hauptprogramm aus.(Null Terminierung hinzufügen und atoi() aufrufen)
    So, würde ich das halt schreiben, ist eine Möglichkeit und muss nicht umbedingt die Beste sein ...

    So, ich hoffe ich habe mich halbwegs verständlich ausgedrückt.

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    07.02.2006
    Ort
    Weimar
    Beiträge
    19
    Hallo Skillii,
    vielen Dank für Deine Hilfe. Ich habe jetzt Deine Hinweise beachtet und mein Programm umgbaut, sodass es jetzt bei einer festen Stringlänge funktioniert. Wahrscheinlich lag es doch an der Abfrage von "while (!(UCSRA & (1<<RXC)));". Die habe ich jetzt komplett weggelassen und das pc_data Array wird nun in der Interrupt-Routine mit Daten gefüllt.
    Vielen vielen Dank nochmal.

    Viele Grüße
    Hendrik

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •