S-function for reading com-port

I'm trying to read data from a serial port in simulink. The serial configuration blocks and query instrument are not working properly for the device I try to read over COM port.
In matlab, I can easily read out data from the device using fopen() and fscanf().
Using the matlab function block in simulink, I get the same result in simulink. Problem is: it needs to open and close the serial connection every step, slowing down my system.
I'm trying to write level1 s-function to overcome this problem. Right now I have:
function [sys,x0,str,ts] = test1(t,x,u,flag)
NMEA = serial('COM2', 'BaudRate', 4800);
switch flag
case 0
[sys,x0,str,ts] = mdlInitializeSizes(NMEA);
case 3
sys = mdlOutputs(t,x,u, NMEA);
case { 1, 2, 4, 9 }
sys = [];
otherwise
error(['Unhandled flag = ',num2str(flag)]);
end;
function [sys,x0,str,ts] = mdlInitializeSizes(NMEA)
sizes = simsizes;
sizes.NumContStates= 0;
sizes.NumDiscStates= 0;
sizes.NumOutputs= 1;
sizes.NumInputs= 1;
sizes.DirFeedthrough=1;
sizes.NumSampleTimes=1;
sys = simsizes(sizes);
x0 = [];
str = [];
ts = [-1 0];
fopen(NMEA);
function sys = mdlOutputs(t,x,u,NMEA)
sys = fscanf(NMEA);
Giving me the error that the port needs to be opened at flag=3 (output). But I don't want to open the com2 every step as this will get really slow. How to solve this? I just want to open the connection once and constantly read from it (in simulink).

Answers (4)

If following Walter's suggestion, you will need:
persistent NMEA;
if isempty(NMEA) %true only the first time
NMEA = serial('COM2', 'BaudRate', 4800);
end
However, persistent variables don't work well if multiple instances of your S-function exist in a model. So we recommend using DWork vectors to store such instance-specific persistent data in S-functions.
Also, remember to use fclose in the mdlTerminate method (flag=9).

5 Comments

I've been looking into the Dwork vectors, but I can't find any examples written in M S-file, only in C... Could you please give me a direction how to declare a Dwork vector for the serial NMEA variable?
Type "sfcndemo_sfundsc2" at the MATLAB prompt to see an example model. Basically, you need to set: "sizes.NumDiscStates = 1;" And return "x0 = NMEA;" from mdlInitializeSizes. In mdlOutputs, it is available as "x".
OK thanks! So far I have:
function [sys,x0,str,ts] = test2(t,x,u,flag)
NMEA = serial('COM3', 'Baudrate', 4800);
switch flag
case 0
[sys,x0,str,ts] = mdlInitializeSizes(NMEA);
case 3
sys = mdlOutputs(t,x,u);
case 9
mdlTerminate(t,x,u);
case { 1, 2, 4}
sys = [];
otherwise
error(['Unhandled flag = ',num2str(flag)]);
end;
function [sys,x0,str,ts] = mdlInitializeSizes(NMEA)
sizes = simsizes;
sizes.NumContStates= 0;
sizes.NumDiscStates= 1;
sizes.NumOutputs= 1;
sizes.NumInputs= 1;
sizes.DirFeedthrough=1;
sizes.NumSampleTimes=1;
sys = simsizes(sizes);
x0 = NMEA;
str = [];
ts = [-1 0];
function sys = mdlOutputs(t,x,u)
sys = fscanf(x);
function mdlTerminate(x)
fclose(x);
Now I get the error
"Invalid X0 vector returned by MATLAB s-function test2". Could you see what I'm doing wrong?
Small correction: the line "NMEA = serial('COM3', 'Baudrate', 4800);" needs to go inside mdlInitializeSizes so it is only called once.
However, I just realized that the function SERIAL returns a MATLAB object which is not a supported type for a DWork, so you can't use DWorks unfortunately. (In C S-functions, PWorks are provided to store any opaque pointers, but no such work vectors are available in MATLAB-file S-functions). For Level-2 MATLAB S-functions, I would have suggested this solution: http://www.mathworks.com/matlabcentral/answers/10418-share-activex-control-between-guide-and-s-function
However, you are using Level-1 S-functions which have been long deprecated. I don't know how the block handle can be accessed inside a Level-1 S-function. If you happen to know, you can apply the solution from the above link. Otherwise, since you are writing a new S-function, I would urge you to convert your Level-1 S-function to a Level-2: http://www.mathworks.com/help/toolbox/simulink/sfg/f7-67615.html#bq3i98j
Ok thanks again... Unfortunately this is getting too complicated for me... So frustrating I can't get something that works so easily in Matlab (using fscanf) into simulink!

Sign in to comment.

Hi Jan,
The Serial Configuration, Serial Receive and Serial Transmit blocks support reading and writing binary data (equivalent of fwrite and fread within MATLAB).
The Query Instrument and To Instrument blocks allow reading and writing ASCII (using fscanf and fprintf) as well as binary data. You need not write an S-Function to accomplish this task. You can import an object created in MATLAB command line into the Simulink model as well using these blocks.
Two things:
1. Can you specify the format of your data and also the settings that you had to perform an ASCII read and I will be able to help you.
2. When you mentioned, Query Instrument block is not working properly, what are you seeing? Are you seeing, no data or dropped data? Please give more info.
Thanks
Shankar

2 Comments

Hi Shankar,
Thanks for your reply.
1) An electronic compass sends the DATA through serial-USB (virtual COM) in the NMEA 0183
standard; i.e. it sends sentences (in ASCII format) 10 times per second, 4800 baud, no parity and 1 stop bit. The terminitor
is CR LF. Sentences typically look like
$HCHDG, hhh.h,,,,<CR><LF>
where hhh.h. represents magnetic heading
2)Using Query Instrument block, I was able to obtain the characters of the sentence above, but not the sentence as a whole. So the block
gave me a sequence of ascii codes representing the characters of the sentence. I didn't manage to obtain the magnetic heading from this sequence
of characters (I only need the hhh.h, e.g. 230.4, to use it as position information for my controller).
If you need more information, please ask. I hope you're able to help as this is still a problem!
I put a "to workspace" block after the query instrument to check the output; this generated a variable with every new character of the ascii sentence in a new row. So the output looked like
36
72
67
72
etc.
representing the $HCH etc. sentence
With the serial config/serial input blocks I could not get any readings; the output constantly was 00

Sign in to comment.

Walter Roberson
Walter Roberson on 12 Apr 2012
Use a persistent variable to hold NEMA . Otherwise it goes out of scope when the function returns and that causes the serial port to be closed.

2 Comments

I've added the line "persistent NMEA" above the line were NMEA is declared, but I still get the same error message:
OBJ must be connected to the hardware with FOPEN.
Hi Jan, were you able to solve this issue, I would be interested, thanks

Sign in to comment.

Zerno
Zerno on 17 May 2012
Please, can somebody help with taking data from comport to simulink model??

1 Comment

I need to write s-function in C for this//

Sign in to comment.

Categories

Find more on Simulink Coder in Help Center and File Exchange

Products

Asked:

on 12 Apr 2012

Community Treasure Hunt

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

Start Hunting!