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" //
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.
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......
1
charpin[20];
2
uart_ini();
3
4
//pin A0/A1/A2 auf ausgang, alle anderen auf input
5
DDRA=(1<<DDA0)|(1<<DDA1)|(1<<DDA2);
6
7
8
for(;;)
9
{
10
uart_puts("AT+CPIN?\r");
11
uart_gets(pin,12);
12
13
if(strncmp(pin,"\r\n+CPIN: SIM PIN",11)==0)
14
{
15
//Pin eingabe
16
uart_puts("AT+CPIN=\"3971\"\r");
17
18
//Warten bis es NETZ hat
19
delay_ms(20000);
20
21
// springe zum anfang der for schleife
22
continue;
23
}
24
elseif(strncmp(pin,"\r\n+CPIN: READY",11)==0)
25
{
26
PORTA|=(1<<PA0);// Grüne lampe an denn es ist alles okay
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!
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).
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):
1
voiduart_gets(char*Buffer,uint8_tMaxLen)
2
{
3
4
uint8_tNextChar;
5
uint8_tStringLen=0;
6
uint8_tFlag=0;
7
8
do{
9
10
NextChar=ser_getc();
11
12
if(NextChar=='\r'||NextChar=='\n'){
13
if(!Flag)
14
continue;// erstmal alle \r und \n am Anfang ignorieren
15
else
16
break;// danach makiert das erste \r oder \n das Ende
17
}
18
else
19
Flag=1;
20
21
*Buffer++=NextChar;
22
StringLen++;
23
24
}while(StringLen<MaxLen-1);
25
26
*Buffer='\0';
27
}
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):
1
#define BUF_SIZE 20
2
...
3
charpin[BUF_SIZE];
4
...
5
uart_gets(pin,BUF_SIZE);
6
...
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.
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??
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. ;-)
1
voiduart_gets(char*Buffer,uint8_tMaxLen)
2
{
3
4
uint8_tNextChar;
5
uint8_tStringLen=0;
6
7
do{
8
9
NextChar=ser_getc();
10
11
if(NextChar=='\r'||NextChar=='\n'){
12
if(!StringLen)
13
continue;// erstmal alle \r und \n am Anfang ignorieren
14
else
15
break;// danach makiert das erste \r oder \n das Ende
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?
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.
>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
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........
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.