Hallo !
Ich bin noch Anfänger in Sachen "c" und steh grad vor nem Problem, das
ich mit Hilfe meines tollen Lehrbuchs irgendwie auch nicht gelöst
bekomme. Wahrscheinlich für die meisten eine simple Sache. Wie kann ich
mehrere Bytes, welche über den USART kommen (maximal 64Byte) in einen
Buffer speichern und auswerten ? Ich möchte also Display Befehle die in
etwa so ankommen"11 04 1B 41 01 01 73" (11 gleich Anfang, 04 gleich
länge der Nutzdaten, 73 = Checksumme) mit einem Switch Case auswerten
können. Hier mal ein Codeschnipsel;
//--------------------DATEN IM EDIP-PUFFER--------------------
4
intpaket_fordern()
5
6
{
7
SBUF_EDIP=0;
8
9
putch(0x12);//<DC2>
10
putch(0x01);//1(len)
11
putch(0x53);//S
12
putch(0x66);//66(bcc)
13
14
while((!(UCSRA&(1<<UDRE))))
15
{
16
getche();
17
}
18
19
charx=UDR;
20
switch(x)
21
{
22
23
case'11041B41010173'://rote LED an
24
{
25
PORTB=(1<<PB0);
26
}
27
28
break;
29
30
case'11041B41010274'://grüne LED an
31
{
32
PORTB=(1<<PB2);
33
}
34
35
break;
36
37
default:
38
{
39
;//beide aus
40
}
41
42
break;
43
}
44
45
return(0);
46
}
Ich müsste wahrscheinlich ein ARRAY anlegen richtig ? Aber wie genau ?
Und kann ichs dann wirklich mit switch case machen ???
Die Daten werden auf jeden Fall schonmal so empfangen, das hat mir AVR
Term gezeigt. Schonmal DANKE für jede Hilfe !
Achso, hier noch die Funktion getche():
1
//Eingabe mit Echo von USART oder UART
2
3
unsignedchargetche(void)//warten und lesen mit echo
Markus S. schrieb:> Ich möchte also Display Befehle die in> etwa so ankommen"11 04 1B 41 01 01 73"
bist du sicher das sie wirklich so gesendet werden, oder werden sie nur
so angezeigt? Hex mit leerzeichen zu senden ist recht ungeöhnlich. Ich
vermute mal das eigentlich nur "bytes" gesendet werden.
Markus S. schrieb:> Da steht aber auch auf Seite 12 unten, dass Ascii und Binary möglich> ist....
dann sollte man erstmal in erfahrung bringen was wirklich ankommt. Er
will ja scheinbar ein Display simulieren.
Also da ja die letzten Zahlen der dargestelten Strings (73 bei grün und
74 bei rot) ja in ASCII s und t sind, und ich in den Anfängen einzelne
bytes im switch ausgewertet hab (in dem Beispiel Case s und Case t),
haben die LEDs darauf reagiert. Also geh ich davon aus, dass ich mit
ASCII darstellung arbeiten kann.
Du empfängst mit dem UART immer nur 1 Byte. Es liegt an dir diese
irgendwie zu speichern. Da wäre schon sowas wie eine Variable mit vielen
Bytes gut. Also ein Array von chars. Das macht man so in C :
char Buffer [16];
danach kannst du über eine Zahl oder Variable (Index genannt) auf
einzelne chars zugreifen
int i=0;
char was;
was=Buffer[5];
was=Buffer[i];
Wobei 0 das erste Element eines Arrays ist.
11 04 1B 41 01 01 73
11 04 1B 41 01 02 74
Du müßtest also an Position 5 gucken.
Aber du solltest dein Protokol interpretieren und die. Denn genau dafür
braucht man so ein Startbyte und die Längeninformation damit man
ausrechenen kann wann die Checksumme kommt. Statemachine bzw.
Zustandsautomat programmieren der dir das Protokoll aufdröselt.
Markus S. schrieb:> Also geh ich davon aus, dass ich mit> ASCII darstellung arbeiten kann.
gut dann sollte du erstmal anfangen das Protokoll umzusetzen. Du muss
also den Anfang und das ende der Nachricht erkennen können.
du braucht einen einen Puffer für die daten der erstmal gefüllt wird
uint8_t[80] data
dort muss du erstmal schaffen ein datenpacket abzulegen, dann kannst du
mit dem auswerten erst weitermachen.
Danke Leute, das könnte mich ja schonmal weiter bringen. Also könnte ich
mir ja aus dem ARRAY jedesmal das zweite byte also Buffer[1] auswerten,
damit ich schonmal die Länge der Nutzdaten habe. Der Anfang ist ja immer
DC1 (also die 11), das steht ja fest
Markus S. schrieb:> Der Anfang ist ja immer> DC1 (also die 11), das steht ja fest
und was ist wenn eine 11 gesendet wird (also eine 11 dargestllt werden
woll)?
Hm ? Die soll ja nie dargestellt werden. Im Grunde gehts grad nur um die
DOWNCODES der Touchbuttons. Der Button "grün" z.B. hat jetzt grad für
Tests die "1", und die steht immer nach "A 1". Also weiss ich, dass
wennich ein Button abfrage, wo ich gucken muss.
Mann mann mann.... ich bekomme bei dem Drücken auf "grün" ja direkt
meinen Code zum Displayspeicher auslesen, das ACK vom Display, dann
nochmal den Auslesecode und dan erst Den Inhalt des Displaypuffers
zurück - alles gleichzeitig !. Ich werde noch verrückt mit der
Auswertung :-(
Das sieht so aus:
12 01 53 66 (Anforderung Sendepuffer) 06 (Das ACK vom Display= 12 01 53
66 (wieder der Code) 11 04 1B 41 01 01 73 (Pufferinhalt des Displays)
Was ein "KOT" !
Ist das denn so möglich ??
Markus S. schrieb:> Buffer[64]=UDR;
was erwartest was was hier passieren soll?
Du sollst zuerst ein vollständiges Packet (mehre zeichen) einlesen und
wenn das vollständig ist auswerten.
Danke, habs auch grad erst verstanden, aber schon umgesetzt. Die
Auswertung stimmt aber immer noch nicht, obwohl ich mit dem Pointer
mehrere Positionen probiert habe.
1
//--------------------DATEN IM EDIP-PUFFER--------------------
Nein.
Was soll das sein?
Tu dir selbst einen Gefallen und lern doch erst mal die Grundlagen.
Versteh, was die einzelnen Komponenten machen und warum der Code so ist
wie er ist
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
Das hat keinen Sinn was du da machst.
Benutz wenigstens die Funktionen, die du im Link finden kannst. Da gibt
es eine Funktion, die auf 1 Zeichen wartet und das dann zurückliefert.
Das ist dein Basisbaustein, den lässt du so wie er ist und den benutzt
du um die Bytes zu empfangen, die einen Frame ausmachen.
Hallo Markus
Ich verwende ebnfalls eine UART und lese Telegramme von einer
Gegenstelle ein.
Ich verwende hizu einen Puffer z.B. InPuffer[255] in dem ich 255 Zeichen
speichern kann. Ich habe zwei Adressen eine Adresse InPufferAdrWr mit
der ich den Puffer beschreibe und eine Adresse InPufferAdrRd mit der ich
den Puffer auslese. Zusätzlich wird bei jedem eingelesenem Zeichen
(8Bit)ein Zähler inc. der die noch nicht ausgewerteten Zeichen zählt.
Ist der Null dann kann ich mir die Auswertung ersparen.
Ich nehem an du weißt wieviele Zeichen du erhalten sollts und erst wenn
die Anzahl eingelangt ist werte ich diese aus.
Ich erkenne einmal das Startzeichen, setze ein Bit für die Erkennung des
Startzeichen lösche das augelesenen Zeichen aus dem Puffer und gehe dann
zur Detailauswertung der verschiedenen Telegammtypen.
Jedesmal wenn ich Zeichen ausgelesen habe werden sie aus dem Puffer
gelöscht, Achtung nicht zu früh löschen du musst ja auch die Checksum
berechnen um einen Vergleich zur Empfangen Sum zu haben.
Lg.
Johann K.
Erstmal vielen Dank für die Tipps!
Aber das klingt ja schon etwas kompliziert für nen Neuling wie mich :-)
Dafür das man "nur " ne Taste auswerten möchte ....
Na ich werd ja nicht drumherum kommen. Hast Du denn mal ein Muster für
mich, ich kann mir das beseer beibringen, wenn ich weiss wie es
auzusehen hat.
Markus S. schrieb:> Erstmal vielen Dank für die Tipps!>> Aber das klingt ja schon etwas kompliziert für nen Neuling wie mich :-)> Dafür das man "nur " ne Taste auswerten möchte ....
Das was du vorhast, erfordert schon einiges an Können.
Bitte, hier meine Einleseroutine
Ist nich schwierig, ich habe zu den einzelnen Zeilen Ziffen
hinzugeschrieben
1... ich beginne den Puffer bei 1 zu beschreiben, wenn die Adresse 512
ist dann schreibe ich 1.
2... ich kontrolliere ob ich vorhanden Daten überschreibe
3... erhöhe den Zähler der noch nicht behandelten Zeichen
4... schreibe das empfangene Zeichen in den Puffer
5... nächste Schreibadresse wird erzeugt.
Einmal der Empfang.
Ich schick dir noch eine Auswertung, aber später.
tschau.
************************************
void vInSerielPufWr(char cData){
1 if(iServInPufWrAdr==512){iServInPufWrAdr=1;}
2 if(caServInPuf[iServInPufWrAdr]!= 0){ //Speicherplatz leer?
//Fehlertabelle beschreiben
}
3 iServInPufCount++; //Anzahl der unbearbeiteten Byte's
4 caServInPuf[iServInPufWrAdr]=cData; //Daten in den Puffer schreiben
5 iServInPufWrAdr++; //nächste Adresse
}//vInSerielPufWr
Klatec, deine Bemühungen in allen Ehren. Aber schau dir seinen Code an.
Da scheiterts daran eine Anzahl Zeichen hintereinander zu empfangen!
Multibuffering ist 3 Stufen über dem Level auf dem seine Probleme
liegen.
Erst mal muss er 1 Zeichen empfangen. In einer Funktion.
Dann in einer Schleife eine antsprechende Anzahl Zeichen empfangen,
indem er die Funktion aufruft.
Das beste am besten gleich unter Berücksichtigung des Protokolls. D.h.
in Frame beginnt mit 0x11 und alles was nicht 0x11 wird verworfen, ehe
der Frameanfang kommt.
Aber eines nach dem anderen. Erst mal die Einzelzeichenfunktionen in
Betrieb nehmen. Und das am besten erst mal im Zusammenspiel mit einem PC
damit man auch sieht was man schickt bzw. per Tastatur gezielt antworten
kann.
2. Teil
Ich verwende den Interrupt der UART für den Enpfang der Zeichen und
springe von der Serviceroutine eben zur Beschreibung des Puffers.
Diese Routine löscht die gelsenen Zeichen aus dem Puffer
void vInServPufClear(void)
int i = 0;
for(i=0;i<512;i++){
caServInPuf[i]=0;
}
}//vInServPufClear
*************************************
Diese Routine verwende ich zum auswerten der Zeichen, wobei ich
Telegramme mit fixer Länge und variabler Länge oder ein ACK-Zeichen mit
einem Byte verwende.
Ich habe mal den Großteil der Funktionen gelöscht so das der Code
einfach zum überschauen ist.
Es ist nur mehr die Auswertung der Telegramme mit fixer Länge geblieben.
Kopier den Code heraus und formatiere ihn neu, weil so sieht er
furchtbar aus.
1... keine neuen Zeichen, dann wieder raus
2... wurde schon ein Startbyte erkannt? (10h)
3... wenn ja, dan warten bis genügend Zeichen vorhanden
4... Startzeichenerkennung
5... Zeichen aus dem Puffer löschen
***************************************
void vInZeichAusweServ(void){
1 while(iServInPufCount!=0) //sind nicht bearbeitet Zeichen im
Eingagnspuffer?
{
2 if(cStartByteServFix == 0xFF){ // Startbyte für Tel. fixer Länge
3 if(iServInPufCount > 6) //Telegrammlänge 8 Byte
{
ucTimeOutServ=0; //Timeout rücksetzen
vInTelServFixErk();
cStartByteServFix=0;
return;
}
else{return;}
}
4 if(caServInPuf[iServInPufRdAdr] == 0x10) /* Startbyte für Tel.
fixer Länge*/
{
ucTimerTimeOutServ=vServsTimeOutCal(7); //Timerladen
cStartByteServFix = 0xFF;
}
5 vServsInCountClear(1);
}
}
**************************+
Lg.
Johann K.
Hallo Markus
NIchts zu danken, hab dich bloß an meinen Gedanken teilhaben lassen.
Ich halt von Internet normalerweise nicht viel aber in diesem Falle
ist's super. Wenn ich an die ersten Schritte denke dich ich mit dem
80C535 (51er Familie) gemacht habe und das in Assambler. Ich benötige
für einen Progammcode der nur über 4 oder 5 Zeilen gegangen ist, zwei
Wochen bis ich ihn verstanden habe und das ohne Internet (1994). Laß
dich von so manchen Aussagen nicht entmutigen.
Lg.
Johann K.