Передача массива uint8_t в Arduino с помощью gcc и termios

В настоящее время я работаю над проектом, который требует последовательной связи между скомпилированной программой g++ и Arduino ATMega2560 с использованием termios в качестве средства последовательной связи. Программа g++ отправляет массив из 5 значений uint8_t, которые анализируются Arduino. Затем Arduino использует эти байты для включения определенного светодиода на полосе.

Вот код программы на C++, скомпилированный с помощью g++:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <termios.h>
    #include <inttypes.h>
    #include <fcntl.h>
    #include <fstream>
    #include <iostream>

    #define BAUD B115200
    #define ARDUINO "/dev/ttyACM0"

    using namespace std;

    struct termios old_io, new_io;
    int arduinoFD, c, res;

    int main (int argc, char* argv[]) {

   arduinoFD = open(ARDUINO, O_RDWR | O_NOCTTY);
   if (arduinoFD < 0){perror(ARDUINO); exit(EXIT_FAILURE);}

   new_io.c_cflag = BAUD | CRTSCTS | CS8 | CLOCAL | CREAD;
   new_io.c_iflag = IGNPAR | ICRNL;
   new_io.c_oflag = 0;
   new_io.c_lflag = ICANON;
   cfsetospeed(&new_io, BAUD);
   cfsetispeed(&new_io, BAUD);
   tcflush(arduinoFD, TCOFLUSH);

       //Byte that tells the arduino to start parsing.
   uint8_t* STARTCMD = (uint8_t*)malloc(1);
   STARTCMD[0]=0x0A;
   write(arduinoFD, STARTCMD, 1);

       //Enable debugging.
   STARTCMD[0]=(uint8_t)'d';
   write(arduinoFD, STARTCMD, 1);

       while(true){
          //Allocate array for LED info.
          uint8_t* testWrite = (uint8_t*)malloc(5);
          for(uint8_t i = 0; i < 240; i++){
             //Loop through all LEDs, setting their (R,G,B) to (220,220,220).
             testWrite[0] = 0x73; // 's'
     testWrite[1] = 0xc8; // Red - 220
     testWrite[2] = 0xc8; // Green - 220
     testWrite[3] = 0xc8; // Blue - 220
     testWrite[4] = (uint8_t)i; // Led Address - i

             //Print out the values to stdout.
     char* outPrint = (char*)malloc(17);
     sprintf(outPrint, "R%03dG%03dB%03dL%03d\n",
         testWrite[1], testWrite[2], testWrite[3], testWrite[4]);
     fwrite(outPrint,17,1,stdout);

             //Send the values from the buffer to the arduino, then sleep for 24 milliseconds.
     write(arduinoFD, testWrite, 4);
     usleep(24*1000);
      }
          //Deallocate the buffer and reallocate a space to send the update value.
      free(testWrite);
      testWrite = (uint8_t*)malloc(1);
      testWrite[0] = (uint8_t)'z';
      write(arduinoFD, testWrite, 1);

          //Deallocate and sleep for 550ms.
      free(testWrite);
      usleep(550*1000);     
       }
    }

А вот и скетч Arduino: #include

    Adafruit_NeoPixel strip = Adafruit_NeoPixel(240, 6, NEO_GRB + NEO_KHZ800);

    int pinRangeStart = 0;
    int pinRangeStop = 0;
    char inByte;
    uint8_t* colorBytes;
    boolean debug = false;

    void setup(){
      Serial.begin(115200);
      while(!Serial);

      Serial.print("Desktop LED Ambience\n");

      strip.begin();
      strip.show();
    }

    void loop(){  
      while(Serial.available() > 0){
        while(Serial.read() != 0x0A);
        Serial.print("Start Byte read!");

        while(true){
          //inByte is the first of 5 bytes to be read. The other four are (R,G,B,L) where
         //R = Red
         //G = Green
         //B = Blue
         //L = LED Number.
          inByte = Serial.read();
          switch(inByte){
            case('r'): {
              for(int i = 0 ; i < strip.numPixels(); i++)
                strip.setPixelColor(i, strip.Color(0,0,0));
              strip.show();
              Serial.println("Reset!");
              Serial.flush();
              break;
            }
            case('d'): {
              Serial.print("Debugging ");
              debug =! debug;
              if(!debug)  
                Serial.println("DISABLED");
              else
                Serial.println("ENABLED");
              break;
            }
            case('s'): {
              colorBytes = new uint8_t[4];
              colorBytes[0] = Serial.read(); // Red
              colorBytes[1] = Serial.read(); // Green
              colorBytes[2] = Serial.read(); // Blue
              colorBytes[3] = Serial.read(); // LED Number
              if(debug){
                Serial.println("Set lights without updating.");
                Serial.print("R=");
                Serial.println(colorBytes[0]);
                Serial.print("G=");
                Serial.println(colorBytes[1]);
                Serial.print("B=");
                Serial.println(colorBytes[2]);
                Serial.print("LED=");
                Serial.println(colorBytes[3]);
              }
              uint32_t newColor = strip.Color(colorBytes[0], colorBytes[1], colorBytes[2]);
              strip.setPixelColor(colorBytes[3], newColor);
              break;
            }
            case('z'): {
              strip.show();
              Serial.println("Updating Lights");
              break;
            }
          }
        }
      }  
    }

Вывод программы g++ можно представить в виде набора байтов, сгруппированных вместе с помощью {} для обозначения отдельных вызовов write().

    {0x0a}
    {0x64}
    {0x73 0xc8 0xc8 0xc8 0x00}
    {0x73 0xc8 0xc8 0xc8 0x01}
    {...}
    {0x73 0xc8 0xc8 0xc8 0xee}
    {0x73 0xc8 0xc8 0xc8 0xef}
    {0x7a}

Arduino отлично считывает первые два байта и правильно интерпретирует первый байт каждой группы из 5, отправляемой как 0x73 (также известный как «s»), но следующие байты в группе не считываются должным образом и интерпретируются. Arduino как значения 255.

Ожидаемый результат:

    Desktop LED Ambience
    Start Byte read!
    Debugging ENABLED
    Set lights without updating.
    R=200
    G=200
    B=200
    LED=0
    Set lights without updating.
    R=200
    G=200
    B=200
    LED=1
    ...
    Set lights without updating.
    R=200
    G=200
    B=200
    LED=238
    Set lights without updating.
    R=200
    G=200
    B=200
    LED=239
    Updating Lights

И это фактический вывод:

    Desktop LED Ambience
    Start Byte read!
    Debugging ENABLED
    Set lights without updating.
    R=255
    G=255
    B=255
    LED=255
    Set lights without updating.
    R=255
    G=255
    B=255
    LED=255
    ...
    Set lights without updating.
    R=255
    G=255
    B=255
    LED=255
    Set lights without updating.
    R=255
    G=255
    B=255
    LED=255
    Updating Lights

Может ли кто-нибудь узнать, что вызывает это в моем коде? Сначала я подумал, что шина перегружена, поэтому я попытался уменьшить скорость передачи данных до 19600, но это ничего не исправило.

Редактировать: Еще одна проблема заключается в том, что после четырех или пяти итераций настройки светодиодов зеленый канал случайным образом выпадает, поэтому все, что получает Arduino, - это еще более искаженное {'s', 255, 0, 255, 255}.


person MSalmo    schedule 19.10.2013    source источник


Ответы (1)


Ваш внутренний цикл while(true) не оценивает Serial.available. Таким образом, он пытается читать, даже если данные недоступны. Это когда он получает 255 вместо ожидаемых значений. Есть много способов это исправить. Одним из способов было бы заблокировать, пока данные не будут доступны.

...
while (true) {
    while (!Serial.available()) {}
...
person Udo Klein    schedule 19.10.2013
comment
Ваш ответ дал мне совет, в котором я нуждался. Кажется, что Arduino слишком быстро считывает программу на C++, поэтому Arduino принимает 0xff вместо того, чтобы ждать фактического ввода. Оттуда я изменил: colorBytes[0] = Serial.read() //red colorBytes[1] = Serial.read() //green colorBytes[2] = Serial.read() //blue colorBytes[3] = Serial.read() //LED address на for(int i = 0 ; i < 4; i++){ while(!Serial.available); colorBytes[i] = Serial.read(); } Что дает мне желаемые байты для чтения. - person MSalmo; 19.10.2013