Manchester decoding 200hz

you could develop the code on your laptop, not the target hardware. generate wavefor, 1s and 0s in an array and attempt to decode it. oversample the data in the array and attempt to decode it at different starting points

i learned about Manchester encoding when using a cassette tape to store data.

Manchester encodes both the clock and data together and tolerates a varying clock (tape stretching).

Cool. I used it for RF comms where it was helpful in achieving DC balance in a digital pulse train, as well as helping with clock speed differences.

That tape stretch also reminds me of bar code scanning algos that account for varying scan speeds when humans are doing the moving.

So yeah, Manchester encoding variants have their places. Not here so much.

For all we know, the OP could just use two wires clock and data, or… whatever.

It leaves the issue of what the bits are and how they are packaged and interpreted.

a7

Also, going back to the general structure of your code, I'd recommend breaking it into at least two pesudo parallel tasks because you are receiving a data stream from a source, asynchronous with your program. There may be a mismatch between the speed of the incoming data and the rate at which you can process it (especially with all the printing you are doing and whatever else may be running in the final application). Task1 would be to interpret the incoming data stream and push the bits onto a queue. Task2 would fetch the bits from the queue, assemble these into bytes and store them (coordinates in your case).

Since this is a school task, it may well be so that the communication protocol (Manchester) may not be optimal for this particular use case but, hey, it is certainly a good test of your programming skills and/or ability to use ChatGPT. The fault recovery (resynchronising clock, waiting for a restart etc.) appears currently to be missing from your code.

He may well scan this forum from time to time to see how his students are progressing, maybe watching with glee as they get tangled up in ChatGPT and having to fight off numberous alternative and better suggestions for solving the problem other than the one mandated in the exercise.

I've just made the point in my previous post but sometimes forcing the students to use a sub-optimal solution is actually a good test.

does this mean you would intentionally stretch a pulse to cancel any DC accumulation?

how was DC monitored?

perhaps it's just easier to measure the pulse width to determine if there was a state change (e.g. from 1s to 0s and visa versa)

ive made a test wave for the real final transmitter, the syncs have changed a bit, the first one is 1111111001 followed by the number of coordinates, followed by the coordinates, and sync2 is 1111111011 followed by the frequency. im thinking of just reading out the bitstream first and then decode it, maybe that will fix the timing issues.

const int outputPin = 9; // Pin to output the waveform //const char* bitstring = "1111111001000100000000000100010001000000000010000110010011111110110101100"; // 4 coordinaten (0,0) (1,2) (2,3) (4,4) freq:44kHz //const char* bitstring = "111111100100001100001001000001000001001010001011111110110110010";// 3 coordinaten (1,1) (4,5) (2,2) freq:50kHz
//const char* bitstring = "11111110010001010000100001001010100100111000010000100101000100000011111110110110110"; // 5 coordinaten (1,1) (1,1) (5,5) (9,2) (7,0) freq:54kHz
const int bitRate = 100;
const int bitDuration = 1000 / bitRate; // 10 ms
const int halfBitDuration = bitDuration / 2;

void setup() {
pinMode(outputPin, OUTPUT);
}

void loop() {
for (int i = 0; bitstring[i] != '\0'; i++) {
char bit = bitstring[i];
if (bit == '0') {
digitalWrite(outputPin, HIGH);
delay(halfBitDuration);
digitalWrite(outputPin, LOW);
delay(halfBitDuration);
} else if (bit == '1') {
digitalWrite(outputPin, LOW);
delay(halfBitDuration);
digitalWrite(outputPin, HIGH);
delay(halfBitDuration);
}
}
}`

In principle, reading the entire bit stream in to say an array in a first run and processing/interpreting it in a second run will work, and is a good way of starting (assumung there is enough storage space) .

Also, to simulate what you are getting from the transmitter, packing a sample bitstream into a character array is a good idea so you can first test the receiver. I can't see though how you have encoded the frequency and coordinates into your sample bit streams. All I see is the 10 bit header.

Can you add spaces into the strings so it is clear how you've encoded these as below.

// 4 coordinaten (0,0) (1,2) (2,3) (4,4) freq:44kHz
"1111111001000100000000000100010001000000000010000110010011111110110101100"  // original string
"1111111001 00010000 00000 00100 01000 10000 00000 01000 01100 10011 11111 01101 01100"; 

// 3 coordinaten (1,1) (4,5) (2,2) freq:50kHz
"111111100100001100001001000001000001001010001011111110110110010"  // original string
"1111111001 00001100001001000001000001001010001011111110110110010"

// 5 coordinaten (1,1) (1,1) (5,5) (9,2) (7,0) freq:54kHz
"11111110010001010000100001001010100100111000010000100101000100000011111110110110110"  // original string
"1111111001 0001010000100001001010100100111000010000100101000100000011111110110110110"
const int outputPin = 9; // Pin to output the waveform
const char* bitstring = "1111111001 0001000 0000000010 0010001000 0000000100 001100100 1111111011 0101100"; // 4 coords (0,0) (1,2) (2,3) (4,4) freq:44kHz
const char* bitstring = "1111111001 000011 0000100100 000100000 10010100010 1111111011 0110010"; // 3 coords (1,1) (4,5) (2,2) freq:50kHz
const char* bitstring = "1111111001 000101 0000100001 0010101001 0011100001 0000100101 0001000000 1111111011 0110110"; // 5 coords (1,1) (1,1) (5,5) (9,2) (7,0) freq:54kHz

It is still not clear to me how this data is encoded. Can you annotate the values marked ?1 through to ?6 with labels saying what values are encoded from the example below. But I think the main problem is that you must have consistent lengths for the data items, padded with leading zeros, if necessary (which you do not appear to have), or you will not be able to determine on the receiver where one digit ends and the next one starts :

const char* bitstring = "1111111001 0001000 0000000010 0010001000 0000000100 001100100 1111111011 0101100"; // 4 coords (0,0) (1,2) (2,3) (4,4) freq:44kHz
1111111001	header
0001000         ?1
0000000010      ?2
0010001000	?3
0000000100	?4
001100100	?5
1111111011	?6
0101100		44KHz ?
const char* bitstring = "1111111001 0001000 0000000010 0010001000 0000000100 001100100 1111111011 0101100"; // 4 coords (0,0) (1,2) (2,3) (4,4) freq:44kHz
1111111001	header 1 and is known
000100         this represents how many coords will follow here its a decimal 4 so 4 coords
00000 00001   coords 1 and 2 (X1, X2)
00010 00100	coords 3  and 4 (X3, X4)
00000 00010	coords 5 and 6 (Y1, Y2)
00011 00100	coords 7 and 8 (Y3, Y4)
1111111011	this is header 2 and is known
0101100		44KHz  this represents the frequency i need to read out

LOL. So, on which side of that were you? :expressionless:

I get that there is some value in this as a learning experience. I've forgotten most of I ever knew about it, so it's been a nice refreshment.

I m happily without the possibility of inspiring any glee.

a7

Your transmitter program looks OK according to my logic analyser:

I just reformatted it slightly :

const int outputPin = 9;  
const char* bitstring = "1111111001000100000000000100010001000000000010000110010011111110110101100"; // 4 coordinaten (0,0) (1,2) (2,3) (4,4) freq:44kHz 
//const char* bitstring = "111111100100001100001001000001000001001010001011111110110110010";// 3 coordinaten (1,1) (4,5) (2,2) freq:50kHz
//const char* bitstring = "11111110010001010000100001001010100100111000010000100101000100000011111110110110110"; // 5 coordinaten (1,1) (1,1) (5,5) (9,2) (7,0) freq:54kHz
const int bitRate = 100;
const int bitDuration = 1000 / bitRate;  // 10 ms
const int halfBitDuration = bitDuration / 2;

void setup() {
  pinMode(outputPin, OUTPUT);
}

void loop() {
  for (int i = 0; bitstring[i] != '\0'; i++) {
    char bit = bitstring[i];
    if (bit == '0') {
      digitalWrite(outputPin, HIGH);
      delay(halfBitDuration);
      digitalWrite(outputPin, LOW);
      delay(halfBitDuration);
    } else if (bit == '1') {
      digitalWrite(outputPin, LOW);
      delay(halfBitDuration);
      digitalWrite(outputPin, HIGH);
      delay(halfBitDuration);
    }
  }
  delay(10000) ; //
}

yess thank you haha, now i still need to get the timing on the receiver right

I'd suggest working backwards.

Put that bitstring in your receiver, write the code to interpret it, then put the coordinates and frequency into their respective containing variables.
Once you have got that far, develop the code analyse the incoming Manchester data stream and load the bits into an array. Finally, join the two parts together.

ive got the coordinate reading on point, but the frequency number doesnt wanna be read out

const int inputPin = 8;
const int bitRate = 100;
const int bitDuration = 1000 / bitRate;

unsigned long lastSampleTime = 0;

const String startHeader = "1111111001";
const String endHeader = "1111111011";

String bitBuffer = "";
bool inSync = false;
int numCoordinates = 0;

void setup() {
  Serial.begin(9600);
  pinMode(inputPin, INPUT);
  lastSampleTime = millis();
}

void loop() {
  unsigned long currentTime = millis();

  if (currentTime - lastSampleTime >= bitDuration) {
    int bitVal = digitalRead(inputPin);
    char bitChar = (bitVal == HIGH) ? '0' : '1'; // Based on your encoding
    bitBuffer += bitChar;

    if (!inSync) {
      // Look for start header
      int idx = bitBuffer.indexOf(startHeader);
      if (idx != -1) {
        inSync = true;
        bitBuffer = bitBuffer.substring(idx + startHeader.length());
      } else if (bitBuffer.length() > 20) {
        // Trim buffer to avoid unbounded growth
        bitBuffer = bitBuffer.substring(bitBuffer.length() - 10);
      }
    } else if (numCoordinates == 0) {
      // After start header, read message count (6 bits)
      if (bitBuffer.length() >= 6) {
        String countBits = bitBuffer.substring(0, 6);
        numCoordinates = strtol(countBits.c_str(), NULL, 2); // Convert binary to decimal
        bitBuffer = bitBuffer.substring(6); // Remove message count from buffer
        Serial.print("Number of Coordinates: ");
        Serial.println(numCoordinates);
      }
    } else {
      // After message count, extract X and Y coordinates
      if (bitBuffer.length() >= 5 * numCoordinates * 2) {  // 5 bits for X and 5 bits for Y per coordinate
        int xCoordinates[numCoordinates];
        int yCoordinates[numCoordinates];

        // Extract X coordinates
        for (int i = 0; i < numCoordinates; i++) {
          String xBits = bitBuffer.substring(0, 5); // First 5 bits for X
          xCoordinates[i] = strtol(xBits.c_str(), NULL, 2); // Convert binary to decimal
          bitBuffer = bitBuffer.substring(5); // Remove the X coordinate from the buffer
        }

        // Extract Y coordinates
        for (int i = 0; i < numCoordinates; i++) {
          String yBits = bitBuffer.substring(0, 5); // Next 5 bits for Y
          yCoordinates[i] = strtol(yBits.c_str(), NULL, 2); // Convert binary to decimal
          bitBuffer = bitBuffer.substring(5); // Remove the Y coordinate from the buffer
        }

        // Print all coordinates in the format (X1,Y1) (X2,Y2) ...
        Serial.print("Coordinates: ");
        for (int i = 0; i < numCoordinates; i++) {
          Serial.print("(");
          Serial.print(xCoordinates[i]);
          Serial.print(",");
          Serial.print(yCoordinates[i]);
          Serial.print(") ");
        }
        Serial.println();

        // Extract and print the last 7 bits from the bitBuffer
        if (bitBuffer.length() >= 7) {
          String last7Bits = bitBuffer.substring(0, 7); // Get the last 7 bits
          Serial.print("Last 7 Bits: ");
          Serial.println(last7Bits);
          bitBuffer = bitBuffer.substring(7); // Remove the last 7 bits from the buffer
        }

        // Reset for next message
        numCoordinates = 0;
        inSync = false;
        bitBuffer = "";
        delay(1000); // optional pause before next message
      }
    }

    lastSampleTime = currentTime;
  }
}

okok i gave up on the second header and just decided to skip the 10 bits of the second header haha and now it works

const int inputPin = 8;
const int bitRate = 100;
const int bitDuration = 1000 / bitRate;

unsigned long lastSampleTime = 0;

const String startHeader = "1111111001";

String bitBuffer = "";
bool inSync = false;
int numCoordinates = 0;

void setup() {
  Serial.begin(9600);
  pinMode(inputPin, INPUT);
  lastSampleTime = millis();
}

void loop() {
  unsigned long currentTime = millis();
  if (currentTime - lastSampleTime < bitDuration) return;
  lastSampleTime = currentTime;

  // Read one bit
  int bitVal = digitalRead(inputPin);
  char bitChar = (bitVal == HIGH) ? '0' : '1';
  bitBuffer += bitChar;

  if (!inSync) {
    // Wait for start header
    int idx = bitBuffer.indexOf(startHeader);
    if (idx != -1) {
      inSync = true;
      bitBuffer = bitBuffer.substring(idx + startHeader.length());
    }
    else if (bitBuffer.length() > 20) {
      bitBuffer = bitBuffer.substring(bitBuffer.length() - 10);
    }
    return;
  }

  if (numCoordinates == 0) {
    // Read 6-bit count
    if (bitBuffer.length() >= 6) {
      String countBits = bitBuffer.substring(0, 6);
      numCoordinates = strtol(countBits.c_str(), NULL, 2);
      bitBuffer = bitBuffer.substring(6);
      Serial.print("Number of Coordinates: ");
      Serial.println(numCoordinates);
    }
    return;
  }

  // Once we have count, wait until we have all coords + end header + 7 bits
  int totalCoordBits = numCoordinates * 5 * 2;   // 5 bits X + 5 bits Y each
  if (bitBuffer.length() < totalCoordBits + 17)   // +10 bits header +7 bits payload
    return;

  // Decode X coords
  int xCoords[numCoordinates];
  for (int i = 0; i < numCoordinates; i++) {
    String xBits = bitBuffer.substring(0, 5);
    xCoords[i] = strtol(xBits.c_str(), NULL, 2);
    bitBuffer = bitBuffer.substring(5);
  }

  // Decode Y coords
  int yCoords[numCoordinates];
  for (int i = 0; i < numCoordinates; i++) {
    String yBits = bitBuffer.substring(0, 5);
    yCoords[i] = strtol(yBits.c_str(), NULL, 2);
    bitBuffer = bitBuffer.substring(5);
  }

  // Print coordinates
  Serial.print("Coordinates: ");
  for (int i = 0; i < numCoordinates; i++) {
    Serial.print("(");
    Serial.print(xCoords[i]);
    Serial.print(",");
    Serial.print(yCoords[i]);
    Serial.print(") ");
  }
  Serial.println();

  // Skip the 10-bit end header, then read the next 7 bits
  String payloadBits = bitBuffer.substring(10, 17);
  int payloadValue = strtol(payloadBits.c_str(), NULL, 2);
  Serial.print("Second payload (7 bits): ");
  Serial.println(payloadValue);

  // Reset for next message
  numCoordinates = 0;
  inSync = false;
  bitBuffer = "";
  delay(1000);
}


if I run the pulse sequence of post 35 thru the ESP32 program referenced in post 7 I get the following serial output

ESP32 measure pins 16 and 17 pulse information
timerBegin() OK frequenmcy 1000000
displaying results
rise 5258620 fall 5263615 period 4995
fall 5263615 rise 5268615 period 5000
rise 5268615 fall 5273615 period 5000
fall 5273615 rise 5278615 period 5000
rise 5278615 fall 5283615 period 5000
fall 5283615 rise 5288615 period 5000
rise 5288615 fall 5293615 period 5000
fall 5293615 rise 5298615 period 5000
rise 5298615 fall 5303616 period 5001
fall 5303616 rise 5308616 period 5000
rise 5308616 fall 5313616 period 5000
fall 5313616 rise 5318616 period 5000
rise 5318616 fall 5328616 period 10000
fall 5328616 rise 5333616 period 5000
rise 5333616 fall 5338616 period 5000
fall 5338616 rise 5348616 period 10000
rise 5348616 fall 5358616 period 10000
fall 5358616 rise 5363616 period 5000
rise 5363616 fall 5368616 period 5000
fall 5368616 rise 5373616 period 5000
rise 5373616 fall 5378617 period 5001
fall 5378617 rise 5388616 period 9999
rise 5388616 fall 5398617 period 10001
fall 5398617 rise 5403617 period 5000
rise 5403617 fall 5408617 period 5000
fall 5408617 rise 5413617 period 5000
rise 5413617 fall 5418617 period 5000
fall 5418617 rise 5423617 period 5000
rise 5423617 fall 5428617 period 5000
fall 5428617 rise 5433618 period 5001
rise 5433618 fall 5438617 period 4999
fall 5438617 rise 5443617 period 5000
rise 5443617 fall 5448617 period 5000
fall 5448617 rise 5453617 period 5000
rise 5453617 fall 5458617 period 5000
fall 5458617 rise 5463617 period 5000
rise 5463617 fall 5468618 period 5001
fall 5468618 rise 5473618 period 5000
rise 5473618 fall 5478618 period 5000
fall 5478618 rise 5483618 period 5000
rise 5483618 fall 5488618 period 5000
fall 5488618 rise 5493618 period 5000
rise 5493618 fall 5498618 period 5000
fall 5498618 rise 5508618 period 10000
rise 5508618 fall 5518618 period 10000
fall 5518618 rise 5523618 period 5000
rise 5523618 fall 5528619 period 5001
fall 5528619 rise 5533619 period 5000
rise 5533619 fall 5538619 period 5000
fall 5538619 rise 5548619 period 10000
rise 5548619 fall 5558619 period 10000
fall 5558619 rise 5563619 period 5000
rise 5563619 fall 5568619 period 5000
fall 5568619 rise 5573619 period 5000
rise 5573619 fall 5578619 period 5000
fall 5578619 rise 5588619 period 10000
rise 5588619 fall 5598619 period 10000
fall 5598619 rise 5603620 period 5001
rise 5603620 fall 5608620 period 5000
fall 5608620 rise 5613619 period 4999
rise 5613619 fall 5618620 period 5001
fall 5618620 rise 5623620 period 5000
rise 5623620 fall 5628620 period 5000
fall 5628620 rise 5633620 period 5000
rise 5633620 fall 5638620 period 5000
fall 5638620 rise 5643620 period 5000
rise 5643620 fall 5648620 period 5000
fall 5648620 rise 5653620 period 5000
rise 5653620 fall 5658620 period 5000
fall 5658620 rise 5663620 period 5000
rise 5663620 fall 5668620 period 5000
fall 5668620 rise 5673620 period 5000
rise 5673620 fall 5678620 period 5000
fall 5678620 rise 5683620 period 5000
rise 5683620 fall 5688620 period 5000
fall 5688620 rise 5698620 period 10000
rise 5698620 fall 5708621 period 10001
fall 5708621 rise 5713621 period 5000
rise 5713621 fall 5718621 period 5000
fall 5718621 rise 5723621 period 5000
rise 5723621 fall 5728621 period 5000
fall 5728621 rise 5733621 period 5000
rise 5733621 fall 5738621 period 5000
fall 5738621 rise 5748621 period 10000
rise 5748621 fall 5753621 period 5000
fall 5753621 rise 5758621 period 5000
rise 5758621 fall 5768621 period 10000
fall 5768621 rise 5773621 period 5000
rise 5773621 fall 5778622 period 5001
fall 5778622 rise 5788621 period 9999
rise 5788621 fall 5798622 period 10001
fall 5798622 rise 5803622 period 5000
rise 5803622 fall 5808622 period 5000
fall 5808622 rise 5818622 period 10000
rise 5818622 fall 5823622 period 5000
fall 5823622 rise 5828622 period 5000
rise 5828622 fall 5833622 period 5000
fall 5833622 rise 5838622 period 5000
rise 5838622 fall 5843623 period 5001
fall 5843623 rise 5848623 period 5000
rise 5848623 fall 5853623 period 5000
fall 5853623 rise 5858623 period 5000
rise 5858623 fall 5863623 period 5000
fall 5863623 rise 5868622 period 4999
rise 5868622 fall 5873623 period 5001
fall 5873623 rise 5878623 period 5000
rise 5878623 fall 5888623 period 10000
fall 5888623 rise 5898623 period 10000
rise 5898623 fall 5903623 period 5000
fall 5903623 rise 5908623 period 5000
rise 5908623 fall 5918623 period 10000
fall 5918623 rise 5928623 period 10000
rise 5928623 fall 5938624 period 10001
fall 5938624 rise 5948623 period 9999
rise 5948623 fall 5953624 period 5001
fall 5953624 rise 5958624 period 5000
rise 5958624 fall 5968624 period 10000
fall 5968624 rise 5973624 period 5000
rise 5973624 fall 5978624 period 5000
fall 5978624 rise 0 period -5978624

which match the timing displayed on the oscilloscope

do you maybe have any idea on how to make it work with the use of Pulsein() instead of using millis()?