www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Modemantwort von Siemens M20 verarbeiten ?


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,
ich hoffe, dass mir einer bei meinem Problem behilflich sein kann.
Und zwar versende ich bei einem Ereignis mehrere SMS über einen 
Atmega32. Hierbei treten jedoch regelmäßig Fehler auf, so dass mehrer 
SMS nicht gesendet werden. Um diese Fehler zu behandeln, möchte ich den 
Ergebniscode den mir das Modem schickt gerne auslesen und darauf 
dementsprechend reagieren. (So dass die SMS evt. nochmal gesendet wird)
Dies wollte ich mit folgenden Methoden realisieren:

/* Zeichen empfangen */
uint8_t uart_getc(void)
{
    while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
        ;
    return UDR;                   // Zeichen aus UDR an Aufrufer 
zurueckgeben
}

void uart_gets( char* Buffer, uint8_t MaxLen )
{
  uint8_t NextChar;
  uint8_t StringLen = 0;

  NextChar = uart_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 != '\n' && StringLen < MaxLen - 1 ) {
    *Buffer++ = NextChar;
    StringLen++;
    NextChar = uart_getc();
  }

                                  // Noch ein '\0' anhängen um einen 
Standard
                                  // C-String daraus zu machen
  *Buffer = '\0';
}




Wenn ich zum testen Daten über das Hyperterminal sende, werden diese 
durch die obenstehenden Methoden richtig erfasst. Die eigentliche 
Aufgabe, den Ergebniscode des Modems abzufangen, wird jedoch nicht 
erfüllt...dies funktioniert nicht. Er hängt sich bei: NextChar = 
uart_getc();  Obwohl ja Daten vom Modem gesendet werden...!? Wie gesagt 
über's Hyperterminal funktionierts.
Würde mich über jede Hilfe freuen!

Vielen Dank im Vorraus
Gruß Thomas

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hängt es bereits im ersten uart_getc()?

Dann könnte z.B. die Hardware nicht stimmen (TXD vom Modem über 
Pegelwandler an RXD vom AVR?) oder die im Codefetzen nicht sichtbare 
UART-Initialsierung ist falsch. Beides schliesse ich aus, weil du 
schreibst, dass die Übertragung AVR-Hyperterminal funktioniert.

Hängt es in einem der uart_getc() in der while-Schleife?

Bist du sicher, dass ein Zeilenende kommt und wenn dass dann ein '\n' 
(LF, Unix-Style) am Zeilenende steht und nicht ein '\r' (CR, Mac-Style) 
oder ein '\r' und ein '\n' (CRLF, PC-Style)? Wie verhält sich das Modem 
an Hyperterminal (besser wäre z.B. Br@y-Terminal o.ä. bei denen man die 
Einzelzeichen hexadezimal anzeigen kann).

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja...das die Hardware nicht stimmt kann man ausschließen. mit 
Hyperterminal geht ja alles. Das ist ja gerade das Merkwürdige.
ich habe mich ja auch im Hyerterminal und mit einem RS232 Sniffer davon 
überzeugt, dass eine Antwort zurückkommt...und welche Datenpakete 
gesendet werden.

Ja es hängt so wie es aussieht schon bei der ersten Abfrage.
Ich habe es auch schon mit

"while( StringLen < MaxLen - 1 )"

statt


"while( NextChar != '\n' && StringLen < MaxLen - 1 )"


probiert... dass hat aber auch nicht funktioniert.?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:

> Ja es hängt so wie es aussieht schon bei der ersten Abfrage.

Wenn du Position ### 1 meinst (s.u.), dann verstehe ich nicht was das 
folgende bringen soll:

> Ich habe es auch schon mit
>     while( StringLen < MaxLen - 1 )
> statt
>     while( NextChar != '\n' && StringLen < MaxLen - 1 )
> probiert... dass hat aber auch nicht funktioniert.?

void uart_gets( char* Buffer, uint8_t MaxLen )
{
  uint8_t NextChar;
  uint8_t StringLen = 0;

  // Warte auf und empfange das ERSTE Zeichen
  NextChar = uart_getc();    // ### 1 

  // Sammle solange Zeichen, bis:
  // * entweder das String Ende Zeichen kam
  // * oder das aufnehmende Array voll ist
  
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) 
  {
    *Buffer++ = NextChar;
    StringLen++;
    NextChar = uart_getc();  // ### 2
  }

  // Noch ein '\0' anhängen um einen Standard
  // C-String daraus zu machen
  *Buffer = '\0';
}


Bei dem Code läuft du in einen Hänger, wenn nie ein '\n' kommt und wenn 
nie mehr oder gleichviel Zeichen wie MaxLen-1 gesendet werden. Durch 
Weglassen der Prüfung auf '\n' verschlimmerst du die Situation.

Den CR-Fall könntest du so abfangen:

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

Es ist auch wichtig, wie der Rest des Programmes konstruiert ist. Wenn 
das Modem im Normalfall keine Statusmeldungen schickt, würde eine 
ständige Prüfung auf Statusmeldungen mit uart_gets() immer zur Blockade 
führen.

Dieses uart_gets ist ja wegen uart_getc an Pos. ### 1 und wegen dem 
while inkl. ### 2 grundsätzlich blockierend.

Man könnte das ändern, indem man z.B. die Daten nebenläufig zum 
Userprogramm in einem RX-Interrupt empfängt, einen Puffer füllt und im 
Programm je nach Füllgrad des Puffers darauf reagiert.

Wenn es ohne Interrupt gehen soll, könnte vor dem Aufruf der uart_getc 
prüfen, ob in der UART Daten vorliegen und dann - und nur dann - dorthin 
verzweigen.

void uart_gets( char* Buffer, uint8_t MaxLen )
{
  uint8_t NextChar;
  uint8_t StringLen = 0;

  // Wenn ein Zeichen in der UART vorhanden ist, 
  // dann empfange das als ERSTES Zeichen einer 
  // Statusmeldung

  if ((UCSRA & (1<<RXC)))
  {
    NextChar = uart_getc();    // ### 1 

    // Sammle solange Zeichen, bis:
    // * entweder das String Ende Zeichen kam
    // * oder das aufnehmende Array voll ist
    while( NextChar != '\n' && StringLen < MaxLen - 1 ) 
    {
      *Buffer++ = NextChar;
      StringLen++;

      // Mit der Annahme, dass dann noch 
      // mehr Zeichen kommen, darauf warten...
      NextChar = uart_getc();  // ### 2
    }
  }

  // Noch ein '\0' anhängen um einen Standard
  // C-String daraus zu machen
  *Buffer = '\0';
}


Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ADD:

In dem letzten Vorschlag würde ich aber den Namen der Funktion ändern, 
weil der normale µC-Programmierer davon ausgeht, dass uart_gets auf 
Gedeih und Verderb auf einen String wartet. Damit dass eine so benannte 
Funktion ohne String (bzw. einem Leerstring) zurückkommt, rechnet er 
eigentlich nie oder selten ;-)

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK vielen Dank für die Vorschläge. Bin noch relativ neu in diesem 
Gebiet. Ich werde es nun mal mit einem Empfangs-Interuppt versuchen und 
einen Puffer vollschreiben...den ich in der Hauptroutine auslesen falls 
das entspechende Flag gesetzt ist.
Wobei es mir immer noch unverständlich ist, wieso er mit dem bisherigen 
Code nichts auslesen konnte (also jedenfalls nicht die Daten vom Modem).

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das Problem nun wie oben beschrieben gelöst. Jetzt habe ich ein 
anderes Problem.... muss nun zum Abschluss noch die ca. 30 Nummern in 
ein Array etc. hinterlegen. Weiß aber nicht genau in welcher 
Datenstrucktur.
kann mir einer einen Vorschlag machen?

mit:

char Number[30];
Nummer[0] = "+49...."; geht es ja nicht !???

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
char Nummer[30];   //  <--- meine ich natürlich
Nummer[0] = "+49...."; geht es ja nicht !???

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:

> char Nummer[30];   //  <--- meine ich natürlich
> Nummer[0] = "+49...."; geht es ja nicht !???

Beginner

char *Nummer[30] = {
    "+49...",
    "+49...",
    "+49...",
    "+49...",
    // usw.
    "+49..."
};


Vergleiche im Programm mit strcmp()

Intermediate
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Expert
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

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.