使用Matlab进行串口通讯与下位机交互
最近用Matlab通过串口与STM32单片机通讯。Matlab在2019b版本以后,要用serialport串口函数集替换掉原有的serial串口函数集。Matlab的serialport串口工具说明文档并不完善,查了一些资料,实现了单字节中断回调式的串口接收。程序执行的效率高,并且在通讯过程中,不会阻塞主程序的运行。通讯程序主要有打开串口、串口通讯和关闭串口三个部分。
一、打开串口
在打开串口之前,要先用serialportlist()函数枚举所有的串口。然后从中选择需要通讯的设备,用serialport()函数打开,打开时要同时传入波特率参数。
devList = serialportlist("available"); % 枚举可用的串口。返回"COM1", "COM5"等
device = serialport(devList(2), 115200); % 打开列表中的第二个串口,波特率设置为115200
二、串口通讯
Matlab程序可以用read()和write()函数进行串口通讯输入和输出。因为用read()输入数据需要指定读取的数据量,在接收完指定的数据量之前,read()函数是不返回的,程序会堵在那里。而低功耗MCU数据传输通常是不定时、不定长的,对这种数据传输来说,直接用read()输入就显得有那么一些笨拙了。所以Matlab还提供了中断回调的方式进行输入,在串口收到数据时,Matlab会主动调用指定的回调函数,在回调函数里就可以用read()函数把数据读出来,有多少就读多少。
定义回调函数是用configureCallback()函数。回调函数有两种触发方式:(1) 接收到设定的终止符时触发;(2) 接收到指定的字节数时触发。如果串口数据量不大,可以设置成接收到每个字节都产生一次中断,然后在中断程序中处理收到的数据。下面是设置回调函数的语句,其中ReceiveCallback()函数就是回调函数。设置完成后,串口只要接收到数据,就会调用ReceiveCallback()函数。
configureCallback(device, "byte", 1, @ReceiveCallback); % 配置串口回调函数,接收到一个字节就调用一次ReceiveCallback()函数
回调函数的第一个参数dev是串口设备句柄,就是serialport()函数打开时返回的设备句柄,可以用来对串口进行操作。回调函数内容主要如下
function ReceiveCallback(dev, event)
SerialBytesAvailable = get(dev, 'NumBytesAvailable'); % 获取串口缓存区中的数据量
if SerialBytesAvailable > 0 % 判断是否有数据可读,如果可读则进行下一步读出的操作
DataReceive = read(dev, SerialBytesAvailable, "char"); % 读取数据
disp(DataReceive);
% 用户数据处理
% ……
end
end
虽然在配置语句中,回调函数ReceiveCallback()应该是接收到一个字节就调用一次,但是在传输整块数据时,串口实际上是一次性接收一批数据的。为了加快执行速度,串口缓冲区有多少数据,可以一次性地全部读出来。缓冲区读空以后,Matlab还会按字节数老老实实地调用回调函数,但这时候缓冲区里已经没有数据了,所以就用不着执行read()指令读取数据了。
下图展示了串口分批传输了10131字节的数据,每次回调函数被调用执行时,实际读取的数据量。可以看到,回调函数的部分调用读取了几十到上百字节,但是更多次被调用时,缓冲区可供读取的数据量实际为0。
Matlab从串口向MCU传输数据是比较简单的,直接调用write()函数就行了。
write(device, uint8([0xA5 0xA5 0x08 0x1F]), 'uint8'); % PC经串口输出4个字节的数据
三、关闭串口
Matlab的帮助里没有说怎样关闭串口。如果不关闭串口,以后就再用就打不开了。关闭串口的方法是清除设备句柄变量device,或者给device设备赋个值,Matlab就会释放device占据的串口。
clear device; % device = []; <--这样也行
四、完整示例
在本示例的硬件环境下,STM32单片机在接收到4字节数据后,会发送10131字节的数据给PC。
% 打开串口,配置回调函数
devList = serialportlist("available"); % 枚举可用的串口。返回"COM1", "COM5"等
device = serialport(devList(2), 115200); % 打开列表中的第二个串口,波特率设置为115200
configureCallback(device, "byte", 1, @ReceiveCallback); % 配置串口回调函数,接收到一个字节就调用一次ReceiveCallback()函数
% 向串口输出
write(device, uint8([0xA5 0xA5 0x08 0x1F]), 'uint8'); % PC经串口输出4个字节的数据。
% STM32单片机收到数据后,将通过串口向PC传送10131字节的数据
% 此处等待数据传输完毕,或者干别的事情……
pause(10)
% 关闭串口
clear device; % device = []; <--这样也行
% 回调函数
function ReceiveCallback(dev, event)
SerialBytesAvailable = get(dev, 'NumBytesAvailable'); % 获取串口缓存区中的数据量
if SerialBytesAvailable > 0 % 判断是否有数据可读,如果可读则进行下一步读出的操作
DataReceive = read(dev, SerialBytesAvailable, "char"); % 读取数据
disp(DataReceive);
% 用户数据处理
% ……
end
end