www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik UART empfängt nur einmal.


Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

ich will den uart benutzen um den status eines gsm modems einzulesen.
dazu sendet der µC ein AT+CPIN?
die antwort ist entweder +CPIN: SIM PIN oder +CPIN: READY .
die beiden fälle unterscheidet das programm schon.
jedoch möchte ich nach der pinausgabe nochmals abfragen ob alles okay 
ist und das modem sich im READY zustand befindet.

mein problem ist nun,
durch den goto befehl springt der µc im programm und durchläuft nochmals 
die if schleife, er erkennt jedoch nicht den READY status des modems 
sondern lässt die led blinken wie es in ELSE angegeben ist.
erst wenn ich den µc resette geht die gleichung der if schleife auf.

kurz gesagt beim ersten mal daten vom uart abfragen läuft wunderbar 
jedoch beim 2. mal (ohne neustart) steht in der variable pin 
warscheinlich nur noch kauderwelsch.

was mach ich falsch? muss ich ein uart reset einbauen? wenn ja wie?

grüße,
Eddy

CODE:::::
****************************************************************

void main()
{


  char pin[20];
  uart_ini();





  DDRA |= ( 1 << DDA0 ); //pin A0 auf ausgang
  DDRA |= ( 1 << DDA1 ); //pin A1 auf ausgang
  DDRA |= ( 1 << DDA2 ); //pin A3 auf ausgang

  abfrage:


  //pin==0;
  uart_clear();
  PORTA |= (1<<PA2); // Pin PA2 "high" //  Rot wärend des Datenempfangs
  uart_puts("AT+CPIN?\r");

  uart_gets(pin,12);
  PORTA &= ~(1<<PA2);// Pin PA2 "low" //   Rot


  if (strncmp (pin,"\r\n+CPIN: SIM PIN",11) == 0)
    {

  PORTA |= (1<<PA1); // Pin PA1 "high" //   Gelb für "Gerät Erkannt 
übertrage PIN"
  uart_puts("AT+CPIN=\"3971\"\r");
  delay_ms(20000);
  PORTA &= ~(1<<PA1);// Pin PA1 "low" //
  goto abfrage;
  }

  else if (strncmp (pin,"\r\n+CPIN: READY",11) == 0)
  {
  PORTA |= (1<<PA0); // Pin PA0 "high" //
  }

  else //---> wenn nichts zu trifft:: ERROR Blinken   (Rot)<-----
  {
  schleife:
  PORTA |= (1<<PA2); // Pin PA2 "high" //
  delay_ms(500);
  PORTA &= ~(1<<PA2);// Pin PA2 "low" //
  delay_ms(500);
  goto schleife;
  }
  //##################################################################

  //PORTA &= ~(1<<PA0);// Pin PA0 "low" //
  //PORTA &= ~(1<<PA1);// Pin PA1 "low" //

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

void main()
{


  char pin[20];
  uart_ini();





  DDRA |= ( 1 << DDA0 ); //pin A0 auf ausgang
  DDRA |= ( 1 << DDA1 ); //pin A1 auf ausgang
  DDRA |= ( 1 << DDA2 ); //pin A3 auf ausgang



//****ab hier läuft das programm nochmals nach der pin eingabe****//
  abfrage2:

  
  uart_puts("AT+CPIN?\r");
  uart_gets(pin,12);
  


  if (strncmp (pin,"\r\n+CPIN: SIM PIN",11) == 0)
    {

  uart_puts("AT+CPIN=\"3971\"\r"); //Pin eingabe//
  delay_ms(20000);                 //Warten bis es NETZ hat //
  goto abfrage2;                    //Nochmal von vorne//
    
    }

  else if (strncmp (pin,"\r\n+CPIN: READY",11) == 0)
  {
  PORTA |= (1<<PA0); // Grüne lampe an denn es ist alles okay
  }

  else // wenn nichts zu trifft:: ERROR Blinken   (Rot) //
  {
  
  PORTA |= (1<<PA2); // Pin PA2 "high" //
  delay_ms(500);
  PORTA &= ~(1<<PA2);// Pin PA2 "low" //
  delay_ms(500);

  }


Autor: fubar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aufgeräumt, aber nicht getestet
void main()
{
  char pin[20];
  uart_ini();

  //pin A0/A1/A2 auf ausgang, alle anderen auf input
  DDRA = ( 1 << DDA0 ) | ( 1 << DDA1 ) | ( 1 << DDA2 );

  
  for (;;)
  {
    uart_puts("AT+CPIN?\r");
    uart_gets(pin,12);

    if (strncmp (pin, "\r\n+CPIN: SIM PIN", 11) == 0)
    {
      //Pin eingabe
      uart_puts("AT+CPIN=\"3971\"\r");
      
      //Warten bis es NETZ hat
      delay_ms(20000);
      
      // springe zum anfang der for schleife
      continue;
    }
    else if (strncmp (pin, "\r\n+CPIN: READY",11) == 0)
    {
      PORTA |= (1<<PA0); // Grüne lampe an denn es ist alles okay
    }
    else
    {
      // wenn nichts zu trifft:: ERROR Blinken   (Rot)
      // Pin PA2 "high"
      PORTA |= (1<<PA2);
      // warte 500 ms
      delay_ms(500);
      // Pin PA2 "low"
      PORTA &= ~(1<<PA2);
      delay_ms(500);
    }
  }
}

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

Bewertung
0 lesenswert
nicht lesenswert
1. Der goto ist ein ziemlich Unnötiger Ballast an der Stelle.

  Warum nicht das Sprachmittel einsetzen, welches sich hier
  anbieten würde: Eine while Schleife?

  Frage das Händi ob es einen PIN braucht
  Solange das Händi nicht mit PIN READY antwortet {
     Schicke Pin
     Warte eine Zeit lang
     Frage das Händi ob es einen PIN braucht
  }

2. Was macht deine uart_get Routine, wenn es mehr Zeichen
   empfängt, als du abholst? Speichert es die überzähligen
   Zeichen zwischen oder verwirft es sie?

   Der Grund warum ich frage:
   uart_gets( pin, 12 );

   Hier sagst du der uart_gets, sie möge Zeichen empfangen, aber
   maximal nur 12 Stück (dazu gleich noch mehr). Deine Texte, auf
   die du vergleichst sind aber länger als 12 Zeichen. Also muss
   uart_gets ein paar Zeichen unter den Tisch fallen lassen, wenn
   es die Antwort liefert (oder zwischenspeichern um sie dann beim
   nächsten Aufruf von uart_gets zu liefern)
   Ausserdem: Warum 12? Dein Array pin ist doch mit 20 definiert!
   Das Array könnte also viel mehr aufnehmen als nur 12 Zeichen.

3. Zähl mal die Zeichen in "\r\n+CPIN: SIM PIN". Das sind mehr als
   11!
   Selbiges für den anderen String

4. Die Sache mit \r\n
   Wenn du nicht verifiziert hast, dass dein Händi (generell: das
   Gerät welches am anderen Ende der Leitung hängt) tatsächlich
   jeden Text mit \r\n abschliesst, dann ist deine beste Strategie,
   wenn uart_gets diese beiden Zeichen \r und \n gleich beim Empfang
   aus dem String ausfiltert, sodass du dich in weiterer Folge bei
   der Stringverarbeitung nicht mehr darum kümmern musst.
   Manche Geräte schicken \r \n
   Manche Geräte schicken \n \r
   Manche schicken nur \r
   Wieder andere schicken nur \n

   Aus diesem Wust an Möglichkeiten ist es am simpelsten wenn man
   zwar mit einem \n oder einem \r eine Eingabezeile als beendet
   erkennt, aber ansonsten werden die \n oder \r ignoriert und tauchen
   im empfangenen String nie auf.

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal ein bisschen anders ...
funzt aber immer noch nicht

merkwürdiges neues problem ist jetzt das wenn modem ready status ausgibt 
und der µC das erkennt blinken grün und rot abwechelnd......




  char pin[20];
  uart_ini();

  //pin A0/A1/A2 auf ausgang, alle anderen auf input
  DDRA = ( 1 << DDA0 ) | ( 1 << DDA1 ) | ( 1 << DDA2 );

  
  for (;;)
  {
    uart_puts("AT+CPIN?\r");
    uart_gets(pin,12);

    if (strncmp (pin, "\r\n+CPIN: SIM PIN", 11) == 0)
    {
      //Pin eingabe
      uart_puts("AT+CPIN=\"3971\"\r");
      
      //Warten bis es NETZ hat
      delay_ms(20000);
      
      // springe zum anfang der for schleife
      continue;
    }
    else if (strncmp (pin, "\r\n+CPIN: READY",11) == 0)
    {
      PORTA |= (1<<PA0); // Grüne lampe an denn es ist alles okay
    }
    else
    {
      // wenn nichts zu trifft:: ERROR Blinken   (Rot)
      // Pin PA2 "high"
      PORTA |= (1<<PA2);
      // warte 500 ms
      delay_ms(500);
      // Pin PA2 "low"
      PORTA &= ~(1<<PA2);
      delay_ms(500);
    continue;


Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nochmals der code:
jetzt checkt ers erst wenn ich halt den reset button drück.
obwohl der danach ja auch nichts anderes macht.
ich checks net.


  char pin[20];
  uart_ini();

  //pin A0/A1/A2 auf ausgang, alle anderen auf input
  DDRA = ( 1 << DDA0 ) | ( 1 << DDA1 ) | ( 1 << DDA2 );

  
  for (;;)
  {
  PORTA |= (1<<PA2);
    uart_puts("AT+CPIN?\r");
    uart_gets(pin,12);
  PORTA &= ~(1<<PA2);

    if (strncmp (pin, "\r\n+CPIN: SIM PIN", 11) == 0)
    {
    PORTA |= (1<<PA1);
      //Pin eingabe
      uart_puts("AT+CPIN=\"3971\"\r");
      
      //Warten bis es NETZ hat
      delay_ms(20000);
      PORTA &= ~(1<<PA1);
      // springe zum anfang der for schleife
      continue;
    }
    else if (strncmp (pin, "\r\n+CPIN: READY",11) == 0)
    {
      PORTA |= (1<<PA0); // Grüne lampe an denn es ist alles okay
      for(;;);
  }
    else
    {
      // wenn nichts zu trifft:: ERROR Blinken   (Rot)
      // Pin PA2 "high"
      PORTA |= (1<<PA2);
      // warte 500 ms
      delay_ms(500);
      // Pin PA2 "low"
      PORTA &= ~(1<<PA2);
      delay_ms(500);
    continue;
    }
  }


hier sind meine anderen voids die ich verwende:
void uart_gets( char* Buffer, uint8_t MaxLen )
{
 
  uint8_t NextChar;
  uint8_t StringLen = 0;
 
  NextChar = ser_getc();         // Warte auf und empfange das nächste Zeichen
 
                                  // Sammle solange Zeichen, bis:
                                  // * entweder das String Ende Zeichen kam
                                  // * oder das aufnehmende Array voll ist
  while( NextChar != 'cr' && StringLen < MaxLen - 1 ) {   //    ---->>>\t<<<????
    *Buffer++ = NextChar;
    StringLen++;
    NextChar = ser_getc();
  }
 
                                  // Noch ein '\0' anhängen um einen Standard
                                  // C-String daraus zu machen
  *Buffer = '\0';
}
 
 
unsigned char ser_getc (void)    
{
  unsigned char c;
 
  while(!rbuffcnt);       // Warte bis ein Zeichen vorhanden ist
 
  cli();            // Interruptbehandlung kurz aussetzen. Ab jetzt muß es schnell gehen (wenig Befehle), damit Zeichen, die 
                // ab jetzt eintreffen nicht verloren gehen.
  rbuffcnt--;          // anschl. ein Zeichen weniger zum ausgeben
  c = rbuff [rbuffpos++];  // Zeichen holen, was nach dem bereits gelesenen liegt
  if (rbuffpos >= RBUFFLEN)  rbuffpos = 0;  // wenn hinterstes Zeichen (rechts im Puffer) gelesen wurde, dann wieder vorne anfangen
 
  sei();            // Interruptbehandlung wieder aktivieren
 
  return (c);        // Zeichen zurückgeben
}

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

Bewertung
0 lesenswert
nicht lesenswert
Da ist offensichtlich eine Interrupt getriebener Ringbuffer
dahinter.
Damit haben sich alle meine Bedenken bezüglich der nicht
abgeholten Zeichen bestätigt.

Soll ich es dir in Stein aufmeisseln oder glaubst du es mir auch
so:
Stell endlich deine String-Längen richtig!

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  while( NextChar != 'cr' && StringLen < MaxLen - 1 ) {

Bei der Zeile dürfte der Compiler ziemlich meckern.
'' nimmt man nur für ein Zeichen, nicht zwei.

  while( NextChar != '\r' && StringLen < MaxLen - 1 ) {

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zusätzlich zu dem was Karl Heinz geschrieben hat, hast du noch ein 
mögliches Problem. Auf das Senden der PIN "AT+CPIN=\"3971\"\r" kommt 
doch sicher auch eine Antwort, oder? Die dürfte beim nächsten 
Schleifendurchlauf auch noch in irgendwelchen Buffern rumgeistern (und 
wenn vielleicht auch nur teilweise).

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja genau das ist mein problem! wie bekomm ich das weg?

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
\r oder \n kann ich als zeilenende nicht nehmen weil das das gsm modem 
auch oft am anfang einer zeile einbaut!

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eddy wrote:

> ja genau das ist mein problem!

Nicht nur das. Dass du bei dem uart_gets eine zu kleine Länge angibst, 
ist definitiv auch ein Problem.

> wie bekomm ich das weg?

Indem du die Antwort aus dem Buffer ausliest, auch wenn sie dich gar 
nicht interessiert.

> \r oder \n kann ich als zeilenende nicht nehmen weil das das gsm modem
> auch oft am anfang einer zeile einbaut!

Na ja, am Ende einer Antwort wird auch schon noch sowas kommen.

Zwei Dinge sind wichtig, damit du deine Probleme in den Griff bekommst.
1) Eine Änderung der Funktion uart_gets.
2) Ein geänderter Aufruf dieser Funktion.

Zu 1) würde ich folgendes vorschlagen (ungetestet):
void uart_gets( char* Buffer, uint8_t MaxLen )
{
 
  uint8_t NextChar;
  uint8_t StringLen = 0;
  uint8_t Flag = 0;

  do {

      NextChar = ser_getc();

      if (NextChar=='\r' || NextChar=='\n') {
          if (!Flag)
              continue;    // erstmal alle \r und \n am Anfang ignorieren
          else
              break;       // danach makiert das erste \r oder \n das Ende
      }
      else
          Flag = 1;

      *Buffer++ = NextChar;
      StringLen++;

  } while (StringLen < MaxLen-1);

  *Buffer = '\0';
}

Zu 2): Du musst die Funktion mit der Größe vom Buffer aufrufen, damit 
sichergestellt ist, dass auch die komplette Antwort gelesen wird.
Am besten so (dann kannst du die Größe schnell und sicher ändern):
#define BUF_SIZE 20
...
char pin[BUF_SIZE];
...
uart_gets(pin,BUF_SIZE);
...

Bei den Vergleichen lässt du dann die \r und \n weg.
Und wenn du nach dem Sender der PIN die Antwort ausliest, kannst du auch 
das "delay_ms(20000);" weglassen.

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hat er dann nicht das problem das er immer die genaue länge des zu 
erwartenden strings angeben muss damit sein mikroprozessor nicht bis in 
nächste jahrtausend auf weitere zeichen wartet??

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn die Antwort des GSM-Modems am Ende entweder ein \r oder ein \n 
(oder auch beides) enthält (und davon gehe ich aus), dann nicht.

Ich sehe aber gerade, dass das Flag in der Funktion ja überflüssig ist. 
Das passiert halt, wenn man den Code "mal eben auf die Schnelle" 
hinschreibt. ;-)
void uart_gets( char* Buffer, uint8_t MaxLen )
{
 
  uint8_t NextChar;
  uint8_t StringLen = 0;

  do {

      NextChar = ser_getc();

      if (NextChar=='\r' || NextChar=='\n') {
          if (!StringLen)
              continue;    // erstmal alle \r und \n am Anfang ignorieren
          else
              break;       // danach makiert das erste \r oder \n das Ende
      }

      *Buffer++ = NextChar;
      StringLen++;

  } while (StringLen < MaxLen-1);

  *Buffer = '\0';
}

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also:

vielen dank ersteinmal für die tatkräftige unterstützung!
das ganze projekt läuft jetzt soweit.


nun möchte ich ja auch gerne per sms befehle schicken können, auf die 
der µC dann reagiert.
dafür würde ich ja wie immer uart_gets() benutzem 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 nicht die uart_gets() 
funktion um mit dem weiteren programm fortzufahren.
heißt: in der zeit zwischen aufruf der funktion und eingehender sms 
beobachtet der µC nicht den status von pinX.
das ist aber fatal da der µC ja eine sms verschicken soll wenn sich was 
an pinX verändert.

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: schurli (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe momentan genau das gleich Problem wie du!
Wie kann man auf einen String vom Modem warten, ohne dass der MC in eine 
Endlosschleife geht?

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja ich hab auch noch nicht weitergebastelt bis jetzt
aber ich denke wir gehen das völlig falsch an.
das muss irgendwie mit interupts gemacht werden oder so so.. ;-)

wenn eine sms an kommt sendet das modem ja sofort einen string
und jedes andere gerät verarbeitet diesen ja auch sofort...irgendwie...

naja vielleicht sollte man es besser auf ne andere tour versuchen..
einfach in ner schleife am programm anfang oder ende den sms speicher 
auslesen und gucken ob was neues da ist .

aber ich denke sowieso das wenn mein µC etwas unerwartes empfängt gibts 
bei der nächsten modemabfrage probleme.

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
poste mal wenn du was neues hast!

was baust du überhaupt?

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich habe momentan genau das gleich Problem wie du!
>Wie kann man auf einen String vom Modem warten, ohne dass der MC in eine
>Endlosschleife geht?

Die Zauberworte sind:
-Interruptgesteuertes Empfangen mit (FIFO)-Puffer
und:
- Zustandsautomaten für den Empfang und die Auswertung

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja das sind ja nette ansätze aber wie bekomm ich das denn jetzt in den 
code oben implementiert??

hat schon lang genug gedauert den scheiß da oben zum laufen zu 
bringen........

Autor: Eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und außerdem....

ich dachte das ganze würde schon mit ringbuffer laufen....
hatte zumindestens früher schon das problem das der noch irgendwelche 
"alten" zeichen  im puffer hatte und mir die dann beim auslesen mit 
ausgespuckt hat.

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.