PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C macht mich wahnsinnig



jagdfalke
13.12.2005, 21:43
Hi,
ich will, dass mein PC mit dem AVR über UART kommunizieren kann. Erstmal soll der Controller nur Befehle empfangen können, später Daten zurücksenden.
Wenigstens kann ich schon mal interruptgesteuert Zeichen vom UART lesen. Das ist ja schon mal was. Aber jetzt kommen wieder C Basics ins Spiel. Ich warte jetzt auf ein Startzeichen und hänge dann alle empfangenen Zeichen aneinander, bis das Stopzeichen kommt. Dann soll das bis jetzt Empfangene ausgewertet werden.

1. Frage:
Wie hänge ich ein char an einen String? Das ganze soll auch in der Länge variabel sein.

2. Frage:
Wie vergleiche ich 2 chars?
if(c == 't') funktioniert ja nicht. Da kommt immer die Meldung, dass das immer false ist aus irgendeinem bescheuerten Grund.


C ist schon seltsam.

mfg
jagdfalke

Andun
13.12.2005, 22:03
Das Problem ist, dass Strings keinen eigenen Datentypen sind. Strings sind arrays. Deswegen kann man sie auch nciht direkt aneinander hängen.

Da gibt es spezielle Funktionen. Musste mal nach suchen in der Doku.

Andun

izaseba
13.12.2005, 23:07
Und was hälst Du von einem Puffer im RAM z.B. 10 Bytes,
dort verschiebst Du Deine empfangenen Zeichen hin, bis ein Stop Zeichen kommt.
Dann kannst Du alles mit weiß was ich was vergleichen, ohne chars an Strings anhängen zu müssen.
C ist nicht seltsam, sondern Deine Denkweise ist seltsam.

Gruß Sebastian

argentan
14.12.2005, 09:48
Moin!

Ein String ist ein Array of Char.
Es gibt zwei Möglichkeiten dein Problem zu lösen.
Die Primitive:
Man kann sich anfangs einen Buffer erzeugen (volatile char ca_x[20];), mit der maximalen Nachrichtengrösse, dazu einen volatile char counter, der bei jedem empfangenen Zeichen hochgezählt wird und als Index für das Array genutzt wird.
Interrupt:
counter++;
ca_x[counter]=Zeichen vom UART;


Eleganter dürfte die Variante mit Pointern sein, aber auch da wird der Pointer im Interrupt hochgesetzt. Und dann an die Stelle auf die der Pointer zeigt das Zeichen geschrieben.


Zum Problem mit dem char Vergleich:
Eigentlich müsste es gehen. (Bei mir geht es, aber ich nutze auch einen Fujitsu Microcotroller & Workbench)

Man könnte das Problem umgehen, in dem man die Zeichen nach dem Ascii Code zu Zahlen umwandelt. Also nicht uc=='a' sondern uc==0x61 oder uc==97.

eine empfehlenswerte Seite:
http://www.pronix.de/pronix-735.html

MfG Argentan

askazo
14.12.2005, 10:10
Umfangreiche String-Funktionen findest Du in der string.h (liegt in avr\include). Wenn Du viel mit Strings arbeitest, kommst Du an ihr nicht vorbei.
Dort findest Du z.B. Funktionen zum Vergleichen von Strings (strcmp), zum ermitteln der Länge von Strings oder zum kombinieren von Strings. Beschrieben sind die Funktionen im libc manual.
Wenn Du Fragen dazu hast, melde Dich, ich kenne die string.h eigentlich recht gut...

askazo

PicNick
14.12.2005, 10:15
Interrupt:
counter++;
ca_x[counter]=Zeichen vom UART;


Incrementieren eher nachher, denk ich, was steht den dann auf ca_x[0] ?


Also nicht uc=='a' sondern uc==0x61 oder uc==97.
Das ist für C Jacke wie Hose. Vergeßt aber nicht die Klein/Großschreibung

jagdfalke
14.12.2005, 12:00
also z.B. so ?




char readChar(void);
char str* = "";

SIGNAL(SIG_USART_RECV) {
s = readChar():
s++;
}



mfg
jagdfalke

PicNick
14.12.2005, 12:54
char readChar(void);
char Instring[MAX_CHAR];
char InIdx = 0;

SIGNAL(SIG_USART_RECV) {
Instring[InIdx] = readChar();
switch (Instring[InIdx])
{
case ENTER: // ev. signalisieren an "Main()"
Instring[InIdx] = 0; // korr. Stringterminator to \0
break;
case START: // Startzeichen ??
InIdx = 0;
break;
default:
InIdx++;
break;
}
if (InIdx > MAX_CHAR)
{ overflow, was machen wir ? }
}

So etwa halt
Nicht berücksichtigt sind falsche Zeichen, CAN od. Delete usw. und ECHO, wenn es eine Tastatureingabe ist
Die Auswertung ist Case-Sensitiv, muß man aufpassen

jagdfalke
14.12.2005, 13:01
START und ENTER sind hier char-Variablen, die die Start- bzw Stoppzeichen enthalten oder? Ok, habs gecheckt.
Das wäre dann die Methode mit begrenzter Länge. Und wie geht das mit diesem Pointer-Ding?

mfg
jagdfalke

PicNick
14.12.2005, 14:09
Pointer oder Index läuft auf das gleiche raus. Index is ein Pointer ab feldanfang, Pointer ab Speicheranfang. Ich würde mich entscheiden, je nachdem WO und WIE ich im restlichen Programm die Daten brauch oder hab'.


char readChar(void);
char Instring[MAX_CHAR];
char* InPnt = (char*)&Instring[0]; // ich geh gern auf Nr.Sicher und caste

SIGNAL(SIG_USART_RECV) {
*InPnt = readChar();
switch (*InPnt)
{
case ENTER: // ev. signalisieren an "Main()"
*InPnt = 0;
break;
case START: // Startzeichen ??
InPnt = (char*)&Instring[0];
break;
default:
InPnt++;
break;
}
}

jagdfalke
14.12.2005, 17:40
Wenn jetzt das Stop-Zeichen kommt setzt du immer das nächste Zeichen auf 0, richtig? Aber dann kann ich ja schlecht ne 0 empfangen ohne, dass die Position gleich als Ende angesehen wird. Ist doch ungüstig oder?

mfg
jagdfalke

jagdfalke
14.12.2005, 17:54
schaut euch mal das hier an:


char inStr[500];
int inCnt = 0;
char stopsign = 'a';
char startsign = 'b';

SIGNAL(SIG_USART_RECV) {
inStr[inCnt] = uart_readChar();

switch (inStr[inCnt])
{
case stopsign:
printf("STOPBIT EMPFANGEN: %s\n\r", inStr);
inCnt=0;
break;
case startsign:
printf("RESTART");
inCnt=0;
break;
default:
inCnt++;
break;
}
}


Die Fehlermeldung hier lautet:


test.c: In function '__vector_13':
test.c:53: error: case label does not reduce to an integer constant
test.c:57: error: case label does not reduce to an integer constant
make: *** [test.o] Fehler 1


Was bedeutet das? "does not reduce to an integer constant" ???

mfg
jagdfalke

Psiyou
14.12.2005, 18:06
Hi,

kannst keine Variable fuer einen Fall verwenden (wert koennte isch dann ja aendern). Nimm einfach ein Define.



#define stopsign 'a'
#define startsign 'b'

jagdfalke
14.12.2005, 18:21
Danke, kann man dann auch den Inhalt des Arrays löschen? Damit bei der Ausgaben nicht immer der Datenmüll vom letzten Empfang angezeigt wird?

PicNick
14.12.2005, 19:13
Wenn du nach dem Stopsign den InIdx NICHT löscht, zeigt er
1 die Länge der Daten an. Nach dem AUSWERTEN setzt du erst auf NULL.
2 isser null, gilt der input als leer, also auch nix zum herzeigen.
Aber bei sowas kommt es jetzt schon sehr auf das Umfeld an, genauso wie mit dem \0 am Schluss. der hat nur einen Sinn bei String-input.

paladin
17.12.2005, 19:42
wenn ich mich nicht ganz irre kannst du wenn du das stop zeichen erhalten hast einfach ein '\0' eintragen wenn ich mich nicht ganz irre ist das das ende signal für ein string.(zumindest beim PC).

Paladin

also sollte der code in etwas so aussehen



#define stopsign 'a'
#define startsign 'b'

char inStr[500]; //könnte ein bischen gross sein
int inCnt = 0;

SIGNAL(SIG_USART_RECV) {
inStr[inCnt] = uart_readChar();

switch (inStr[inCnt])
{
case stopsign:
inStr[inCnt]='\0';
printf("STOPBIT EMPFANGEN: %s\n\r", inStr);
inCnt=0;
break;
case startsign:
printf("RESTART");
inCnt=0;
break;
default:
inCnt++;
break;
}
}


dadurch wird aber die ISR eigentlich ziehmlich lang weil print lange dauern kann besser währe es wenn du auf ein start signal wartest und dann in einen buffer schreibst und wenn du ds stop bit erhälts dann soll ein stringready flag gesetzt werden was dann im hauptrogramm abgerufen wird.





#define stopsign 'a'
#define startsign 'b'

char inStr[500]; //könnte ein bischen gross sein
int inCnt = 0;
flag_string_da=0;
flag_string_lesen=0;

SIGNAL(SIG_USART_RECV) {
unsigned char tmp=UDR; //auslesen der gesendeten daten

if (tmp == startbit)
flag_string_lesen=1;
else if (tmp == startbit){
inStr[count] = '\0';// ende des strings
flag_string_lesen=0;
flag_string_da=1;
// hier kann auch eine eventuelle rücksetztung des count stattfinden je nach auswertung
}
if ( flag_string_lesen==1){
inStr[count++] = tmp;
}

}

in der main muss jetzt nur noch flag_string_da im MAIN ausgewertet werden.



Der code ist nicht getestet aber das prinzip sollte funktionieren ohne dabei alle interrupts oder den controller zu blockieren.