задержки при чтении UART
- Войдите на сайт для отправки комментариев
Пнд, 26/11/2018 - 21:03
Добрый вечер друзья, подскажите осваивающему:
имеется управляющее устройство, которое по 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);
}
}
Так и должно быть. Отпрравляете Вы по 32 байта, а считать пытаетесь 64. Функция принимаеи 32, после чего ждет секунду и вываливается по таймауту.
Начинайте разбор сразу прямо с первого байта.
на скорую руку, не проверял
//#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;} }так я читаю 64 байта (весь буфер) для защиты от мусора, фактически при чтении из порта у меня может быть массив переменного размера, чет не соображу как выкрутиться
а как вы определите потом где мусор? читайте по 32 байта, если последние 7B B7 делайте чёнить, иначе игнор
Благодарю, буду пробовать
Я же написал в сообщении №1 - разбирайте принятое сразу.
Кстати, у Вас внутри передаваемых данных может случиться комбинация B7 7B или 7B B7?
читайте по 32 байта,
Я бы даже сказал - по одному байту читать надо.
Теоретически может, буду пробовать и далее развивать идею, все спвсибо
http://arduino.ru/forum/programmirovanie/peredat-i-prinyat-integer-po-se...