MATLAB Appdesigner实用技巧(二):MATLAB App建立TCP服务端和下位机通信
1. MATLAB App建立TCP服务端和下位机通信
在数据传输上方式上,笔者选择了使用ESP8266进行通信。ESP8266模块作为AP,TCP客户端模式;电脑作为TCP服务端。在MATLAB中,“tcpserver”函数可以建立一个TCP服务端。查询”tcpserver“函数的基础使用用法为:
ts = tcpserver(address,port);
其中,“address”为TC服务器的地址,“port”为端口号。使用上述基础语法,我们就可以在电脑上创建一个TCP服务器和下位机通信了。接下来,我将详细介绍如何在App中使用TCPserver和下位机进行通信。
1.1 查看电脑端IP地址
1.按照下图所示的点击顺序,点击模块热点的“属性”。
2.弹出如下窗口:
找到属性中的“IPv4地址”,这个就是模块分配给电脑的IP地址了。在我的组网中,我的电脑被分配的地址为192.168.4.2。
1.2 在MATLAB中创建TCPserver变量
1.在MATLAB脚本中输入如下代码:
address = '192.168.4.2';
port = 8080;
ts = tcpserver(address,port);
注意,“address”为字符串变量,而“port”为double类型变量。
P.S.关于对应的下位机代码部分,笔者将会在硬件相关的章节(待更新)详细介绍。在这里,我做一个简要的解释:在驱动ESP8266的代码中,我将该模块设置为向远端IP地址为“192.168.4.2”,端口号为“8080”的TCP服务器发起连接。相关代码如下:
uint8_t AT_START[] = "AT+CIPSTART=\"TCP\",\"192.168.4.2\",8080\r\n";//建立TCP连接
#define ATSTART HAL_UART_Transmit(&huart3, (uint8_t *)AT_START, sizeof(AT_START), 0xFFFF) //发送建立TCP连接命令
回到MATLAB脚本中来。运行建立TCP服务端的代码,我们就可以创建一个TCPserver变量。在工作区双击打开“ts”变量:
可以看到TCPserver变量所具有的属性。当有TCPClient接入时,”Connected“属性会显示为接入的Client的数量,未有Client接入则为零。
2.注意上图中的“NumBytesAvailable”属性,这一属性代表当前通信状态下的数据字节数。在下一小节中,该属性将作为标准判断是否可以读取数据。
1.3 配置数据读取模式并编写回调函数
1.在下位机的代码中,我将数据发送的格式设置为每包数据末尾添加“\r\n”字符。那么在MATLAB上位机端,我们就需要设置TCPserver在遇到这两个字符后开始读取并处理数据。在创建好了TCP服务端后,添加如下代码:
configureTerminator(ts,"CR/LF");
这段代码的作用是将回调函数触发条件设置为“Terminator”,通俗来说就是读到特定字符时触发回调函数。另外还有一种方式,是在串口中数据量到达固定字节后触发串口回调函数。在这里,我们只详细介绍“Terminator”方式。
2.设置好后,我们就需要编写相应的回调函数了。在上面的代码下面添加如下代码:
configureCallback(ts,"terminator",Receive_Callback);
这段代码的作用是,当读到terminator设置的字符后,程序进入回调函数。所以在这时,我们还需要添加相应的回调函数:
function Receive_Callback(ts,~)
TCPBytesAvailable = get(ts,'NumBytesAvailable');
if TCPBytesAvailable % 判断是否有数据可读,如果可读则进行下一步读出的操作
data = read(src,SerialBytesAvailable,"char");
disp(data); % 将读出的数据在命令行显示出来
end
end
完整的代码如下:
clc; clear; close all
%% 打开串口
address = '192.168.4.2'; % 这里读者需要改成自己相应的IP地址
port = 8080; % 同样,读者需要改为自己在下位机设置的端口号
ts = tcpserver(address,port);
%% 清空数据并打开回调函数
flush(ts);
configureTerminator(ts,"CR/LF");
configureCallback(ts,"terminator",@Receive_Callback);
% 这里pause的效果是,按下键盘上任意键,代码从这一行继续运行。
% 如果不加这一行,则程序将直接运行到configureCallback(ts,"off");即关闭回调函数
% 回调函数将不会运行
pause;
configureCallback(ts,"off");
function Receive_Callback(ts,~)
TCPBytesAvailable = get(ts,'NumBytesAvailable');
if TCPBytesAvailable % 判断是否有数据可读,如果可读则进行下一步读出的操作
data = read(ts,TCPBytesAvailable,"char"); % 读出的数据类型为char
disp(data); % 将读出的数据在命令行显示出来
end
end
运行上述代码,结果如下:
可以看到,下位机发送上来的数据显示在了命令行窗口中。
1.4 在App中实现上述功能
1.在MATLAB脚本中做好调试后,我们就需要将该功能移植到App当中。我们需要一个“编辑字段(文本)”控件、一个“编辑字段(数值)”控件、两个按钮控件,分别用于IP地址的输入、端口号输入、建立TCP服务端和关闭TCP服务端。我们将控件变量分别命名为:
- IPEditField
- PortEditField
- OpenTCPButton
- CloseTCPButton
创建好的控件如下图所示:
2.创建好控件后,我们需要给这些控件添加功能代码。分为如下几个部分:
- “建立TCP服务端”按钮和“关闭TCP服务端”按钮的回调函数
- 在公共方法中添加TCPserver的回调函数
- 在公共属性中添加要创建的TCPserver变量。命名为“ts”;添加TCP读出的数据变量,命名为“TCPData”。
如何添加回调函数和公共属性,请参考MATLAB Appdesigner开发独立桌面App全流程(一):以打开串口功能为例介绍Appdesigner的基本使用第8节。在这里,笔者只给出代码。这三部分的代码如下:
properties (Access = public)
ser; % Serial
serialname;
model; % To store the model data
modelvisual; % Store the patch handle
baud = 115200; % baud rate
datetimer; % To show time
SerialData;
%% 以下为本节新添加的变量
ts;
TCPData;
end
methods (Access = public)
function TCPReceive_Callback(app, src,~)
TCPBytesAvailable = get(src,'NumBytesAvailable');
if TCPBytesAvailable % 判断是否有数据可读,如果可读则进行下一步读出的操作
app.TCPData = read(src,TCPBytesAvailable,"char");
% SerialTextArea是在6.9.2节创建的文本区控件。这里方便起见,就直接调用了该控件来显示数据
set(app.SerialTextArea,"Value",app.TCPData);
end
end
end
% Button pushed function: OpenTCPButton
function OpenTCPButtonPushed(app, event)
try
address = app.IPEditField.Value;
port = app.PortEditField.Value;
app.ts = tcpserver(address,port);
flush(app.ts);
configureTerminator(app.ts,"CR/LF");
configureCallback(app.ts,"terminator",@app.TCPReceive_Callback);
catch ME
report = getReport(ME);
uialert(app.UIFigure,report,'Error Message','Interpreter','html');
end
end
% Button pushed function: CloseTCPButton
function CloseTCPButtonPushed(app, event)
try
configureCallback(app.ts,"off");
delete(app.ts);
catch ME
report = getReport(ME);
uialert(app.UIFigure,report,'Error Message','Interpreter','html');
end
end
运行App,效果如下:
可以看到,下位机的数据显示在了文本区域当中。这样,我们就使用TCPserver建立了与下位机的通信。在下次更新中,我将介绍如何利用这些数据在App的坐标区中显示实时波形——也就是示波器的效果。