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?
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