Send two-byte data from Arduino to PC via USB

I want to use a potentiometer to send a throttle and brake signal to my PC using the USB serial data port. One byte (0 to 255) is throttle and one byte (0 to 255) is brake.

On the Arduino end, I send the two bytes using Serial.write(WriteBuffer, 2). On the PC end I use ReadFile(hSerial, &ReadBuff, 2, &BytesRead, NULL) to get the data. I take the two bytes read by ReadFile and process them.

I had a few problems getting the communications to work. But now they do work well, except for one problem. About half the time, the order of the two bytes is reversed.

It's no problem is data is occasionally lost. But this reversal of bytes is a real problem. I cannot figure out how it is happening.

If it will help, I can post either or both of the C++ (PC end) or Arduino code.

If there is any better way to do this, I'm all ears. I've looked over the forum, but found no solution to sending two bytes like this.

Any ideas greatly appreciated.

If it will help, I can post either or both of the C++ (PC end) or Arduino code.

Sure, without it nobody has a clue as to what you have done. The arduino code is probably most appropriate for this forum. Generally, different types of data that are basically the same need some type of identifier attached, like t255 and b255 to identify which value is being sent.

The code for both the Arduino and the PC are below.

Your point about putting an identifier on the value (like T255 for throttle) is a good one.

But that does not solve the problem of the bytes getting mixed up in order. That's the tricky thing about this. I cannot figure out why the two bytes are getting switched in their order, but only some of the time.

Here's the Arduino code:

int potPin = 2; // select the input pin for the potentiometer

float Temp;
int potValue;
unsigned char outputPotValue, Throttle, Brake, WriteBuffer[2];

void setup()
{
  // start serial port at 19200 bits per second
  Serial.begin(19200);

  // clear the serial port buffer
  Serial.flush();
}

void loop() 
{
  Serial.flush();
  potValue = analogRead(potPin);
//  Serial.print("PotValue is: ");
//  printNum(potValue);
  if (potValue > 1023) {
    potValue = 1023;
  }
  if ((potValue <= 1023) && (potValue >= 894)) {          // between 894 and 1023 are brake command
    Throttle = 0;
    Temp = (float(potValue) - 894.0) * 255.0 / (1023.0 - 894.0);
    if (Temp > 255.0) {
      Temp = 255.0;
    }
    if (Temp < 0.0) {
      Temp = 0.0;
    }
    Brake = int(Temp);  // scale brake command from 0 (none) to 255 (full)
  } 
  if ((potValue < 894) && (potValue > 846)) {
    Throttle = 0;
    Brake = 0;
  }
  if ((potValue <= 846) && (potValue >= 467)) {
    Temp = (846.0 - potValue) * 255.0 / (846.0 - 467.0);
    if (Temp > 255.0) {
      Temp = 255.0;
    }
    if (Temp < 0.0) {
      Temp = 0.0;
    }
    Throttle = int(Temp);
    Brake = 0;
  }
  if (potValue < 467) {
    Throttle = 255;
    Brake = 0;
  }
 WriteBuffer[0] = Throttle;
 WriteBuffer[1] = Brake;
 Serial.write(WriteBuffer, 2);

  delayMicroseconds(500);
}

Here's the relevant Windows code on the PC:

int DriverControlUnit()
{
      HANDLE hSerial;                                                            // set up COM7 as serial port for writing to Arduino

      hSerial = CreateFile(_T("COM7"),
                                    GENERIC_READ | GENERIC_WRITE,
                                    0,
                                    0,
                                    OPEN_EXISTING,
                                    FILE_ATTRIBUTE_NORMAL,
                                    0);

      if(hSerial==INVALID_HANDLE_VALUE){
            if(GetLastError()==ERROR_FILE_NOT_FOUND){
                  cout<<"serial port does not exist.\n";
            }
      cout<<"some other error occurred.\n";
      }
      DCB dcbSerialParams = {0};

      dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

      if (!GetCommState(hSerial, &dcbSerialParams)) {
            cout<<"error getting state.\n";
      }

      dcbSerialParams.BaudRate = CBR_19200;
      dcbSerialParams.ByteSize = 8;
      dcbSerialParams.StopBits = ONESTOPBIT;
      dcbSerialParams.Parity = NOPARITY;

      if(!SetCommState(hSerial, &dcbSerialParams)){
            cout<<"error setting serial port state.\n";
      }
      COMMTIMEOUTS timeouts={0};
      timeouts.ReadIntervalTimeout=50;
      timeouts.ReadTotalTimeoutConstant=50;
      timeouts.ReadTotalTimeoutMultiplier=10;
      timeouts.WriteTotalTimeoutConstant=50;
      timeouts.WriteTotalTimeoutMultiplier=10;

      if(!SetCommTimeouts(hSerial, &timeouts)){
            cout<<"error setting timeouts.\n";
      }
      DWORD queueNum = 2;
      SetupComm(hSerial, queueNum, queueNum);

      unsigned char ReadBuff[3];
      DWORD BytesRead;
      int CommandCount = 0;

      unsigned char Stee, Throt, Brak;

      SetCommBreak(hSerial);
      PurgeComm(hSerial, PURGE_RXCLEAR);
      ClearCommBreak(hSerial);
      ReadFile(hSerial, &ReadBuff, 2, &BytesRead, NULL);

      Throt = ReadBuff[0];
      Brak = ReadBuff[1];
      CommandString[CommandCount++] = 'T';
      CommandString[CommandCount++] = Throt;
      CommandString[CommandCount++] = 'B';
      CommandString[CommandCount++] = Brak;
      CommandString[CommandCount++] = 'S';
      CommandString[CommandCount++] = 128;
      CommandString[CommandCount++] = NULL;
      CommandString[CommandCount++] = NULL;
      CloseHandle(hSerial);
      return 0;
}

Transmission of serial data follows the United States Postal Service model.

They guaranteed to attempt to deliver the mail. They do not guarantee to deliver it.

The order of the bytes in the packet is not being swapped. One of the bytes is being lost, so you are using the 2nd value from the 1st pair, and the 1st value from the next pair as a packet.

You really should have start and end of packet markers, so that you can see when a packet is not complete. If you were sending ..., instead of xyxyxyx..., you could see when you received ... or <xy... or xy>... instead of xyyxy...

A complete packet can be see two consist of 4 bytes - a start marker, two bytes, and an end marker. If the start and end markers do not have two bytes between them, discard the packet. If a start marker arrives before an end marker, the previous packet was incomplete. Discard it. If data arrives after an end marker, before a start marker, the packet is incomplete. Ignore it.