Задать вопрос
@ustivanon

Почему в самописном приёмнике данные не принимаются без Serial.print()?

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

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

Ниже приведу скетчи
Приёмник

#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;  // syn1[0]

    uint8_t syn1 = d1 ^ d2 ^ d3 ^ p1;  // syn1[1]

    uint8_t syn2 = d0 ^ d1 ^ d3 ^ p2;  // syn1[2]

    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;

}



Передатчик


#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);

  }

}

  • Вопрос задан
  • 126 просмотров
Подписаться 1 Средний 3 комментария
Помогут разобраться в теме Все курсы
  • PROFIFUTURE
    1С программист
    6 недель
    Далее
  • Нетология
    Инженер по автоматизации
    13 месяцев
    Далее
  • Skillbox
    C++ для робототехников
    1 месяц
    Далее
Пригласить эксперта
Ответы на вопрос 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
декодирование кода Хэмминга происходит неверно(да и приём байт в целом), если в цикле заполнения буфера отсутствует вывод serial

это происходит потому, что приём буфера синхронизируется только в его начале, по преамбуле, после этого никакой синхронизации нет. Чтобы приём выполнялся корректно, задержки при семплировании битов приёмником не должны отличаться от задержек при передаче больше чем на (длительность одного бита)/(максимальное число битов в сообщении). В передатчике из дополнительных задержек -- печать байта и пробела после каждого переданного байта:
for(int i = 0;i<24;++i) {
    sendByte(block[i]);
    Serial.print(block[i],HEX);Serial.print(' ');
}


В приёмнике -- печать двух байт и двух пробелов после приёма каждых двух байтов:
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 совпадают. А при удалении печати в приёмнике задержки начинают расходиться слишком сильно.

Я бы не рекомендовал вставлять вызовы Serial.print() или других функций с переменным временем выполнения в алгоритм требующий работы в режиме реального времени.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы