Баг в самописном приёмнике на базе RP2040

Girafivan

✩✩✩✩✩✩✩
19 Дек 2025
5
0
Занимаясь некоторым извращением, а если быть точным, писал код в arduino ide под RP2040(планировался оптический приёмник в связке с с передатчиком Arduino nano на Atmega168p, но пока что увяз на самом процессе передачи). В чем суть возникшей проблемы:

  1. Система использует код Хэмминга(8,4) (никакой практической пользы в нём нет в данных условиях, просто спортивный интерес), и во время тестовых передач без его использования всё работает прекрасно
  2. Тут уже интереснее проблема, точнее первая вытекает отсюда, по абсолютно неизвестной мне причине декодирование кода Хэмминга происходит неверно(да и приём байт в целом), если в цикле заполнения буфера отсутствует вывод serial.
Конечно можно оставить всё как есть, ведь вроде как работает, но мне интересно почему прекращается адекватный приём в отсутствии связи с компом.

Скетчи ниже

Receibver:
#include <Arduino.h>




#define RECEIVEPIN 26

#define DIGRECEIVERPIN 11

#define THRESHHOLD 3320

#define BITRATE 400

#define BITPERIOD 1000/BITRATE

#define THFOBITPERIOD BITPERIOD*0.75

#define GET_BYTE(val, n) (((val) >> (8 * (n))) & 0xFF)




#define TEST




uint32_t _time;

uint32_t prevtime;




uint32_t fullTime = 0;       // 32-битное полное время

uint16_t lastTime16 = 0;     // последнее полученное 16-битное значение

bool firstPacket = true;     // флаг первого пакета




uint32_t FullTime(uint16_t currentTime16) {

    if (firstPacket) {

        fullTime = currentTime16;

        lastTime16 = currentTime16;

        firstPacket = false;

        return fullTime;

    }

    int16_t diff = currentTime16 - lastTime16;

    if (diff < 0) {

        diff += 65536;

    }

    fullTime += diff;

    lastTime16 = currentTime16;

    

    return fullTime;

}




void mig() {

  for(int i = 0; i < 10; ++i) {

    digitalWrite(LED_BUILTIN, HIGH);

    delay(200);

    digitalWrite(LED_BUILTIN, LOW);

    delay(200);

  }

}




void setup()

{

  pinMode(DIGRECEIVERPIN,INPUT);




  _time = 0;prevtime = 0;




  Serial.begin(115200);

  mig();

  Serial.print(F("Receiver start work"));

  while(digitalRead(11)!=1){}

  delayMicroseconds(THFOBITPERIOD*1000);

}




void loop()

{

        preambleSearch();

        uint8_t buffer[20];

        for(int i = 0;i<10;++i)

        {

          uint8_t byte1 = receiveByte();uint8_t byte2 = receiveByte();

          buffer[i*2] = byte1; buffer[i*2+1] = byte2;

          //delay(200);

         Serial.print(byte1,HEX); Serial.print(' '); Serial.print(byte2,HEX);Serial.print(' ');

        }

        Serial.println();

        bool firstByte = decode(buffer[16],buffer[17]) == 0xAA;

        bool secondByte = decode(buffer[18],buffer[19]) == 0x55;

        if(firstByte && secondByte)

        {

        uint8_t bufferr[8];

        for(int i = 0;i<8;++i)

          bufferr[i]=decode(buffer[i*2],buffer[i*2+1]);

        uint16_t data[4];

        for(int i = 0;i<4;++i)

          data[i] = (bufferr[i*2]<<8)|bufferr[i*2+1];

        

        Serial.print(F("Transmitter time work: "));

        Serial.print(FullTime(data[0])/1000);

        Serial.print(F(" T = "));

        Serial.print(data[1]*0.01);

        Serial.print(F(" P = "));

        Serial.print(data[2]+90000);

        Serial.print(F(" H = "));

        Serial.print(data[3]);

        Serial.print('\n');}

}




bool preambleSearch()

{

  uint16_t preamble = 0;

  uint32_t bitbuffer = 0;

  while(digitalRead(11)!=1){}

  delayMicroseconds(THFOBITPERIOD*1000);

  while (preamble != 0x4845)

  {

    bitbuffer = (bitbuffer<<1)|digitalRead(DIGRECEIVERPIN);

    preamble = (decode(GET_BYTE(bitbuffer,3),GET_BYTE(bitbuffer,2))<<8)|decode(GET_BYTE(bitbuffer,1),GET_BYTE(bitbuffer,0));

    delayMicroseconds(BITPERIOD*1000);

  }

  return true;

}



uint8_t receiveByte()

{

  uint8_t byte = 0;

  for(int i = 0;i < 8;++i)

    {

      byte = (byte << 1) | digitalRead(DIGRECEIVERPIN);

      delayMicroseconds(BITPERIOD*1000);

    }

  return byte;

}



uint8_t decode(uint8_t byte1, uint8_t byte2)

{

  return ((decodeHamming(byte1) << 4) | decodeHamming(byte2));

}

uint8_t decodeHamming(uint8_t sembyte) {

    uint8_t d0 = (sembyte >> 7) & 1;

    uint8_t d1 = (sembyte >> 6) & 1;

    uint8_t d2 = (sembyte >> 5) & 1;

    uint8_t d3 = (sembyte >> 4) & 1;

    uint8_t p0 = (sembyte >> 3) & 1;

    uint8_t p1 = (sembyte >> 2) & 1;

    uint8_t p2 = (sembyte >> 1) & 1;

    uint8_t parity = sembyte & 1;

    uint8_t syn0 = d0 ^ d1 ^ d2 ^ p0; 

    uint8_t syn1 = d1 ^ d2 ^ d3 ^ p1; 

    uint8_t syn2 = d0 ^ d1 ^ d3 ^ p2; 

    uint8_t error_pos = (syn0 << 2) | (syn1 << 1) | syn2;

    if (error_pos != 0) {

        uint8_t bit_to_flip = 8 - error_pos;

        switch (bit_to_flip) {

            case 7: d0 ^= 1; break;  // bit 7

            case 6: d1 ^= 1; break;  // bit 6

            case 5: d2 ^= 1; break;  // bit 5

            case 4: d3 ^= 1; break;  // bit 4

            case 3: p0 ^= 1; break;  // bit 3

            case 2: p1 ^= 1; break;  // bit 2

            case 1: p2 ^= 1; break;  // bit 1

            case 0: parity ^= 1; break; // bit 0

        }

    }

    uint8_t decSemByte = (d0 << 3) | (d1 << 2) | (d2 << 1) | d3;

    return decSemByte;

}

Transmitter:
#include <GyverBME280.h>

#include <math.h>


#define LASER_PIN 9

#define MAXPACKETSIZE 25

#define BITRATE 400

#define BITPERIOD 1000/BITRATE

#define BITBLOCKSIZE BITRATE

#define BMEADRESS 0x76

#define PREAMBLE 0x4845

#define POSTAMBLE 0xAA55

#define CONSTANT 29.254

#define BAR 101325




#define TEST




GyverBME280 dataMaker;


uint16_t packet[6];


uint8_t HammingEncode(uint8_t sembyte);

void sendBlock(uint8_t *block);


const size_t SerialPrintf (const char *szFormat, ...)

{

    va_list argptr;

    va_start(argptr, szFormat);

    char *szBuffer = 0;

    const size_t nBufferLength = vsnprintf(szBuffer, 0, szFormat, argptr) + 1;

    if (nBufferLength == 1) return 0;

    szBuffer = (char *) malloc(nBufferLength);

    if (! szBuffer) return - nBufferLength;

    vsnprintf(szBuffer, nBufferLength, szFormat, argptr);

    Serial.print(szBuffer);

    free(szBuffer);

    return nBufferLength - 1;

}




void setup()

{

  Serial.begin(9600);

  pinMode(LASER_PIN,OUTPUT);


  packet[0] = PREAMBLE;

  packet[5] = POSTAMBLE;

  if (!dataMaker.begin(0x76)) Serial.println("Error!");

}




void loop()

{

      setpacketPayload();

      uint8_t buffer[(MAXPACKETSIZE-1)/2];

      buffer[0] = 0x48;

      buffer[1] = 0x45;

      buffer[((MAXPACKETSIZE-1)/2)-2] = 0xAA;

      buffer[((MAXPACKETSIZE-1)/2)-1] = 0x55;

      for(int i = 1;i<6;++i)

      {

        buffer[i*2] = (packet[i]>>8) & 0xFF;

        buffer[i*2+1] = packet[i] & 0xFF;




      }

      uint8_t encoded_packet[24];

      for(int i = 0;i<12;++i)

      {

        encoded_packet[i*2] = HammingEncode((buffer[i]>>4)&0x0F);

        encoded_packet[i*2+1] = HammingEncode(buffer[i]&0x0F);

      }

      sendBlock(encoded_packet);

      delayMicroseconds(BITPERIOD*1000);

}




void setpacketPayload()

{

  packet[1] = uint16_t(millis());

  packet[2] = uint16_t(dataMaker.readTemperature() * 100);

  packet[3] = uint16_t(dataMaker.readPressure()-90000);

  packet[4] = uint16_t(CONSTANT*(dataMaker.readTemperature()+273)*log(BAR/dataMaker.readPressure()));

}




uint8_t HammingEncode(uint8_t sembyte)

{

    uint8_t d0 = (sembyte >> 3) & 1;

    uint8_t d1 = (sembyte >> 2) & 1;

    uint8_t d2 = (sembyte >> 1) & 1;

    uint8_t d3 = (sembyte >> 0) & 1;

    uint8_t p0 = d0 ^ d1 ^ d2;

    uint8_t p1 = d1 ^ d2 ^ d3;

    uint8_t p2 = d0 ^ d1 ^ d3;

    uint8_t parity = d0 ^ d1 ^ d2 ^ d3 ^ p0 ^ p1 ^ p2;

    uint8_t byte = 0;

    byte = (byte << 1) | (d0 & 1);

    byte = (byte << 1) | (d1 & 1);

    byte = (byte << 1) | (d2 & 1);

    byte = (byte << 1) | (d3 & 1);

    byte = (byte << 1) | (p0 & 1);

    byte = (byte << 1) | (p1 & 1);

    byte = (byte << 1) | (p2 & 1);

    byte = (byte << 1) | (parity & 1);

    

    return byte;

}




void sendBlock(uint8_t *block)

{

  digitalWrite(LASER_PIN, 1);

  for(int i = 0;i<24;++i)

  {

    sendByte(block[i]);

    Serial.print(block[i],HEX);Serial.print(' ');

  }

  Serial.println();

}




void sendByte(uint8_t byte)

{

  for(int i = 7;i>=0;--i)

  {

    digitalWrite(LASER_PIN, ((byte>>i)&1));  // Сдвиг вправо

    delayMicroseconds(BITPERIOD*1000);

  }

}
Использование delay() не принесло результатов, да и интересует меня в основном причина такого поведения, ибо хочется решить самому. Никакой мега-проблемы такой баг не создаёт, планирую использовать oled дисплей, но всё-же
 

Bruzzer

★★★★✩✩✩
23 Май 2020
742
227
Если неправильно передается один байт, то зачем такой большой скетч? Производите поиск ошибки и отладку передачи одного байта. Когда получится двигайтесь дальше.
 

Girafivan

✩✩✩✩✩✩✩
19 Дек 2025
5
0
@Bruzzer, проблема не в одном неверно передаваемом байте :) Все байты передаются верно, проблема одна - без serial в приёмнике ничего не работает. И все проблемы начались с добавлением помехоустойчивого кода.
 

Bruzzer

★★★★✩✩✩
23 Май 2020
742
227
Если бы вы написали упрощенный скетч передачи одного конкретного байта, и спросили - почему я передаю 0xA7, а получаю в таком то случае XX, а в токам случае YY, понять причину ошибки было бы проще. Лично мне не интересно искать непонятно какую ошибку в не самом простом для понимания коде. Но может найдутся те, кому чем сложнее и запутанней, тем интереснее.

К делу не относится, но как вы думаете одинаковые будут задержки или разные
delayMicroseconds(BITPERIOD*1000);
delayMicroseconds(1000*BITPERIOD);
 

Girafivan

✩✩✩✩✩✩✩
19 Дек 2025
5
0
Если бы вы написали упрощенный скетч передачи одного конкретного байта
Хорошо

C++:
#define BITPERIOD 1000/200


void setup()
{
  Serial.begin(115200);
    pinMode(9,OUTPUT);
}


void loop()
{
     uint32_t test = 0xAABBCCDD;
    sendByte(test&0xFF);
    sendByte((test>>24)&0xFF);
    sendByte((test>>16)&0xFF);
    sendByte((test>>8)&0xFF);
    digitalWrite(9,LOW);
}


void sendByte(uint8_t byte)
{
    for(int i = 7;i>=0;--i)
    {
        digitalWrite(9,(byte>>i)&1);
        delay(BITPERIOD);
    }
}
[CODE=cpp]
#define BITPERIOD 1000/200
void setup()
{
  Serial.begin(115200);
  pinMode(11,INPUT);
  while(digitalRead(11)!=1){}
  delay(BITPERIOD*0.75);
}
bool findPreamble(){
  uint8_t bitbuffer = 0;
  while(digitalRead(11)!=1){}
  delay(BITPERIOD*0.75);
  while(bitbuffer!=0xAA)
  {
    bitbuffer = (bitbuffer<<1)|digitalRead(11);
    delay(BITPERIOD);
  }
  return true;
}
uint8_t receiveByte()
{
  uint8_t byte = 0;
  for(int i = 0;i < 8;++i)
    {
      byte = (byte << 1) | digitalRead(11);
      delay(BITPERIOD);
    } 
  return byte;
}
void loop()
{
  findPreamble();
  uint8_t b1 = 0xAA;
  uint8_t b2 = receiveByte();
  uint8_t b3 = receiveByte();
  uint8_t b4 = receiveByte();
  uint32_t full = (b1<<24)|(b2<<16)|(b3<<8)|b4;
  Serial.println(full,HEX);
  delay(2000);
}
Проблема лишь в том, что данный упрощённый скетч работает как надо, и реальная система тоже работает как надо, но лишь с имением в цикле для заполнения буфера Serial вывода.


delayMicroseconds(BITPERIOD*1000);
delayMicroseconds(1000*BITPERIOD);
Разное. Забыл макрос в скобки заключить, спасибо за подсказку
 

Girafivan

✩✩✩✩✩✩✩
19 Дек 2025
5
0
В общем-то вопрос решился добавлением
C++:
delayMicroseconds((1000*BITPERIOD)-(1000*THFOBITPERIOD));
Но вопрос причины всё ещё остаётся открытым
 

Bruzzer

★★★★✩✩✩
23 Май 2020
742
227
@Girafivan,
Я вас не понимаю, поэтому отключаюсь.
Возможно вам стоит проверить: равны ли рассчитанные (реально выполняемые) задержки тому, что вы ожидаете.
delayMicroseconds(BITPERIOD*1000);
delay(BITPERIOD);
delay(BITPERIOD*0.75);
и т.д.