Forum: Projekte & Code Manchester- & Biphasedecoder


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Stefan S. (energizer)


Lesenswert?

Hallo, ich möchte hier ein Stück Quellcode beschreiben welcher 
manchester- oder biphasencodierte Signale dekodiert. Das besondere dabei 
ist dass der Code baudratenunabhängig arbeitet, und Biphase und 
Manchester gleichzeitig parallel dekodiert werden können. Die Baudrate 
darf sich mitten im Signal in gewissen umfängen ändern (z.B. Timecode 
auf Bändern während dem Spulen, etc...)

Der Interrupt wird immer bei einer Pegeländerung des Signals aufgerufen.
Ein (Hardware-)Zähler, im Beispiel Timer0, muss mit geeignetem Takt 
laufen.
Tritt ein Pegelwechsel im Signal auf, wird zunächst die vergangene Zeit 
zum letzten Pegelwechsel in "diff" abgespeichert. Anschließend wird 
diese Pulslänge (diff) mit der vorhergehenden verglichen; Ist die 
aktuelle Pulslänge größer als 1,5x alte Pulslänge (timebase), handelt es 
sich beim aktuellen Puls um einen langen (bitstate wird auf 0 gesetzt). 
Ansonsten wird überprüft ob die Pulslänge kleiner als 0,75 der 
vorhergehenden (timebase / 2) ist. Falls ja hat man einen kurzen Puls, 
der einem langen Puls gefolgt ist, und bitstate wird auf 1 gesetzt. Ist 
keine der beiden vorgehenden Bedingungen erfüllt, ist der aktuelle Pulse 
in etwa der gleichen Länge wie der vorherige. Falls in diesem Fall der 
vorangegangene Puls ein kurzer war, wird bitstate abwechselnd auf 1 oder 
2 gesetzt. Jetzt wird die "Zeitbasis", also die Zeit des letzten Pulses 
aktualisiert (timebase). Da einmal auf das 1,5fache und einmal auf das 
0,75fache dieses Wertes im nächsten Durchlauf geprüft wird, wird direkt 
der 1,5fache Wert abgespeichert, so dass für den 0,75fachen Vergleich 
nur noch durch 2 dividiert werden muss.

Nun folt die eigentliche Auswertung:
Bei Manchester sind wir nach einem langen Pulse (bitstate 0) oder nach 
einer geraden Anzahl von kurzen Pulsen (bitstate 2) in der Bitmitte, nun 
muss nur noch der Pegel gelesen werden und man hat eine Daten 0 oder 1.
Bei Biphase entspricht ein langer Puls (bitstate 0) einer Daten-0, zwei 
aufeinanderfolgende kurze Pulse (bitstate 2) einer Daten-1.

Anwendung:
- Timecode
- SPDIF
- RFID Transponder
- Propelleruhren
- uvw.

Viel Spaß damit
Stefan
1
SIGNAL (SIG_INTERRUPT0)
2
{
3
  uint8_t cnt = TCNT0;
4
  static uint8_t timebase;
5
  static uint8_t bitstate = 0;
6
  static uint8_t old_cnt;
7
  uint8_t diff = (uint8_t) (cnt - old_cnt);
8
  old_cnt = cnt;
9
  static uint16_t fifo;
10
  
11
  if (diff > timebase) //this is a long pulse after a short pulse
12
    bitstate = 0;
13
  else
14
    if (diff < (timebase / 2)) //this is a short pulse after a long pulse
15
      bitstate = 1;
16
    else //same pulse length (within 0.75x and < 1.5x of last length)
17
      if (bitstate == 1) //even number of consecutive short times at this place
18
        bitstate = 2;
19
      else
20
        if (bitstate == 2) //odd number of short times at this place
21
          bitstate = 1;
22
          
23
  timebase = 3 * diff / 2;
24
    
25
  
26
  if (bitstate != 1)
27
  {
28
    /* Manchester-II / Biphase-L decoding:
29
      Here we are in the middle of a bit (bitstate)
30
      for IEEE 802.3 just invert polarity
31
    */
32
    if (bit_is_clear(PIND, PD2))
33
      ; //falling edge in bit middle -> shift out a 1
34
    else
35
      ; //rising edge in bit middle -> shift out a 0
36
    
37
    /* Biphase-marc-code (BMC) decoding
38
      Here we are at the end of a bit
39
    */
40
      
41
    if (bitstate)
42
      ; //even number of consecutive short pulses, shift out a 1
43
    else
44
      ; //long pulse, shift out a 0
45
  }
46
}

von Markus W. (elektrowagi78) Benutzerseite


Lesenswert?

Hat jemand einen Tipp, wie man das am Einfachsten codiert?

Von der Wikipedia sieht es mir doch so aus, also ob man das mit einem 
Exor machen können müsste.

von Bernhard L. (bernhard_r84)


Lesenswert?

Habe gerade den Code an meinem RFID-Leser probiert aber leider 
funktioniert er nicht.
Die Standardvariante mit dem Vergleich der Differenz mit 
MANCHESTER_MIDDLE klappt hingegen einwandfrei.
Die CPU läuft auf 16MHz und der Prescaler von TIM0 steht auf 256, der 
Takt ist also 62,5kHz

Was mich an der neuen Routine etwas wundert ist, dass timebase immer 
unterschiedlich ist, je nach long oder short Pulse.

Kann es daran liegen? Ist der obige Code aktuell?

Würde mich über eine kurze Nachricht freuen :)

von Stefan S. (stefan_s40)


Lesenswert?

Lass Dir am besten die einzelnen Bits die Du empfängst irgendwie 
ausgeben und schau Dir die "zu Fuß" an, evtl. falsche Transponder...

von Bernhard L. (bernhard_r84)


Lesenswert?

Hier eine optimierte Variante die einige wertvolle Codewörter spart und 
die ISR beschleunigt:

1
ISR(INT0_vect)
2
{
3
  uint8_t cnt = TCNT0;
4
  static uint8_t timebase;
5
  static uint8_t bitstate = 0;
6
  static uint8_t old_cnt;
7
  uint8_t diff = (uint8_t) (cnt - old_cnt);
8
  old_cnt = cnt;
9
  
10
  if (diff > timebase) // this is a long pulse after a short pulse
11
          bitstate = 0;
12
  else
13
          if (diff < (timebase / 2)) // this is a short pulse after a long pulse (timebase / 2)
14
                  bitstate = 1;
15
          else
16
                  bitstate ^= 0x03;
17
          
18
  timebase = 3 * diff / 2;
19
    
20
  if (bitstate == 1)
21
         return;
22
23
  /* Manchester-II / Biphase-L decoding:
24
    Here we are in the middle of a bit (bitstate)
25
    for IEEE 802.3 just invert polarity
26
  */
27
  if (bit_is_clear(PIND, PD2))
28
    ; //falling edge in bit middle -> shift out a 1
29
  else
30
    ; //rising edge in bit middle -> shift out a 0
31
  
32
  /* Biphase-marc-code (BMC) decoding
33
    Here we are at the end of a bit
34
  */
35
    
36
  if (bitstate)
37
    ; //even number of consecutive short pulses, shift out a 1
38
  else
39
    ; //long pulse, shift out a 0
40
}

Der Timer0 läuft bei mir mit 250kHz, damit gehen 125kHz RFID Tags 
einwandfrei.

: Bearbeitet durch User
von Philipp (Gast)


Lesenswert?

Bin gerade über den Artikel zur Manchester Decodierung auf diesen Thread 
gestoßen.
Ich möchte einen Manchester-Codierten Datenstrom von einem PCF7945 125 
kHz Transponder empfangen.

Der Code von Bernhard L. funktioniert nicht!

Kann man sich schon an einem Beispiel vor Augen führen warum:

Angenommen, wir hätten mehrere aufeinanderfolgende gleiche Bitwerte, 
z.B. 1111. Das wären codiert dann kurze Bitzeit 1, gefolgt von kurze 
Bitzeit 0. Das ganze 4 Mal hintereinander.
Wir wären also immer im folgenden Pfad:
1
          else
2
                  bitstate ^= 0x03;

Eigentlich dürfte hier nur bei jeder 2. Flanke der Signalwert in die 
Daten-Variable geshiftet werden. Dafür sollte wohl das
1
  if (bitstate == 1)
2
         return;
 gedacht sein.
Stattdessen toggelt in meinem Beispiel bitstate bei jedem Flankenwechsel 
zwischen 0x03 und 0x00, wodurch auch bei JEDEM Flankenwechsel ein Bit 
gesampelt ("in die Daten-Variable geshiftet") wird. Im Beispiel empfange 
ich also anstatt 1111 stattdessen 10101010.

Habe ich etwas übersehen, oder kann dieser c-Code so gar nicht 
funktioniert haben?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.