задержки при чтении UART

Region62
Offline
Зарегистрирован: 31.10.2018
Добрый вечер друзья, подскажите осваивающему:
имеется управляющее устройство, которое по UART должно слать ардуине 32 байта инфы (115200 8N1)
при этом кадр имеет вид "B7 7B 28байт данных 7B B7"
соответственно ардуина должна ответить в таком же формате... из-за аппаратной реализации возможен мусор, т.е. МК должен найти в входном буфере признаки начала, отсчитать 32 байта, проверить признак конца пакета, сформировать ответный кадр в соответствии с форматом.
все бы ничего, и все работает, тока вот протеус показывает дикие задержки (порядка 5000-1000 мс) на чтении принятого сообщения.
на реальной железке уно в3 задержки примерно такиеже
помогите разобраться в чем причина!
в коде пины 12, 13 использую в качестве точек контроля кода на осциллограф 
 
P/S/ время на посылку в одну сторону при моих подсчетах = 2.8 мс при 115200 и 5.6 мс при 57600, явно не бьется с более чем 500 мс
 

void setup()
	{
	Serial.begin(57600); //скорость занижена для виртуального порта proteus
	pinMode(13,OUTPUT);
	pinMode(12,OUTPUT);

	
	}
 
 
 // инициализация массивов
byte buf[64]={0}; // временный массив для вычитывания порта
byte buf_in[32]={0}; // массив принятого кадра
byte buf_out[32]={0}; //массив кадра для отправки
 
 // инициализация вспомогательных переменных
bool good_kadr=false;
int k=0;

 //




void loop()

  {  
     k=0; 
    good_kadr=false;
    byte b=Serial.available();
    if (b>0) //если что-то приняли
      {
		digitalWrite(13, HIGH);
		digitalWrite(12, HIGH);
      Serial.readBytes(buf,64);      // вычитываем весь буфер, ищем кадр, 
		digitalWrite(13, LOW);
      for (int i=0; i<=32; i++)  //буфер порта 64Б, если i>32 то конец посылки не поместится
        {
        if ((buf[i]==0xB7)&&(buf[i+1]==0x7B)&&(buf[i+30]==0x7B)&&(buf[i+31]==0xB7))  // ищем начало пакета, проверяем конец пакета и длинну
          {
          good_kadr=true;
          k=i;
          break;
          }
        else {good_kadr=false;
}
        }
      }
    if (good_kadr==true)
      {
      for (int m=0; m<=31; m++)
        {
        buf_in[m]=buf[m+k]; 
        }
	  for (int i=2; i<=29; i++)
		{buf_out[i]=buf_in[i]+1;}
      buf_out[0]=0xB7;
      buf_out[1]=0x7B;
      buf_out[30]=0x7B;
      buf_out[31]=0xB7;
      // delay(1000);
	  Serial.write(buf_out,32);
		digitalWrite(12, LOW);
	  }



  }

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Так и должно быть. Отпрравляете Вы по 32 байта, а считать пытаетесь 64. Функция принимаеи 32, после чего ждет секунду и вываливается по таймауту.

Начинайте разбор сразу прямо с первого байта.

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

на скорую руку, не проверял

//#include <SoftwareSerial.h>
//SoftwareSerial UART(7,8 ); // RX, TX

#define debug        // закоментировать эту строку, если не нужна отладка в сериал монитор 

#ifdef debug 
#define UART Serial1 // нужный сериал для связи с устройством 
#define DEBUG Serial // сериал для отладки в терминале (монитор порта)
#else
#define UART Serial  // нужный сериал для связи с устройством в случае отсутствия отладки (если выше строка debug закоментирована)
#endif 


byte header = 0;           // состояние заголовка (заголовок определяется по первым байтам 0хB7 и 0х7B см. ниже в скетче)
byte message_size = 32;    // размер тела принимаемого сообщения, кол-во байт

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

uint32_t curmillis = 0;     // снимок системного времени

byte waitbyte_time = 1;   // задержка, мс для успевания заполнения буфера RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
uint32_t timerdelay = 0;  // таймер ожидания байт (для успевания заполнения буфера УАРТ)
bool Delay = 0;           // таймер ожидания байт (для успевания заполнения буфера УАРТ)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis  // включение этого таймера

uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
bool RESETheader_timer = 0; // таймер сброса заголовка если в момент приёма заголовка данные оборвались


void setup() {

UART.begin (115200);   
#ifdef debug
DEBUG.begin (38400); 
#endif

}


void loop() {
  
  curmillis = millis();

  receive (); // приём данных по UART 
  }

void receive () {
  
  if (UART.available() ){
    

 // первый старт байт
 if (header == 0 && Delay){buf[0]=UART.read();   if (buf[0]==0xB7){
  TIMER_DELAY ; header = 1; 
#ifdef debug
  DEBUG.print (buf[0], HEX);
  DEBUG.print (" "); 
#endif
RESETheader_timer =1; prevRESETheader = curmillis; }}

 // второй старт байт
 if (header == 1 && Delay){buf[1]=UART.read(); if (buf[1]==0x7B){
  TIMER_DELAY ; 
#ifdef debug
  DEBUG.print (buf[1], HEX);  DEBUG.print (" "); 
#endif  
  header = 4;} 
  else {header = 0; j=2; RESETheader_timer = 0;}} 
 
 
 // пишем тело сообщения 
 if (header == 4 && Delay && j< message_size) {
 buf[j] = UART.read(); 
 
 if (j==message_size-1) header = 5; // закончили принимать
TIMER_DELAY ; 
#ifdef debug
 debug DEBUG.print (buf[j], HEX);  DEBUG.print (" "); 
#endif  
 
 j++;} 
 }

 // если сообщение приняли, действуем
 if (header == 5) {TIMER_DELAY ;  
#ifdef debug
 DEBUG.println(); 
#endif
   
header=0; j=2; RESETheader_timer = 0;

if (buf[30]==0x7B && buf[31]==0xB7){
//  тут далаем что нибудь полезное по данным принятого сообщения!!!!!!!!!!!!!!!!!!!!!!!
}

}

if (!Delay && curmillis - timerdelay > waitbyte_time) Delay = 1; // таймер ожидания байт (для успевания заполнения буфера УАРТ)

// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}  
  
     }

 

Region62
Offline
Зарегистрирован: 31.10.2018

так я читаю 64 байта (весь буфер) для защиты от мусора, фактически при чтении из порта у меня может быть массив переменного размера, чет не соображу как выкрутиться

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

а как вы определите потом где мусор? читайте по 32 байта, если последние 7B B7 делайте чёнить, иначе игнор

Region62
Offline
Зарегистрирован: 31.10.2018

Благодарю, буду пробовать

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Я же написал в сообщении №1 - разбирайте принятое сразу.

Кстати, у Вас внутри передаваемых данных может случиться комбинация B7 7B или 7B B7?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

MaksVV пишет:

читайте по 32 байта, 

Я бы даже сказал - по одному байту читать надо.

Region62
Offline
Зарегистрирован: 31.10.2018

Теоретически может, буду пробовать и далее развивать идею, все спвсибо

Pyotr
Offline
Зарегистрирован: 12.03.2014