Hallo Ich will mit einem Atmega auf Zeichen von einem GSM Modem warten. Wenn das Modem meldet das es eine SMS empfangen hat soll die SMS vom Speicher geholt und weiterverarbeitet werden. Folgende Funktion zickt herum: //Abfrage Serielle Schnittstelle 0 if((UCSR0A & (1<<RXC0))) { uart0_getstring(&temp1[0],16); //Problem: Viele Zeichen werden Versäumt } Damit überprüfe ich ob das Modem etwas gesendet hat. Die uart0_getstring versäumt jedoch fast alles was daherkommt. Wenn ich die Routine mit Hyperterminal von Hand durchgehe (entsprechend langsam) funktioniert die Funktion - am GSM Modem mit 19200 Baud jedoch nicht. Meine Frage: Wenn ich die "uart0_getstring" mit Interrupt statt Polling löse muss ich ja trotzdem irgendwie abfragen ob das Modem etwas sendet. Wie macht man das am besten? Wieder mit if((UCSR0A & (1<<RXC0))) ???
georg wrote: > Meine Frage: Wenn ich die "uart0_getstring" mit Interrupt statt Polling > löse muss ich ja trotzdem irgendwie abfragen ob das Modem etwas sendet. Nein. Der Interrupt ist ja die Benachrichtigung von der UART, dass ein Zeichen eingetroffen ist. Wenn also der Interrupt ausgelöst wird, ist sichergestellt, dass ein Zeichen empfangen wurde. Kein Zeichen, kein Interrupt. Edit: reden wir vom selben Interrupt? Sieh dir einfach mal die UART Library vom Peter Fleury an (googeln). Die verwendet interrupt gesteuerten Empfang und einen Ringbuffer, damit kein Zeichen verlorengeht (solange der Buffer nicht überläuft).
Ich habe vor, dass ich die UART Library von Peter Fleury in mein Projekt einbinde. Irgendwie kann ich mir momentan nicht vorstellen wie ich feststelle das sich etwas am UART ändert und ich dann 2 Srings einlese die aus folgender Antwort vom Modem stammen: \r\n+CMTI: "SM", 5\r\n Der zweite eingelesene String (bis "\n" wird gelesen) soll anschließend behandelt werden. Meine Idee: Die globale Variable "x" die größer als 0 ist, falls Zeichen im Empfangsbuffer sind. Mein Hauptprogramm wird dann so aussehen: while (1) { if(x) { getstring(...); } } Wäre das eine Lösung?
georg wrote:
> Wäre das eine Lösung?
So ungefähr. Sieh dir die Library an. Die kommt mit einem Demo, wie man
sie benutzt.
Es funktioniert mit Peters Library. Bitte kurz anschaun ob die Lösung auch sinnvoll ist:
1 | /*Zusätzliche Funktion zum checken ob das Modem mindestens 1 Byte gesendet hat
|
2 | */
|
3 | int check_data_uart(void) |
4 | {
|
5 | |
6 | if ( UART_RxHead != UART_RxTail ) { |
7 | return 1; /*data available */ |
8 | }
|
9 | else { |
10 | return 0; /*no data available */ |
11 | }
|
12 | }
|
13 | |
14 | |
15 | |
16 | |
17 | //Hauptprogramm
|
18 | for(;;) |
19 | {
|
20 | |
21 | |
22 | if (check_data_uart()) |
23 | {
|
24 | uart_gets(buffer,7); //7 Zeichen werden eingelesen |
25 | uart_putc('\n'); |
26 | uart_putc('\r'); |
27 | uart_puts(buffer); //gibt Buffer wieder aus |
28 | }
|
29 | else
|
30 | {
|
31 | uart_putc('#'); //flutet Hyperterminal mit # Zeichen |
32 | }
|
33 | |
34 | }
|
> Bitte kurz anschaun ob die Lösung auch sinnvoll ist:
check_data_uart prüft ja nur, ob Zeichen da sind, aber nicht, wie viele.
Das funktioniert also nur dann sinnvoll, wenn uart_gets seinerseits ggf.
auf die restlichen Zeichen wartet. Wenn es das aber tut, wozu dann noch
das check_data_uart vorher?
@Stefan Ja, die Funktion gets() waret auf nachfolgende Zeichen. Meine Anforderung ist: GSM-Modem sendet zu irgendeinem Zeitpunkt Daten aus (einen String). Der AVR soll nicht ewig auf einen String warten, sondern nebenbei noch Tastenabfragen und sonstiges machen. Würde man nicht check_data_uart() abragen, dann würde der AVR ewig in gets() warten. Irgendwie gefällt mir meine Funktion nicht so ganz, da shon bei einem einzigen Zeichen ein String eingelesen wird und der AVR somit hängen bleibt, weil kein '\n' daherkommt. Hat dazu jemand eine Idee? (Falls nicht, bin ich gezwungen einen Watchdog einzubauen) mfg
georg wrote:
> (Falls nicht, bin ich gezwungen einen Watchdog einzubauen)
Quatsch
Dann kannst du die String-Einlese-Funktionalität so nicht in eine
Funktion stecken, sondern in die Hauptschleife. Du liest nicht einen
String ein, sondern holst ein Zeichen von der UART, wenn eines da ist.
Dieses Zeichen wird an die bereits geholten Zeichen hinten drangehängt.
Wenn sich dadurch eine komplette Eingabezeile ergibt -> super, den jetzt
kompletten String verarbeiten. Wenn nicht, gehts weiter in der
Hauptschleife.
1 | char receivedString[80]; |
2 | uint8_t receivedStringLen; |
3 | ....
|
4 | |
5 | int main() |
6 | {
|
7 | int c; |
8 | |
9 | ....
|
10 | |
11 | |
12 | receivedStringLen = 0; |
13 | receivedString[0] = '\0'; |
14 | |
15 | while( 1 ) { |
16 | |
17 | c = uart_getc(); |
18 | if ( !( c & UART_NO_DATA ) ) { // die UART hat was empfangen |
19 | if( c == '\n' ) { |
20 | // mach was mit dem jetzt kompletten String
|
21 | ....
|
22 | receivedString[0] = '\0'; |
23 | receivedStringLen = 0; |
24 | }
|
25 | |
26 | else { |
27 | receivedString[ receivedStringLen++ ] = c; |
28 | receivedString[ receivedStringLen ] = '\0'; |
29 | }
|
30 | }
|
31 | |
32 | ....
|
33 | }
|
34 | }
|
Du musst anfangen, auf einem µC deine Aufgaben in kleine Häppchen aufzuteilen. Die Hauptschleife in main() ist dann dafür zuständig, dass reihum immer wieder diese kleinen Häppchen ausgeführt werden. So ergibt sich ganz von alleine, dass dein µC scheinbar mehrere Dinge gleichzeitig macht. PS: Fehlerabfragen musst du noch einbauen. uart_getc liefert nicht nur UART_NO_DATA, sondern auch Fehlercodes. Und bei dem dranhängen ans Array wäre es gut auf einen möglichen ArrayOverflow zu testen.
Karl heinz Buchegger wrote: > Dann kannst du die String-Einlese-Funktionalität so nicht in eine > Funktion stecken, sondern in die Hauptschleife. Na ja, so pauschal kann man das nicht unbedingt sagen. Ich würde es z.B. so machen, dass eine Funktion die Zeichen (wenn denn eines da ist) in einem lokalen static Array sammelt und dann über den Rückgabewert mitteilt, ob der String komplett ist. Z.B. ein Zeiger auf das lokale Array bei "String da" und sonst 0. In der Hauptschleife könnte dann sowas stehen:
1 | char * str; |
2 | ...
|
3 | if (( str = GetString() )) { |
4 | // tue was mit dem String
|
5 | }
|
Damit wäre dann das komplette Einlesen (inkl. aller Checks) in eine Funktion ausgelagert, und die Hauptschleife wäre deutlich übersichtlicher.
Hier ein einfaches Beispiel mit String-Empfang und Auswertung: Beitrag "programmierbare 16 Kanal PWM Lightshow" Die UART ist in Software, aber da das Programm modular ist, kann man das leicht ändern. Das Hauptprogramm läuft nebenher unbeeinflußt weiter. Peter
vorübergehend mal danke an alle. ich werde mich den Antworten mal näher widmen
Hallo Das Einlesen eines Strings (mit Endezeichen '\n') funktioniert nicht richtig. Kann mir jemand weiterhelfen
1 | #define size_of_buffer 10
|
2 | |
3 | |
4 | int check_string_availiable(char *combuffer, int buffersize) |
5 | {
|
6 | uint8_t i = 0; |
7 | uint8_t c; |
8 | |
9 | |
10 | if (check_data_uart()) //wenn >=1 Byte empfangen wurde |
11 | {
|
12 | c = uart_getc(); |
13 | |
14 | switch( c ) |
15 | {
|
16 | case '\n': //wenn Stringende erreicht |
17 | i = 0; |
18 | return 1; |
19 | break; |
20 | |
21 | default: //wenn Stringende nicht errreicht |
22 | if( i < buffersize) |
23 | *combuffer++ = c; |
24 | }
|
25 | }
|
26 | |
27 | return 0; |
28 | |
29 | }
|
30 | |
31 | |
32 | int main(void) |
33 | {
|
34 | char buffer[size_of_buffer]; //Empfangsbuffer |
35 | |
36 | for(;;) |
37 | {
|
38 | |
39 | if ( check_string_availiable(&buffer[0], size_of_buffer) ) |
40 | {
|
41 | uart_puts(&buffer[0]); //Eingelesenen String ausgeben |
42 | uart_putc('\r'); |
43 | uart_putc('\n'); |
44 | }
|
45 | |
46 | }
|
47 | }
|
Wenn ich folgendes an den AVR Sende: abcdefgh '\n' kommt folgendes zurück h4 '\r''\n' Warum gibt er nur den letzten Buchstaben aus und woher kommt die Zahl 4 ???
Sorry, wenn das jetzt etwas hart rüberkommt, aber die ganze Funktion check_string_availiable ist "für'n Hintern". 1) Wozu das check_data_uart()? Genauso gut kannst du die Rückgabe von uart_getc auswerten. Solltest du wegen der Fehlerauswertung ja eh machen. 2) Du schreibst das empfangene Zeichen immer wieder an die selbe Stelle. (Ursache für das "Warum gibt er nur den letzten Buchstaben aus") 3) Nirgendwo machst du anstallten, den String zu terminieren. (Ursache für das "und woher kommt die Zahl 4")
Du hast scheints flüchtig auf mein get_command( void ) geschaut, aber wohl arge Probleme mit der Sprache C: Man muß nicht auf Biegen und Brechen Parameter übergeben, wenn es eh nur einen möglichen Aufruf gibt. Parameter werden als Kopie übergeben, d.h. Änderungen (Pointerincrement) sind wirkungslos. Der Compiler wird es wohl auch wegoptimiert haben. Das "static u8 idx" hat seinen Grund in dieser Funktion. Schau in Dein C-Buch, was static lokale Variablen sind. Peter
Bin auf die Fehler jetzt eingegangen und das Programm macht was ich will. Ließt einen String ein String bis '\n' aus dem Empfangspuffer ohne das der AVR in einer while Schleife wie bei üblichem einlesen mit "normalem" getstring() Bitte um Verbesserungsvorschläge im Algorithmus:
1 | uint8_t i = 0; //global definiert |
2 | |
3 | int check_string_availiable(char *combuffer, int buffersize) |
4 | {
|
5 | unsigned int c; |
6 | |
7 | c = uart_getc(); |
8 | |
9 | if (!(c & UART_NO_DATA)) //wenn >=1 Byte empfangen wurde |
10 | {
|
11 | |
12 | switch( c ) |
13 | {
|
14 | case '\n': //wenn Stringende erreicht |
15 | *(combuffer+i) = 0; //String 0 terminiert |
16 | i = 0; |
17 | return 1; |
18 | break; |
19 | |
20 | default: //wenn Stringende nicht erreicht |
21 | if(i < (buffersize-1)) |
22 | // 0 bis 8, Platz 9 ist für Zahl 0 reserviert
|
23 | {
|
24 | *(combuffer+i) = c; |
25 | i++; |
26 | }
|
27 | else
|
28 | {
|
29 | i = 0; //wieder von vorne beschreiben |
30 | }
|
31 | |
32 | }
|
33 | |
34 | }
|
Eine weitere Frage habe ich. Es ist durchaus möglich dass das GSM Modem auf die schnelle 200 Zeichen ausspuckt in dem 4 Strings enthalten sind. Für ein 160 Zeichen SMS brauche ich ein 161 Zeichen Array in dem ich das SMS + '\0' abspeicher. Wie groß sollte man den Empfangspuffer vom UART wählen? 200 Zeichen? Wenn ich dass mit dem Ringpuffer richtig verstanden habe, kann dieser auch viel kleiner sein als 200 nur wird dann der Abarbeitungsvorgang gebremst? Bitte korrigiert meine Aussage... mfg
@Peter Danke für den Hinweis, habe gegoogelt und weiß jetzt warum du mit static und nicht mit irendeiner globalen Variable arbeitest. Habe ich ausgebessert...
> Eine weitere Frage habe ich. Es ist durchaus möglich dass das > GSM Modem auf die schnelle 200 Zeichen ausspuckt in dem 4 > Strings enthalten sind. > Für ein 160 Zeichen SMS brauche ich ein 161 Zeichen Array in > dem ich das SMS + '\0' abspeicher. > > Wie groß sollte man den Empfangspuffer vom UART wählen? So gross, dass er alle Zeichen aufnehmen kann, die reinkommen, während du einen String weiterverarbeitest. Hinweis: Im Vergleich zu der Rechengeschwindigkeit ist eine UART Übertragung bei 9600 oder 19200 Baud schnarchlangsam. > Wenn ich dass mit dem Ringpuffer richtig verstanden habe, > kann dieser auch viel kleiner sein als 200 nur wird dann der > Abarbeitungsvorgang gebremst? Bitte korrigiert meine Aussage... Du hast nicht verstanden was dieser Buffer macht. Der ist sozusagen dein Eingangslager aus dem sich die Arbeiter ihre Materialien holen, während die Lieferanten neue Ware bringen. Wenn die Arbeiter wesentlich schneller Material aus dem Lager holen, als die Lieferanten nachliefern, genügt ein kleines Lager. Nur dann, wenn die Lieferanten ständig nachliefern und keiner holt das Zeugs ab, kriegst du ein Problem. Egal wie gross du das Lager machst, es wird immer irgendwann voll sein.
Karl heinz Buchegger wrote:
> Aber diesen check.... Mist braucht kein Mensch.
Warum soll etwas Mist sein, nur weil Du es nicht verwendest (nicht
verstehst)?
Ich mache es ja ähnlich und finde es äußerst praktisch. Das Main muß
dann nämlich nirgends warten und kann andere Sachen machen.
Die Routine holt sich die Bytes vom UART-FIFO und prüft auf \n oder \r.
Und erst dann übergibt sie den Puffer dem Parser zur Auswertung.
Bei mir macht sie noch einiges zusätzlich (Echo, Backspace, Umwandlung
in Großbuchstaben).
Peter
Peter Dannegger wrote: > Karl heinz Buchegger wrote: > >> Aber diesen check.... Mist braucht kein Mensch. > > Warum soll etwas Mist sein, Weil ich beim hochscrollen, bei der falschen Version gelandet bin. Die von 18:08 int check_string_availiable(char *combuffer, int buffersize) { uint8_t i = 0; uint8_t c; if (check_data_uart()) //wenn >=1 Byte empfangen wurde { c = uart_getc(); Und das ist Mist
> nur weil Du es nicht verwendest (nicht > verstehst)? Das nehm ich jetzt persönlich.
georg wrote: > Das Einlesen eines Strings (mit Endezeichen '\n') funktioniert nicht > richtig. Was funktioniert bzw. was funktioniert GENAU nicht? Auf Fehlermöglichkeiten in check_data_uart() und uart_getc() gehe ich nicht ein, weil die Funktionen in deinem Codefetzen fehlen. > int main(void) > { > char buffer[size_of_buffer]; //Empfangsbuffer buffer ist hier eine lokale Variable und deshalb nicht notwendigerweise mit Nullbytes initialisiert! Und wird hier > case '\n': //wenn Stringende erreicht > i = 0; > return 1; > break; > > default: //wenn Stringende nicht errreicht > if( i < buffersize) > *combuffer++ = c; auch nicht bewusst mit einem Nullbyte abgeschlossen. Auch nicht unbewusst, wenn per UART nur ASCII Zeichen und keine Binärzeichen ("Zufallsnull") kommen. Dadurch kann dies > uart_puts(&buffer[0]); //Eingelesenen String ausgeben einen Pufferüberlauf beim Lesen produzieren. uart_puts gibt solange aus, bis zufällig ein Nullbyte gefunden wird. Es wird eine Ausgabe produziert, die den gesendeten String liefert, aber manchmal auch Müll hinterher.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.