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
}
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.
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.
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.
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.
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)
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
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 *} "###########"
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
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?
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)
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,
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.
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?
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
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
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.
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