Pages: [1]   Go Down
Author Topic: Serial Comm between Arduino Mega and Matlab  (Read 1516 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all, i was trying to send some float values from matlab representing voltages from 0 to 10V. They way of transmitting them is to multiply them by 10000 to get them integers. Then send it to the serial port as strings and conver it into integers in arduino. Hence the conversion is made to double and then the original valu sent from matlab is set to the analog ports. This is to send a DC control voltage values generated from matlab and set the analog output ports with these DC control voltages.

The ports used are 8. From 6 to 13. If there are more incoming voltages values, the programs starts again setting the port 6 and goes ahead.

This is the code in MATLAB:

Code:
%Creates a serial connection
serialPort=serial('COM4','BaudRate',9600);
%Change the Terminator property of the serial port to make it faster
%set(serialPort,'Terminator','CR');
%Informs about errors
warning('off','MATLAB:serial:fscanf:unsuccessfulRead');
%Opens the serial port
fopen(serialPort);

volt=[10,5,0,3,0,8,0,1];

%Voltages are mapped from 0-10 to 0-100000
for i=1:length(volt)
    voltmapped(i)=map2(volt(i),0,10,0,100000);
end

display('Press any button to continue.');
pause

for i=1:length(voltmapped)
    fprintf(serialPort,'%d',voltmapped(i));
end

fclose(serialPort);

% This function converts one value within the range [fromLow,fromHigh]
% to the corresponding value within the range [toLow,toHigh].
%
% INPUT PARAMETERS:
% val: Value which it is going to be converted.
% fromLow: Minimum value of the origin range.
% fromHigh: Maximum value of the origin range.
% toLow: Minimum value of the destination range.
% toHigh: Maximum value of the destination range.
%
% OUTPUT PARAMETERS:
% num: Converted value of val within the range [toLow,toHigh]
%
function [num]=map2(val,fromLow,fromHigh,toLow,toHigh)

aux1=val/(fromHigh-fromLow);
aux2=aux1*(toHigh-toLow);
num=floor(aux2);

end

Arduino:

Code:
float data_rec;
float data_conv1,data_conv2;
float volt;
int portNum;


void setup(){
  portNum=6;
  Serial.begin(9600);//A serial communication is defined
  for(int i=6;i<14;i++){
    analogWrite(i,0);
  }

}

void loop(){
  //If there is data to read at the serial port
  if(Serial.available() > 0){
    if(portNum>13){
      portNum=6;  //All ports have a voltage, then start again to set
                  //values from port 2
    }
    data_rec=Serial.parseInt();  //Converts the string received into an integer
                                 //it is also converted into a double by implicit conversion
    data_conv1=(data_rec)/10000;  //Voltage value sent from Matlab through the serial port
    volt=convert(data_conv1,0,10,0,255);  //Voltage value converted, to set the voltage value
                                          //into the analog port
    analogWrite(portNum,volt);  //Sets the output port with the desired voltage value
    portNum++;
  }
  delay(100);
}
 /* Function responsible for expressing the voltage values within the interval [0,255] */
float convert(double val,double fromLow,double fromHigh, double toLow, double toHigh){
  double aux1,aux2;
  aux1=val/(fromHigh-fromLow);
  aux2=aux1*(toHigh-toLow);
  return aux2;
}

But it does not work. Only works if I write line by line in matlab. It does not work with scripts or loops like:

Code:
for i=1:length(voltmapped)
    fprintf(serialPort,'%d',voltmapped(i));
end

I get a solution but is very slow and inefficient. It consist of doing the same but the arduino sends the values received from matlab. but i cant use it in scripts and i have problems using the code in guide.
The solutions are:

Matlab:The serial port is has been already declared. It is better obviate the parameter scan angle. From this value the matlab obtain the voltage values required to be sent.
Code:
function main(ScanAngle,serialPort)

clc
f=2.4*10^9;
c=3*10^8;
lambda=c/f;

N=8;

d=0.055;
phase_sf=calculate_phasesf(lambda,d,ScanAngle);
disp(['phase shift = ' num2str(phase_sf)]);
phases=calculate_phases2(N,phase_sf);
if(ScanAngle<0)
    phases=toggle(phases);
end

disp(['phases = ' num2str(phases)]);
for i=1:length(phases)
    voltages(i)=get_voltage(phases(i));
end
disp(['voltages = ' num2str(voltages)]);
for i=1:length(voltages)
    voltages_mapped(i)=map2(voltages(i),0,10,0,100000);
end
for i=1:length(voltages_mapped)
    fprintf(serialPort,'%d',voltages_mapped(i));
    a(i)=fscanf(serialPort,'%d');
end
disp(['a = ' num2str(a)]);
Aduino:
Code:
float data_rec;
float data_conv1,data_conv2;
float volt;
int portNum;


void setup(){
  portNum=6;
  Serial.begin(9600);//A serial communication is defined
  for(int i=6;i<14;i++){
    analogWrite(i,0);
  }
  /* Definition of analog output ports*/
//  pinMode(2,OUTPUT);
//  pinMode(3,OUTPUT);
//  pinMode(4,OUTPUT);
//  pinMode(5,OUTPUT);
//  pinMode(6,OUTPUT);
//  pinMode(7,OUTPUT);
//  pinMode(8,OUTPUT);
//  pinMode(9,OUTPUT);
   
}

void loop(){
  //If there is data to read at the serial port
  if(Serial.available() > 0){
    if(portNum>13){
      portNum=6;  //All ports have a voltage, then start again to set
                  //values from port 2
    }
    data_rec=Serial.parseInt();  //Converts the string received into an integer
                                 //it is also converted into a double by implicit conversion
    data_conv1=(data_rec)/10000;  //Voltage value sent from Matlab through the serial port
    volt=convert(data_conv1,0,10,0,255);  //Voltage value converted, to set the voltage value
                                          //into the analog port
    analogWrite(portNum,volt);  //Sets the output port with the desired voltage value
    Serial.println(volt);
    portNum++;
  }
  delay(100);
}
 /* Function responsible for expressing the voltage values within the interval [0,255] */
float convert(double val,double fromLow,double fromHigh, double toLow, double toHigh){
  double aux1,aux2;
  aux1=val/(fromHigh-fromLow);
  aux2=aux1*(toHigh-toLow);
  return aux2;
}

This salution works, but at some cases, like in gui, or loops does not work. The error in matlab is
subscription assignment mismatch with a(i).

This is for a research , please if anyone knows the answer please i would be glad if i could get some help.
Thank you
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your MatLab code seems to be sending a continuous stream of characters, like "123452345612345...". How is the Arduino, in the call to parseInt() supposed to know where to stop reading? Try adding a space in the format string, after the %d.

Why are you storing the output from parseInt() in a float? Wasting memory isn't a good idea.

Why is volt a float? The analogWrite() function expects an int.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi thank you for answering. Here is the explanation:

I have so send float values to the arduino. Hence, I only reach to do that in this way:

If I have to send the value 3.4512 in matlab I multiply this value by 10000 to get 34512. I send this value as a string. Then in arduino I convert it in integer by using Serial.parseInt(). Then I get 34512, and i divide this value by 10000 to get again 3.4512 and finally I convert this value from 0 to 5 to from 0 to 255.
That is what I am trying to do. If you know a more efficient way to send numbers by the serial port, it should be great to learn it.
The point is that it works, but just in any cases. I know that is not a good solution because I have a lot of errors.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you send the string of data as "1223417265434647514426262..." where does one value end and the next begin?

If you send the string of data as "1223 417 265 434 64 7514 426 262 ..." where does one value end and the next begin?

Much easier to get correct results in the second case, isn't it?

Something to consider, though. Instead of sending the actual voltage multiplied by 10000, and having the Arduino divide and compute the PWM setting, have the PC do the math. It's much faster at it than the Arduino. Send just an int value in the range 0 to 255 to the Arduino.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you PaulS. One more question. Should i send the values from matlab :

1.
Code:
fprintf(serialPort,'%d ',voltage);

2.
Code:
fprintf(serialPort,'%d\n',voltage);

What would be better?
« Last Edit: June 21, 2013, 01:27:04 pm by gabri187 » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I tried both lines but it does not work. How could I detect a " " or "," reading from serial port in arduino?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have tried this other way to send voltages from 0 to 5, sending integers from 0 to 255.

matlab:

Code:
%Creates a serial connection
serialPort=serial('COM4','BaudRate',9600);
%Informs about errors
warning('off','MATLAB:serial:fscanf:unsuccessfulRead');
%Opens the serial port
fopen(serialPort);

option=input('Introduce the voltage value between 0 and 5 volts or esc to exit: ','s');
while strcmp(option,'esc')==0
    voltage=str2double(option);
    while (voltage<0)||(voltage>5)||isnan(voltage)&& (strcmp(option,'esc')==0)
        disp('Value non-valid, introduce a value from 0 to 5');
        disp('Press any key to continue.');
        pause
        clc
        option=input('Introduce the voltage value between 0 and 5 volts or esc to exit: ','s');
        voltage=str2double(option);
    end
    if strcmp(option,'esc')==0
        volt_mapped=map2(voltage,0,5,0,255);
        disp(['voltage = ' num2str(volt_mapped)]);
        fwrite(serialPort,volt_mapped,'int8');
        disp('Press any key to continue');
        pause
        clc
        option=input('Introduce the voltage value between 0 and 5 volts or esc to exit: ','s');
    end
end
%Closes the serial port
fclose(serialPort);
clear serialPort
clear all

arduino:
Code:
int incomingByte = 0; // para el byte leido
int portNum;

void setup() {
Serial.begin(9600); // abre el puerto serie a 9600 bps
        portNum=6;
        analogWrite(portNum,0);
}

void loop() {

// envia datos solamente cuando recibe datos
if (Serial.available() > 0) {
// lee el byte entrante:
incomingByte = Serial.read();
                analogWrite(portNum,incomingByte);
}
}

But when I introduce a value of 5 in matlab the voltage at the port in arduino is 2.56. Why? When i introduce 1 or 2 the output corresponds with these values.
« Last Edit: June 21, 2013, 03:12:49 pm by gabri187 » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
But when I introduce a value of 5 in matlab the voltage at the port in arduino is 2.56. Why? When i introduce 1 or 2 the output corresponds with these values.

Code:
while strcmp(option,'esc')==0
Which ONE key are you pressing to get the ONE character 'esc'? There is NOTHING on my keyboard capable of producing the ONE character 'esc'.

Why should the ONE character 'esc' match a string (a NULL terminated array of chars)?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for answering again PaulS. I got it. The problem was that in Matlab i was seding this:

Code:
fwrite(serialPort,volt_mapped,'int8');

With 8 bits with sign, the MSB is the sign and the other 7 bits are for the magnitude. Therefore the magnitude can be from 0 to 2^7-1, 127. And 127 in the arduino is 2.55V.

Then, I changed this line by:

Code:
fwrite(serialPort,volt_mapped,'uint8');

That means, unsigned integers. 8 bits for magnitude. Numbers from 0 to 2^8-1, 255.

Regarding the matlab code, is just type esc when they ask for the scan angle or esc.
Logged

Odisha, India
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I wrote the following program to transfer a number to ARDUINO by giving the desired input from the MATLAB command window. But I need to transfer a number say "2" directly to ARDUINO without any input from the MATLAB command window. Please help me out.

avg= input ('ENTER ANY VALUE BETWEEN 1 TO 8');
th=5;
if(avg>th)
d=msgbox('OVERSHOOT THERSHOLD');
delete(d)
% ----------------------------------
answer=1;
arduino=serial('COM10','BaudRate',9600);
fopen(a);
 
while (answer)
fprintf(a,'%s',char(answer));
answer=input('Enter led value 1 or 2 (1=ON, 2=OFF, 0=EXIT PROGRAM): ');
end
fclose(arduino);
%
end[/b]
Logged

BISWAJEET CHAMPATY
Doctoral Fellow
Medical Electronics Lab
Department of Biotechnology & Medical Engineering
National Institute of Technolog

Pages: [1]   Go Up
Jump to: