Forum: Mikrocontroller und Digitale Elektronik Prüfroutine implementieren


von Lars (Gast)


Angehängte Dateien:

Lesenswert?

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

von Lars (Gast)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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

von weinbauer (Gast)


Lesenswert?

brauchts keinen 1280, n tiny 2313 reicht dicke mit softuart

von Lars (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Lars (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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?

von Lehrmann M. (ubimbo)


Lesenswert?

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

von Lars (Gast)


Lesenswert?

Ich hab ne SD-Karte in Erwägung gezogen...

von Karl H. (kbuchegg)


Lesenswert?

Und wozu soll das gut sein?

(Ausser das es aufwändig ist)

von Lars (Gast)


Lesenswert?

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

von Karsten Ka, (Gast)


Lesenswert?

> 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

von Lars (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Lars (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Lars (Gast)


Lesenswert?

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

von Lars (Gast)


Lesenswert?

Passt dass soweit?

von Karsten K. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.