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?
> 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
charreceivedString[80];
2
uint8_treceivedStringLen;
3
....
4
5
intmain()
6
{
7
intc;
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
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:
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
return1;
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
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]; //Empfangsbufferbuffer 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.