www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik UART String einlesen


Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Kann mir jemand sagen was für Flags gesetzt werden, wenn auf der 
seriellen Schnittstelle Daten daherkommen?

Ich möchte in einer while(1) schleife Strings einlesen. (Aber nur dann 
einlesen wenn welche daherkommen).

Kann mir jemand ein Teilfragment vom einlesen eines Strings posten?

mfg

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Kann mir jemand ein Teilfragment vom einlesen eines Strings posten?

Siehe Datenblatt, Kapitel U(S)ART- Data Reception

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Um welchen µC geht es?

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Atmega 64.

Hier meine Problembeschreibung:

Ich möchte mit dem Atmega64 SMS lesen und versenden können.
Dafür würde ich ja wie immer uart_gets() benutzen um etwas vom modem
einzulesen.
Jedoch weiß ich ja nicht wann eine sms eintrifft und um dies zu erkennen
müsste der µC ja permanent an der seriellen Schnittstelle auf text
warten.
Dies wäre mit dem aufruf von uart_gets() erledigt, da die funktion erst
beendet wird wenn die max string länge erreicht wurde oder ein string
endzeichen erkannt wird.
eine ausgabe vom modem wäre z.B. +CMTI:"SM",3 diese zeile sagt mir das
eine neue sms im speicherbereich 3 gespeichert wurde.
die darauf folgende antwort vom µC wäre dann (öffne SMS 3)-->AT+CMGR=3.
folglich wird der inhalt der sms ausgegeben mit dem sich dann arbeiten
ließe.

mein problem ist nun:
nach dem aufruf der funktion uart_gets() wartet der µC auf zeichen.
falls aber keine sms eintrifft, empfängt der µC keine zeichen vom modem,
wartet bis ins nächste jahrhundert und beendet die uart_gets()
funktion nicht um mit dem programm fortzufahren.

kurz gesagt in zwei fällen soll reagiert werden:
wenn sich pinX verändert und wenn eine sms mit befehl eintrifft.

wie löse ich dieses problem?

Autor: Florian Pfanner (db1pf)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

schau mal ins Datenblatt vom ATMega64. In einem UART-Register UCSRA 
gibt's ein Flag, das heißt RXC. Es wird auf 1 gesetzt, wenn ein Zeichen 
empfangen wurde.
Es reicht also wenn du vor dem Aufruf von uart_gets() überprüfst ob 
dieses Bit gesetzt ist. Wenn nein kannst den PinX abfragen, oder 
sonstige Aktionen durchführen.

Gruß, Florian

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du mit
>uart_gets()
nichts anfangen kannst, dann ist das die falsche Funktion für dich.

In eine Hauptprogrammschleife vom Typ
while(1){}
gehört nichts, was die Ausführung der Schleife grundsätzlich verhindern 
kann.

Mein Tipp:
1) sieh nach, ob ein Zeichen gekommen ist z.B. über uart_getc()
2) falls nein: mach weiter mit der Schleife 4)
3) falls ja: füge es zu deinem String dazu,
   ist es ein CR oder LF dann ersetze es durch \0 und
   werte dann den so erhaltenen String aus
4) Tu den Rest der Schleife (Pinabfrage....)
5) Weiter bei 1)

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Florian Pfanner

Werde ich später ausprobieren!
Wird aber warscheinlich zur Lösung führen.
Danke!

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand sagen wo da der Fehler liegen könnte.
Der Atmega bleibt in der While(1) schleife hängen.

unsigned char neu[10];

while (1)
{
  if((UCSR0A & (1<<RXC)))
  {
   printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
   gets(neu);           //Speichert den String auf neu ab.
  }
}

Wie gesagt will ich einen String einlesen, sobald ich was auf der 
seriellen Schnittstelle empfang, sonst soll das Programm andere 
Tätigkeiten ablaufen lassen.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist printf schon auf STDOUT gerichtet und gets auf STDIN?

Siehe http://www.nongnu.org/avr-libc/user-manual/group__...

"The standard streams stdin, stdout, and stderr are provided, but 
contrary to the C standard, since avr-libc has no knowledge about 
applicable devices, these streams are not already pre-initialized at 
application startup..."

Und wie man die Zuordnung mit Hilfe von FDEV_SETUP_STREAM  macht 
(http://www.nongnu.org/avr-libc/user-manual/group__... 
und Democode in 
http://www.nongnu.org/avr-libc/user-manual/group__...)

EDIT: Siehe auch 
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ist drauf gerichtet und funtkioniert auch, aber irgenwas hats mit der 
abfrage von der seriellen schnittstelle glaube ich.

Autor: Michael H* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
schurli wrote:
> Kann mir jemand sagen wo da der Fehler liegen könnte.
> Der Atmega bleibt in der While(1) schleife hängen.
warum eigentlich nicht über den RXC interrupt?

>
> unsigned char neu[10];
> 
> while (1)
> {
>   if((UCSR0A & (1<<RXC)))
                       ^^^ RXC0 muss es heißen
>   {
>    printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
>    gets(neu);           //Speichert den String auf neu ab.
>   }
> }
> 
>
> Wie gesagt will ich einen String einlesen, sobald ich was auf der
> seriellen Schnittstelle empfang, sonst soll das Programm andere
> Tätigkeiten ablaufen lassen.
klingt wie gemacht für interrupts

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
//Installation der Seriellen Schnittstelle
void Handy_Init (void){

  //Enable TXEN im Register UCR TX-Data Enable
  UCR=(1 << TXEN | 1<<RXEN);
  //Teiler wird gesetzt 
  UBRR=(SYSCLK / (BAUD_RATE * 16L) - 1);
  
  //öffnet einen Kanal für printf (STDOUT)
  fdevopen (uart_putchar, uart_getchar);
};


//Routine für die Serielle Ausgabe
int uart_putchar (char c){

  if (c == '\n')
    uart_putchar('\r');
  //Warten solange bis Zeichen gesendet wurde
  while(!(USR & (1<<UDRE)));
  //Ausgabe des Zeichens
  UDR = c;
  return (0);
};

//Routine für die Serielle Ausgabe
int uart_getchar (void){

  while(!(USR & (1<<RXC)));
  return(UDR);
};


Hier der Codeausschnitt.

Wie kann man es über den RXC interrupt machen?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
schurli wrote:
> ist drauf gerichtet und funtkioniert auch, aber irgenwas hats mit der
> abfrage von der seriellen schnittstelle glaube ich.

Dan erläutere bitte, was genau du mit "bleibt in der While(1) schleife 
hängen" meinst.

Im Moment besteht dein Codeschnippsel nämlich aus einer Endlosschleife; 
das Programm MUSS in der while(1) Schleife bleiben.

Wenn du andere Tätigkeiten abzuarbeiten hast, könntest du die hier 
unterbringen:

unsigned char neu[10];

while (1)
{

  // Auf UART-Eingabe prüfen
  if((UCSR0A & (1<<RXC)))
  {
    printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
    gets(neu);           //Speichert den String auf neu ab.
  }

  // ggf. Eingabe auswerten und
  // sonstigen Code ausführen

}

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gets(neu) bringt den MC zum absturz?

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... obwohl ich weniger als 10 zeichen eingebe und Enter drücke

Autor: Michael H* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
deine register stimmen nicht. die routinen wurden wohl für einen andren 
µc geschrieben. lies dir einfach mal das datenblatt und das tutorial 
hier jeweils zum thema uart durch

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry hab vergessen das die mit dem Präprozessor definiert wurden.
#if defined (__AVR_ATmega64__)
#  define USR UCSR0A
#  define UCR UCSR0B
#  define UDR UDR0
#  define UBRR UBRR0L
#  define EICR EICRB
#endif

Autor: Michael H* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ahja. dann stimmt aber trotzdem RXC noch nicht. muss RXC0 heißen. die 
sind nicht an der gleichen stelle bei anderen typen.

Autor: Michael H* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und noch hinterher:

> int uart_putchar (char c){
warum denn int? void tuts doch.
>  if (c == '\n')
>    uart_putchar('\r');
rekursion?
> ...
> };

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat zwar schon anstandslos mit RXC statt RXC0 funktioniert obwohl es 
definitiv falsch ist.

Trotzdem hängt das Programm beim Einlesen des Strings.
"Hallo" wird mir auf der Seriellen ausgegeben, aber dann steht alles.

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Funtkion stammt von Ulrich Radig und ist auf Siemens Handys 
zugeschnitten.

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
unsigned char neu;

while (1)
{
  if((UCSR0A & (1<<RXC0)))
  {
   printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
   neu=uart_getchar();          
  }
}

Komischerweise funktioniert das einlesen eines Zeichens wunderbar.
Wenn ich im Hyperterminal irgenwas eingebe, schickt mir der AVR "Hallo" 
zurück und das Programm läuft in der while(1) weiter.

10mal irgendwas drücken ergibt 10mal "Hallo" also funktiniert es.

Warum funktioniert gets() nicht?

mfg

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welches Zeichen ist den das Zeilenendezeichen in gets? Tipp, dies ist 
der Code von gets() aus avr-libc 1,6.2:
#include <stdio.h>

#include "stdio_private.h"

char *
gets(char *str)
{
  char *cp;
  int c;

  if ((stdin->flags & __SRD) == 0)
    return NULL;

  for (c = 0, cp = str; c != '\n'; cp++) {
    if ((c = getchar()) == EOF)
      return NULL;
    *cp = (char)c;
  }
  *--cp = '\0';

  return str;
}

Und welches Zeichen schickt dein UART-Sender (Terminalprogramm?, Handy?) 
am Ende einer Zeile?

Autor: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Danke funktioniert.
"\n" wird gesendet.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan "stefb" B. wrote:

> Wenn du andere Tätigkeiten abzuarbeiten hast, könntest du die hier
> unterbringen:
>
> unsigned char neu[10];
>
> while (1)
> {
>
>   // Auf UART-Eingabe prüfen
>   if((UCSR0A & (1<<RXC)))
>   {
>     printf("Hallo\n");   //Gibt Hallo an die Serielle Schnittstelle aus.
>     gets(neu);           //Speichert den String auf neu ab.
>   }
>
>   // ggf. Eingabe auswerten und
>   // sonstigen Code ausführen
>
> }

Das setzt allerdings voraus, dass der restliche Code nicht zu viel Zeit 
braucht (abh. von F_CPU und BAUDRATE). Der Hardware-UART-Puffer ist 
derzeit nur 2 Zeichen gross und es besteht grosse Gefahr, dass Zeichen 
verloren gehen.

Ein grösserer Empfangspuffer und eine vom Userprogramm unabhängig 
laufende RX-Interruptroutine wären sicher die geschicktere Lösung.

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.