Hi ich habe mir eine Funktion geschrieben um mit einem Modem über die
UART Schnittstelle zu kommunizieren.
1
//uart
2
voiduart_init(unsignedint);
3
voiduart_c(unsignedchar);
4
voiduart_str(char*);
5
unsignedcharuart_getc(void);
6
voiduart_get_str(char*);
7
8
//at
9
unsignedcharat_send(char*,char*);
10
11
//at responding strings
12
char*_AT_pin_ready="+CPIN: READY";
13
char*_AT_sim_pin="+CPIN: SIM PIN";
14
char*_AT_ok="OK";
15
16
intmain(void)
17
{
18
init_io();
19
uart_init(MYUBRR);
20
21
at_send("ate0","OK");
22
at_send("at","OK");
23
24
while(at_send("at+cpin?","ERROR"))
25
{
26
//display message that no sim is inserted
27
}
28
29
if(at_send("at+cpin?","+CPIN: SIM PIN"))
30
{
31
at_send("at+cpin=XXXX","OK");
32
}
33
_delay_ms(1000);
34
at_send("at","OK");
35
at_send("at","OK");
36
at_send("at","OK");
37
}
38
39
voiduart_get_str(char*s)
40
{
41
unsignedcharc;
42
43
while(count_lf!=2)
44
{
45
c=uart_getc();
46
if(c==10)
47
{
48
count_lf++;
49
}
50
if(c!=10&&c!=13)
51
{
52
*s=c;
53
s++;
54
}
55
}
56
*s=0;
57
count_lf=0;
58
}
59
60
unsignedcharat_send(char*cmd,char*a)
61
{
62
uart_str(cmd);
63
uart_c(13);
64
clear_answer();
65
uart_get_str(&answer);
66
if(strcmp(answer,a)==0)
67
{
68
led_ok();
69
return1;
70
}
71
else
72
{
73
led_error();
74
return0;
75
}
76
}
77
78
voidclear_answer(void)
79
{
80
strcpy(answer,"");
81
}
Also das ganze funktioniert einwandfrei bis ich das erstemal das AT
Commando AT+CPIN verwende.. ab dem Zeitpunkt gibt die Funktion at_send()
nur noch 0 wieder.
Wo liegt mein Fehler?
f95 schrieb:> unsigned char at_send(char *cmd, char *a)> {> uart_str(cmd);> uart_c(13);> clear_answer();> uart_get_str(&answer);
Da würde ich mir doch glatt mal ausgeben lassen, welche Antwort das
Modem zurückschickt und den Text einfach mal irgendwo ausgeben lassen.
Es ist nie gut, wenn man 'Programmieren mittels Stochern im Nebel'
betreibt. Das erste was man praktisch immer braucht, ist eine
Ausgabemöglichkeit, damit man sich auch mal irgendwelche
Zwischenergebnisse ansehen kann.
Das du hier
uart_get_str(&answer);
allerdings die Adresse von answer übergibst, macht mich stutzig. Wie ist
den answer definiert?
Ich programmiere schon sehr kleinschrittig. Wenn ich jeden Befehl
einzelnt nach einander ins Modem lade, geht es. Sobald ich aber eine
Pinabfrage mit einer anderen kombiniere, funktioniert es nciht mehr. Und
ab irgend einem Punkt muss man etwas größere Schritte in der Entwicklung
machen. Ich habe das ganze jetzt mal Simuliert mitm Terminal und da
funktioniert es. Aber ich werde mir das ganze nochmal ausgeben lassen.
Danke
count_lf sollte eigentlich lokale Variable in der Funktion sein. (UNd
dann besser uint8_t und nicht char)
answer ist ok. Nimm aber dann den & weg.
uart_get_str(answer);
f95 schrieb:> Ich habe das ganze jetzt mal Simuliert mitm Terminal und da> funktioniert es.
Das ist grundsätzlich nicht schlecht ...
> Aber ich werde mir das ganze nochmal ausgeben lassen.
... das ist aber besser.
Hi also ich hab die uart_get_str methode umgeschrieben sodass es mir
eigentlich den String den es bekommt noch einmal ausgibt. Doch es kommt
nur das Linefeed welches dadrunter ist.
1
voiduart_get_str(char*s)
2
{
3
unsignedcharc;
4
5
while(count_lf!=2)
6
{
7
c=uart_getc();
8
if(c==10)
9
{
10
count_lf++;
11
}
12
if(c!=10&&c!=13)
13
{
14
*s=c;
15
s++;
16
}
17
}
18
*s=0;
19
count_lf=0;
20
uart_str(answer);
21
uart_c(10);
22
}
und es funktioniert auch nicht, wenn ich mir s oder *s ausgeben lasse
Habe die Ausgabe in eine andere Funktion gesetzt und die Strings die
miteinander vergleichen werden, sind identisch. Habe mir die Hexwerte
angesehen. Rückgabewerte auch korrekt in der Simmulation.. Doch sobald
UART und Modem zusammen sind funktioniert es nicht mehr.
f95 schrieb:> Habe die Ausgabe in eine andere Funktion gesetzt und die Strings die> miteinander vergleichen werden, sind identisch. Habe mir die Hexwerte> angesehen. Rückgabewerte auch korrekt in der Simmulation..
AB sofort kannst du die Simulation vergessen.
Deine get_str Funktion kommt mit den CR LF #so wie sie das Modem
schickt# durcheinander.
Das musst du erst mal richtig stellen.
Wieso kommen die durcheinander durch die if abfrage werden die doch
einfach ignoriert. Und bevor ich sie ignoriere, wird doch immer geguckt
ob ein LF kommt denn damit beginnt eine Antwort und endet auch wieder.
Wie z.B. <CR><LF>OK<CR><LF>
Also eine andere Methode an den String zu kommen den ich abfragen kann
ist mir nicht gekommen als LF zu zählen und beide für die Stringbildung
zu überspringen.
Die CRLF vor dem OK kommen von dem Echo, was eingeschaltet ist. Du
solltest besser erstmal das echo mit ATE0 abschalten, dann bekommst Du
ein reines
OK<CR><LF>
als Antwort zurück. Das ist wesentlich einfacher auszuwerten als die
Sache mit der LF-Zählerei.
f95 schrieb:> Mit ate0 schalte ich nur aus, das der Befehl nicht wiederholt wird und> ich nur ein reines <cr><lf>OK<cr><lf> habe daher ja die Zählerei.
Das glaub ich dir alles.
Aber erzähl das nicht mir.
Schau dir an, was dein Code tatsächlich für Zeichen bekommt und bestimme
dann, was da schief geht! Es ist eine Sache, in der Theorie zu wissen,
wie das ablaufen sollte, es ist aber eine andere Sache, welche Zeichen
dann tatsächlich daher kommen. Das ist ein Unterschied!
Und wenn das bedeutet, dass du dir hier
1
voiduart_get_str(char*s)
2
{
3
unsignedcharc;
4
5
while(count_lf!=2)
6
{
7
c=uart_getc();
8
9
***************************
10
11
12
if(c==10)
13
{
14
count_lf++;
15
}
16
if(c!=10&&c!=13)
17
{
18
*s=c;
19
s++;
20
}
21
}
22
*s=0;
23
count_lf=0;
24
uart_str(answer);
25
uart_c(10);
26
}
an der markierten Stelle das c (also ASCII und als Hex) mal ausgeben
lässt, dann bedeutet es das eben. Und wie schon gesagt: die Variable
count_lf würde ich auf jeden Fall in die Funktion mit reinziehen, damit
sicher gestellt ist, dass du sie vor dem ganzen Klimbin auf 0 stellen
kannst und das dann auch stimmt. Sich darauf zu verlassen, dass die 0
vom return bis zum nächsten Aufruf erhalten bleibt, ist ein Spiel mit
dem Feuer. Eigentlich sollte es so sein. Aber eigentlich sollte in einem
C-Programm auch kein Buffer Overflow stattfinden, der andere Variablen
niederbügelt.
Und PS: die Kontrollausgabe auf der UART ist keine so gute Idee. Ein LCD
wäre besser.
Grund: Für jedes Zeichen, welches du bekommst darfst du nur 1 Zeichen
(bei gleicher Baudrate) wieder ausgeben, sonst verlierst du Zeichen am
Input.
Du brauchst eine Ausgabemöglichkeit, mit der du auch ein wenig
Zwischenwerte ausgeben kannst, ohne dass du dir gleich das komplette
Timing versaust.
Karl Heinz Buchegger schrieb:> Schau dir an, was dein Code tatsächlich für Zeichen bekommt
UND ZWAR VOM MODEM !
Irgendwelche SImulationen oder wenn du dich vor ein Terminal klemmst und
Modem spielst bringen dich jetzt nicht mehr weiter. Du musst mit dem
Modem selber arbeiten. Es bestimmt jetzt, wie es weitergeht.
Da der LCD auf dem Weg ist Habe ich nur 2 LEDs und stöpsel ständig
zwischen Modem und allem hin und her, um die Ausgabe ans Modem zu
überprüfen. Gibt es denn keienn Trick wie man so eine Verbindung
spiegeln kann, sodass ich mir den Datenfluss im Terminal angucken kann?
Erstmal Danke für eure Hilfe ich werde gucken, das ich die get_str
Funktion abändern werde das sie stabieler läuft.
Bin offen für Tipps :)
f95 schrieb:> Hier ein Beispiel:>> at<\r><\r><\n>OK<\r><\n>> ate0<\r><\r><\n>OK<\r><\n>> <\r><\n>> OK<\r><\n>
Ich pflücke das mal auseinander:
1. Zeile:
at\r das ist das Echo des Modems auf Dein at<\r>
\r\n das Modem schickt nun einen Zeilenumbruch CRLF auf Deine Eingabe
OK\r\n das Modem sendet OK und CRLF
Das ist alles normal.
Auch die zweite Zeile ist ganz normal. Aber mich hätte interessiert, wie
ein AT\r DANACH ausgesehen hätte, also NACHDEM das Echo
ausgeschaltet wird - nicht vorher. Denn dann hättest Du nur noch
empfangen dürfen:
OK\r\n
OK\r\n
OK\r\n
... usw.
Leider hast Du den spannenden Teil weggelassen.
Gruß,
Frank
EDIT:
Ich würde das Modem an eine Terminalemulation anschließen und selbst
dauerhaft auf ohne Echo umprogrammieren, also:
ATE0 Echo aus
AT&W Konfiguration abspeichern (Vorsicht: Modem-Typ-Relevant!)
f95 schrieb:> Gibt es denn keinen Trick wie man so eine Verbindung> spiegeln kann, sodass ich mir den Datenfluss im Terminal angucken kann?
Häng dich an die Leitungen zum Modem.
Entweder vollduplex, dann brauchst du zwei weitere serielle Ports.
Oder nutze den Umstand, dass die Kommunikation halbduplex abläuft und
schalte die beiden Datenleitungen über ein Dioden-Oder zusammen.
Zur Grundidee des Dioden-Oder siehe
http://www.serialmon.com/cables/3.html
Grüße
Stefan
und Danke für den Tipp mit den Dioden doch das lässt sich leider hier
nicht verbauen.
Also ich habe jetzt noch ein wenig weiter rumgespielt und mir die
letzten ampfangenen befehl auf Knopfdruck, also wenn die UART umgesteckt
wurde auf das Terminal. Dann ist die Antwort nachdem ich den Befehl
at+cpin benutzt habe.
Es liegt wahrscheinlich an meiner Zählmethode nur fällt mir gerade keine
andere Möglichkeit ein den Text zwischen <CR><LF>TEXT<CR><LF> auszulesen
außer die Zeichen zu ignorieren und die letzten Zeichen sprich das LF zu
zählen.
f95 schrieb:> Modem start> ->at<\r>>> Antwort:> at<\r><\r><\n>OK<\r><\n>
Das ist das was du im Terminal siehst.
Tatsächlich ist aber die zeitliche Abfolge höchst wahrscheinlich ein
wenig anders.
Du tippst 'a' und das Modem antwortet sofort mit dem Echo 'a'. Du tippst
't' und das Modem antwortet sofort mit einem 't'. Du tippst Enter (also
\r) und das Modem antwortet sofort mit einem \r.
Bis hier her ist das nicht die 'Antwort' sondern das Echo.
Dann bearbeitet das Modem die Zeile und erst jetzt antwortet es
\r\nOK\r\n
Jetzt kommt der knifflige Punkt. Je nachdem wie schnell dein Programm
ist und wie lange das Modem zur Bearbeitung des Kommandos braucht,
kriegt es vom Echo noch was mit oder eben auch nicht. Das kann zb ein \r
(vom Echo) zuviel sein.
Wie kann man das Problem lösen, dass man nicht weiß, was man genau
kriegt. Eine Möglichkeit ist zb: Echo dauerhaft abschalten. Das ist
unumgänglich. Dein Programm braucht das Echo nicht, es verkompliziert
nur alles, weil das Programm dann eigentlich das Echo ausfiltern muss.
Echo ist gut, wenn ich mich mit einem Terminal an ein Gerät klemme,
damit ich beim Tippen sehe was ich tippe. Echo ist auch gut, damit ich
im Terminal sofort sehe ob die Baudrate stimmt oder ob es da ein Problem
gibt. Aber für ein Programm ist es die Hölle vom Gerät ein Echo zu
bekommen, das ausgefiltert werden muss. Das legt dir ein sehr enges
Korsett an, wie du das Timing deines Programmes gestalten musst. Denn:
Du darfst vom Echo kein einziges Byte verpassen. Du musst jederzeit in
der Lage sein Echo und Antwort auseinander zu halten.
Zum anderen wissen wir, dass das Modem NIE mit einer leeren Zeile
antwortet. Die Antwort auf irgendein AT-Kommando ist immer eine
nichtleere Zeile. Ist also ein \r\n empfangen worden UND ist dabei eine
leere Zeile entstanden, dann war dieser \r\n noch nicht der letzte
sondern da kommt noch was. Nämlich die Zeile in der dann die richtige
Antwort steht. Dadurch dass du das erste \r vom Echo fälschlicherweise
mitgezählt hast, ist alles durcheinander gekommen.
f95 schrieb:> nur fällt mir gerade keine andere Möglichkeit ein den Text zwischen> <CR><LF>TEXT<CR><LF> auszulesen außer die Zeichen zu ignorieren und> die letzten Zeichen sprich das LF zu zählen
Bau dir doch eine finite state machine (FSM) für die Analyse des
Zeichenstroms.
Grüße
Stefan
f95 schrieb:> Weiterer AT Befehl:> ->at<\r>>> Antwort:> <\r><\n>> OK<\r><\n>
Okay, jetzt, wo das Echo abgeschaltet ist, siehst Du eine Leerzeile vor
dem OK.
Dann könnte nun die Empfangsroutine folgendermaßen aussehen:
1
voiduart_get_str(char*s)
2
{
3
unsignedcharlen=0;
4
unsignedcharc;
5
6
while(1)
7
{
8
c=uart_getc();
9
10
if(c=='\n')
11
{
12
if(len>0)
13
{
14
break;
15
}
16
}
17
elseif(c!='\r')
18
{
19
*s++=c;
20
len++;
21
}
22
}
23
*s=0;
24
uart_str(answer);
25
uart_c('\n');
26
}
Diese Funktion ignoriert Leerzeilen, indem sie die Anzahl der zu
speichernden Zeichen mitzählt. Finde ich einfacher und sicherer, als
Zeilenenden zählen zu wollen.
Danke hat super funktioniert. Habe zwar jetzt ein paar Attefakte auf der
Leitung. Ab und zu sendet er das letzte empfangene Zeichen aber das hat
keinen Einfluss auf das Modem. Da sehe ich eher das fehlende Quarz als
Problem.
Nochmals vielen Dank