I am trying to establish a serial link in Matlab with an Arduino board. Reading data from the board goes well. However, writing data to the board takes about a second for each block of information I send.
The code I am running to write data:
s = serial(comprt,'BaudRate',9600,'DataBits',8);
fopen(s);
fprintf(s, '%c', 'c');
fprintf(s, '%u %u %u %u \n', [A B C D]);
pause(1);
fprintf(s, '%c', 'a');
pause(1);
A, B, C, D are 8-bit numbers anywhere from 0 - 255, 'c' and 'a' are characters commands that do stuff on the Arduino board and tap into the firmware on the board.
If I do not include the pause(1) commands, so when I do not stop Matlab from executing the next command for at least a second, the serial information doesn't get through.
Can anyone help me to speed up writing stuff to the serial port? I checked with the Arduino editor, and when I enter equivalent commands via their interface, everything is fine. So the delays are not related to the Arduino board or device drivers, it's definitely on the Matlab side of things.
I have used MATLAB quite a bit with Arduino. Ex: see here (http://www.instructables.com/id/Arduino-to-MATLAB-GUI-Live-Data-Acquisition-Plotti/) [see link in instructable for my GitHub Arduino and MATLAB code] and here (https://www.youtube.com/watch?v=wY3oh2GIfCI).
I believe your problem IS on your Arduino side of things.
Add this line to your setup() function:
Serial.setTimeout(100); //this will make the Arduino wait a max of only 100ms per incoming set of serial data, before moving on
Read here: http://arduino.cc/en/Serial/SetTimeout
Then, decrease the timeout progressively until you get bad results, to minimize wasted waiting time. Then increase it a bit again to ensure it's set high enough.
This is a quick and dirty method. Basically, your Arduino is set to wait 1 sec by default before continuing on, once incoming data is read in.
A better method is to use a terminating character. Ex: have the MATLAB send a terminating Newline character, and use the Arduino function Serial.readBytesUntil() to read up to the terminating character. Then, the serial input timeout will never be reached, and you can set the timeout to be long again (Ex: 1 sec), without actually having to wait for that delay.
Related
I have a problem about receiving 16-bit data in MATLAB.I cannot receive 16-bit data at high speed through UART in MATLAB software.
Using stm32, I divide a 16-bit data belonging to a sensor into two 8-bit data and send it to MATLAB through UART. And in MATLAB software, I combine these two 8-bit data together and 16-bit sensor data is obtained. In MATLAB software, at first a valid data is sent to stm32. until this data is not sent to stm32, stm32 does not send data, This is so that MATLAB gets the data order right, but it only happens once.
With the test I did, I realized that the process of separating and combining the data is done correctly.
But when I want to receive sensor data, only the first data is stored in each loop (2530) and for example if I receive 1000 data, 1000 of the first data are stored (2530).
I received the sent data of the stm32 using a serial plotter software on the computer and the data is sent to the computer correctly.
When I put a delay of 20 milliseconds in the stm32, the problem is solved and I think that the code I wrote for MATLAB is not optimal and maybe there is a better code for this task.
And the delay of 20 milliseconds is too much for my work . I need to send the data to MATLAB as fast as possible and the data will be ploted live in MATLAB.
When I delete the plot command from MATLAB, the performance of the program improves, but the problem is not solved
What should I do to fix this problem?
clear
close all;
load('fi4.mat');
clc
serialportObj = serialport("COM3",115200);
i=2
tim=0;
data=0;
w=0;
data_valid=0;
validate=11;
write(serialportObj, validate, "uint8");
while(1)
tic
data=read(serialportObj,2,"uint8");
res = double(typecast([uint8(data(2)), uint8(data(1))], 'uint16'))
%FilterdSignal=filter(Hd, res);
sig(i)=res;
w(i)=sig(i)+(0.95*w(i-1));
ff(i)=w(i)-w(i-1);
if i <=300
figure(2)
plot (sig);
else
figure(2)
plot(sig(end-300:end));
end
i=i+1;
c=toc;
tim=c+tim;
end
I am running a code on arduino which works fine in arduinoide, I want to get those values in simulink for real time using serial connection.
I am burnig a program in arduino and want to access both send and receive function of serial monitor, on simulink. I want these to plot graphs in real time and run PID algorithm using simulink.
But for some odd reason, simulink values are either not updating(in external mode) or fluctuating some odd values(in normal mode). Any help.
If you are doing a communication between the Arduino and Simulink there might be some problems in your connection. I'm assuming you are using the Serial Send and Serial Receive block to do the communication.
I did a complete tutorial how to connect both platforms in my Github page.
By your description I can think of this problems:
Simulink is not updating?
If your Simulink is not updating probably because it is waiting Arduino to send some serial data, but is not receiving anything. Some possible causes of this problem might be:
Wrong Serial baud rate
Wrong data type (i.e. If you are sending Arduino float you have to receive a single in Simulink.)
Wrong data size
Different step time (Remember to use the same step time in Simulink and Arduino)
Simulink receiving odd values?
If Simulink is updating but showing odd values, the communication between both might be damaged.
Desynchronization of the communication - Try to use a Header and a Terminator in the Serial Send and Serial Receive block and remember to set this in your Arduino code.
Different step time - Make sure both application are sending and receiving at same rate.
Verify what you are sending - You can check what exactly you are sending to the serial with a scope, remember that in the Serial Send block the input signal must be a byte. If you are using a single or double remember to cast it to byte with a Byte Pack block.
I'm having an issue which is partially Matlab- and partially general programming-related, I'm hoping that somebody can help me brainstorm for solutions.
I have an external microcontroller that generates a large stream of binary data (~40kb) every 400ms and sends it via UART to a PC running Matlab scripts. The data is not encoded in hexa or dec characters, but true binary (hence, there's no terminator defined as all 256 values are possible, valid combinations of data). Baudrate is set at 1024000. In short, it takes roughly 375ms for a whole stream of data to be sent, with 25ms of dead time in between streams
In Matlab, the serial port is configured correctly (also 1024000, 8x bits, 1x stop bit, no parity, no hardware flow control, etc.). I am able to readout the data I'm sending via the microcontroller correctly (i.e. there's no corruption of data), but I'm not being able to synchronize the serial readout on Matlab. My script is as follows:
function data_show = GetDATA
if ~isempty(instrfind)
fclose(instrfind);
end
DATA_TOTAL_SIZE = 38400;
DATA_buffer = uint8(zeros(DATA_TOTAL_SIZE,1));
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])';
f_data_in = false;
f_data_out = true;
serialport = serial('COM11','BaudRate',1024000,'DataBits',8,'FlowControl','none','Parity','none','StopBits',1,...
'BytesAvailableFcnCount',DATA_TOTAL_SIZE,'BytesAvailableFcnMode','byte','InputBufferSize',DATA_TOTAL_SIZE * 2,...
'BytesAvailableFcn',#GetPortData);
fopen(serialport);
while (get(serialport,'BytesAvailable') ~= 0) % Skip first packet which might be incomplete
fread(serialport,DATA_TOTAL_SIZE,'uint8');
end
f_data_out = true;
while (1)
if (f_data_in)
DATA_buffer = fread(serialport,DATA_TOTAL_SIZE,'uint8');
DATA_show = reshape(DATA_buffer(1:2:end)',[160,120])'; %Reshape array as matrix
DATAsc(DATA_show);
disp('DATA');
end
pause(0.01);
end
fclose(serialport);
delete(serialport);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function GetPortData (obj,~)
if f_data_out
f_data_in = true;
end
end
end
The problem I see is that what I end up reading is always the correct size, but belongs to multiple streams, because I haven't found a way to tell Matlab that these 25ms of no data should be used to synchronize (i.e. data from before and after that blank period should belong to different streams).
Does anyone have any suggestions for this?
Thanks a lot!
For completeness, I would like to post the current implementation I have fixing this issue, which is probably not a suitable solution in all cases but might be useful in some.
The approach I took consists in moving into a bi-directional communication protocol, in which Matlab initiates the streaming by sending a very short command as a trigger (e.g. single, non-printable character). Given the high baudrate it does not add significant delay due to processing in the microcontroller's side.
The microcontroller, upon reception of this trigger, proceeds to transmit only one full package (as opposed to continuously streaming package at a 5Hz rate). By forcing Matlab to pickup a serial package of the known length right after issuing the trigger, it ensures that only one package and without synchronization issues is received.
Then it becomes just a matter of encapsulating the Matlab script in a routine with a 5Hz tick given by a timer, in which the sequence is repeated (send trigger, retrieve package, do whatever processing, and repeat).
Advantages of this:
It solves the synchronization problems
Disadvantages of this:
Having Matlab running on a timer tick does not ensure perfect periodicity, and hence the triggers might not always be sent at exactly 5Hz. If triggers are sent at "inconvenient" times for the microcontroller, packages might need to be skipped in order to avoid that a package is updated in memory while it is still being transmitted (since transmission takes a significant part of the 200ms time slot)
From experience, performance can vary a lot depending on what the PC running Matlab is doing. For example, it works fine when the PC is left on its own to do the acquisition, but if another program is used (e.g. Chrome), Matlab begins to lag and that results in delays in transmission of triggers.
As mentioned above, it's not a complete answer, but it is an approach that might be sufficient in some situations. If someone has a more efficient option, please fell free to share!
I'm using MATLAB to read from a serial port. A colleague of mine is doing the same thing with LabVIEW. He told me that I needed a pause in my code to allow the system time to write the data back. However, I've read that "pause(n)" halts execution for n seconds.
I'm not totally sure what it means by "halts execution." Does is stop the serial port from reading and writing, therefore nullifying my purpose?
Should I use another function, or should pause(n) be okay for my purposes?
pause(n) basically makes your program sleep for n seconds. As such, when you invoke pause, it makes your program wait there for n seconds, then proceeds to the next line of code.
For example:
a = rand(3,3);
pause(2); % // Pause for 2 seconds
b = rand(4,4);
This creates a random 3 x 3 matrix stored in a, then the program waits at the second line for two seconds. The program does nothing and sleeps. After, a 4 x 4 random matrix is created.
To answer your question, this does not stop the serial port. All you're doing is allowing the data enough time to be written to the serial port before you decide to write more to the port. Similarly, you're allowing the serial port enough time to buffer enough data to the port so you can read the right amount of bytes in one read.
I'd like to send multiple signals (4 inputs and outputs and 7 outputs) from my Laptop to a microcontroller. I'm thinking of using a USB to serial converter and multiplexing the data through the port. I'll need to write codes both in the laptop end and in the microcontroller to multiplex the data.
Eg:
Tx of microcontroller:
1.Temperature sensor ADC output->Laptop
2.Voltage sensor to laptop
3.Current Sensor to Laptop
4.Photodiode current to Laptop
So I need to write a program in the microcontroller to send the data in this order. How can I accomplish this? I was thinking of an infinite loop which sends the data with time delays in between.
At the Rx pin of Microcontroller,
Seven bit sequences. Each bit sequence will be used to set the duty cycle of a PWM generated by the microcontroller.
I also need the same multiplexing or demultiplexing arrangement in the matlab end. Here too, I'm thinking of allotting some virtual 'channels' at different instants of time. What kind of algorithm would I need?
In case you always send all the inputs/outputs at the same rate, you could simply pack them into 'packets', which always start with one or more bytes with a fixed value that form a 'packet header'. The only risk is that one of the bytes of the sensor data might have the same value as the start-byte at the moment you try to start receiving bytes and you are not yet synchronized. You can reduce this risk by making the header longer, or by choosing a start-byte that is illegal output for the sensors (typically OxFF or so).
The sending loop on the microcontroller is really easy (pseudocode):
while True:
measure_sensors()
serial.send(START_BYTE)
serial.send(temperature)
serial.send(voltage)
serial.send(current)
serial.send(photodiode)
end while
The receiving loop is a bit more tricky, since it needs to synchronize first:
while True:
data = serial.receive()
if data != START_BYTE:
print 'not synced'
continue #restart at top of while
end if
temperature = serial.receive()
voltage = serial.receive()
current = serial.receive()
photodiode = serial.receive()
do_stuff_with_measurements()
end while
This same scheme can be used for communication in both directions.