如何实现matlab GUI串口通信设计
扫描二维码
随时随地手机看文章
本文利用Matlab GUI设计通过串口进行数据发送和接收的界面,并利用内置于Matlab的串口通信API实现串口数据发送与接收功能。
1 Matlab GUl介绍
启动Matlab后,运行guide命令即可以启动Matlab GUI开发工具。
新建Blank GUI,如图2所示。
在新建Blank GUI界面中,包含了一般的界面元素,如菜单、按钮、坐标轴、控件等。添加必要的串口通信参数设置按钮。
运行后的界面如图3所示。
2 串口数据发送与接收功能实现
2.1 建立串口通信流程的基本步骤
Matlab提供了对串口进行打开、关闭、以及串口参数设置等操作的一系列函数。利用这些函数可以选择串口号、设置串口通信参数(波特率、数据位、停止位、校验位等)、进行中断控制、流控制。从建立串口通信到结束串口通信的完整流程包括以下几个步骤:
(1)为应用程序创建串口对象。实现该功能的函数为:
其中参数port为完整的串口名称,如cornl。PropertyName为串口通信参数,如baudrate,startbits等。创建串口对象的过程中,也可以忽略PropertyName。其函数为:
(2)连接打开串口。实现该功能的函数为:
obj即为使用创建串口对象函数的返回值。在连接打开串口后,可以对串口通信参数进行修改。
(3)设置或者修改串口通信参数。在能够有效地进行串口通信前,必须设置正确的串口通信参数。实现该功能的函数为:
obj即为使用创建串口对象函数的返回值;PropertyName为串口通信参数,如baudrate,startbits等。
(4)从串口读写数据。在前面三个步骤正常完成后,即可以从串口读数据或者向串口写数据,也就是接收或者发送数据。实现读串口功能的函数有多个。其区别在于根据到达串口数据的类型选择合适的读函数。主要包括:fgetl,fgets,fread,fscanf。这里主要介绍fread,fread函数实现从串口读入二进制数据。fread的实现形式为:
A=fread(obj,size)
A为读入的数据,以数组的形式存储,存储数据形式为字节;obj即为使用创建串口对象函数的返回值;size指定一次读操作读入字节的个数。实现写串口的函数有两个,分别为fwrite和fprintf。fwrite以二进制形式向串口写入数据,实现形式为:
fwrite(obj,A)
obj即为使用创建串口对象函数的返回值;A为写入的数据,以数组形式存储。fwrite以文本形式向串口写入数据,即以ASCII码的形式向串口写数据,实现形式为:
fprintf(obj,'cmd')
obj即为使用创建串口对象函数的返回值;cmd为写入的文本数据,以数组形式存储。
(5)关闭串口以及释放串口对象占用的存储空间。关闭串口函数为:fclose(obj)。释放串口对象占用的内存空间,函数为:delete(obj)。释放串口对象在Matlab工作区中占用的存储空间,函数为:clear obj。
以上5步是建立串口通信过程到关闭串口,释放串口占用资源的基本步骤。基本步骤可以实现手动收发数据。其例程如下:
运行以上语句后,显示的结果如下:
串口数据接收完毕后,需要关闭串口,并释放串口对象占用的资源,使用的命令如下:
2.2 串口中断设置及中断处理函数要实现自动收发数据,还需要定义串口中断处理函数以及触发串口中断的方式。定义串口中断处理函数也就是定义串口数据接收或者发送函数。定义触发串口中断的方式其目的是为了在串口检测到接收数据的时候,通知并启动串口数据接收函数进行数据接收操作;在串口输出缓存为空的时候,通知启动串口数据发送函数。
(1)触发串口中断的方式。在Matlab串口通信编程中,Matlab通过检测到串口通信事件,从而触发串口中断。涉及到串口读写的事件包括:Bytes available,Output empty。其中Bytes available事件有两种:一种是接收到的字符数达到人工设定的数目时,则系统产生该事件;另一种是当接收到指定字符时,系统产生该事件。Output erupty事件是在系统检测到输出缓存区为空时,产生该事件。
Bytes available事件需要事先设置。可以使用函数:set(obj,'By tesAvailableFcnMode','byte');set(obj,'BytesAvailableFcn-Count',240);以上两个函数设置当串口检测到输入缓存中到达了240个字符的数据时,则触发串口中断。另外,也可以设置为当系统检测到某个字符达到串口,则触发串口中断。其设置函数为:set(obj,'BytesAvailableFcnMode','terminator');set(obj,'terminator', 'H')。以上两个函数设置当串口检测到字符H时,则触发串口中断。
输出缓存为空事件的产生。该事件由系统自动检测产生,不需要用户特别设置。该事件一般在输出缓存中的最后一个字符发送完毕后产生。用户可以定义该事件引起的串口中断处理函数。
(2)串口中断处理函数。串口中断处理函数可以根据用户需要自行定义。如串口读中断处理函数可以这样定义:obj.BytesAvailableF-cn=@reeeiveData。receiveData即为串口读中断处理函数。在读中断处理函数中可以进行串口读操作。即将输入缓存区中的数据读到用户自定义的存储变量中,以备后续的数据处理与分析。类似可以定义输出缓存为空时触发的串口中断处理函数:obj.OutputEmptyFcn=@write-Data。
本文开发的串口通信程序用于接收采集IMU(InerTIal Measurement Unit)输出的加速度计和陀螺的测量数据。通过定义串口读中断事件和串口中断处理函数,实现了数据的自动采集,并以Matlab图形方式实时显示数据。
最近做了一个康复辅助设备的小项目,其中一部分设计串口通信及其对应知识,也是整个项目挺重要的一部分,故单独摘出来写成笔记以加强记忆。如有错误之处望诸君指正。
串口通讯初始化
串口通讯的第一步便是初始化,即配置串口参数与打开串口。
在matlab中,我们可以通过调用几个简单的指令来实现这一步骤。
首先是配置串口参数:
一般来讲,串口参数包括:串口名、波特率、奇偶校验位(起始位)、数据位、停止位这几项。
串口名是指:串口在系统中的名称,一般以COM加数字命名。如:COM2、COM11。
波特率是指:上位机与下位机通讯时的传输速度。常见的波特率有9600、14400、115200等,其单位为波特/秒,即b/s。
需要注意区分的一点是波特率不是比特率,比特率的单位是比特/s,即bit per second-bps/s;波特率中的波特与比特存在这样的关系,如果发送的内容有1位起始位、1位终止位、8位数据位,那么1波特便等于10比特。
如果下位机的采样频率过快(数据小于等于8位),比如达到了10kHZ,那么就要求在1秒以内上传10000个数,需要10000个波特,在这种情况下9600的波特率就不满足要求了,我们便需要更大的波特率。
另外顺便区分一下比特bit与字节Byte,在一般情况下1Byte=2^8bit,即一个字节由256个比特组成。在串口通讯中,如果设置数据位为8,那么我们一个波特所能携带的数最大便为11111111,因此对超过8位的数据我们需要将其拆分成高低位发送。
奇偶校验位(起始位)、数据位、停止位是指:每一个波特中所含的这些有不同含义的数的位数。一般奇偶校验位为0,数据位为8,停止位为1。
以上配置串口参数的过程可以用简单的matlab语句实现:
s=serial("COM8");%设置串口的句柄
set(s,'BaudRate',14400,'DataBits',8,'StopBits',1,'Parity','none');
%配置串口参数 波特率14400 无起始位 1终止位 8数据位
123
其次是打开串口:
在matlab中可用简单语句实现:
fopen(s);%配置并打开串口
1
这样,便完成了串口通讯的初始化,接下来便是发送数据和接收数据了。
串口发送数据
在matlab中,发送数据的函数有fprintf、fwrite、fscanf等,由于这次我使用的是fwrite,故下文只介绍fwrite。
先上代码:
fwrite(s, D, 'uint8'); %对定义的串口s发送该数据
1
fwrite一般以上述形式使用,第一位是串口名的句柄,第二位是所要发送的数据,第三位位发送数据的数据类型。
因为做的是上下位机之间的指令型通讯,所以一般采用的数据类型是uint8。而设置指令D的方法如下:
Str ='20';%字符串定义需要发送的十六进制内容
D = sscanf(Str,'%2x'); %将字符串转换成十六进制数据 其中x是16进制的意思
12
可将字符串中的数字转化为16进制数字(数字本身不改变)并由fwrite发送。
串口读取数据
串口读取数据的方式有很多种,本质上都是通过fread函数接受数据并进一步处理。但由于下位机发送的方式不同,接收的方式也有所不同。
有些下位机是以一个数据一个数据的形式发送的,这种发送方法在低速通信的时候没有什么问题;但如果发送的速度较快,上位机的代码运行时间较长,很容易发生丢失数据的现象,这对于需要将第八位与高八位拼接的读取方式来说是致命的。
因此,我推荐下位机将一次需要发送的数据以一个数组一个数组的方式发送。这样,上位机可一个一个数组的读取,在一定程度上可以有效避免上述问题。
这里略加一句,在Labview中,由于串口读取是以字符串的形式进行的,那么就会存在一个问题。平常情况下读取的字符串是一个字母一个字节,但是由于Labview直接将下位机发送的8位16进制数识别成了字符串,那么对于这个字符串来说,就变成了2个字母占1个字节;这就造成了普通的字符串转数字控件无法工作,需要将其转换为1个字母占1个字节的形式才可以工作。不过,好在matlab并不存在这个问题。
对于我这次的项目,由于下位机发送数据的方式是这样的:
所以根据下位机发送数据的方式,我使用了一种兼顾显示和采集的读取方式。下面给出我这次项目串口读取部分使用的代码:
%-------读取串口数据
for i=1:20
data=fread(s,4,'uint8');
data2=fread(s2,4,'uint8');%提取串口数据
if(data(1)==32&&data2(1)==32)
wave(1,:)=data(2)+data(3)*256;
wave(2,:)=data2(2)+data2(3)*256;
waveform=[waveform,wave];
end
end
%------------------
1234567891011
这个for循环是在一个大的for循环或者while循环下的。首先,使用fread语句读取串口数据(注意的是每次读取了4个字节,与下位机发送的数组字节数相符);之后用if循环寻找起始标志,再根据顺序判断出高低位并将其合成一个数;最后将每次读取到的数动态依次合成到同一个数组中。
另外,由于考虑到波形显示问题,我并没有每次都把波形数组输出。这是因为虽然这么做能让图像显示看起来更流畅,但是由于plot函数耗时较长,会造成上位机运行跟不上下位机发送,造成图像显示迟滞现象。因此,我选择了让它循环20次即获取20个点后再刷新图像。
串口波形的图像显示
本质上是使用plot函数将同一数组中的数据以两通道的形式显示出来。
不过需要注意的一点是,plot函数只会机械的将你需要显示的数组显示出来,并不具有类似Labview波形图标控件那样自动调整横坐标,使波形只有最近的一段显示,给人波形在滚动的感觉,也就是我们在示波器中看到的那样(如果不加干涉,波形只会越来越长,越来越小)。