www.mikrocontroller.net

Forum: Compiler & IDEs String mit Uart empfangen


Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich versuche gerade eine ATMega32 mit C zu programmieren. Mein Problem 
ist nun, dass ich vom Hyperterminal einen string an den Controller 
senden will. Die Eingabe sollte mit der Entertaste beendet werden.
Ich habe mir nun folgendes überlegt:

unsigned char empfangen()
{
  unsigned char receive;
  int i=0;
  while (uart_getc_wait()!=10)
  {
    receive[i]=UDR;
    i++;
  }
  receive[i]='\0';
return receive;

Diesen String möchte ich dann später wieder auf dem Hyperterminal 
ausgeben. Dafür habe ich schon eine Funktion geschrieben die mir beim 
Aufruf senden_string("test"); test auf dem Bildschirm ausgibt.
Leider funktioniert die Sache mit dem empfangen nicht richtig.
Sieht jemand meinen Fehler, oder kann mir jemand einen Code-Vorschlag 
schicken´, mit dem ich nicht nur einzelne Zeichen empfangen kann??
Danke schonmal für die Hilfe!

Autor: remote1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hab so was auch schon mal gemacht:
#ifndef F_CPU
#define F_CPU 16000000           
#endif

#define BAUD 19200UL //Baudrate 
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)


#define length 10  //Textlänge ab welcher Empfangen beendet wird


void uart_init(void)
{
  UCSRB = (1<<RXEN)|(1<<TXEN);      // UART TX und RX einschalten    
    UCSRC |= ( 1 << URSEL )|( 3<<UCSZ0 );  // Asynchron 8N1
  //nur für 19200 Baud bei 16MHz für Mega32
    UBRRH  = 0;                             // Highbyte ist 0
    UBRRL  = 51;                            // Lowbyte ist 51
  
  //falls anderer Mega bzw andere Frequenz
  //UBRRH = (uint8_t) (UBRR_BAUD>>8);
    //UBRRL = (uint8_t) (UBRR_BAUD & 0x0ff);
} 

void uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE))) {}  // warten bis Senden möglich 
    UDR = c;                         // Zeichen senden   
}

uint8_t uart_getc(void)
{
    while (!(UCSRA & (1<<RXC))) {} // warten bis Zeichen verfügbar
    return UDR;                    // Zeichen aus UDR zurueckgeben
}


int main (void)
{
  uint8_t i;
  char c;
  char* s;
  char string[length+1];

  uart_init();
  
while(1)
{    
  
  s=string;
  i=0;

  do
  {
    c=uart_getc();    
    if (c!='\r') 
     {
      *s=c;      
      uart_putc( c );    
    s++;
    i++;
     }       
  }
  while( i!=length && c!='\r');  
  *s=0;

  uart_puts( "\r\n" );
  uart_puts( "eingegebender Text: " );
  uart_puts( string );
  while (!(UCSRA & (1<<UDRE))) {}
    uart_puts( "\r\n" );

}
return (0);
}

Autor: remote1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
im prinzip empfange ich solange einen char vom PC, bis die maximallänge 
erreicht ist bzw. bis ein ENTER kommt
die einzelnen char werden dann noch in ein string zusammengepack

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das trifft es schon fast! Danke!
Nur würde ich gern den Teil vom Empfangen in einer Funktion schreiben.
Habs gerade mal probiert, jetzt ergibt sich für mich allerdings das 
Problem mit der Rückgabe.... Was muss ich nun zurückgeben und wie lautet 
der Funktionsaufruf dafür dann?

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat sich erledigt. Ich habs hinbekommen!
Danke für die Hilfe!

Autor: remote1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kannst ja mal deine Lösung noch mal posten, damit auch andere davon 
profitieren können

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kein Problem! Hab noch eine Funktion zum empfangen von Integer Zahlen 
hinzugefügt.

//Empfangen

int input_int()
{
  int zahl;
  char zahl_c[100];

  zahl=atoi(input_string());
  return zahl;
}


 char input_string()
{
  char string[100];
  int i=0;
  char c;
  do
  {
    c=uart_getc_wait();
    if (c!='\r')
     {
         string[i]=c;
      i++;
     }
  }
  while(i!=99 && c!='\r');
  string[i]='\0';

  return string;
}

unsigned char uart_getc_wait()
{
    // Warten, bis etwas empfangen wird
    while (!(UCSRA & (1 << RXC)));
    // Das empfangene Zeichen zurückliefern
    return UDR;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> char input_string()
> {
>   char string[100];
>   int i=0;
>   char c;
>   do
>   {
>     c=uart_getc_wait();
>     if (c!='\r')
>      {
>           string[i]=c;
>       i++;
>      }
>    }
>   while(i!=99 && c!='\r');
>   string[i]='\0';
>
>   return string;
> }

Da fehler erst einmal ein * in der Funktionsdefinition

char* input_string()
{
  ...
}

In input_int braucht wohl niemand das Array zahl_c.
Das verbraucht nur Speicherplatz bzw., wenn der Optimizer
es rausschmeist, verwirrt nur.

Aber, das ist alles Kleinkram. Das folgende aber nicht:
Deine input_string() Funktion ist fehlerhaft:
Du gibst einen Pointer auf eine lokale Variable zurück.
Das darfst du aber nicht. Lokale Variablen werden beim
verlassen einer Funktion zerstört. Damit gibst du aber
dem Aufrufer der Funktion einen Pointer zurück, der
auf Speicher zeigt, der schon längst freigegeben wurde ->
auf einem System, dass den Speicher etwas riguroser überwacht,
kann es durchaus passieren, dass sich dann das Betriebssystem
einschaltet und deinem Programm auf die Finger klopft.
Aber auch auf einem AVR ohne Betriebssystem ist das nach
wie vor fehlerhaft. In deiner Verwendung in input_int()
wird das zwar funktionieren, allerdings nur zufällig.
* Wenn atoi ein bischen mehr auf dem Stack allokiert, hast
  du ein Problem.
* Wenn zwischen dem Empfang des Pointers beim Aufrufer und
  der Verwendung der Daten auf die der Pointer zeigt noch
  weitere Funktionsaufrufe liegen, die lokale Variablen
  anlegen, hast du ein Problem.

Gib niemals die Adresse einer lokalen Variablen aus einer
Funktion zurück! Das ist in C-speak: undefined behaviour.
Alles Mögliche kann und wird passieren.

Du hast mehrere Möglichkeiten um das Problem zu umgehen:
* allokiere den 100-Zeichen Buffer als globale Variable
* allokiere den 100 Zeichen Buffer zwar innerhalb der
  Funktion, dort aber als static Variable
* Die Funktion input_string() kümmert sich überhaupt nicht
  mehr um den Buffer, sondern verlangt vom Aufrufer, dass
  er einen Buffer (ausreichender Größe) übergibt.
* Du allokierst den Buffer dynamisch innerhalb der Funktion
  (diese Variante ist nur der Vollständigkeit halber aufgeführt,
   sie ist in C selbst auf einem nicht µC System nur eingeschränkt
   zu empfehlen. Das Problem ist: Wer gibt den Speicher wieder
   frei?)

Autor: Steffen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Verbesserung!
Das Programm lief bis jetzt auch so, aber vielleicht wäre es irgendwann 
zu Problemen gekommen und ich hätte wieder ewig nach dem Fehler suchen 
müssen.

>In input_int braucht wohl niemand das Array zahl_c.
>Das verbraucht nur Speicherplatz bzw., wenn der Optimizer
>es rausschmeist, verwirrt nur.

Der Array war nur ausversehen noch drin, hatte vorher eine andere Lösung 
und dafür habe ich ihn gebraucht....

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Steffen wrote:
> Danke für die Verbesserung!
> Das Programm lief bis jetzt auch so,

Wie gesagt: Das war ein glücklicher Zufall(*)
und funktioniert nur deswegen, weil input_int so aussieht
wie es aussieht.

Wenn ich zb mache:

int foo( char c )
{
  char tmp[20];
  int i;

  for( i = 0; i < 20; ++i )
    tmp[i] = c;

  return tmp[0] + tmp[9];
}

void bar()
{
   char* Input = input_string();
   foo( 'a' );

   // an dieser Stelle sollte eigentlich bereits der
   // Inhalt von *Input zerstört sein
}

dann wird das zu Problemen führen. Die tatsächliche
Funktionalität von foo() spielt keine Rolle, die Hauptsache
sie legt ein paar lokale Variablen an. Auch wenn das vom
C-Standard nirgends gefordert wird, so ist die Wahscheinlich-
keit sehr hoch, dass diese Variablen genau in dem Speicher
erzeugt werden, der einen Moment vorher noch die bewusste
lokale Variable 'string' in input_string() gehalten hat.
Und damit zerstört dir jeder Schreibzugriff die Daten, auf
die du einen Pointer von input_string() bekommen hast.


(*) glücklicher Zufall
eigentlich ist das kein glücklicher Zufall, sondern ein sehr
schlechter Zufall. Wenn du Glück gehabt hättest, dann wäre das
Programm sofort abgestürzt und du hättest mitbekommen, dass es
da ein Problem gibt. So hast du Pech und alles schaut so aus,
als ob es in Ordnung wäre.

Autor: Phillip Hommel (philharmony)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn der Post schon was älter ist, ich bin grade an etwas ählichem:
Ich wollte dazu einfach die Funktion aus dem Manual benutzen:

while(!(UCSRA&(1<<RXC)));
return UDR;

Was mir dabei nicht so ganz klar ist: Was genau macht "return UDR"?
Wenn ich das, was ich empfange jetzt zb auf den LEDs (meintewegen Port 
B) anzeigen lassen will, wie komme ich dann an die Daten ran?
"PORTB=UDR"?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.