Dieser Beitrag wurde auf Wunsch des Autors geloescht.
Hi Guido, das Dekodieren ist eigentlich sehr einfach, wenn man erstmal synchron ist. Wenn Du bei jedem Startbyte neu synchronisieren willst, sollte es mit 01xxxxxxb anfangen. D.h. Du wartest so lange, bis eine lange Pulszeit erkannt wird. Bei 400 Zyklen Takt, läßt Du T0 mit Vorteiler 1/64 laufen, dadurch ergeben sich T0-Werte von 6 bzw. 12. Und wenn Du dann synchron bist, kannst Du ähnlich wie meine RC5-Routine die weiteren Bits empfangen. Statt im Timerinterrupt eben im externen Interrupt und statt rc5_time wertest Du CT0 aus und statt 13 Bits eben alle 8 Bits. Damit Du auch sicher auf 01xxxxxxb synchronisieren kannst, sollte davor ein 00000000b Byte gesendet werden. Peter
Ja, diesen Unsinn mit dem 3/4-Takt machen die meisten. Ist aber unnötig und viel zu kompliziert. Wenn Du Dir mal das Taktdiagramm genauer ansiehst, merkst Du, daß eine 1 immer bei einem 1-0 Wechsel und eine 0 immer beim 0-1-Wechsel erfolgt. D.h. der invertierte Zustand nach dem Wechsel ist bereits das Bit ! Du must bloß eben die Hilfimpulse ausblenden, die bei 00 oder 11 benötigt werden. Und das geht am einfachsten, wenn Du sie ignorierst, weil sie zu kurz sind: static unsigned char old_ct0, data, bitcount; if( (TCNT0 - old_ct0) < 8 ) // zu kurz return; old_ct0 = TCNT0; data <<= 1; // schieben if( (PIND & 1<<PD2) == 0 ) // nach 1-0-Wechsel data++; // bit = 1 setzen if( --bitcount == 0 ){ dataout = data; //1 byte fertig bitcount = 8; // die naechsten 8 bits } usw. TCNT0 muß man auch setzen können (in Assembler geht es). Aber oft braucht man den Timer ja noch für andere Sachen. Deshalb ist es besser, man läst ihn durchlaufen und merkt sich einfach den alten Stand. Dann hat man mit (TCNT0 - old_ct0) die vergangene Zeit seit dem letzen old_ct0 = TCNT0;. Peter
Der Interrupt muß natürlich auf beide Flanken triggern. Bei einigen AVRs ist dafür nötig, die Flankenerkennung bei jedem Interrupt umzuschalten. Dann muß man auch nochmal den Pegel des Pins prüfen ob nicht gerade während des Umschaltens eine Flanke durchgerutscht ist. Dann funktioniert die 1- und 0-Erkennung ohne Probleme. Sieh Dir doch Dein eigenes Taktdiagramm mal an und denke alle Flankeninterrupts weg, die zwischen den Bits sind. Der Manchestercode ist auch sehr tolerant in Bezug auf die Frequenz. Bei Deinem Beispiel muß man nur erkennen, ob die Zeit ~6 oder ~12 ist und das macht die Zeile: if( (TCNT0 - old_ct0) < 9 ) // zu kurz return; old_ct0 = TCNT0; Eine genauen Timer braucht man also nicht. Du kannst sogar AVRs mit internem RC-Oszillator nehmen. Peter
Zu den Zahlen: Du must nichts berechnen, das kann doch alles der Compiler für Dich tun: #define XTAL 8e6 // 8MHz #define T0_PRE 64 // Vorteiler 1/64 #define MAN_BAUD 20e3 // Manchester mit 20kHz // und jetzt laß ihn rechnen: #define T0_MAN_SHORT ((unsigned char)(XTAL MAN_BAUD T0_PRE)) //= 6 (6,25) #define T0_MAN_LONG (2 * T0_MAN_SHORT) //= 12 #define T0_CHECK_LONG_SHORT ((T0_MAN_SHORT + T0_MAN_LONG) / 2) //= 9 if( (TCNT0 - old_ct0) < T0_CHECK_LONG_SHORT ) // zu kurz return; old_ct0 = TCNT0; Also mit 9 bist Du in der Mitte zwischen kurz und lang. Damit hast Du die maximale Toleranzbreite. Wenn der Impuls kurz ist, dann kommt return bevor old_ct0 neu gesetzt wird. Dadurch wirds mit dem nächsten kurzen als ein langer erkannt, die Hilfsflanke zwischen den Bits wurde also ausgeblendet. Ist der Empfänger noch nicht synchronisiert, kann es sein, daß gerade ein kurzer ausgeblendet wurde, bevor der lange vom Startbyte kommt. Dann sind eben 6+12=18 Takte von CT0 vergangen, aber das ist ja auch >9 und wird somit erkannt. Danach ist dann alles synchron. Ich hoffe, das war jetzt verständlich. Peter
Ich habe eine noch viel einfachere Methode. Ist zwar kein "sauberer" Manchester-Code, aber man kann sich viel Software-Bastelei sparen. Ich wandle jedes zu übertragende Byte in zwei Bytes Manchester um - das ist eine einfache Bit-Schieberoutine, und sende diesen Code über den stinknormalen UART raus. Zwar hat man dann Start- und Stop-Bit mit drin und auch die Timing-Toleranz wird schlechter, aber es funktioniert. Beispiel: Ein Byte $CA = 0b11001010 wird umgewandelt in die Bytes 0b10100101 und 0b10011001, über den UART gesendet, auf der Empfängerseite empfangen und dekodiert. Um ungültige Übertragungen auszufiltern, schaut man sich die empfangenen Daten einfach 2-Bit weise an: 10 = 1, 01 = 0, 11 und 00 sind ungültig und damit fehlerhaft. Die Synchronisation mache ich über eine gezielte Sendung eines fehlerhaften Bytes mit Kennung.
Hallo eine Frage zu dem Code von oben. Was macht man eigentlich wenn TCNT0 wechselt, also ich meine nach dem überlauf fängt er ja wieder bei null an. Dadurch gibts doch einen Fehler bei current_t=TCNT0-last_t; // Timer merken oder sehe ich da was falsch? mfg mathias
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.