0
$\begingroup$

I have an array (2x4) in Matlab which may contains integer values as well as values in decimals. For example: [1.1, 23, 1.56, 5.29; 2.14, 2.39, 67, 4.001]. I have to send these values to arduino using matlab. How to do so? I know how to send integer values to arduino from matlab but it is not working with decimal values.

Matlab Code to send integer values is below:

portName = 'COM5';
s = serial(portName,'BaudRate',9600,'Terminator','LF');
s.timeout = 1;
try 
    try
        fopen(s);
    catch
        delete(s);
        fopen(s);
    end
catch
    disp('Unable to open the port ');
end

angle = [1.3,2];
    dataOut = angle;
    dataOut_ = char(dataOut);
    fprintf(s,'%d',dataOut_);

Arduino code is given below:

int d1,d2;
char d[4];

    void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(13, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
if(Serial.available()>0)
{
  for(int i=0; i<3;i++)
  {
    d[i]= Serial.read();
  }
  d1 = d[0]-'0';
  if (d1 == 1.3)
  {
    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(2000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
  }
}
}
$\endgroup$
  • $\begingroup$ That's the code you're using to send integers - what code are you using to send decimal values? What output are you seeing when you attempt to send the decimal values? $\endgroup$ – Chuck Apr 18 '17 at 13:08
  • $\begingroup$ I wrote this to send all type of values but it send only integers values only. I'm new and learning arduino so what I do is I wrote arduino code like if I send 1, pin at 13 will be high for 1 second and if 2 then for 4 seconds and if input value is 1.5 then it should be high for say 2 seconds. But when send 1 or 2 it works fine but for 1.5 value it continuously at high. So I unable to tell you what value I'm getting for decimal values. $\endgroup$ – Naseeb Gill Apr 18 '17 at 13:41
2
$\begingroup$

What I've found out that using char([float]) converts decimal numbers into the integer numbers in MATLAB 2016a.

>> x = [1.1, 23, 1.56, 5.29; 2.14, 2.39, 67, 4.001]

x =

    1.1000   23.0000    1.5600    5.2900
    2.1400    2.3900   67.0000    4.0010

>> xch = char(x)

xch =


C

>> fprintf('%f\n',xch)
1.000000
2.000000
23.000000
2.000000
1.000000
67.000000
5.000000
4.000000

So you can send the values as

fprintf('%f\n',x)

and at the arduino end you can receive the data as

float d1,d2;
float d[4];

    void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}

void loop() {
if(Serial.available()>0)
{
  for(int i=0; i<3;i++)
  {
    d[i]= Serial.parseFloat();
  }
  d1 = d[0];
  if (d1 == 1.3)
  {
    digitalWrite(13, HIGH);
  delay(2000);
  digitalWrite(13, LOW);
  delay(1000);
  }
}
}
$\endgroup$
3
$\begingroup$

You haven't posted any of the code you're using to receive the values, but I'm guessing the problem is with your casting and decoding of the dataOut value.

Consider the following (direct from my copy of Matlab):

dataOut = 1.3;
dataOut_ = char(dataOut);
fprintf('%d\n',dataOut_);

1 

This is because your dataOut_ variable is not a string or character array of values! If you were to instead try fprintf('%d\n',dataOut); (note the lack of trailing underscore), you get:

fprintf('%d\n',dataOut);

1.300000e+00

If you want to convert 1.3 to a character array (what I'm assuming you actually want to do, but again you never posted the receiving code so I don't know really what you're anticipating receiving), then you should use either the long-hand form:

dataOut_ = char(string(dataOut));

or the built-in function that does the same thing:

dataOut_ = num2str(dataOut);

Both of those return the same:

dataOut_ = char(string(dataOut));
fprintf('%d\n',dataOut_);
49
46
51

These are bytes that correspond to Unicode characters. You can translate those bytes back to characters by casting them to ascii/unicode on the receiving end, BUT then you also need to put those characters into a character array and then convert that character array back to a number.

Matlab has a built in function that could do that, but you're (presumably) not using Matlab on the receiving end:

>> dataIn = native2unicode([49,46,51])

dataIn =

1.3

But again, that 1.3 is a character array. You need to cast it to a number, usually with double(dataIn).


There is an easier solution.

Multiply the number by 100. Round using the Matlab command round, pass that value. On the receiving end, divide by 100. Now you have timing control to a hundredth of a second. A uint8 could do up to 2.55 seconds, a uint16 could do up to 655.35 seconds.

Keep in mind that you'll need to send multiple bytes anyways if you're planning on converting a floating point number to a character array, so using a uint16 shouldn't be a problem as far as your data packets go.

dataOut = 1.3;
dataOut_ = round(dataOut*100);
fprintf('%d\n',uint16(dataOut_));
130

:EDIT:

OP posted some more code, but it doesn't look like everything, but I can comment from here:

  1. I don't see where you multiply by 100 in your transmit code. Is that code current?
  2. In your Arduino code, you use Serial.read(); but you don't ever cast the output. This means that each byte of d is a number from 0-255. If you want to use it as a character array, you (probably) need to cast it to a string/char before you make the comparison check.
  3. In your Arduino code, you're just checking if d is the floating point number 1.3. You haven't done anything (like char(1.3) or string(1.3)) to cast 1.3 to a character array so you can do byte-by-byte comparisons.

You have a number of options here, but I'm not sure what you want to do:

  1. Cast the floating point number to a byte array, send the resulting byte array, and then recast the byte array back to floating point. In Matlab, use fprintf('%d\n',typecast(1.3,'uint8')).
  2. Cast the floating point number to a character (Unicode) byte array, transmit the byte array, and then convert the byte array back to characters, then convert the characters back to a number. In Matlab, use fprintf('%d\n',char(string(1.3))).
  3. Multiply from fractional seconds to tenths or hundredths or milliseconds, etc. Round/truncate the number, transmit the number, then convert back to fractional seconds. In Matlab, use fprintf('%d\n',uint16(round(1000*1.3))).

Matlab inherently uses 64 bit (double) numbers for everything, so keep that in mind when you try to reassemble the bytes on the Arduino end. If you want to transmit the byte array for a 32 bit number, use the single() command, as in fprintf('%d\n',typecast(single(1.3),'uint8')). This produces a four byte array, as opposed to the eight byte array produced when you run the same command without the single command.

$\endgroup$
  • $\begingroup$ Thanks for replay. I thought arduino code in this question is not so important so I skipped it initially. But now I pasted in my question you can see this. Hope this will help to solve this problem. I tried by multiplying by 100 but matlab shows error as "The third input argument must be a string." What is wrong? $\endgroup$ – Naseeb Gill Apr 18 '17 at 18:55
  • $\begingroup$ @NaseebGill - Please see my edit. $\endgroup$ – Chuck Apr 18 '17 at 19:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.