Forum: Compiler & IDEs UART Code Optimierung


von Christoph K. (klemze)


Lesenswert?

Hallo,

ich habe hier meine ISR, die ich zum empfangen von messwerten verwende,

ich habe einen algorithmus eingebaut, um das "digitale Rauschen", mit 
dem meine Nachricht verseucht ist, herauszufiltern.

Wenn die Filterung abgeschlossen ist sollen die Messwerte im EEPROM 
abgespeichert werden. Anbei ist mein derzeitiger Code

ich hoffe ihr könnt mir helfen

mfg


  int us_start_bed = 0;
  int us_mess_start = 0;
  int us_dp_zaehler = 0;
  int us_zaehler = 0;
  int us_endzaehler = 0;
  int us_mitlauf=0;
  int us_i = 0;
  int mw = 0;
  int us_messwert_counter_bit = 0;
  char receive_char_fsk;

  #if defined (_AVR_ATmega644P_)
  #if RCV_FSK


ISR (USART_RX1)

{
  #if USE_FSKP
  /*
  Die Messwerte müssen aus dem Rauschen herausgefiltert, dies
  wird durch mehrere If schleifen durchgeführt. Möglicherweise später
  durch eine gemeinsame Switch Anweisung,defines um die Int in bit 
umzuwandlen

  Übermittelte Nachricht ..........:wert1*wert2*wertn###########
  */
//  usart_write_char(UDR1);
    us_mitlauf++;
    if(UDR1 == '.' && us_mitlauf <10)

    {
    us_zaehler++;
    us_mitlauf = 0;
    if(us_zaehler == 7)
    {
    us_zaehler = 0;
    us_start_bed = 1; //Startbedingung erfüllt
    DEBUG1("Start\n");
    }
    }

    if(us_mess_start == 1)
    {
    if(UDR1 == '*'){
    mw++;
      if(mw==2)
      {
      us_mess_start =0;
      }
    }
    else
    {
    rcf[us_messwert_counter_bit] = UDR1;
    us_messwert_counter_bit++;
    if(us_messwert_counter_bit == 2)
    {
    usart_write("%c%c:", rcf[0], rcf[1]);
    us_messwert_counter_bit = 0;
    us_mess_start = 0;
    }
    }
    if(UDR1 == '#')
    {
    us_endzaehler++;


      if(us_endzaehler == 5)
      {
        us_endzaehler = 0;
        us_mess_start = 0;
        us_start_bed = 0;
        DEBUG1("Ende\n");
        usart_write("%c.%c.%c.%c\r\n", rcf[0], rcf[1], rcf[2], rcf[3]);
        /*nun müssen die erhaltenen Werte in dem EEPROm geschrieben 
werden
         for (unsigned char count = 0; count<4; count++)

                {

                  eeprom_busy_wait ();

                  eeprom_write_byte((unsigned char *)(WERT_EEPROM_STORE 
+ count),rcf[count]);

                }*/

      }
      }
    }
  if(us_start_bed == 1)
  {

    if(UDR1 == ':')
    {
    us_mess_start = 1;
    }

}


  return;

  #endif
}

von Karl H. (kbuchegg)


Lesenswert?

Was ist jetzt deine Frage?

Du darfst UDR1 nur einmal in der ISR lesen!

Auszug Datenblatt Mega16 (ist bei dir aber sicher auch nicht anders

<quote>
A second Buffer Register has been added. The two Buffer Registers
operate as a circular FIFO buffer. Therefore the UDR must only be
read once for each incoming data! More important is the fact that
the Error Flags (FE and DOR) and the 9th data bit (RXB8) are
buffered with the data in the receive buffer. Therefore the status
bits must always be read before the UDR Register is read. Otherwise
the error status will be lost since the buffer state is lost.
</quote>


Das zurücksenden von Charactern in der Empfangs-ISR mag gerade noch 
angehen (wenn dort ein Ringbuffer sitzt, der die Zeichen zwischendurch 
aufnimmt, ist das auf jeden Fall ok) aber das Speichern im EEPROM geht 
gar nicht. Dauert einfach zu lange.

von Karl H. (kbuchegg)


Lesenswert?

>  Die Messwerte müssen aus dem Rauschen herausgefiltert, dies
>  wird durch mehrere If schleifen durchgeführt.

Ein if ist keine Schleife!

von Karl H. (kbuchegg)


Lesenswert?

1
   us_mitlauf++;
2
    if(UDR1 == '.' && us_mitlauf <10)
3
4
    {
5
    us_zaehler++;
6
    us_mitlauf = 0;
7
    if(us_zaehler == 7)
8
    {
9
    us_zaehler = 0;
10
    us_start_bed = 1; //Startbedingung erfüllt
11
    DEBUG1("Start\n");
12
    }
13
    }

Selten eine so komplizierte Art gesehen um 70 aufeinanderfolgende '.' 
abzuzählen. Und dann sind auch noch alle Variablen int, also 16 Bit. Und 
du fragst ernsthaft um Optimierungen an?

Räum doch bitte erst mal den Code auf! Und zwar so, dass man auch ohne 
ständiges Hin und Herscrollen verfolgen kann, wie du dir die Absicherung 
gegen zufälliges Auslösen durch Leitungsrauschen vorstellst. Und wenn du 
schon dabei bist: optisch ansprechendes, konsistentes Einrücken ist kein 
Selbstzweck oder Schnickschnack.

von Christoph K. (klemze)


Lesenswert?

ich zähle 7 Punkte.....

wie bekomme ich dann die werte ins EEPROM?

von Karl H. (kbuchegg)


Lesenswert?

Christoph K. schrieb:
> ich zähle 7 Punkte.....
>

Das solltest du gleich mal als Indiz werten, dass dein Code nicht 
wirklich gut nachvollziehbar ist.

> wie bekomme ich dann die werte ins EEPROM?

Im main in der Hauptschleife. So wie man das üblicherweise macht. Die 
ISR wertet (im Rahmen ihrer zeitlichen Möglichkeiten) die auslösende 
Bedingung aus und hinterlässt der Hauptschleife ein Flag, dass Arbeit 
vorliegt.

von Karl H. (kbuchegg)


Lesenswert?

Christoph K. schrieb:
> ich zähle 7 Punkte.....
>

Wenn ich das richtig im Kopf dechiffriere, dann liegt die Startbedingung 
dann vor, wenn in 70 Zeichen 7 mal das Zeichen '.' war und die einzelnen 
'.' nicht weiter als 10 Zeichen voneinander entfernt sind.
Was passiert eigentlich, wenn diese Bedinung nicht zutrifft? Nur mal 
angenommen us_mitlauf wird größer als 10. Dann dauert es ~65530 Zeichen, 
bis us_mitlauf überläuft und jemals wieder eine Chance hat <10 zu sein, 
damit die Triggerung erfolgen kann.

von Karl H. (kbuchegg)


Lesenswert?

Wie kann es eigentlich sein, dass sich hier

>  Übermittelte Nachricht ..........:wert1*wert2*wertn###########

zwischen den einzelnen Zeichen, irgendwelche Zeichen durch Rauschen 
einschleichen? Sollte es nicht eher so sein, dass diese Zeichen 
tatsächlich ohne Unterbrechung vom Sender daherkommen?
(Denn woher weißt du, dass sich nicht auch zwischen den Bytes für die 
Werte ein paar Rauschbytes eingeschlichen haben und du daher etwas 
völlig Falsches für die Werte nimmst)

von Michael A. (micha54)


Lesenswert?

Karl heinz Buchegger schrieb:
>
> Du darfst UDR1 nur einmal in der ISR lesen!
>
> Auszug Datenblatt Mega16 (ist bei dir aber sicher auch nicht anders
>
> <quote>
> A second Buffer Register has been added. The two Buffer Registers
> operate as a circular FIFO buffer. Therefore the UDR must only be
> read once for each incoming data!

Hallo,

na da haben wir doch schon eine mögliche Quelle des "Rauschens".

Also ich würde hier erstmal die normale Funktion, so wie in den 
Applikationsschriften oder im Datenblatt vorgesehen, sicherstellen und 
dann ermitteln, ob wirklich ein Rauschen vorliegt.

Gruß,
Michael

von Karl H. (kbuchegg)


Lesenswert?

Michael Appelt schrieb:

> na da haben wir doch schon eine mögliche Quelle des "Rauschens".

Wenn ich das richtig in Erinnerung habe und den TO richtig zuordne, dann 
beschäftigt er sich mit einer Datenübermittlung über Funk, wobei die 
Funkstrecke nur dann 'steht' wenn der Sender sendet. In den Sendepausen 
empfängt der Empfänger alles mögliche und gibt das auch aus.

Meiner Meinung nach sollte man da ansetzen und erst mal aus dem 
Empfänger herauskitzeln, ob ein Signal vorliegt, welches stark genug 
ist. Dann auf jeden Fall die Statusbits der UART auswerten und dann 
würde ich nicht lange fackeln und jedes Zeichen einfach in eine 
etntsprechend lange Queue schreiben. Einfach hinten drann, wobei die 
ältesten Zeichen vorne raus fallen. Noch ein Check, ob in der Queue das 
Muster

"..........:" {abwechselnd Byte und *} "###########"

von Christoph K. (klemze)


Lesenswert?

Karl heinz Buchegger schrieb:
> Wie kann es eigentlich sein, dass sich hier
>
>>  Übermittelte Nachricht ..........:wert1*wert2*wertn###########
>
> zwischen den einzelnen Zeichen, irgendwelche Zeichen durch Rauschen
> einschleichen? Sollte es nicht eher so sein, dass diese Zeichen
> tatsächlich ohne Unterbrechung vom Sender daherkommen?
> (Denn woher weißt du, dass sich nicht auch zwischen den Bytes für die
> Werte ein paar Rauschbytes eingeschlichen haben und du daher etwas
> völlig Falsches für die Werte nimmst)

ja aber davor und danach schlecht sich rauschen ein, weil

1.)das funkmodul bei fehlendem eingangssignal ein schwankendes 
ausgangssignal ausgibt
2.)der avr dieses signal als eine zufällige anordnung von ASCI zeichen 
anzeigt

die Punkte sind dazu da um sicherzustellen, dass jetzt die richtige 
nachricht folgt

von Christoph K. (klemze)


Lesenswert?

Karl heinz Buchegger schrieb:
> Meiner Meinung nach sollte man da ansetzen und erst mal aus dem
> Empfänger herauskitzeln, ob ein Signal vorliegt, welches stark genug
> ist. Dann auf jeden Fall die Statusbits der UART auswerten und dann
> würde ich nicht lange fackeln und jedes Zeichen einfach in eine
> etntsprechend lange Queue schreiben. Einfach hinten drann, wobei die
> ältesten Zeichen vorne raus fallen. Noch ein Check, ob in der Queue das
> Muster
>
> "..........:" {abwechselnd Byte und *} "###########"

und wie macht man das jetzt praktisch?

von Karl H. (kbuchegg)


Lesenswert?

Christoph K. schrieb:
> Karl heinz Buchegger schrieb:
>> Meiner Meinung nach sollte man da ansetzen und erst mal aus dem
>> Empfänger herauskitzeln, ob ein Signal vorliegt, welches stark genug
>> ist. Dann auf jeden Fall die Statusbits der UART auswerten und dann
>> würde ich nicht lange fackeln und jedes Zeichen einfach in eine
>> etntsprechend lange Queue schreiben. Einfach hinten drann, wobei die
>> ältesten Zeichen vorne raus fallen. Noch ein Check, ob in der Queue das
>> Muster
>>
>> "..........:" {abwechselnd Byte und *} "###########"
>
> und wie macht man das jetzt praktisch?

Hast du immer die gleiche Anzahl an Datenbytes, bzw. kannst du das 
sicherstellen, dass das so ist (Dummy Bytes einfügen)
(Dann vereinfacht sich das Mustersuchen)

von Christoph K. (klemze)


Lesenswert?

Karl heinz Buchegger schrieb:
> Hast du immer die gleiche Anzahl an Datenbytes, bzw. kannst du das
> sicherstellen, dass das so ist (Dummy Bytes einfügen)
> (Dann vereinfacht sich das Mustersuchen)

ja ich habe immer Werte von 0 bis 40,

von Karl H. (kbuchegg)


Lesenswert?

Christoph K. schrieb:
> Karl heinz Buchegger schrieb:
>> Hast du immer die gleiche Anzahl an Datenbytes, bzw. kannst du das
>> sicherstellen, dass das so ist (Dummy Bytes einfügen)
>> (Dann vereinfacht sich das Mustersuchen)
>
> ja ich habe immer Werte von 0 bis 40,

Also 40 Bytes maximal.
Du kommen also dahinter noch 11 mal #, macht 51
und davor noch 7 mal ., macht 58
und der :, macht 59

also

unsigned char ReceiveBuffer[59]

beim Empfang eines neuen Zeichens, werden die Zeichen 1 bis 58 um 1 
Stelle nach vor gerückt, das neue Zeichen an die Position 58.

Und dann fang ich von hinten an.
Sind die Zeichen 58 bis 58-11 alle '#'
Wenn nein, kann es schon mal keine gültige Message sein
Dann weiter nach vorne gehen und das jeweils übernächste Byte 
betrachten, dass muss sein
  * '*'   in dem Fall gehts weiter mit dem übernächsten Vorgänger
  * '.'   die Präambel ist erreicht. Abtesten ob die 6 Zeichen davor
          ebenfalls '.' sind. Wenn ja: die ganze Nachricht ist gültig
  * irgendwas anderes: keine gültige Nachricht.

Ist die ganze Nachricht gültig, kennt man dann auch gleich die 
Positionen, an denen die Nutzbytes stehen.

Der ganze Abtest-Mechanismus erfolgt bei jedem Zeichen. Da man bei jedem 
Zeichen ein wenig Zeit hat, bis das nächste eintrudelt, denke ich sollte 
das schnell genug gehen.

Stell es dir einfach so vor:
Du hast einen Papierstreifen. Immer wenn ein Zeichen eintrudelt 
schreibst du es auf den Papierstreifen. Über dem Streifen liegt ein 
Fenster, welches dir genau die letzten 59 empfangenen Zeichen zeigt. Und 
dann schaust du dir sichtbaren Zeichen im Fenster an und entscheidest, 
ob das was du siehst, gültig ist. Du fängst dabei hinten (rechts im 
Fenster) an, mit der Kontrolle, weil deine Anzahl Nutzbytes nicht immer 
gleich lang ist.

Alternativ könnte man auch eine Statemachine aufsetzen, die bei jedem 
einlangenden Zeichen dieses anhand des Zustands klassifiziert und 
gegebenenfalls den Zustandswechsel in einen anderen Zustand durchführt. 
Das geht sicherlich schneller, ist aber mit mehr Code verbunden.

von Christoph K. (klemze)


Lesenswert?

also ich soll jedes ankommende zeichen überprüfen?

von Christoph K. (klemze)


Lesenswert?

wenn ich richtig verstanden habe,

dann muss ich warten biss der buffer voll ist,
dann mit einem Muster den Inhalt überprüfen
und dann die Messwerte herausnehmen?

von Christoph K. (klemze)


Lesenswert?

ReceiveBuffer[us_mitlauf] = UDR1;
us_mitlauf++;
if(ReceiveBuffer[us_mitlauf] = muster[us_mitlauf])richtig++;
if((mitlauf=20)&&(richtig<7)mitlauf=0;


hallo,

ich habe jetzt diese ISR geschrieben, und wollte fragen, ob ich auf dem 
richtigen weg bin.
Stimmen 7 Werte des Buffers mit dem Muster überein, so wird der Buffer 
vollgemacht und dieser dann verwendet

von Peter D. (peda)


Lesenswert?

Du solltest erstmal ne Präambel senden, damit sich die UART 
synchronisieren kann, sonst kommt immer nur Müll raus.
Und damit das Synchronisieren klappt muß die Praämbel aus Bytes 
bestehen, die nur eine 1-0 Flanke haben, also 0x00, 0x80, 0xC0, 0xE0, 
... 0xFF.
Sonst kann es passieren, daß die UART die falsche Flanke als Startbit 
erkennt.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Mein Tip

Programmiere die wesentlichen Teile erst mal auf dem PC aus. Dort hast 
du bessere Debugmöglichkeiten.

Wenn du auf dem PC mit einem von dir vorgefertigtem Array soweit bist, 
dass deine Erkennung sauber funktioniert, ist es banal den Code dann ins 
AVR Programm zu übernehmen.

if(ReceiveBuffer[us_mitlauf] = muster[us_mitlauf])

Ich denke nicht, dass du hier eine Zuweisung willst.
-> Code auf dem PC vorbereiten, debuggen und erst dann übernehmen.

von Christoph K. (klemze)


Lesenswert?

Karl heinz Buchegger schrieb:
> Ich denke nicht, dass du hier eine Zuweisung willst.

will ich auch nicht ;)

der verstand war nur schneller als die finger

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.