Очищается ли содержимое буфера порта после операции Serial.read()?

nik182
Offline
Зарегистрирован: 04.05.2015

А не проще взять MODBUS и ничего ждать и парсить не придётся. Данные по приходу сами будут складываться  в нужные ячейки памяти? Заодно имеем проверку на целостность пакета. Да и посылать можно адресно, например по одному значению. Порог входа в MODBUS на ардуино достаточно низок.  

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

ЕвгенийП пишет:

Входите в луп, смотрите сколько символов пришло. Допустим прийти успело 26 (один ещё не успел). Поскольку их не 27, Вы выбрасываете их и "делаете всё как раньше". При следующем лупе приходит не успевший в прошлый раз 27-ой символ. Поскольку символов опять не 27, а один, Вы и его выбрасываете и "делаете всё как раньше".

Правильно, Вам так надо?

Вот что значит профи! Три слова, и "мысь по древу" сформулирована! Спасибо, именно это мне и было надо. Понял сразу всё. Буду думать дальше. Первая же мысль - читать не в каждом лупе, а периодически ("millis()" в помощь). Наконец добрался до платы. Поковыряюсь, думаю большая часть вопросов отвалится на практике. Что останется - приду снова сюда.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Sonologist пишет:

Первая же мысль - читать не в каждом лупе, а периодически ("millis()" в помощь). 

нет, так не надо делать. Лови.  Сообщение применяются такого вида:

   AA  55  XX  байты полезной нагрузки CS

где  АА и 55 старт байты,   XX - байт длины сообщения, CS - контрольная сумма (простое сложение, для увеличения надёжности можно взять далласовский CRC) 

#define BUS Serial  // UART на котором висит наша шина

byte meSS[] = {1,2,3,4,5,1,8,9,0,0,0,0,123,123,156,255}; // сообщение для примера 

const bool echo = 0;  // делаем тут 1 , если шина имеет эхо (когда отправленные байты сразу появляются в приёмнике, например к-лайн)

const byte bufsize = 150;           // размер буфера принятого сообщения
static byte buf [bufsize] = {0};    // буфер принятого сообщения


uint32_t currmillis = 0; // таймер системного времени

void setup() 
{
BUS.begin(9600); 
sendMessage (meSS, sizeof(meSS)); // отправляем сообщение в шину для примера
pinMode (13, OUTPUT);
}

void loop() 
{
currmillis = millis();  // снимок системного времени
BUSread();              // читаем шину  

digitalWrite(13, buf[3]); // например из байта буфера принятого сообщения рулим диодом
}


 void messageOKreceived()
{
 //  ТУТ ДЕЛАЕМ ЧТО-ТО НУЖНОЕ, например только когда СООБЩЕНИЕ УСПЕШНО ПРИНЯТО!
}



void sendMessage(const byte *payload, const size_t size)
{
  const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) 
  {
    if (i==0) {Mes[i] = 0xAA;}
    if (i==1) {Mes[i] = 0x55;}
    if (i==2) {Mes[i]=size;}    
    if (i==3) 
    {
      for (byte t=0; t<size; t++ ) 
         {
          Mes[i]=payload[t]; Checksum+=Mes[i]; BUS.write (Mes[i]); 
          if (echo) BUS.read(); 
          i++;
         }
    }
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    BUS.write (Mes[i]);  if (echo) BUS.read(); 
  }
} 


void BUSread()
{
  static byte header = 0;             // состояние заголовка 
  static byte message_size = 0;       // размер тела принимаемого сообщения, кол-во байт
  static byte j = 3;                  // инкремент
  static byte checksum = 0;           // контрольная сумма входящего сообщения
  static uint32_t prevRESETheader=0;  // таймер сброса заголовка если в момент приёма сообщения данные оборвались
  static bool RESETheader_timer = 0;  // таймер сброса заголовка если в момент приёма сообщения данные оборвались

if (BUS.available()){
    

 // первый старт байт
 if (header == 0)
      {
        buf[0]=BUS.read();  
        if (buf[0] == 0xAA){header = 1; RESETheader_timer=1; prevRESETheader = currmillis; }
      }                  

 // второй старт байт
 else if (header == 1)
      {
        buf[1]=BUS.read(); 
        if (buf[1]==0x55){ header = 2;} else {header = 0; RESETheader_timer=0;}
      } 

 // третий старт байт
 else if (header == 2)
      { 
        buf[2]=BUS.read(); 
        message_size = buf[2]; 
        header = 4; checksum = 0;
     if (message_size>bufsize){header = 0; RESETheader_timer=0;}
      }
                            
  // пишем тело сообщения 
 else if (header == 4 && j< message_size+4) 
      {
        buf[j] = BUS.read(); 
        if (j<message_size+3) checksum+= buf[j]; // подсчёт КС
        if (j==message_size+3) header = 5; 
        j++;
      } 

 } // end of BUS.available()

 // сообщение приняли, действуем
 if (header == 5) 
 {  
    for(byte i = 0; i<3; i++) checksum+=buf[i]; // прибавляем к контрольной сумме старт байты
    
    // если контрольная сумма верна: 
    if (buf[message_size+3] == checksum) 
  {
  // распечатаем сообщение в отладку
  for (int g = 0; g < message_size+4; g++) {BUS.print(buf[g], HEX); BUS.print(F(" "));}
  BUS.println();
  
  messageOKreceived(); //  ТУТ ДЕЛАЕМ ЧТО-ТО НУЖНОЕ, ПОТОМУ ЧТО СООБЩЕНИЕ УСПЕШНО ПРИНЯТО!
  }   

    // если контрольная сумма не совпала: 
    else Serial.println("CRC fail!!!" );
    message_size = 0; header=0; RESETheader_timer=0; j=3; checksum = 0;
  }

// таймер сброса сборки пакета, если данные перестали поступать более чем полсекунды 
if (RESETheader_timer && currmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}   
}

Sonologist пишет:
........ просто проверять Serial.avalable () на наличие чего-то в порту, и если есть - выполнять программу с новыми параметрами, а если нет - продолжать это делать со старыми. ........

вот и выполняйте свою программу с параметрами, которые будут поступать от ПК в созданный буфер buf . Если с ПК пришло сообщение, этот buf  уже будет "с новыми параметрами", если не пришло - будет "продолжать это делать со старыми". Только само собой на ПК нужно упаковывать данные по тем же правилам. 

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Премного благодарен. Записал себе в анналы. Сразу понять все не смог (низкая квалификация), но полноценные комменты помогут. Буду разбираться. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вот полезная для тебя функция 

http://arduino.ru/Reference/Serial/Peek

Sonologist
Sonologist аватар
Offline
Зарегистрирован: 08.06.2018

Спасибо, до ПИКа еще не добрался :) Изучу.