Связь двух arduino через Serial

Тема в разделе "Arduino & Shields", создана пользователем gfox, 13 дек 2017.

  1. gfox

    gfox Нерд

    Добрый день, помогите пожалуйста! Делаю беспроводной джойстик, имею в наличии bluetooth модуль hm-10. Все вроде работает, но некорректно. Включаю джойстик, который начинает передавать по 2 байта, принимающая ардуинка начинает обрабатывать полученные байты, и все вроде нормально, но моментами случаются коллизии, вроде передаю одно, а получаю совсем другое:
    Код (Text):
    1000010000000000
    1000010000000000
    0001001100000000
    1000010000000000
    1000010000000000
    1000010000000000
    В результате "случайно" нажимаются не те кнопки.
    Далее код передающий:
    Код (C++):
    #include <Button.h>
    #include <SoftwareSerial.h>
    byte ButtonState[2];

    Button btnLeft = Button(17,PULLUP);
    Button btnLRight = Button(16,PULLUP);
    Button btnUp = Button(19,PULLUP);
    Button btnDown = Button(18,PULLUP);
    Button btnStart = Button(15,PULLUP);
    Button btnA = Button(9,PULLUP);
    Button btnB = Button(8,PULLUP);
    Button btnC = Button(7,PULLUP);
    Button btnZ = Button(6,PULLUP);
    Button btnY = Button(5,PULLUP);
    Button btnX = Button(4,PULLUP);
    Button btnMode = Button(3,PULLUP);

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

    void loop() {

       if(btnLeft.isPressed())    bitWrite(ButtonState[0],0, 1);    else bitWrite(ButtonState[0],0, 0);
       if(btnLRight.isPressed())  bitWrite(ButtonState[0],1, 1);    else bitWrite(ButtonState[0],1, 0);
       if(btnUp.isPressed())    bitWrite(ButtonState[0],2, 1);    else bitWrite(ButtonState[0],2, 0);
       if(btnDown.isPressed())    bitWrite(ButtonState[0],3, 1);    else bitWrite(ButtonState[0],3, 0);
       if(btnStart.isPressed())   bitWrite(ButtonState[0],4, 1);    else bitWrite(ButtonState[0],4, 0);
       if(btnA.isPressed())     bitWrite(ButtonState[0],5, 1);    else bitWrite(ButtonState[0],5, 0);
       if(btnB.isPressed())     bitWrite(ButtonState[0],6, 1);    else bitWrite(ButtonState[0],6, 0);
       if(btnC.isPressed())     bitWrite(ButtonState[0],7, 1);    else bitWrite(ButtonState[0],7, 0);
       if(btnZ.isPressed())     bitWrite(ButtonState[1],0, 1);    else bitWrite(ButtonState[1],0, 0);
       if(btnY.isPressed())     bitWrite(ButtonState[1],1, 1);    else bitWrite(ButtonState[1],1, 0);
       if(btnX.isPressed())     bitWrite(ButtonState[1],2, 1);    else bitWrite(ButtonState[1],2, 0);
       if(btnMode.isPressed())    bitWrite(ButtonState[1],3, 1);    else bitWrite(ButtonState[1],3, 0);
     
       Serial.write(ButtonState,2);
       delay(20);
    }
    Далее код обрабатывающей стороны:
    Код (C++):
    #include <Joystick.h>
    #include <SoftwareSerial.h>

    SoftwareSerial mySerial(8, 9); // RX, TX
    byte ButtonState[2]; // Массив кнопок byte
    bool ButtonStateBool[12]; // Массив кнопок bool

    Joystick_ Joystick;

    void setup() {
        Joystick.begin();
        mySerial.begin(9600);
        mySerial.setTimeout(1); //пробовал убирать и менять, не помогает
    }
    void loop() {

    if(mySerial.available()) {
         mySerial.readBytes(ButtonState,2); //читаем по 2 байта

         // записываем в логический массив первый байт
    for(int i=0;i<8;i++){
      if(bitRead(ButtonState[0],i)==1) ButtonStateBool[i]=true; else ButtonStateBool[i]=false;
      }
        // записываем в логический массив второый байт
    for(int i=8;i<12;i++){
      if(bitRead(ButtonState[1],i-8)==1) ButtonStateBool[i]=true; else ButtonStateBool[i]=false;
      }
    }
        // записываем состояние кнопок
    for (int i=0; i<12; i++){
                Joystick.setButton(i, ButtonStateBool[i]);
              }
      }
     
    Собственно такое ощущение, что он неправильно читает байты из буфера, если я делаю небольшую задержку в принимающей программе, то становится еще хуже. Что я делаю не так?
     
  2. rkit

    rkit Гуру

    А как у вас приемник должен угадать, какой из байтов какой?
     
    arkadyf нравится это.
  3. ostrov

    ostrov Гуру

    Где стартовый и стоповый байты? О КС уж молчу. И готовьте цепочку в массиве, это и наглядней и компактней.
     
    arkadyf нравится это.
  4. MihaNN52

    MihaNN52 Нерд

    Каждый раз все придумывают свой протокол передачи, для новичка это проблема, а готового них нет.
    Вот тебе вариантик достаточно стабильный. Допилишь сам. Или напишешь аналогичное.
    Формат - символ начала, символ команды, значение, символ окончания
    типа того &A843877#
    Код (C++):
    template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

    enum AUTOMATA_STATE { // Возможные состояния разборщика
        WAITING_AMPERSAND,    // ожидание начала пакета
        WAITING_NAME,     //    ожидание имени
        WAITING_NUMBER    //    ожидание числа
    };

    #define    PACKET_BEGIN    '&'

    void setup(void) {
        Serial.begin(115200);
    }

    void loop(void) {
        // Изначально автомат в состоянии ожидания
        static AUTOMATA_STATE state = WAITING_AMPERSAND;
        static char variableName;
     
        if (! Serial.available()) return;    // не пришёл символ? Ну, и нечего тут делать
        //
        // Что делать дальше определяется состоянием автомата
        switch (state) {
            case WAITING_AMPERSAND:
                // В состоянии ожидания мы ждём символа PACKET_BEGIN и игнорируем любые другие
                if (Serial.read() != PACKET_BEGIN) return;
                // Пришёл символ начала пакета. Переходим в состояние PARSING
                state = WAITING_NAME;
                break;
            case WAITING_NAME:
                // В состоянии ожидания имени мы мы должны получить латинскую букву.
                // Если получили - переходим в состояние ввода числа
                // Если пришло что-то другое - ошибка, переходим обратно в ожидание &
                variableName = Serial.read();
                state = isalpha(variableName) ? WAITING_NUMBER : WAITING_AMPERSAND;
                break;
            case WAITING_NUMBER:
                // читаем число
                float value = Serial.parseFloat();
                Serial << variableName << "=" << value << '\n';
                ///////////////////////////
                //    В этом месте мы имеем результат !!!!
                //    Имя находится в переменной variableName, а значение - в переменной value
                //    Что с ними делать решайте сам - сериал-то у нас занят другим устройством
                //    так что печатать результат некуда
                ///////////////////////////
                state = WAITING_AMPERSAND;
                break;
        }
    }
    Если в сериал ввести строку

    $&a29.72&b20.44&c748.35&d26.20#

    то печатает

    a=29.72
    b=20.44
    c=748.35
    d=26.20

    Для повышения стабильности надо вводить контрольную сумму. Но этот вариант отлично работал, для начала пойдет.
     
    arkadyf нравится это.
  5. ostrov

    ostrov Гуру

    Есть тут хороший пример в вики Амперки. Называется "карта офисной активности". Там все разжовано, но под свою задачу мозг напряч все таки придется.
     
    arkadyf нравится это.
  6. MihaNN52

    MihaNN52 Нерд

    Чет не увидел там ни каких проверок вообще, ни начала ни конца ни crc. Ткни носом. Еще надо посылать ответ если все удачно пришло, а тот кто отправлял должен делать попытки отправки n раз пока не придет ответ. На самом деле ни кто ни кому не должен, просто для полноты картины.
     
  7. MihaNN52

    MihaNN52 Нерд

    Вот мой пример отправки и получения подтверждения получения.
    Код (C++):
    bool send_stm32(char command, char * valve) { //отправка команды
        byte tries = 2; // количество попыток отправки
        while (--tries) { // цикл из n подходов отправки
            swSer.write('&'); //начало пакета
            swSer.write(command); // имя команды
            swSer.print(valve); // значение передаваемой переменной
            swSer.write('#'); // окончание передачи

            Serial.print("Tries");
            Serial.println(tries);
            if (report()) { // если ответ 1 то выходим
                Serial.println("GOOD");
                return true;
            } else
                Serial.println("Error");

        }
        return false;
    }

    bool report() { //подтверждение от о получении

        byte tries = 15; // сколько циклов ждем подтверждение
        char OK;
        delay(100);
        while (--tries) {

            OK = swSer.read();
            Serial.print("OK=");
            Serial.println(OK);

            if (OK == '*') { // пришел ответ '*'
                return true;
            }
            delay(100);
        }
        return false;
    }
     
    arkadyf нравится это.
  8. MihaNN52

    MihaNN52 Нерд

    Вот пример получения.
    Код (C++):
    void resiveSwSer(char usartData) {

        switch (mode) {
        case 1:
            //ожидание символа начала  пакет @
            if (usartData == '@') {
                mode = 2;
            }
            break;
        case 2:
            //проверка второго символа и присвоение название переменной
            name = usartData;
            //printf("Name = %c\n\r" ,name );
            if (isalpha(name)) {
                mode = 3;
            } else {
                mode = 1;
                name = 0;
            }
            break;
        case 3:
            //собираем массив дата
            data[byteData++] = usartData;
            //printf("Data = %s\n\r" ,data);
            if (usartData == '$') {
                //если пришел символ конца сообщения $ завершаем сбор массива
                mode = 4;
                //printf("Data = %s\n\r" ,data);
                goto label;
            }
            if (byteData >= 26) {
                //если массив переполнен то обнуляем все и выходим.
                Serial.println("Error too loooong");
                resetData();
                break;
            }
            break;
        case 4:
            //разбираем дату,
            //проверяем на содержание
            label:

            for (uint8_t i = 1; i <= strlen(data) - 2; i++) {
                // if (name != 'M'){// проверяем если это не данныее eeprom
                if (isdigit(data[i]) != 1 && data[i] != '.' && data[i] != 'T' && data[i] != 'A' && data[i] != 'Z' && data[i] != ':') {
                    //если есть не числа или точка - разделитель
                    //printf("Error ABCdef= %c\n\r" ,data[i]);
                    Serial.print("Error ABCdef:");
                    Serial.println(data[i]);
                    resetData();
                    break;
                } else
                // }
            }

            data[strlen(data) - 1] = '\0'; //  удалим #  и поставим \0
            //printf("Data no $ = %s\n\r" ,data);
            paser(name, data);
            // тут можно отправить подтверждение но лучше это делать в пасере
            resetData();
            break;
        }
    }
    Это сброс данных если пришло что то не то что ожидали
    Код (C++):
    void resetData() {// сброс данных
        //Serial_print("Reset data all");
        mode = 1;
        byteData = 0;
        name = 0;
        memset(data, 0, sizeof(data));
    }
     

    usartData получаем в цикле
    Код (C++):
     while (swSer.available()) { //
        usartData = swSer.read();
        //Serial.println(usartData);
        resiveSwSer(usartData);

      }
    И наконец разбираем данные. Тут пример присвоения значения переменной и разбор пакета даты и времени с контрольной суммой.
    Код (C++):
    void paser(char name, char * data) {

        if (name == 'x') { //если имя x
          // имя х содержание data. Делаем все что нужно например
          temp = atoi(data);//перевели в число и присвоили переменной  
        }

        if (name == 'T') { //тут приходит дата и время, данные через : т.е 15:25:50:11:12:17:crc
        // c контрольной суммой последним байтом
            Serial.println("Yes Т");
            Serial.println(data);
            uint8_t CRC = 0; // контрольная сумма
            uint8_t sec,min,hour,day,month,year;
            uint8_t _buf[9];// буфер для данных
            uint8_t i = 0;// счетчтк
            char * pch = strtok(data, " ,.:-"); // варианты разделения на лексимы
            int z = 0;
            while (pch != NULL) { // пока есть лексемы  разбираем и присваиваем
                sscanf(pch, "%d",  &z);
                _buf[i] = (uint8_t)z;
                //Serial.print("Strok:");Serial.println(_buf[i]);
                pch = strtok(NULL, " ,.:-");
                i++;
                delay(10);
            }
            //  присваиваем значения
            hour = _buf[0];
            min = _buf[1];
            sec = _buf[2];
            day = _buf[3];
            month = _buf[4];
            year = _buf[5];
            CRC = _buf[6];
            //проверяем crc
            if ((hour + min + sec + day + month + year) != CRC) {// если сумма не сошлась
                Serial.println("CRC not correct");
                send_stm32('t', "002");// слезно попросим выслать нам данные еще раз
            } else {
                setTime(hour, min, sec, day, month, year);//функция установки времени тут ее нет
                Serial.println("Time set ok.");
               // тут стоит отправить подтверждение что все получили
            }

        }

    }
     
    Последнее редактирование: 14 дек 2017
  9. ostrov

    ostrov Гуру

    Тыкаю носом.
    Код (C++):
    byte msg[4] = { 0x03, 0x20, 0x00, 0x05 };
    Код (C++):

    static byte imsg[4];

    imsg[0] = imsg[1];
    imsg[1] = imsg[2];
    imsg[2] = imsg[3];
    imsg[3] = Serial1.read();
    if(imsg[0] == 0x03 && imsg[3] == 0x05)
                {...
    }
    Это называется пакет данных. Если есть желание разберетесь.
     
    MihaNN52 нравится это.
  10. MihaNN52

    MihaNN52 Нерд

    Если размер пакета можно держать фиксированным то почему бы и нет.
    Еще момент т.к в этом случае не откидываем мусор, вероятны ошибки при получении. Все должно совпасть и начало и конец и длина, может прилететь что то в начале или в конце и сдвинет все в нитуда. В результате пакет может и пришел целый но его уже не прочитать. В общем маловероятное использование в реальном проекте.
     
    Последнее редактирование: 14 дек 2017
  11. DIYMan

    DIYMan Guest

    Вы ошибаетесь: это самое вероятное использование в реальном серьёзном проекте. Именно так, и только так и делается: у пакета есть признаки начала и конца, контрольная сумма. И по этим признакам в потоке данных пакет и ищется, по итогу - неважно, когда слушающую сторону включили в розетку - она найдёт пакет, и ей неважно вот это:
     
    MihaNN52 нравится это.
  12. MihaNN52

    MihaNN52 Нерд

    Может быть и так, надо тестить.

    ************************
    Да вы правы работает нормально. Вопрос удобства если пакеты одной длины можно сделать то надо пользоваться.
     
    Последнее редактирование: 14 дек 2017
  13. ostrov

    ostrov Гуру

    Делайте пакеты с запасом по длине. Но обычно для одной задачи они одинаковые. Зачастую хватает пары значащих байтов, а то и одного.
     
  14. gfox

    gfox Нерд

    Всем спасибо за ответы.
    MihaNN52, я делаю джойстик для старых игр, использовать такие проверки с обратной связью - слишком долго. Нужно все сделать быстро, чтобы не чувствовать дискомфорта в игре. Поэтому использовал ваш первый скетч. С небольшой доработкой:
    Формирую пакет из 4 байт.
    Первый стартовый: 10100101 (взял от балды)
    Далее два байта - данные
    Четвертый стоповый: 10111101 (тоже взял от балды)
    Для контроля целостности данных использую следующее ухищрение - так как кнопок всего 12, остается еще 4 бита свободных, их использую для подсчета четности каждых 3 бит данных.
    Все вроде работает быстро и без ошибок.
    Вот код джойстика:
    Код (C++):
    #include <Button.h>
    #include <SoftwareSerial.h>
    byte ButtonState[4]={165,0,0,189};

    Button btnLeft = Button(17,PULLUP);
    Button btnLRight = Button(16,PULLUP);
    Button btnUp = Button(19,PULLUP);
    Button btnDown = Button(18,PULLUP);
    Button btnStart = Button(15,PULLUP);
    Button btnA = Button(9,PULLUP);
    Button btnB = Button(8,PULLUP);
    Button btnC = Button(7,PULLUP);
    Button btnZ = Button(6,PULLUP);
    Button btnY = Button(5,PULLUP);
    Button btnX = Button(4,PULLUP);
    Button btnMode = Button(3,PULLUP);

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

    void loop() {
       int k=0;
       if(btnLeft.isPressed()) {   bitWrite(ButtonState[1],0, 1); k++;   } else bitWrite(ButtonState[1],0, 0);
       if(btnLRight.isPressed()) {  bitWrite(ButtonState[1],1, 1);k++;   } else bitWrite(ButtonState[1],1, 0);
       if(btnUp.isPressed())   {   bitWrite(ButtonState[1],2, 1); k++;  } else bitWrite(ButtonState[1],2, 0);
     
       if (k&1) bitWrite(ButtonState[2],4, 1); else bitWrite(ButtonState[2],4, 0);
       k=0;
     
       if(btnDown.isPressed()) {   bitWrite(ButtonState[1],3, 1);  k++;  } else bitWrite(ButtonState[1],3, 0);
       if(btnStart.isPressed()) {  bitWrite(ButtonState[1],4, 1);  k++;  } else bitWrite(ButtonState[1],4, 0);
       if(btnA.isPressed()) {      bitWrite(ButtonState[1],5, 1);  k++;  } else bitWrite(ButtonState[1],5, 0);
     
      if (k&1) bitWrite(ButtonState[2],5, 1); else bitWrite(ButtonState[2],5, 0);
       k=0;
     
       if(btnB.isPressed()) {    bitWrite(ButtonState[1],6, 1); k++;   } else bitWrite(ButtonState[1],6, 0);
       if(btnC.isPressed()) {    bitWrite(ButtonState[1],7, 1);  k++;  } else bitWrite(ButtonState[1],7, 0);
       if(btnZ.isPressed()) {    bitWrite(ButtonState[2],0, 1); k++;  }  else bitWrite(ButtonState[2],0, 0);
     
       if (k&1) bitWrite(ButtonState[2],6, 1); else bitWrite(ButtonState[2],6, 0);
       k=0;
     
       if(btnY.isPressed()) {    bitWrite(ButtonState[2],1, 1); k++;  } else bitWrite(ButtonState[2],1, 0);
       if(btnX.isPressed())  {   bitWrite(ButtonState[2],2, 1);  k++;  } else bitWrite(ButtonState[2],2, 0);
       if(btnMode.isPressed()) {  bitWrite(ButtonState[2],3, 1);  k++; } else bitWrite(ButtonState[2],3, 0);
     
      if (k&1) bitWrite(ButtonState[2],7, 1); else bitWrite(ButtonState[2],7, 0);
       k=0;
     
     
       Serial.write(ButtonState,4);
       delay(20);
    }
    А вот код приемника:
    Код (C++):
    #include <Joystick.h>
    #include <SoftwareSerial.h>

    SoftwareSerial mySerial(8, 9); // RX, TX
    byte ButtonState[4]; // Массив кнопок byte
    bool ButtonStateBool[12];
    Joystick_ Joystick;

    enum  AUTOMATA_STATE { // Возможные состояния
        WAITING_START,    // ожидание начала пакета
        WAITING_DATA,     //    ожидание данных
        WAITING_END,    //    ожидание конца пакета
        WORK            // Нажимаются кнопки
    };



    void setup() {
        Joystick.begin();
        mySerial.begin(9600);
        mySerial.setTimeout(1);
         
    }



    void loop() {
     
        static AUTOMATA_STATE state = WAITING_START;
        int k;
        if(!mySerial.available())return;
         switch (state) {
           
             case WAITING_START: //ждем стартовый байт
                if(mySerial.read()!=165)return;
                state=WAITING_DATA;
             break;
           
             case WAITING_DATA: //читаем данные и проверяем каждые 3 бита на четность
               mySerial.readBytes(ButtonState,2);
             
               k=0;
               if(bitRead(ButtonState[0],0)==1) k++;
               if(bitRead(ButtonState[0],1)==1) k++;
               if(bitRead(ButtonState[0],2)==1) k++;
             
               if((k&1)!=bitRead(ButtonState[1],4)){state = WAITING_START;return;}
               k=0;
             
               if(bitRead(ButtonState[0],3)==1) k++;
               if(bitRead(ButtonState[0],4)==1) k++;
               if(bitRead(ButtonState[0],5)==1) k++;
             
               if((k&1)!=bitRead(ButtonState[1],5)){state = WAITING_START;return;}
               k=0;
             
               if(bitRead(ButtonState[0],6)==1) k++;
               if(bitRead(ButtonState[0],7)==1) k++;
               if(bitRead(ButtonState[1],0)==1) k++;
             
               if((k&1)!=bitRead(ButtonState[1],6)){state = WAITING_START;return;}
               k=0;
             
               if(bitRead(ButtonState[1],1)==1) k++;
               if(bitRead(ButtonState[1],2)==1) k++;
               if(bitRead(ButtonState[1],3)==1) k++;
             
               if((k&1)!=bitRead(ButtonState[1],7)){state = WAITING_START;return;}
               k=0;
           
             state=WAITING_END;
           
             break;
           
           
             case WAITING_END: //ждем стоповый байт
           
             if(mySerial.read()!=189){state = WAITING_START; return;}
                state=WORK;
             break;
           
             case WORK:  // стартовый и стоповый получены, данные проверены на четность => в работу!
           
                for(int i=0;i<8;i++){
                    if(bitRead(ButtonState[0],i)==1) ButtonStateBool[i]=true; else ButtonStateBool[i]=false;
                        }
               
                for(int i=8;i<12;i++){
                    if(bitRead(ButtonState[1],i-8)==1) ButtonStateBool[i]=true; else ButtonStateBool[i]=false;
                    }

                for (int i=0; i<12; i++) Joystick.setButton(i, ButtonStateBool[i]);
             state=WAITING_START;
             break;
           
         }        
    }
    Если есть замечания, буду только рад!
     
  15. MihaNN52

    MihaNN52 Нерд

    Вот у меня в проекте во время работы датчика холла по прерыванию который стоит на счетчике жидкости, надо отправлять данные и там не получится кидаться большими пакетами, между тем для настройки приходят большие пакеты, в итоге я пользуюсь таким вот switch case и размер меня не парит вообще. Но вариант который вы предложили хорош, обязательно буду им пользоваться в других проектах. если не критично по времени то можно сделать буфер 16 байт и спокойно работать.
    Еще чтоб не кидать постоянно большие пачки между МК я подключаю еепром по i2c на два контроллера а-ля общая помойка.
     
  16. MihaNN52

    MihaNN52 Нерд

    Мне кажется стоит попробовать вариант который парни предложили.
    А у вас джостик дает коды как клавиатура, типо писи пополам?
    11байт посылка, одна клавиша три посылки?
     
  17. gfox

    gfox Нерд

    Нет, джойстик старый от сеги, все кнопки заведены на пины (это видно из скетча), собственно каждый раз формируется пакет из 4 байт, как я описал выше. На данные - всего два байта, а далее записываем биты, если 1 - клавиша нажата, если 0 - не нажата. После обхода всех кнопок, отправляем их через Serial на bluetooth модуль. Далее другой беспроводной модуль их принимает и по Serial передает их другой ардуинке, которая в ОС видется как геймпад. Ну а дальше читаем пришедшие пакеты и "нажимаем" кнопки. Т.е. На все - 4 байта.
    Если честно, мне кажется это абсолютно тоже самое, только без контроля четности.
     
  18. MihaNN52

    MihaNN52 Нерд

    Не не не... если у тебя размер пакета постоянный то добавляй crc и юзай вариант парней. Размер кода будет меньше и функции выполнять будет. Сразу в код я вникнуть не смог как и ты судя по всему.
    Там в массиве при поступления символа он пишется в край массива и при поступления следующего байта двигается в начало(можно назвать кольцевым массивом который пишет с конца в начало) при этом когда дойдет до нуля будет проверка первого и последнего байта в массиве если они являются началом и концом пакета то делай дальше с ним что хочешь. От того что первый байт придет мусор ни что не значит, если пакет целый то он мусор вылетит из массива. В конце пакета если что то и придет то это уже не важно т.к пакет уже получили и разобрали. CRC нужен тебе однозначно т.к вероятность что что то изменится пока долетит большая.
     
  19. gfox

    gfox Нерд

    Да я понял, все равно не вижу отличая, кроме размера кода. Там пакет собирается с конца массива, тут пакет собирается с начала массива, причем там я не увидел проверки целостности данных. Вопрос в том, что быстрее работает, надо бы сравнить как-нибудь.
     
  20. MihaNN52

    MihaNN52 Нерд

    Ну проверку делай какую угодно.
    Вот я немного пописал проверь.
    Код (C++):
    #include <Button.h>
    #include <SoftwareSerial.h>
    uint8_t ButtonState[4];

    Button btnLeft = Button(17,PULLUP);
    Button btnLRight = Button(16,PULLUP);
    Button btnUp = Button(19,PULLUP);
    Button btnDown = Button(18,PULLUP);
    Button btnStart = Button(15,PULLUP);
    Button btnA = Button(9,PULLUP);
    Button btnB = Button(8,PULLUP);
    Button btnC = Button(7,PULLUP);
    Button btnZ = Button(6,PULLUP);
    Button btnY = Button(5,PULLUP);
    Button btnX = Button(4,PULLUP);
    Button btnMode = Button(3,PULLUP);

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

    void loop() {

       if(btnLeft.isPressed())    bitWrite(ButtonState[1],0, 1);    else bitWrite(ButtonState[1],0, 0);
       if(btnLRight.isPressed())  bitWrite(ButtonState[1],1, 1);    else bitWrite(ButtonState[1],1, 0);
       if(btnUp.isPressed())    bitWrite(ButtonState[1],2, 1);    else bitWrite(ButtonState[1],2, 0);
       if(btnDown.isPressed())    bitWrite(ButtonState[1],3, 1);    else bitWrite(ButtonState[1],3, 0);
       if(btnStart.isPressed())   bitWrite(ButtonState[1],4, 1);    else bitWrite(ButtonState[1],4, 0);
       if(btnA.isPressed())     bitWrite(ButtonState[1],5, 1);    else bitWrite(ButtonState[1],5, 0);
       if(btnB.isPressed())     bitWrite(ButtonState[1],6, 1);    else bitWrite(ButtonState[1],6, 0);
       if(btnC.isPressed())     bitWrite(ButtonState[1],7, 1);    else bitWrite(ButtonState[1],7, 0);
       if(btnZ.isPressed())     bitWrite(ButtonState[2],0, 1);    else bitWrite(ButtonState[2],0, 0);
       if(btnY.isPressed())     bitWrite(ButtonState[2],1, 1);    else bitWrite(ButtonState[2],1, 0);
       if(btnX.isPressed())     bitWrite(ButtonState[2],2, 1);    else bitWrite(ButtonState[2],2, 0);
       if(btnMode.isPressed())    bitWrite(ButtonState[2],3, 1);    else bitWrite(ButtonState[2],3, 0);
       send_bt();// выведем отправку отдельно... и все что выше тоже надо отдельно, негоже луп захламлять.
       delay(20);
    }

    void send_bt(){
        uint16_t CRC = 0;//контрольная сумма
        ButtonState[0] = '&';// начало пакета
        ButtonState[4] = '#';// конец пакета
        CRC = ButtonState[1] + ButtonState[2];//счиаием контрольную сумму она 16 битная, она такая
        ButtonState[3] = (uint8_t)CRC;// нам не нужна по этому оставим только младший байт.
        Serial.write(ButtonState,sizeof(ButtonState);
    }


    //Получение
    // опустим сетапы и т.д
    void loop() {

    if(Serial.available())
            {
                static uint8_t imsg[4];
                static uint16_t CRC = 0;
                imsg[0] = imsg[1];
                imsg[1] = imsg[2];
                imsg[2] = imsg[3];
                imsg[3] = imsg[4]
                imsg[4] = Serial.read();
                if(imsg[0] == '&' && imsg[4] == '#'){// если пакет пришел
                    CRC = imsg[1] + imsg[2];//считаем сумму
                    if((uint8_t)CRC == imsg[3]){//если сумма верна
                        x =    imsg[1]; // делаем с данными все что надо
                        y = imsg[2];
                    }
                }

    }
    видишь на сколько компактней в твоем случае можно сделать
    Можно идентифицировать пакет по символам начала и конца, допустим если &# это одна переменная. Если $# тодругая и т.д т.е
    Код (C++):
                if(imsg[0] == '&' && imsg[4] == '#'){// если пакет пришел
                    CRC = imsg[1] + imsg[2];//считаем сумму
                    if((uint8_t)CRC == imsg[3]){//если сумма верна
                        x =    imsg[1]; // делаем с данными все что надо
                        y = imsg[2];
                    }
                }
                if(imsg[0] == '$' && imsg[4] == '#'){// если пакет другой
                    CRC = imsg[1] + imsg[2];//считаем сумму
                    if((uint8_t)CRC == imsg[3]){//если сумма верна
                        z =    imsg[1]; // делаем с данными все что надо
                        c =    imsg[2];
                    }
                }
    Делай как удобно, не ставь рамки. Можешь добавить еще один байт для идентификации пакета...
     
    Последнее редактирование: 14 дек 2017