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


von Thomas (Gast)


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

von Stefan B. (stefan) Benutzerseite


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).

von Thomas (Gast)


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.?

von Stefan B. (stefan) Benutzerseite


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.?
1
void uart_gets( char* Buffer, uint8_t MaxLen )
2
{
3
  uint8_t NextChar;
4
  uint8_t StringLen = 0;
5
6
  // Warte auf und empfange das ERSTE Zeichen
7
  NextChar = uart_getc();    // ### 1 
8
9
  // Sammle solange Zeichen, bis:
10
  // * entweder das String Ende Zeichen kam
11
  // * oder das aufnehmende Array voll ist
12
  
13
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) 
14
  {
15
    *Buffer++ = NextChar;
16
    StringLen++;
17
    NextChar = uart_getc();  // ### 2
18
  }
19
20
  // Noch ein '\0' anhängen um einen Standard
21
  // C-String daraus zu machen
22
  *Buffer = '\0';
23
}

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.
1
void uart_gets( char* Buffer, uint8_t MaxLen )
2
{
3
  uint8_t NextChar;
4
  uint8_t StringLen = 0;
5
6
  // Wenn ein Zeichen in der UART vorhanden ist, 
7
  // dann empfange das als ERSTES Zeichen einer 
8
  // Statusmeldung
9
10
  if ((UCSRA & (1<<RXC)))
11
  {
12
    NextChar = uart_getc();    // ### 1 
13
14
    // Sammle solange Zeichen, bis:
15
    // * entweder das String Ende Zeichen kam
16
    // * oder das aufnehmende Array voll ist
17
    while( NextChar != '\n' && StringLen < MaxLen - 1 ) 
18
    {
19
      *Buffer++ = NextChar;
20
      StringLen++;
21
22
      // Mit der Annahme, dass dann noch 
23
      // mehr Zeichen kommen, darauf warten...
24
      NextChar = uart_getc();  // ### 2
25
    }
26
  }
27
28
  // Noch ein '\0' anhängen um einen Standard
29
  // C-String daraus zu machen
30
  *Buffer = '\0';
31
}

von Stefan B. (stefan) Benutzerseite


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 ;-)

von Thomas (Gast)


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).

von Thomas (Gast)


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 !???

von Thomas (Gast)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Thomas wrote:

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

Beginner
1
char *Nummer[30] = {
2
    "+49...",
3
    "+49...",
4
    "+49...",
5
    "+49...",
6
    // usw.
7
    "+49..."
8
};

Vergleiche im Programm mit strcmp()

Intermediate
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Vereinfachung_f.C3.BCr_Zeichenketten_.28Strings.29_im_Flash

Expert
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Array_aus_Zeichenketten_im_Flash-Speicher

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.