прошу помощи по заполнению и обработке массива

SHA_MAN
Offline
Зарегистрирован: 10.05.2019



#include <SoftwareSerial.h>

#define LOOP_DELAY 50
#define SW_SERIAL_BAUD_RATE 9600
#define HW_SERIAL_BAUD_RATE 9600
#define SW_SERIAL_RX_PIN 11
#define SW_SERIAL_TX_PIN 10

SoftwareSerial mySerial(SW_SERIAL_RX_PIN, SW_SERIAL_TX_PIN); // RX, TX

int IBUSreceiveByte = 0;                   // byte reading from I-BUS 
byte IBUSbyte[7] = {0,0,0,0,0,0,0};       // key byte sequence 
int Delay = 0;                           //delay in millisec 
int ButtonPressed = 0;                    //boolean value set 1 if key press detected 
int KeyID = 0;                            // key press number (for easy select case routine) 

//hold keys flags 
//int N_HOLD_F = 0; //next track hold flag 
//int P_HOLD_F = 0; //prev track hold flag  
//int V_HOLD_F = 0; // r/t key hold flag 


byte PLUS_DOWN[7] = {0, 0x50, 0x04, 0x68, 0x32, 0x11, 0x1F}; // + press button 
byte MINUS_DOWN[7] = {0, 0x50, 0x04, 0x68, 0x32, 0x10, 0x1E}; // - press button 

byte NEXT_DOWN[7] = {0, 0x50, 0x04, 0x68, 0x3B, 0x01, 0x06}; // > press button 
byte NEXT_HOLD[7] = {0, 0x50, 0x04, 0x68, 0x3B, 0x11, 0x16}; // > hold button 
byte NEXT_REL[7] = {0, 0x50,  0x04, 0x68, 0x3B, 0x21, 0x26}; // > release button 

byte PREV_DOWN[7] = {0, 0x50, 0x04, 0x68, 0x3B, 0x08, 0x0F}; // < press button 
byte PREV_HOLD[7] = {0, 0x50, 0x04, 0x68, 0x3B, 0x08, 0x0F}; // < hold button 
byte PREV_REL[7] = {0, 0x50, 0x04, 0x68, 0x3B, 0x08, 0x0F}; // < release button 

byte VOICE_DOWN[7] = {0, 0x50, 0x04, 0xC8, 0x3B, 0x80, 0x27}; // voice press button 
byte VOICE_HOLD[7] = {0, 0x50, 0x04, 0xC8, 0x3B, 0x90, 0x37}; // voice hold button 
byte VOICE_REL[7] = {0, 0x50, 0x04, 0xC8, 0x3B, 0xA0, 0x07}; // voice release button 

byte RT_DOWN[7] = {0, 0x50, 0xFF, 0x03, 0xC8, 0x01, 0x9A}; // voice release button 

void setup() 
  { 
   mySerial.begin(9600);
   Serial.begin(9600);  
  } 


void loop() 
{ 
  if (Serial.available() && ButtonPressed==0){ 
    TryReadIBUSmsg(); 
  } 
   
   
  if (ButtonPressed==1){ 
    mySerial.print(millis()); 
    mySerial.println(" ----------------------------------------------- "); 
     
    switch (KeyID){ 
      case 100:                                     //Если клавиша не  опознана или какие-то ошибки в шине при чтении 
        mySerial.print("UNKNOWN KEY: "); 
        SerialPrintKey(); 
        break; 
         
      case 40: 
        mySerial.print("R/T KEY: "); 
        SerialPrintKey(); 
        break;   
         
      case 1: 
        mySerial.print("VOL + key: "); 
        SerialPrintKey(); 
        break;         
      case 2: 
        mySerial.print("VOL - key: "); 
        SerialPrintKey(); 
        break;  
         
      case 11: 
        mySerial.print("NEXT FLAG HOLD=0: "); 
        SerialPrintKey(); 
      //  N_HOLD_F=0; 
        break;  
      case 12: 
        mySerial.print("NEXT FLAG HOLD=1: "); 
        SerialPrintKey(); 
     //   N_HOLD_F=1; 
        break;  
    /*  case 13: 
       if (N_HOLD_F==0){ 
          mySerial.print("NEXT TRACK key: "); 
          SerialPrintKey(); 
            }  
        else { 
          mySerial.print("NEXT FOLDER key: "); 
          SerialPrintKey(); 
        } 
        break;  
     */    
      case 21: 
        mySerial.print("PREV FLAG HOLD=0: "); 
        SerialPrintKey(); 
      //  P_HOLD_F=0; 
        break;  
      case 22: 
        mySerial.print("PREV FLAG HOLD=1: "); 
        SerialPrintKey(); 
     //   P_HOLD_F=1; 
        break;  
     /* case 23: 
        if (P_HOLD_F==0){ 
          mySerial.print("PREV TRACK key: "); 
          SerialPrintKey(); 
        }  
        else { 
          mySerial.print("PREV FOLDER key: "); 
          SerialPrintKey(); 
        } 
        break;   
     */    
      case 31: 
        mySerial.print("VOICE FLAG HOLD=0: "); 
        SerialPrintKey(); 
      //  V_HOLD_F=0; 
        break;  
      case 32: 
        mySerial.print("VOICE FLAG HOLD=1: "); 
        SerialPrintKey(); 
     //   V_HOLD_F=1; 
        break;  
     /* case 33: 
        if (V_HOLD_F==0){ 
          mySerial.print("VOICE key press: "); 
          SerialPrintKey(); 
        }  
        else { 
          mySerial.print("Voice key hold: "); 
          SerialPrintKey(); 
        } 
        break; */  
    } 
           ButtonPressed = 0; 
    } 
}  


void TryReadIBUSmsg() 
{ 
      IBUSreceiveByte = Serial.read();    //read 1-st byte Если 50 то это начало посылки от рулевых кнопок 
      if (IBUSreceiveByte==0x50) 
      { 
        IBUSbyte[1]=0x50; 
        for (int i=2; i <= 7; i++){   
          IBUSbyte[i] = Serial.read();                 //read  2,3,4,5,6,7 bytes of data   -  читаем следующие байты 
          delay(Delay); 
          SerialPrintKey(); 
        } 
        KeyID=100; //Устанавливаем по умолчанию что клавиша не опознана 
         
                   
        if(memcmp(IBUSbyte, PLUS_DOWN, 7) == 0 ){KeyID=1;}      // и меняем если опознана на соответствующий код 
        if(memcmp(IBUSbyte, MINUS_DOWN, 7) == 0 ){KeyID=2;} 
         
        if(memcmp(IBUSbyte, NEXT_DOWN, 7) == 0 ){KeyID=11;} 
        if(memcmp(IBUSbyte, NEXT_HOLD, 7) == 0 ){KeyID=12;} 
        if(memcmp(IBUSbyte, NEXT_REL, 7) == 0 ){KeyID=13;} 
         
        if(memcmp(IBUSbyte, PREV_DOWN, 7) == 0 ){KeyID=21;} 
        if(memcmp(IBUSbyte, PREV_HOLD, 7) == 0 ){KeyID=22;} 
        if(memcmp(IBUSbyte, PREV_REL, 7) == 0 ){KeyID=23;} 
         
        if(memcmp(IBUSbyte, VOICE_DOWN, 7) == 0 ){KeyID=31;} 
        if(memcmp(IBUSbyte, VOICE_HOLD, 7) == 0 ){KeyID=33;} 
        if(memcmp(IBUSbyte, VOICE_REL, 7) == 0 ){KeyID=32;} 
         
        if(memcmp(IBUSbyte, RT_DOWN, 7) == 0 ){KeyID=40;} 
         
        ButtonPressed=1; 
      } 
      else 
      { 
        ButtonPressed=0; 
      } 
    
} 

void SerialPrintKey()                                     // печать в ком порт посылки  
{ 
    for (int x=1; x <= 7; x++){   
            mySerial.print(IBUSbyte[x], HEX); 
            mySerial.print(" "); 
        } 
    mySerial.println(); 
}  

 

SHA_MAN
Offline
Зарегистрирован: 10.05.2019

Здравствуйте все

Нужна помощь новичку. 

Прошу подсказки, в чем может быть проблема - пробую переделать найденный скетч для распознавания нажатий кнопок руля.

Не могу понять, почему на месте первого байта массива появляется FF 

 

на картинке ситуация в мониторе порта, после нажатия кнопки руля - первый раз (кстати тоже не могу понять почему одно нажатие выводит две распечатки) - на месте второго байта FF, и соответственно, сравнение массива не успешное. Тут же появляется вторая распечатка - видно как (для меня странно) дублируются байты, смещаясь по мере заполнения. Но при этом посылка уже правильная, 04 вместо FF и таки в конце распознается скетчем. 

Собственно, задача более чем тривиальная - принять в порт посылку, и на основании ее содержания (условия строятся на основании определенных байт посылки) - выполнять те или иные действия. Но пока какой-то тотальный бардак с заполнением массива из посылки.

Подскажите, кто знает - где ошибка?

Спасибо!

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Знаю есть тут люди с машинами понимающие. Я пока со своей колокольни брякну, может и не поможет, но на мысли какие наведёт. Байты же справа на лево читаться должны, полагаю FF это заполнение не достающих данных, типа нету ничего поэтому по максимуму. Но это я так, со своей колокольни и вообще ничего не понимая брыкнул. Удачи вам!

SHA_MAN
Offline
Зарегистрирован: 10.05.2019

Спасибо за участие.

У меня есть решение как обойти это - просто "подогнать" строку для сравнения с тем, что приходит на экран. Но это не выход. Я принципиально где-то недопонимаю и ошибаюсь. А очень хочется таки разобраться и сделать как надо. 

SHA_MAN
Offline
Зарегистрирован: 10.05.2019

напал на след этого безобразия.

Вот такой скетч 

#include <SoftwareSerial.h>

#define LOOP_DELAY 50

#define BUFFER_SIZE 7
#define BUFFER_OFFSET 0
#define SW_SERIAL_BAUD_RATE 9600
#define HW_SERIAL_BAUD_RATE 9600
#define SW_SERIAL_RX_PIN 11
#define SW_SERIAL_TX_PIN 10

SoftwareSerial mySerial(SW_SERIAL_RX_PIN, SW_SERIAL_TX_PIN); // RX, TX

uint8_t IBUSbytes[BUFFER_SIZE];

void setup()
{
	mySerial.begin(SW_SERIAL_BAUD_RATE);
	Serial.begin(HW_SERIAL_BAUD_RATE, SERIAL_8E1);
}

void loop()
{
	tryReadIBUSmsg();
	delay(LOOP_DELAY);
}

void tryReadIBUSmsg()
{
	if (Serial.available() )
	{
		for (uint8_t index = BUFFER_OFFSET; index < sizeof(IBUSbytes); index++)
		{
			IBUSbytes[index] = Serial.read();
      
		}
   printCode();
  
   
	}

}

void printCode()
{
	for (int index = BUFFER_OFFSET; index < sizeof(IBUSbytes); index++)
	{
		mySerial.print(IBUSbytes[index], HEX);
		if (index < sizeof(IBUSbytes) - 1)
		{
			mySerial.print(" ");
		}
	}
	mySerial.println();
  mySerial.println("income");
}

Дает в монитор следующее :

 

Получается, что если отправить посылку (я с эмулятора вручную пока пробую) длинной равной длине объявленного массива - то ( с горем пополам) посылка в монитора показывается верно. Периодически "пролетает" какой-то мусор (видно на левой части) но, это скорее всего к портам-таймингам вопрос. 

А самый главный вопрос - почему вторая часть строки все равно попадает в массив, хотя он ограничен по размеру? Получается, что все, что пришло в порт "загоняется" в массив по кругу. 

Как сделать так, чтобы принимались только необходимые мне байты, а остальное просто игнорировалось?

На правой части картинки видно, что все, что отправлено в порт попадает в массив, а мне это не нужно.

Я вижу вариант - через условие, в посылке ведь есть длинна сообщения. Но если кто-то подскажет решение проще - буду благодарен.

Грубо говоря, какой бы длинны не было принято сообщение - в массив записать только 8 байт. Остальное игнорировать.

Спасибо всем!

sadman41
Offline
Зарегистрирован: 19.10.2016

Почему вы читаете из буфера N байт, не убедившись, что они там есть?

SHA_MAN
Offline
Зарегистрирован: 10.05.2019

Прошу понять и простить, я начинающий

if (Serial.available() - это не проверка наличия чего-то в буфере?

sadman41
Offline
Зарегистрирован: 19.10.2016

Именно - чего-то. Но считываете вы не чего-то, а 7 байт.

SHA_MAN
Offline
Зарегистрирован: 10.05.2019

if (Serial.available() > 7)

так?

 

void tryReadIBUSmsg()
{
	if (Serial.available() >7)
	{
		for (uint8_t index = BUFFER_OFFSET; index < sizeof(IBUSbytes); index++)
		{
			IBUSbytes[index] = Serial.read();
      
		}
   printCode();
  
   
	}
}

Сделал так. Стало намного лучше. Отсекает "хвост" в 7 байт, если посылка до 14. Если длиннее - получается 7 первых приняло, потом 7 пропустило, и оставшиеся снова приняло.

Я может неправильно понимаю как это работает. Моя расшифровка   if (Serial.available() > 7) - если в буфере есть что-то длинной больше 7 байт, то....  

Стало быть, по условиям - приняло первые 7, ок. Проверили остаток, и если меньше 7 - то ничего, а если больше, то снова условие выполняется и "остатки" попадают в порт. 

Так? 

Можно как-то очистить буфер после успешного принятия первых N байт? 

Я пробовал втыкнуть flush, но не сработало. Это для отправки, как я понял. 

Спасибо

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Нельзя очистить то, что ещё не принято. Переходите от парадигмы "данные ждут в массиве" к парадигме "данные придут хрен знает когда": ждете маркера начала пакета, считываете после этого N байт в свой массив (буферизуете), обрабатываете. Потом всё заново.

SHA_MAN
Offline
Зарегистрирован: 10.05.2019

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