Hallo!
Ich möchte verschiedene Befehle an ein GSM Modul schicken. Dafür habe
ich ein Struct definiert, in dem alle Strings (Befehle) stehen.
Dies sieht so aus:
Die Subroutine, die die Stings dann über USART an das GSM Modul schickt
siehst so aus:
1
voidGSM_WRITE(unsignedchar*CMD)
2
{
3
// clear display
4
LCD_COMMAND(0x01);
5
6
while(*CMD)
7
{
8
LCD_DATA(*CMD);
9
USART_TX(*CMD++);
10
}
11
}
Zum schluss, hier noch der Aufruf über eine Art state-machine. Der
Subroutine wird der Pointer auf den jeweiligen string im struct
übergeben.
1
while(1)
2
{
3
switch(STATE)
4
{
5
// init GSM module, just wait and send some CR
6
case0:
7
_delay_ms(1000);
8
_delay_ms(1000);
9
_delay_ms(1000);
10
11
USART_TX(0x0D);
12
USART_TX(0x0D);
13
USART_TX(0x0D);
14
15
NEXT_STATE=1;
16
break;
17
18
// send AT command to check state
19
case1:
20
GSM_WRITE(AT_CMD_PTR->AT);
21
22
ERROR=GSM_CHECK();
23
if(ERROR==0)NEXT_STATE=2;
24
if(ERROR==1)NEXT_STATE=1;
25
break;
26
27
// turn off echo
28
case2:
29
GSM_WRITE(AT_CMD_PTR->ATE0);
30
31
ERROR=GSM_CHECK();
32
if(ERROR==0)NEXT_STATE=3;
33
if(ERROR==1)NEXT_STATE=2;
34
break;
35
36
// send PIN code
37
case3:
38
GSM_WRITE(AT_CMD_PTR->AT_CPIN);
39
40
ERROR=GSM_CHECK();
41
if(ERROR==0)NEXT_STATE=4;
42
if(ERROR==1)NEXT_STATE=3;
43
break;
44
45
// set SMS to text mode (1)
46
case4:
47
GSM_WRITE(AT_CMD_PTR->AT_CMGF);
48
49
ERROR=GSM_CHECK();
50
if(ERROR==0)NEXT_STATE=5;
51
if(ERROR==1)NEXT_STATE=4;
52
break;
53
54
// set SMS notification and storage (1,1,0,2,1)
55
case5:
56
GSM_WRITE(AT_CMD_PTR->AT_CNMI);
57
58
ERROR=GSM_CHECK();
59
if(ERROR==0)NEXT_STATE=6;
60
if(ERROR==1)NEXT_STATE=5;
61
break;
62
63
// idle state, wait for input from GSM (SMS)
64
case6:
65
while(1)BLINK();
66
}
67
68
// set current state to next state
69
STATE=NEXT_STATE;
70
}
Es gibt noch viel mehr code mit den ganzen LCD subroutinen, aber ich
glaube das hat mit meinem probmel nichts zum tun. Wenn ich den code so
compiliere und an den Attiny2313 schicke, dann kommt ein ganz komisches
verhalten raus. Die Pointeradressen, die der subroutine übergeben
werden, stimmen nicht, die Ausgabe an der rs232 schnittstelle sieht dann
so aus:
Statt dem CPIN string: #Q
Statt dem CNMI string: <>i
Statt dem CMGF string: 11AT+CNMI=1
und so weiter. Es werden also irgendwelche chars übertragen. teilweise
dann auch wieder halbe strings. So, jetzt der komische / verwirrende
Teil. wenn ich vor dem struct, ein dummy array mit mindestens 2 x 10
elementen definiere (trial and error gg), funktioniert alles
einwandfrei:
1
unsignedcharDUMMY[2][10]={"X","X"};
2
3
// initialise struct and define pointer
4
CHAR_ARRAYAT_CMD=
5
{
6
"AT\0",
7
"ATE0\0",
8
"AT+CPIN=4053\0",
9
"AT+COPS=?\0",
10
"AT+CMGF=1\0",
11
"AT+CNMI=1,1,0,2,1\0",
12
"AT+CMGR=0\0",
13
"AT+CMGS=\"+436645416393\"\0",
14
"HZG EIN!\0",
15
"HZG AUS!\0"
16
};
Womit kann das zusammenhängen? wird das struct vielleicht in
irgendwelchen nicht zulässigen speicherbereichen definiert? Ich hoffe
die Frage ist so halbwegs verständlich :)
Vielen Dank im Voraus!
Daniel
Ja, und noch dazu:
Evtl. (insbesondere, wenn die Strings alle konstant sind), ist es auch
viel einfacher, gar nicht sie in der struct zu halten, sondern dort nur
Zeiger abzulegen (const char*).
Dann brauchst du gar nicht zu zählen, wie lang sie sind; der Compiler
macht den Rest.
Guten Morgen!
Danke für die schnellen Antworten! Also wenn ich das Array "AT" im
Struct definiere, hat das die größe 3 obwohl nur 2 chars enthalten sind?
Das '\0' Zeichen wird also automatisch hinzugefügt?
Erklährt diese falsche größendefinition auch das komische verhalten bei
der ausgabe der strings?
@Klaus: Hast du für für die abgelegten Zeiger vielleicht ein kurzes
code-schnipsel als beispiel? Ich bin leider noch nicht so fit was
pointer betrifft :)
Vielen Dank!
Ja, wenn Du ein String definierst, dann fügt der Compiler automatisch
noch das Stringende \0 hinzu. das erklärt dann auch das komische
Verhalten, die Struktur-Pointer passen nicht mehr...
Daniel K. schrieb:> Erklährt diese falsche größendefinition auch das komische verhalten bei> der ausgabe der strings?
Nein, das ist nicht die Ursache. Und die Größendefinition ist auch nicht
falsch. Bei
1
chara[3]="AT\0";
wird die automatische Null weggeschnitten und das Endergebnis ist exakt
das gleiche wie beim "korrekteren"
1
chara[3]="AT";
oder
1
chara[]="AT";
Daniel K. schrieb:> wenn ich vor dem struct, ein dummy array mit mindestens 2 x 10> elementen definiere (trial and error gg), funktioniert alles> einwandfrei:
Dann hast du vermutlich irgendeine Art von Memory-Corruption, z.B. ein
Out-Of-Bounds Schreibzugriff auf ein Array.
Daniel K. schrieb:> @Klaus: Hast du für für die abgelegten Zeiger vielleicht ein kurzes> code-schnipsel als beispiel? Ich bin leider noch nicht so fit was> pointer betrifft :)
Dann solltest du um die Dinger einen Bogen machen.
Bis jetzt konnte ich deinem Beispiel nicht wirklich entnehmen, wozu du
da überhaupt eine struct brauchst und warum du auf die struct über einen
Pointer zugreifst.
Alternativ kannst und solltest du natürlich die Dinge allerdings auch
richtig lernen. Mit STrings, und damit auch mit Pointern, korrekt
hantieren zu können ist eine der Grundfertigkeiten in C
So würde das aussehen
1
// define struct with all AT commands
2
typedefstruct
3
{
4
char*AT;
5
char*ATE0;
6
char*AT_CPIN;
7
char*AT_COPS;
8
char*AT_CMGF;
9
char*AT_CNMI;
10
char*AT_CMGR;
11
char*AT_CMGS;
12
char*SMS_TEXT_ON;
13
char*SMS_TEXT_OFF;
14
}CHAR_ARRAY;
15
16
// initialise struct and define pointer
17
CHAR_ARRAYAT_CMD=
18
{
19
"AT",
20
"ATE0",
21
"AT+CPIN=4053",
22
"AT+COPS=?",
23
"AT+CMGF=1",
24
"AT+CNMI=1,1,0,2,1",
25
"AT+CMGR=0",
26
"AT+CMGS=\"+436641111111\"",
27
"HZG EIN!",
28
"HZG AUS!"
29
};
Das würde dem ganze dann wenigstens die Wendung geben, die eine
derartige Struktur rechtfertigen würde: Für unterschiedliche Geräte
sehen die Strings anders aus und haben natürlich auch andere Längen, was
mit dieser Lösung kein Problem mehr darstellt.
Aber wie Stefan schon sagte: Das ist nicht dein eigentliches Problem. Da
muss in deinem Programm noch was anderes faul sein.
PS: Deine konsequente Grossschreibung aller Variablennamen ist keine
gute Idee. Wenn es eine Übereinkunft gibt, an die sich tatsächlich mehr
oder weniger alle C-Programmierer weltweit halten, dann ist es die,
dass Namen komplett in Grossbuchstaben ausschliesslich für Makros
reserviert sind. Im Code kann es einen Unterschied machen, ob man es mit
einem echten Makro oder mit einer echten Funktion zu tun hat, so dass es
an manchen Stellen lebenswichtig sein kann, diese Information schnell zu
sehen. Die Konvention von "ausschliesslich Grossbuchstaben sind ein
Kennzeichen für ein Makro" erfüllt diese Information, so dass es Sinn
macht sich an diese Konvention zu halten.
Auch du solltest das tun. Denn auf lange Sicht gesehen erzeugst du mit
einer anderen Konvention (deiner eigenen) nur Konfusion.
Karl Heinz Buchegger schrieb:> So würde das aussehen
danke, ja.
So meinte ich das.
Karl Heinz Buchegger schrieb:> Dann solltest du um die Dinger einen Bogen machen.
Wenn er Felder nimmt, hat er doch auch Zeiger - er sieht nur erst etwas
später.
Klaus Wachtler schrieb:>> Dann solltest du um die Dinger einen Bogen machen.>> Wenn er Felder nimmt, hat er doch auch Zeiger - er sieht nur erst etwas> später.
Jein.
Ein Array wird per Zeiger an eine Funktion übergeben. Schon richtig.
Aber ein Array ist kein Zeiger.
Im Programm ist die Verwendung der Struktur faul. Eine Struktur ist kein
Array und somit zieht sowas wie *CMD++ nicht. Damit würde dein Programm
auf speicher zurück greifen der hinter deine Struktur liegt. Also leg
dir lieber ein Array mit Pointern auf const char an dann kannst du
solche späße wie CMD++ machen.
Gruß Stefan
Stefan schrieb:> Im Programm ist die Verwendung der Struktur faul. Eine Struktur ist kein> Array und somit zieht sowas wie *CMD++ nicht.
Sorry, aber das ist Unsinn. CMD ist ja kein Pointer auf die Struktur,
sondern auf ein Array in dieser. Mit der Funktion GSM_WRITE und der
Verwendung von *CMD++ darin ist alles in Ordnung.
Hallo Leute!
wow, sehr viel input, danke euch. Das ist mein erstes Atmel C Programm,
habe früher immer PICs mit ASM programmiert, deshalb noch die ganzen
"Unschönheiten" im code.
Ist es theoretisch nicht egal ob man einzelne Arrays anlegt, die die
ganzen Strings enthalten oder die alle zusammen in einem struct
unterbringt? Der Hintergrund für das struct war eigentlich der ein
Artikel über Codeoptimierung. Die Idee des Zusammefassens von Variablen
in einem Struct hat mir gut gefallen:
http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Statische_.28globale.29_Variablen_in_einer_Struktur_sammeln
Zu den Variablennamen: Danke für den tip. wollte hier natürlich nicht
für verwirrung sorgen. Wird auf jeden Fall beim nächsten Projekt
berücksichtigt.
Ich werde heute Abend das Programm mal auf einem anderen Attiny laufen
lassen um zu sehen, ob das unerklärbare Verhalten immer noch auftritt.
Daniel
Daniel K. schrieb:> Ist es theoretisch nicht egal ob man einzelne Arrays anlegt, die die> ganzen Strings enthalten oder die alle zusammen in einem struct> unterbringt?
Mit der jetzigen struct Lösung (die mit den Pointern) verbrauchst du
mehr Speicher. Die vorhergehende struct Lösung hatte das Problem, dass
ein Ändern der Strings viel Arbeit nach sich zieht.
> Der Hintergrund für das struct war eigentlich der ein> Artikel über Codeoptimierung. Die Idee des Zusammefassens von Variablen> in einem Struct hat mir gut gefallen:>> http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Statische_.28globale.29_Variablen_in_einer_Struktur_sammeln>
Vergiss den Artikel. Besser gesagt diesen einen Abschnitt über
Strukturvariablen. Das dort gezeigte Beispiel ist nicht repräsentativ,
weil dieses gewählte Beispiel etwas ausser acht lässt: Die 3 Variablen
sind nicht voneinander unabhängig, sondern haben als Uhrzeit einen
logischen Zusammenhalt. Den hast du mit deinen Strings aber nicht.
Alleine die ganzen Strings brauchen bei einem ATTiny2313 (oder welcher
Tiny ist da drin?) über 80% vom Ram. Nachdem die gezeigten Sourcen nicht
komplett sind, ist es durchaus möglich, dass es noch wesentlich mehr
ist. Somit tippe ich auf einen Stackoverflow.
Dass der gcc bis zu eine \0 am Stringende automatisch wegschneidet hab
ich noch nicht gewusst. Stimmt aber, habs gerade ausprobiert. Erst wenn
mehrere \0 am Ende sind, sind die auch im Code enthalten.
Die ganzen Texte sollten im Flash abgelegt werden und die Fehler mit den
Pointern behoben werden (es gibt beim Compilieren von obigem Code
mindestens 2 Warnings wegen falschen Datentypen).
Grüße,
Peter
Karl Heinz Buchegger schrieb:> Jein.> Ein Array wird per Zeiger an eine Funktion übergeben. Schon richtig.> Aber ein Array ist kein Zeiger.
Auch in anderen Ausdrücken ist der Feldname ein (const-) Zeiger auf das
erste Element.