Hallo zusammen, ich zerbreche mir jetzt schon seit Tagen den Kopf, wie ich folgendes Problem am besten lösen kann: Ich möchte einen 110 Zeichen langen String auf bestimmte Zeichen untersuchen, die immer an der gleichen Stelle auftreten können. Stelle 31, 32 und 38 sind für meine Anwendung wichtig. Wenn dort die Zeichen 1,2,4 und 8 auftreten soll mittels Counter „hoch gezählt“ werden. Die Daten sollen nur untersucht werden. Für diese Auswertung soll ein ATmega 1280 eingesetzt werden, dessen USARTs mit zwei Geräten verbunden werden soll. Der Mikrocontroller empfängt die seriellen Daten und soll die besagten Stellen überprüfen. Wurden 50 mal das Auftreten der erwähnten Zeichen detektiert, also Conter=50, soll ein Befehl ausgesandt werden, der zum Gerät 1 sagt, sende mir die Log-Daten. Diese Log-Daten sollen dann an Gerät 2 weitergesendet werden. Im Forum hab ich vereinzelt, Beiträge gefunden, die sich mit der gleichen Thematik auseinandersetzen. Leider haben sie mir nicht weiter geholfen. Frage 1: Hat jemand eine Idee, wie ich die Prüfroutine am besten realisieren könnte? Ich steh total auf dem Schlauch! Ich benötige ja eine Art Terminator, um das erste Zeichen eindeutig zu identifizieren. Dann muss ich ja irgendwie bis zur Stelle 31, 32 bzw. 38 zählen und das dort stehende Zeichen mit 1,2,4 und 8 vergleichen. Wenn eine Übereinstimmung vorliegt, Counter um eins erhöhen. Wie mach ich das??? Warten bis Zeichen empfangen wurde… while (!(UCSR0A & (1<<UDRE0))); UDR0 = x; . . . und dann? Oje… Frage 2: Den im HTerm abgegriffener String liegt im ASCII-Format vor. Der USART empfängt allerdings die Hex-Bytes, oder? Ein String sieht bspw. so aus: 09450455627…12BC\r\n bzw. wird so im HTERM dargestellt. Beginnt also immer mit bzw. 0x04. Wie empfange ich jetzt bei meinem USART die Zeichen? Mittels UCSR0C kann ich ja die Datenlänge einstellen, also 8 Bit UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00); Ich empfange also als erstes Zeichen 0x04, oder? Frage 3: Wie könnte ich das mit den ausgelesenen Log-Daten am besten handeln? Txt-File draus machen und weiter senden? Oder einfach USART RXEN0=auf TXEN1 setzen? Ich wäre wirklich dankbar, wenn mir jemand Hinweise und Tipps geben könnte. Vielen Dank und VG
Fehler: >> Wie mach ich das??? Warten bis Zeichen empfangen wurde… >> while (!(UCSR0A & (1<<UDRE0))); >> UDR0 = x; >> . >> . >> . >> und dann? Oje… while (!(UCSRDA & (1 << RXC))); x=UDR0; Keiner ne Ahnung, wie ich das am besten machen könnte?
Die kurze Anteort ist: lerne programmieren. Und zwar mit einfacheren Dingen, wenn dir etwas derart Popeliges schon seit Tagen Kopfzerbrechen bereitet.
1 | uint8_t uart_getc(void) |
2 | {
|
3 | while (!(UCSR0A & (1<<RXC))) // warten bis Zeichen verfuegbar |
4 | ;
|
5 | return UDR; // Zeichen aus UDR an Aufrufer zurueckgeben |
6 | }
|
7 | |
8 | |
9 | int main() |
10 | {
|
11 | |
12 | ...
|
13 | |
14 | while( 1 ) { |
15 | |
16 | c = uart_getc(); // warte auf Zeichen |
17 | |
18 | if( c == 0x04 ) // war es der Terminator? |
19 | charCounter = 0; // wenn ja, dann fängt die Zählung der Zeichen von vorne an |
20 | |
21 | else { |
22 | charCounter++; |
23 | |
24 | if( charCounter == 31 || |
25 | charCounter == 32 || |
26 | charCounter == 38 ) { // die neuralgischen Punkt |
27 | |
28 | if( c == '1' || |
29 | c == '2' || |
30 | c == '4' || |
31 | c == '8' ) { // UND dann auch noch das richtige Zeichen |
32 | hitCount++; |
33 | |
34 | if( hitCount == 50 ) { |
35 | ....
|
36 | hitCount = 0; |
37 | }
|
38 | }
|
39 | }
|
40 | }
|
41 | }
|
42 | |
43 | ....
|
Hallo Karl-Heinz, danke für die Antwort...Ich hab mir das doch etwas komplizierter vorgestellt, als es am Ende ist. Nochmals vielen Dank und schönen Abend noch. VG
Bedenke aber: Ich hab keine Ahnung ob bei dir tatsächlich 0x04 der Terminator ist, der einen neuen Datensatz kennzeichnet. Das ganze ist nur ein ungefährer Entwurf. Es geht einfach nur darum, dass du ein paar Zähler hast, die ab Empfang des Terminators mitzählen, das wievielte Zeichen da gerade reingekommen ist und bei deinen magischen Zeichenzahlen sich das Zeichen selber ansehen und dann entsprechend agieren.
OK, ich hab da viel zu kompliziert gedacht.... Oh, zu meiner zweiten Frage, zwecks den Log-Daten. Reicht es da RX von meinem USART1 (Gerät1) auf den TX von meinem USART2 (Gerät2) zu setzen und die Daten einfach durch zugeben, geht das ohne weiteres, oder doch ein File? @ K.-H.: In der Tat, ich habe nicht allzu viel Erfahrung, aus diesem Grund frag ich ja. Das einem erfahrenen Prog. die Fragen etwas dümmlich vorkommen, kann ich allerdings gut verstehen:-) Bis dann und schöne Feiertage
Lars schrieb: > OK, > ich hab da viel zu kompliziert gedacht.... > Oh, zu meiner zweiten Frage, zwecks den Log-Daten. > Reicht es da RX von meinem USART1 (Gerät1) auf den TX von meinem USART2 > (Gerät2) zu setzen und die Daten einfach durch zugeben, geht das ohne > weiteres, oder doch ein File? Wie willst du denn auf dem µC ein File erstellen? Oder hast du am µC eine Festplatte oder wenigstens ein Dikettenlaufwerk angeschlossen? SD-Karte?
Lars schrieb: > Ich hab mir das doch etwas komplizierter > vorgestellt, als es am Ende ist. Darum gab er dir auch den guten Rat Programmieren zu lernen ...
Das war nur so ein Gedanke... Wobei das mit dem RX von USART 1 auf den TX von USART 2 legen gehen würde, oder? Ich hab da immer noch diese Vorstellung im Kopf, dass ich komplette Datenblöcke über den USART senden kann. Es gehen ja allerdings nur 8 Bit. Sprich, einzelne ASCII Zeichen bzw. deren Hex-Bytes, wie bspw. 0x04. Wenn ich das jetzt an ein Funkmodul schicken würde, wie bspw. an ein GSM-Modem, dann muss ich ja im Grunde die Daten erst zwischenspeichern, dann mittels AT-Befehlen einen Verbindung initiieren und die Daten dann übertragen. Und genau das versteh ich nicht. Kann ich das evtl. mit einem Ringpuffer lösen? Ich will wirklich nicht, dass man mir hier alles hin trägt. Möchte mich nur in die Thematik rein knien und das Ganze verstehen. Dir K.-H. nochmal Danke, dass hat mir doch schon sehr weiter geholfen. VG
> Das war nur so ein Gedanke... Wobei das mit dem RX von USART 1 auf den > TX von USART 2 legen gehen würde, oder? Geht, stell dir einfach vor, dass der uC dann nicht existieren würde--> Du würdest die Geräte mit einem RS-232-Kabel verbinden. Baudrate und Datenformat beider Geräte beachten! > Ich hab da immer noch diese Vorstellung im Kopf, dass ich komplette > Datenblöcke über den USART senden kann. Es gehen ja allerdings nur 8 > Bit. Sprich, einzelne ASCII Zeichen bzw. deren Hex-Bytes, wie bspw. > 0x04. Stimmt, es werden immer nur 8 Bit/ 1Byte über den USART gejagt. In deinem Programm kannst du dann die einzelnen Zeichen die empfangen werden an die bereits Empfangenen anhängen. Dann hast du ein String...Dieser String, wird aber auch wieder nur byteweise über den USART ausgegeben. Und pass auf, wenn du mit den AT-Comannds arbeitest! Du musst du die Zeichen in Hex-Bytes über den USART jagen also AT--> 0x41 0x54! > Wenn ich das jetzt an ein Funkmodul schicken würde, wie bspw. an ein > GSM-Modem, dann muss ich ja im Grunde die Daten erst zwischenspeichern, > dann mittels AT-Befehlen einen Verbindung initiieren und die Daten dann > übertragen. Und genau das versteh ich nicht. Kann ich das evtl. mit > einem Ringpuffer lösen? Du musst die einzelnen Zeichen wieder "auffangen" zusammensetzen und dann mittels AT-Befehlen verschicken! Also wieder bspw. mit Terminator zählen--> hab ich meinen ersten String? Ja?--> Achtung wieder die Hex-Umwandlung beachten! Zudem sendet dein Modem ja auch Befehle zurück. Die musst du natürlich auch berücksichtigen. Bspw. OK oder ERROR und die musst du natürlich auch auswerten. Falls Gerät2 auch Befehle/Nachrichten senden kann, du also ne bidirektionale Kommunikation hast, müsstest du das evtl. in einer Interruproutine rein packen, nicht das du was senden willst und der Interrupt von deinem USART2 wird ausgelöst und sag: Hey, ich hab was von Gerät zwei bekommen. Zuvor Pineingabe, etc. initialisieren, sodass du nur noch die Nachricht bzw. deine Daten übergeben musst, und ab geht die Post. Aufpassen! Es ist nur möglich, 160 Zeichen zu versenden (mit SMS)! Hoffe das hilft dir mal soweit weiter. Greez
Hallo Karsten, zunächst einmal Danke für die Antwort. Ich hab allerdings gelesen, dass man längere Auswertungen bzw. Ausgaben nicht in einem Interrupt behandeln sollte. Wenn ich bspw. ein Befehl zum Auslesen der Log-Daten sende, und diese dann empfangen und weiterleiten will,muss ich das irgendwie anders regeln, oder? Trotzdem Danke für die Antwort
Lars schrieb: > Hallo Karsten, > zunächst einmal Danke für die Antwort. Ich hab allerdings gelesen, dass > man längere Auswertungen bzw. Ausgaben nicht in einem Interrupt > behandeln sollte. definiere 'länger' > Wenn ich bspw. ein Befehl zum Auslesen der Log-Daten > sende, und diese dann empfangen und weiterleiten will,muss ich das > irgendwie anders regeln, oder? Du empfängst ja nicht das komplette Log-File in einem ISR Aufruf. Sondern wieder: Zeichen für Zeichen. Wenn du daher dieses eine Zeichen, deretwegen die ISR aufgerufen wurde, gleich wieder auf der anderen UART in den Ausgabebuffer stellst (mglw. mit einer FIFO), wie lange dauert das wohl? Daumenregeln wie 'ISR sollten kurz sein' sind gut. Aber sie sind in erster Linie auch nur das 'Daumenregeln', denen man mit Mass und Ziel gegenübertreten sollte.
Hi Karl-Heinz, wenn hitcount ==50 will ich ja einen Befehl an Gerät1 senden, und dieses Sendet mir nun die 50 Ereignisse (1 String=66 Zeichen). Wenn man jetzt das Bsp von Karsten nimmt und sagt, dass man jeden String versenden will, dann müsste man doch wie folgt vorgehen: Wenn also 50 erreicht sind, sende den Befehl zur Log-Übergabe! Dann kommt das Interrupt ins Spiel, oder? Wobei ich ja hier eigentlich wieder die folgende Funktion verwenden könnte...Bspw: uint8_t uart_getc_LOG(void) { while (!(UCSR0A & (1<<RXC))) ; return UDR; } Ich empfange ein Zeichen nach dem anderen. Ausgehend von meinem Terminator zähle ich dann die empfangenen Zeichen. Die einzelnen Zeichen muss ich dann in eine Art Buffer ablegen. OK, wenn nun dieser Buffer die 66 Zeichen voll hat, übergebe ich das Array an meine Sendefunktion. Muss das Bspw in einem Interrupt erfolgen. Das ich sage, ich unterbreche jetzt alles und empfange und versende nur noch die Log-Daten? VG
Lars schrieb: > Wenn also 50 erreicht sind, sende den Befehl zur Log-Übergabe! Dann > kommt das Interrupt ins Spiel, oder? Kann man so machen. > Wobei ich ja hier eigentlich wieder > die folgende Funktion verwenden könnte...Bspw: > > uint8_t uart_getc_LOG(void) > { > while (!(UCSR0A & (1<<RXC))) > ; > return UDR; > } > > Ich empfange ein Zeichen nach dem anderen. Darauf läuft es immer hinaus. > Ausgehend von meinem > Terminator zähle ich dann die empfangenen Zeichen. Die einzelnen Zeichen > muss ich dann in eine Art Buffer ablegen. OK, wenn nun dieser Buffer die > 66 Zeichen voll hat, übergebe ich das Array an meine Sendefunktion. Warum? Ich meine: warum willst du die Log-Daten zwischenspeichern? Machst du etwas damit? Wenn nicht, spricht doch nichts dagegen, jedes Zeichen das zu den Log-Daten gehört, sofort und ohne Verzögerung auf der anderen UART gleich wieder weiterzugeben. Dein Programm interessiert ja nicht, was in den Log-Daten selber enthalten ist. Es reicht einfach nur weiter. Und das kann es genausogut auf Zeichenebene machen als auf ganzen Strings. Die Zeichen abzählen kannst du auch, ohne sie zwischenspeichern zu müssen.
Wenn ich jetzt aber sagen will, bezogen auf das GSM-Modem"-Beispiel,
Sende den ersten String via SMS. Ich meine wenn der Mikrocontroller mit
Gerät1 und einem GSM-Modem verbunden ist.
Im Grunde muss ich ja, bevor ich was ans Modem schicke, die AT-Befehle
verwenden. Wenn ich ich jetzt jedes einzelne Zeichen so versenden bzw.
ans Modem weiterleiten würde, wäre das ja eigentlich kein Sinn machen,
zwecks Kosten.
OK, ich hab mich da auch ein bisschen ungeschickt ausgedrückt...
Ich will einen kompletten String "sammeln" damit ich ihn dann zum
Versand übergeben kann.
--> Nächster String "sammeln", versenden... Und so weiter.
> definiere 'länger'
Ich meinte damit genau dieses Procedere. Also die 50 Strings mit ihren
jeweils 66 Zeichen im Interrupt zu empfangen und dann bspw. jeden mit
SMS zu versenden.
Ok, dann war ja da nochmal so ne Sache, die Karsten angesprochen hat.
Und zwar wenn Gerät2 auch ne Nachricht mittels SMS an GSM-Modem 1 senden
würde. Der uC erhält ja dann die Nachricht eines Empfangs mittels
Interrupts. Wenn ich jetzt aber meinen "Log-Interrupt" zuvor ausgelöst
habe, werden zuerst meine Log-Daten versendet und dann kommt erst die
Bearbeitung der Nachricht von Gerät 2. Ein Interrupt müsste hier also
auf jeden Fall angewandt werden, sodass ich meine Sendefunktion nicht
durch das Interrupt von USART2 unterbrochen wird, oder?
VG
Was meinst du mit: "Passt das soweit?" Das hier? > Und zwar wenn Gerät2 auch ne Nachricht mittels SMS an GSM-Modem 1 senden > würde. Der uC erhält ja dann die Nachricht eines Empfangs mittels > Interrupts. Wenn ich jetzt aber meinen "Log-Interrupt" zuvor ausgelöst > habe, werden zuerst meine Log-Daten versendet und dann kommt erst die > Bearbeitung der Nachricht von Gerät 2. Ein Interrupt müsste hier also > auf jeden Fall angewandt werden, sodass ich meine Sendefunktion nicht > durch das Interrupt von USART2 unterbrochen wird, oder? --> Hmmm, im Grunde hast du da ja ne Art Multitasking-Programm...Also so wie ich das jetzt verstanden habe soll der uC Daten vom Gerät1 Daten abholen und an Gerät2 senden. Gerät zwei kann allerdings auch ne Anfrage an den UC starten und sagen, dass er jetzt gleich die Daten haben will bzw. ähnliches. OK, im Grunde müsstest du den ersten Prozess dann mittels Interrupt "schützen". Also den Vorgang Befehl Senden und Daten an Gerät2 senden. So würde ich das machen. Ich denke da gibts sicherlich noch nen besser Ansatz, aber der fällt mir spontan jetzt so ein. Greez
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.