MATLAB Answers

Arduino serial read bug

22 views (last 30 days)
Jonathan
Jonathan on 8 Oct 2015
Commented: Kiki on 29 Mar 2016
What I want to do is to sample an analog voltage from an Arduino pin (0 to 5 V, read as integer values from 0 to 1024), and transmit these samples to Matlab to be plotted. The code below is for the Arduino, it sets up the serial port and then in the loop it reads the voltage from pin 1, sends it to the serial port using "Serial.println", pauses and then keeps repeating this. The sample rate is set by the pause length.
int analogPin = 1; // Analog read pin. This is the e.g. photodiode input
int result;
int sample = 100; // Sampling period (ms)
int Baud = 9600; // Serial baud rate
void setup() {
pinMode(analogPin,INPUT);
Serial.begin(Baud); // Setup serial port
delay(1000); // 1 sec delay
}
void loop() {
result = analogRead(analogPin); // read the analog pin
Serial.println(result);
delay (sample);
}
The following Matlab code configures and opens the serial port, and reads the serial port 100 times and saves these sample values to "y". The results are then plotted.
clear all
clc
baud = 9600;
arduino=serial('COM3','BaudRate',baud);
fopen(arduino);
x=linspace(1,100);
y=zeros(1,100);
for i=1:length(x)
y(i) = fscanf(arduino,'%d');
end
fclose(arduino);
disp('making plot..')
plot(x,y);
When I have a relatively long delay between sampling the pin (say, 100 ms), everything works perfectly. I switch the input to pin 1 between the 3.3 V and 5 V pins on the Arduino, and the correct values are plotted in Matlab. The problem I encounter is when I decrease the sampling rate (to, say 1 ms). I get the following error:
Warning: Unsuccessful read: Matching failure in format.. In an assignment A(I) = B, the number of elements in B and I must be the same. Error in Testexample (line 12) y(i) = fscanf(arduino,'%d');
I guess I'm having a problem with reading the serial data, either Matlab is reading in more than one value, or there's no value to read, and the error occurs because the array y(i) will only accept one entry per column? The data looks fine on the Arduino serial monitor, it looks the same there regardless of the sampling rate.
I don't really know how to troubleshoot this further, so any pointers would be appreciated. Thanks!
  2 Comments
Jonathan
Jonathan on 9 Oct 2015
Hi walter,
It's serial over USB.

Sign in to comment.

Answers (3)

Madhu Govindarajan
Madhu Govindarajan on 8 Oct 2015
If you are using one of the latest releases of MATLAB, try using the support package for the same - http://www.mathworks.com/hardware-support/arduino-matlab.html

Jonathan
Jonathan on 9 Oct 2015
Hello again,
I found something that works for me:
I changed the line in my Matlab script:
From
[Select]
y(i) = fscanf(arduino,'%d');
To
y(i) = fread(arduino,1,'uint8');
On my Arduino code, I changed the "void loop" so that the AnalogRead value (which is usually a value from 0 to 1023) is now mapped to a value between 0 and 255. The idea behind that is to map the AnalogRead value to a single byte - I copied the idea from: here
New void loop code:
void loop() {
result = analogRead(analogPin); // read the analog pin
outputValue = map(result, 0, 1023, 0, 255);
Serial.write(outputValue);
delay (sample);
}
It's now working (at least, working as well as I need it to work), but of course if anyone else has some more elegant solutions or improvements I'd be happy to hear them :)
  3 Comments
Kiki
Kiki on 29 Mar 2016
Hi
So if I use print() in my arduino code, I should use %f in my matlab code as follows to read it, right?
y(i) = fscanf(arduino,'%f');
Thank you.

Sign in to comment.


Walter Roberson
Walter Roberson on 9 Oct 2015
USB is not a dedicated channel. USB is a system whee a master device goes around polling the attached devices asking each one in turn if they have any data to send. If they do and it is a relatively small amount of data they might reply with the data, but if it is more data they they are just to reply Yes and the master will get back to them when there is time for them to send the data.
Because of this behaviour, when data is ready to send, it cannot just be sent: the device has to wait for the master to tell it to go ahead.
In documents I read a few years ago but am having difficulty locating now, I found that furthermore, for serial-port emulating devices, USB is designed to wait until either a complete packet is full or else that no data has been received for a time before it will release the packet. This is good for efficient use of shared bandwidth but it is not good for latency. If your bytes are available more slowly than the wait for data then you don't really notice much (provided that your data is not too time sensitive), but after a point you get stuck: before the end of the wait period you get another byte and since the packet isn't full yet the timer restarts.... only to be interrupted by the next packet. And so on, until the packet is full. This can end up with longer latency than if the data rate was slower. But, hey, it is efficient use of the bandwidth and that is what is important, right?
So... you might not get data for a while. And you might time-out if you are not set to handle the worst-case of the timer being reset just as it was due to expire, over and over again. And even if that does not happen, batches of bytes arrive rather than single bytes and your code might not expect that...
Serial over USB is... Bovine Growth Hormone... for data acquisition unless both sides know how to trigger immediate data sending (which requires talking to the master device, and which MATLAB does not provide an interface for.)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!