[SOLVED]Byte processing , serial communication

Hello,

i’m working on a GUI project for arduino and i want to send 7 bytes to arduino. The array should look like 16115061 where 16 is the SOP and 61 is EOP. The 1 is the parameter type(1 would be the speed,2 would be the proportional value, etc.) and the 150 would be the pwm value.

For example if i wanted the speed of a motor to be 150(pwm) the packet would lool like 16115061, if i wanted to send a value of 10,54 for the proportional value the packet should look like 16210,5461.

I made a numericUpDown control which should ,by pressing enter, send a packet to the arduino

private void numericSetpoint_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13) 
            {
                if (serialPort1.IsOpen) 
                {
                    byte[] send = new byte[7];
                    float setpoint = (float)numericSetpoint.Value;
                    byte[] x = BitConverter.GetBytes(setpoint);
                    send[0] = Convert.ToByte(16);
                    send[1] = Convert.ToByte(1);
                    send[2] = x[0];
                    send[3] = x[1];
                    send[4] = x[2];
                    send[5] = x[3];
                    send[6] = Convert.ToByte(61);
                    //Array.Reverse(x);
                    serialPort1.Write(send, 0, 1);
                    PrintByteArray(send);
                }

PrintByteArray() is a helper function which shows the array in the console. If I enter 40 it prints new byte { 16, 1, 0, 0, 72, 66, 61, }, for 255 it prints new byte { 16, 1, 0, 0, 127, 67, 61, }.

The receiving part on the arduino looks,so far, like this:

int motorPin = 9;
byte ByteArray[7];
float Speed;

union
{
  byte b[4];
  float kfloat;
}p;

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

void loop()
{
  if(Serial.available() == 7)
  {
  for(int i = 0; i<7; i++)
  {
    ByteArray[i] = Serial.read();
  }
  }
  //convert to float
  p.b[0] = ByteArray[2];
  p.b[1] = ByteArray[3];
  p.b[2] = ByteArray[4];
  p.b[3] = ByteArray[5];
  
  Speed = p.kfloat;
 
  analogWrite(motorPin,Speed);
  
     
}

The problem is i don’t know how to convert those 4 bytes to float and pass them to analogwrite. The motor doesn’t start. How should i proceed ? What am i doing wrong ?

The second parameter in analogWrite is a byte not a float.

try:

union {
   float     fNumber;       // number as floating point
   uint8_t  bytes[4];         // number as byte array
} floatConversion;

bytes is a 4 byte array on top of float. You can fill either one to get the other.

Perhaps the examples in serial input basics would help - simple reliable way to receive data.

...R

Robin2:
Perhaps the examples in serial input basics would help - simple reliable way to receive data.

...R

The union solution didnt really work so ,after reading the serial input basics, i will try the approach from the guide with chars. Sending part is almost done so i'll report back when i hit a wall again (probably when i start parsing :slight_smile: ). Thank you!

I made the changes and now i can send a packet which looks like <,S,1,0,0,>. The arduino reads it and responds with S100. Life is good.

But, when i send a value like 1,54 or 12,45 from my other control i get no response. The sending part is ok, it sends <,P,1,2,5,4,>. My first thought was that the additional comma was the problem so i changed it to a dot and now the packet looks like <,P,1,2,.,4,5,> but still no response. Why isn’t the dot recived like a normal char? How could i fix this?

The receiving part on the arduino is the same as the one from Serial Input Basics. Will post it if necessary.

ManFish:
Will post it if necessary.

Not just necessary, ESSENTIAL

...R

Some times it is easier to figure out the easiest data decoding setup, then send the data in that format. Below is how I send/decode data to control servos.

//zoomkat 11-22-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added 
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 

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

  //myservoa.writeMicroseconds(1500); //set initial servo position if desired

  myservoa.attach(6);  //the pin for the servoa control
  myservob.attach(7);  //the pin for the servob control
  myservoc.attach(8);  //the pin for the servoc control
  myservod.attach(9);  //the pin for the servod control 
  Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}

void loop() {

  //expect single strings like 700a, or 1500c, or 2000d,
  //or like 30c, or 90a, or 180d,
  //or combined like 30c,180b,70a,120d,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
          if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.write(n);
          if(readString.indexOf('b') >0) myservob.write(n);
          if(readString.indexOf('c') >0) myservoc.write(n);
          if(readString.indexOf('d') >0) myservod.write(n);
        }
         readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Found the problem. serialPort.Write somehow ended under multi-line comments and wasn't even sending to arduino. Works now, life is good again :slight_smile: Parsing time :slight_smile:

I’m stuck on the parsing part. I can’t split the packet. Setpoint is always zero and param_simbol shows nothing.

I’ve modified my code so the packet looks like . The “-” was added as a delimeter so i could split the string in two parts using strtok().

primChars is from my getData() function and works as intended. If i enter it prints S-123-.

char param_simbol[1] = {0};
int setpoint = 0;
void parseData() {

      
  char * strtokIndx; 
  
  strtokIndx = strtok(primChars,"-");      
  strcpy(param_simbol, strtokIndx); 
  
  strtokIndx = strtok(NULL, "-"); 
  setpoint = atoi(strtokIndx);    
   
}

My getData().

const byte numChars = 15;
char primChars [numChars];
boolean newData = false;

void getData()
{
  static boolean get = false;
  static byte index = 0;
  char start = '<';
  char end = '>';
  char paket;
  
  if(Serial.available() > 0)
  {
    paket = Serial.read();
    
    if(get == true)
    {
      if(paket != end)
      {
        primChars[index] = paket;
        index++;
        if(index >= numChars)
        {
          index = numChars - 1;
        }
      }
      else
      {
        primChars[index] = '\0'; 
        get = false;
        index = 0;
        newData = true;
      }
    }
    else if (paket == start)
    {
      get = true;
    }
  }
}
char param_simbol[1] = {0};
int setpoint = 0;
void parseData() {

      
  char * strtokIndx; 
  
  strtokIndx = strtok(primChars,"-");      
  strcpy(param_simbol, strtokIndx); 
  
  strtokIndx = strtok(NULL, "-"); 
  setpoint = atoi(strtokIndx);    
   
}

strtokIndex is a terrible name for a variable that is not an index at all, but a pointer to a char.

Why do you declare param_simbol as a single character array? That is effectively just a char variable.

Are you aware that the strcpy to param_simbol will also write 0 to setpoint, when it writes the null to terminate the string? And, of course, if the user types ", it’ll clobber a lot more than that. Maybe harmless now, but at some point that will cause you a really hard-to-find bug…

The extra ‘-’ characters are really unnecessary. Once you have the string, use strtok to get whatever is between the ‘<’ and ‘>’. Then check to make sure it is properly formatted as a single alphabetic character, followed by some number of digits. Only then should you parse it to extract the information. Otherwise, you’re eventually going to try to parse invalid data, which will not end well. Once you’re satisfied you have a properly formatted message, verify the first character is an ‘S’, then you know characters 1-n are a number you can parse with atoi or whatever. No need to throw in extra characters - they just create extra work, and new ways for the user to create invalid messages that will cause you problems.

Regards,
Ray L.

RayLivingston:
And, of course, if the user types ", it’ll clobber a lot more than that. Maybe harmless now, but at some point that will cause you a really hard-to-find bug…

The user types from a gui, he can only change the numeric value which has a fixed lenght (if the user enters 5 it will be converted to 005);

RayLivingston:
The extra ‘-’ characters are really unnecessary. Once you have the string, use strtok to get whatever is between the ‘<’ and ‘>’. Then check to make sure it is properly formatted as a single alphabetic character, followed by some number of digits. Only then should you parse it to extract the information. Otherwise, you’re eventually going to try to parse invalid data, which will not end well. Once you’re satisfied you have a properly formatted message, verify the first character is an ‘S’, then you know characters 1-n are a number you can parse with atoi or whatever.

I modified the code as you’ve suggested and it’s working now.
The code:

char param_simbol[32] = {0};

void parseData() {
    
  char * token; 
  
  token = strtok(primChars,",");  
  strcpy(param_simbol, token); 
  if(param_simbol[0] == 'S')
  {
      char num[3];
      num[0] = param_simbol[1];
      num[1] = param_simbol[2];
      num[2] = param_simbol[3];
      setpoint = atoi(broj);
      //Serial.print("S:");
      //Serial.println(setpoint);
   }else if(param_simbol[0] == 'P')
    {
      char num[5];
      num[0] = param_simbol[1];
      num[1] = param_simbol[2];
      num[2] = param_simbol[3];
      num[3] = param_simbol[4];
      num[4] = param_simbol[5];
      proportional = atof(num);
      Serial.print("P:");
      Serial.println(proportional);
    }
}

Thank you! If you have any suggestions on improving the code, please do :slight_smile: