Последовательная запись Windows API в Arduino работает один раз, но при перезаписи того же сообщения отправляет поврежденные данные. - PullRequest
0 голосов
/ 05 декабря 2018

Я использую стороннюю библиотеку SerialPort на основе WinAPI (SerialPort) в программе на C ++ для управления светодиодной полосой (iLED и цвет пикселя), но оказывается, что она работает только для одной команды - если я отправлюта же команда во второй раз, цвет этого пикселя принимает другой случайный цвет, и по какой-то причине первый светодиод тоже включается со случайным цветом.

Вот ссылка на видео о том, что происходит, когда запускается приведенный ниже упрощенный код, т. Е. Когда пикселям 3, 5 и 7 снова и снова выдается команда на красный, зеленый и синий цвета соответственно.https://drive.google.com/file/d/1RRAshnhPz96YGJtmETy3vuGi25QjxqJz/view?usp=drivesdk

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

Что происходит?

SerialPort.h (источник: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)

#ifndef SERIALPORT_H
#define SERIALPORT_H

#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

class SerialPort
{
private:
    HANDLE handler;
    bool connected;
    COMSTAT status;
    DWORD errors;
public:
    SerialPort(char const *portName, unsigned long baudrate);
    ~SerialPort();

    int readSerialPort(char *buffer, unsigned int buf_size);
    bool writeSerialPort(char *buffer, unsigned int buf_size);
    bool isConnected();
};

#endif // SERIALPORT_H

SerialPort.cpp (источник: https://blog.manash.me/serial-communication-with-an-arduino-using-c-on-windows-d08710186498)

#include "serialport.h"

SerialPort::SerialPort(char const *portName, unsigned long baudrate)
{
    this->connected = false;

    this->handler = CreateFileA(static_cast<LPCSTR>(portName),
                                GENERIC_READ | GENERIC_WRITE,
                                0,
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);
    if (this->handler == INVALID_HANDLE_VALUE){
        if (GetLastError() == ERROR_FILE_NOT_FOUND){
            printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
        }
    else
        {
            printf("ERROR!!!");
        }
    }
    else {
        DCB dcbSerialParameters = {0};

        if (!GetCommState(this->handler, &dcbSerialParameters)) {
            printf("failed to get current serial parameters");
        }
        else {
            dcbSerialParameters.BaudRate = baudrate;
            dcbSerialParameters.ByteSize = 8;
            dcbSerialParameters.StopBits = ONESTOPBIT;
            dcbSerialParameters.Parity = NOPARITY;
            dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;

            if (!SetCommState(handler, &dcbSerialParameters))
            {
                printf("ALERT: could not set Serial port parameters\n");
            }
            else {
                this->connected = true;
                PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
                Sleep(ARDUINO_WAIT_TIME);
            }
        }
    }
}

SerialPort::~SerialPort()
{
    if (this->connected){
        this->connected = false;
        CloseHandle(this->handler);
    }
}

int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
    DWORD bytesRead;
    unsigned int toRead;

    ClearCommError(this->handler, &this->errors, &this->status);

    if (this->status.cbInQue > 0){
        if (this->status.cbInQue > buf_size){
            toRead = buf_size;
        }
        else toRead = this->status.cbInQue;
    }

    if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;

    return 0;
}

bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
    DWORD bytesSend;

    if (!WriteFile(this->handler, (void*) buffer, buf_size, &bytesSend, 0)){
        ClearCommError(this->handler, &this->errors, &this->status);
        return false;
    }
    else return true;
}

bool SerialPort::isConnected()
{
    return this->connected;
}

main.cpp

#include <iostream>
#include "serialport.h"

using namespace std;

int main()
{
    SerialPort serial("COM3", 115200);

    while(1) {
        unsigned char buffer[] = {255,3, 254, 0, 0};
        serial.writeSerialPort((char*)buffer, 4);
        unsigned char buffer2[] = {255,5, 0, 254, 0};
        serial.writeSerialPort((char*)buffer2, 4);
        unsigned char buffer3[] = {255,7, 0, 0, 254};
        serial.writeSerialPort((char*)buffer3, 4);
    }
    return 0;
}

Прошивка Arduino

#include <FastLED.h>

#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6

CRGB leds[N_LEDS] = {0};

void setup() {
  FastLED.addLeds<WS2811, DATA_PIN, BRG>(leds, N_LEDS); //I don't know why the colours are BRG on this strip
  FastLED.show();
  Serial.begin(BAUDRATE);
}

void loop() { 
  //Check for a quadruplet of bytes (iLED R G B) led by start byte
  if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {    
    //Read message
    unsigned char buf[N_BYTES_MSG] = {0};
    for(unsigned char i=0; i < N_BYTES_MSG; i++) {
      buf[i] = Serial.read();
    }

    if(buf[0] < N_LEDS) { //Valid ID
      leds[buf[0]] = CRGB(buf[1],buf[2],buf[3]); //Update LED state in internal representation
      FastLED.show(); //Refresh LEDs based on internal representation
    }
  }
}

Обратите внимание, что светодиодная лента, кажется, работает нормально сама по себе, так как я успешно проверил движение с постоянной скоростью на один пиксель.Самый простой путь отладки, который у меня есть, так как мне еще не удалось заставить readSerialPort () работать, и COM-порт перегружен программой, поэтому я не могу понять его (можем ли мы как-то это понюхать?).

1 Ответ

0 голосов
/ 05 декабря 2018

Я тестирую serial.writeSerialPort на рабочем столе Windows 10 с Arduino Uno.Это работает для меня.

Ниже приведен код, который я использовал:

В Windows:

#include <iostream>
#include "serialport.h"

using namespace std;

int main()
{
    SerialPort serial("COM4", 115200);

    while (1) {
        unsigned char buffer[] = { 255,3, 254, 0, 0 };
        serial.writeSerialPort((char*)buffer, 5);


        unsigned char buffer2[] = { 255,5, 0, 254, 0 };
        serial.writeSerialPort((char*)buffer2, 5);

        unsigned char buffer3[] = { 255,7, 0, 0, 254 };
        serial.writeSerialPort((char*)buffer3, 5);
    }
    return 0;
} 

В Arduino:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

#define BAUDRATE 115200
#define N_BYTES_MSG 4
#define N_LEDS 120
#define DATA_PIN 6

void setup() {
  Serial.begin(BAUDRATE);
  mySerial.begin(BAUDRATE);
  mySerial.println("Start reading.");
  delay(5000);
}

void loop() { 
  //Check for a quadruplet of bytes (iLED R G B) led by start byte
  if(Serial.available() >= N_BYTES_MSG+1 && Serial.read() == 255) {    
    //Read message
    unsigned char buf[N_BYTES_MSG] = {0};
    for(unsigned char i=0; i < N_BYTES_MSG; i++) {
      buf[i] = Serial.read();
    }

    for(unsigned char i=0; i < N_BYTES_MSG; i++) {
      mySerial.print(buf[i]);
      mySerial.print(",");
    }

      mySerial.print("\r\n");

      //Serial.write("Read complete!");
  }
}

Iнапечатать полученные данные на Arduino:

enter image description here

Я заметил, что напечатанные данные испортились, когда Windows отправляет быстро, как вы это делали в то время(1) без задержки.Поэтому попробуйте добавить задержку между двумя записями, чтобы увидеть, работает ли она.

Добавьте также отметьте проблему, как указал @paddy.

enter image description here

Мне пока не удалось заставить работать readSerialPort ()

Set unsigned int toRead = buf_size; в SerialPort.cpp работает для меня.Используйте следующий код для чтения:

    unsigned char readBuffer[20] = {};
    serial.readSerialPort((char*)readBuffer, 20);
    printf((char*)readBuffer);
    printf("\n");

Чтение из результата Arduino:

enter image description here

...