MATLAB Appdesigner开发独立桌面App全流程(一):以打开串口功能为例介绍Appdesigner的基本使用_matlab开发安卓手机app

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

本系列博客仅为学习记录不定期更新。

1.MATLAB Appdesigner 的基本使用

MATLAB目前内置的App开发工具为Appdesigner。Appdesigner使用面向对象的方式进行编写并且在开发工具中所有控件的生成代码由开发工具自动生成用户只需要按照自己的实际需要添加全局变量、回调函数修改控件属性即可。按照官方文档的说法GUIDE将会被逐渐移除出MATLAB。因此我们需要尽快学习并掌握Appdesigner的使用。

1.打开Appdesinger先打开MATLAB界面如下所示
在这里插入图片描述
2.点击上图中红色圈圈出的“设计App”进入如下界面
在这里插入图片描述
3.在第一行根据需要可以选择新建App空白模板或者自动调整的分为两栏和三栏的模板。此处我们选择“可自动调整布局的两栏式App”进入如下界面
在这里插入图片描述
4.左侧方框内为MATLAB开发工具中所附带的控件中间方框为App视图右侧方框为各个控件的一些属性以及组件树我们可以在此处修改各种属性以达到美化App的目的。点击App视图右上角的“代码视图”界面如下
在这里插入图片描述
这是还没有添加任何控件和用户代码的App代码由设计工具自动生成不需要用户一个个编写属性。

至此我们就新建了一个.mlapp工程可以开始使用Appdesigner开发工具开发出符合我们需要的App了。将工程保存到自己想要保存的路径后开始添加控件和回调函数以便达到我们的设计目的。下面几小节将介绍部分常见控件的使用以及不同类型回调函数的编写。

2.按钮

1.首先我们需要将按钮控件添加到设计画布上。在左边常用控件里找到“按钮”鼠标左键按住将其拖动到画布上以后松开鼠标左键。这样一个按钮控件就添加好了。
在这里插入图片描述
2.如上图所示当添加好按钮控件后单击控件周围会出现一个蓝色框。这个和我们在PPT里常见的文本框性质是相同的我们可以直接拖拽右下角调整控件的大小按住整个控件可以改变其位置。右侧的组件浏览器中上方为组件树下方为我们所选中的组件的属性。最常用的属性为“Text”这个属性代表了控件在图窗中显示的名字。比如此处我将其命名为“打开串口”那么在图窗中这个按钮控件就会显示为“打开串口”
在这里插入图片描述
3.多数情况下按钮并不会被其他控件调用。但是其他控件比如坐标区、文本框等会经常被其他控件的回调函数调用。很多时候我们需要调用多个坐标区或文本框。因此为了方便我们在写代码时准确调用其他控件我们需要养成良好的命名习惯保证我们在写代码时不会混淆各个控件和变量。那么在此我们需要给这个按钮变量注意按钮显示在图窗上的名字和按钮变量自身的名字并不是一回事命名。此处我们给按钮控件命名为“OpenSerialButton”。在控件树中找到刚才创建的按钮变量如下图所示
在这里插入图片描述
4.双击该控件我们就可以给控件重命名了。重命名后如下所示
在这里插入图片描述
这样我们就创建好了一个按钮。

3.下拉框

在实际使用中一个功能可能要对应多个不同的参数输入。这个时候我们需要使用下拉框控件。

1.和按钮一样我们在控件树中找到“下拉框”将其拖拽进画布如下图所示。
在这里插入图片描述
2.打开串口需要设置波特率在此处我们设置4个波特率分别为9600,14400,19200,115200。双击上图中“倒三角”符号的位置出现如下界面
在这里插入图片描述
3.双击各个“Option”可以给这些Option命名。单选选中一个Option后点击右侧的“-”会将其删除而点击“+”将会新建一个Option。在这里我们把Options设置成各个波特率
在这里插入图片描述
红色框中的小黑点选中后代表默认的选项。这个选项将会默认出现在软件图窗上。

4.和按钮组一样我们把这个下拉框命名为“波特率”下拉框变量命名为“BaudRateDropDown”
在这里插入图片描述
5.注意橙色框圈出的两个下拉框属性。“ItemData”中有四个元素分别对应当前选项。比如现在选中的选项为“115200”是4项中的第4项则“Value”属性就是4。这个“ItemData”为了后续编程时调用方便这一部分将在第8节回调函数详细介绍我将其手动改为了1,2,3,4更改的过程中要这样输入1,2,3,4——横排输入不要按回车。否则Value属性调用出来为元胞数组。默认状态下“ItemData”缺省而“Value”的值就是当前选中的选项的值此例中是115200。

到这里我们就创建了一个下拉框控件并配置好了我们所需要的一些属性。

4.坐标区

坐标区在App的开发中是至关重要的。很多时候我们需要使用坐标区绘制数据、显示图像、显示模型等。因此我们需要掌握坐标区的使用。

1.同样在控件树中找到“坐标区”控件将其拖拽进画布如下图所示。
在这里插入图片描述
2.上图中红色框中为坐标区的名字而蓝色区中为坐标区的各个属性。可以看到坐标区具有三个方向的属性“X、Y、Z”。要调整坐标区是二维坐标区还是三维坐标区需要在“视角”这一属性中改变。在这里我们要显示模型则将坐标区的名字改为“ModelUIAxes”并调整“视角属性”。效果如下所示。
在这里插入图片描述
3.“View”属性中为一个二维向量分别表示了观察者视角与X轴和Z轴之间的夹角。通过改变这个值我们可以将坐标区旋转到一个适合的位置以最好地显示我们的模型。在这里方便起见就调整为45,45.

这样我们就创建好了一个坐标区控件。

5.文本框

有些时候我们需要使用文本框来显示我们接收到的数据便于我们调试设备或者查找bug。

1.在控件树中找到“文本区域”控件将其拖拽进画布如图所示

在这里插入图片描述
2.注意文本区域变量的属性名为“Value”。这个是文本区域所显示的字符串。因此在将收上来的数据显示在文本区域时要将数据赋给这个属性即

app.SerialTextArea.Value = 'Submarine'; % or the following syntax
set(app.SerialTextArea,"Value",'Submarine');

3.通过上面两个语句任意一个即可可以将我们想要的信息显示在文本区域当中。左上角的“Text Area”是一个标签单击后可以删除或者在右侧属性栏“标签”里为它命名。在这里我先把它删除。最后效果如下图所示。
在这里插入图片描述
这样我们就完成了文本区域的添加。

6.选项卡组

很多时候我们开发的App功能较多需要的控件数量较多。但是整个图窗的面积有限而且如果所有控件都堆在一个画布上排版美观也很难保证。因此这时候我们就需要使用选项卡组来帮助我们进行排版。

1.找到选项卡组将其拖拽进画布
在这里插入图片描述
2.选项卡组的属性较少一般我们只改变其变量名称即可。在这里我们暂不修改“TabGroup”只修改下面两个子Tab的变量名称分别改为“ModelTab”和“ButtonTab”分别摆放我们显示模型的坐标区和一些按钮控件。将刚才创建的坐标区和按钮拖拽进两个选项卡效果如下图所示
在这里插入图片描述
3.双击图窗里Tab组件的文字可以给这个Tab重命名。在上图里我分别给两个图窗命名为“模型显示”和“按钮控件”表明它们的用途。同时注意右侧控件树的变化坐标区变成了选项卡组的一个子级。单击点击“模型显示”和“按钮组件”可以在两个选项卡中进行切换
在这里插入图片描述
这样我们就创建好了一个选项卡组控件。

至此我们已经创建好了我们所需的控件。接下来就要进入编写程序的环节让这些控件在程序运行后真正发挥作用。第7节和第8节将从全局变量和回调函数的角度详细介绍如何编写程序给App的控件添加功能。

7.全局变量

首先考虑一个问题在某一个控件里产生的数据该如何被其他控件知道呢比如说当我按下某个按钮按钮中的某个变量被赋值为1但在另一些时候另一个控件需要使用这个变量将其赋值为2。那如何使两个控件都能使用这个变量或者两个控件之间要进行通信呢这个时候就需要全局变量的引入。这一节将介绍在Appdesigner中全局变量的使用。

1.点击代码视图将界面切换到代码效果如下图所示
在这里插入图片描述
2.上图中蓝色方框圈起来的部分就是添加函数和属性的位置。点击“函数”或者“属性”下面的箭头会显示“公共属性”或“私有属性”。在这里我们选择“公共属性”和“公共函数”将其添加到代码当中结果如下图所示。
在这里插入图片描述
在代码框里就会出现一个“properties”和“methods”块。在properties中我们就可以添加我们的全局变量了。而在methods中我们需要添加一些非控件的回调函数此处暂时不表我们放在第8节中详细说明。

3.这时我们就可以在properties块中添加我们所需要的全局变量了。在此项目中我们需要如下变量

  • 一个串口变量用来连接串口和读取串口的数据
  • 一个串口名称变量用来存储串口名称的字符串
  • 一个模型变量用来存储我们的模型数据
  • 一个波特率变量用以表明我们所选择的波特率
  • 一个定时器变量用来创建定时器调度任务。

设置好变量名称效果如下
在这里插入图片描述
要想给这些变量赋一个初始值按照MATLAB给变量赋初值的语法就可以了。上面三个变量中只有baud可以赋为浮点数其他变量的建立需要使用函数和不同的参数涉及串口变量的使用和导入数据文件。这两部分将在第8节以及后续的文章中详细介绍。这里给变量赋初值上面的代码可以改写为

properties (Access = public)
	ser; % Serial
	serialname;
	model; % To store the model data
	baud = 115200; % baud rate
	datetimer; % To show time
end

这样我们就添加好了App所需要的全局变量。在读者具体的项目中读者也可以根据自己的需要添加变量也可以定义不同的变量类型。

P.S.在后面回调函数的编写中我可能会添加另外一些变量。在每处新增的变量我都将进行说明。

8.回调函数

这一部分将介绍在Appdesigner中不同类型的回调函数的编写。

我们以创建串口变量为例来介绍按钮控件回调函数的编写。

1.Serialportlist函数的使用

在2019b版本中引入serialport函数后MATLAB不太推荐使用原有的serial函数而是推荐使用serialport函数。根据官方文档使用serialport函数至少需要两个参数portname和baudrate。因此我们至少需要知道连接到我们电脑上的串口名称和波特率。在MATLAB中serialportlist函数可以获取与我们电脑上相连的串口名称

serialname = serialportlist;

函数的返回值如下
在这里插入图片描述
该函数将返回一个string类型的数组是电脑目前所有可用串口的名称。

2.串口类型的查看

串口类型常见的是蓝牙标准串行和CH340而硬件接上来的串口类型一般为CH340。打开文件资源管理器找到“此电脑”鼠标左键单击后出现如下界面
在这里插入图片描述
然后单击“管理”弹出如下窗口
在这里插入图片描述
之后点击“设备管理器”再点击“端口(COM和LPT)”将其展开显示电脑目前可用的串口以及类型。可以看到COM8口为CH340口这个是和我们的硬件设备相连接的COM口。

3.添加按钮回调

此时我们就可以针对创建串口变量这一功能添加按钮的回调函数了。在这里我引入一个新的按钮用作查找串口号新建一个下拉框用以显示串口号。将这两个控件分别命名为“FindSerialportButton”和“SeriallistDropDown”。

鼠标右键单击按钮按如下路径左键点击“回调” → \rightarrow “添加ButtonPushedFcn回调”如下图所示。
在这里插入图片描述
转到代码视图我们可以发现自动生成了一个代码块
在这里插入图片描述
4.在这个白色框中我们就可以编写“查询串口”按钮的功能代码了

% Button pushed function: FindSerial
function FindSerialportButtonPushed(app, event)
	app.serialname = serialportlist;
	Devices = app.serialname;
	num = length(Devices); % 传回设备个数信息
	items = cell(1,num);
	itemsdata = zeros(1,num);
	for i = 1:num
		items{i} = [char(Devices(i)),' USB-Serial'];
		itemsdata(i) = i;
	end
	% 还记得上面讲的下拉框ItemsData属性和Items属性的关系吗在这里我们把Items属性设置成文本信息显示串 口号而ItemsData对应他们的序号方便我们选中某个之后其他控件可以知道我们到底选中的是哪个选项。
	app.SeriallistDropDown.Items = items;
	app.SeriallistDropDown.ItemsData = itemsdata; 
end

这段代码一共实现了两个功能

  • 找到目前电脑上所有可用的串口
  • 将这些串口设置成显示串口号的下拉框的选项。

5.点击“运行”我们就可以测试这段代码的效果了
在这里插入图片描述
可以看到这个时候“串口号”这个下拉框里还没有任何内容当我们点击“查询串口”按钮后串口号便会显示出电脑上所有的串口号信息。点击下拉框我们就可以选中我们想要的那个串口号
在这里插入图片描述
这样一个查询串口号的按钮功能就做好了。

6.“打开串口”按钮功能

当我们找到串口名称、设置好波特率后就可以打开串口了。那么现在就有了一个问题“打开串口”这个按钮该如何得知我们选中的是哪个串口呢这就涉及到不同控件之间的“交流”了。和上面一样我们先给“打开串口”按钮添加回调函数然后在代码视图中给按钮添加功能代码

function OpenSerialButtonPushed(app, event)
	% 获取当前选中的串口名称
    serName = app.serialname(app.SeriallistDropDown.Value);
    % 获取当前选中的波特率
    app.baud = app.BaudRateDropDown.Items{app.BaudRateDropDown.Value};
    % 创建串口变量
    app.ser = serialport(serName,str2double(app.baud));
end

注意当我们调用Items属性时注意一下返回值类型。在这里我们在上面代码块中的第7行代码处添加一个调试断点如下图所示
在这里插入图片描述
这时候我们回到命令行窗口输入如下指令

app.BaudRateDropDown.Items

返回值如下图所示
在这里插入图片描述
可以看到下拉框的Items属性存储数据是元胞数组的形式。那么每个元胞数组里的数据又是什么形式呢在命令行中输入如下指令

ans{1} % 元胞数组内数据的调用要使用{}。元胞数组的具体使用方法请参考官方文档。

返回值如下
在这里插入图片描述
可以看到这个返回了第一个选项但是是以字符串的形式返回的。因此我们需要将它转变成double类型才能输入进serialport函数。字符串变成double的函数方法如下

str2double(app.baud);

至此我们就获得了串口名和波特率两个基本参数可以用来创建串口了。上述代码便是“打开串口”按钮的功能代码。而上面所讲的也是一个例子提醒读者注意我们调用其他组件属性时返回值是什么从而在本控件的代码中做出一定的调整以适应我们所用函数的需要。接下来我将详细介绍串口回调函数的使用。

9.串口回调

1.创建好了串口变量我们就需要读取和处理串口数据了。在这个项目中我们使用“Terminator”来判断是否应该读取数据。在下位机传上来的数据包中每组数据的末尾都添加了“\r\n”字符。那么上位机端我们就使用这两个字符作为是否该读取数据的标志。在serialport函数后我们需要添加如下一行代码

configureTerminator(app.ser,"CR/LF");

这段代码的作用是将回调函数触发条件设置为“Terminator”通俗来说就是读到特定字符时触发回调函数。另外还有一种方式是在串口中数据量到达固定字节后触发串口回调函数。在这里我们只详细介绍“Terminator”方式。

2.设置好后接下来需要添加调用回调函数的代码

configureCallback(app.ser,"terminator",@app.SerialReceive_Callback);

在这里我们调用的是名为“SerialReceive_Callback”的函数。但是注意在函数名称前面要加上“app.”。这是因为回调函数是app这个变量的一个methods需要用app来调用。具体的细节读者可以自行参考MATLAB面向对象编程的一些资料此处不再赘述。

3.回顾一下第7节全局变量我们在那里不只创建了公共属性也创建了一个公共函数
在这里插入图片描述
我们需要将串口的回调函数放在这里。在这里我们实现一个简单的功能将串口接收到的数据显示在文本框里。回调函数的全部代码如下

properties (Access = public)
    ser; % Serial
    serialname;
    model; % To store the model data
    baud = 115200; % baud rate
    datetimer; % To show time
    SerialData;
end

methods (Access = public)

    function SerialReceive_Callback(app, src,~)
 		SerialBytesAvailable = get(src,'NumBytesAvailable');
       	if SerialBytesAvailable % 判断是否有数据可读如果可读则进行下一步读出的操作
         	app.SerialData = read(src,SerialBytesAvailable,"char");
          	set(app.SerialTextArea,"Value",app.SerialData);
       	end
    end

end

在properties中我添加了一个新的变量SerialData用以存储每一次串口读取的数据。上面代码块中的第16行实现将串口数据原封不动地显示到我们在第5节创建的文本控件当中。

“开启串口”回调的全部代码为

% Button pushed function: OpenSerialButton
function OpenSerialButtonPushed(app, event)
    serName = app.serialname(app.SeriallistDropDown.Value);
    app.baud = app.BaudRateDropDown.Items{app.BaudRateDropDown.Value};
    app.ser = serialport(serName,str2double(app.baud));
    %% 清除缓冲区
    flush(app.ser);
    %% 设置中断回调
    configureTerminator(app.ser,"CR/LF");
    configureCallback(app.ser,"terminator",@app.SerialReceive_Callback);
end

运行App初始界面如下
在这里插入图片描述
这个时候文本框中的内容还是我们在画布上设置的“Submarine”而“串口号”下拉框中也没有内容。按如下流程点击操作“查询串口” → \rightarrow 在“串口号”下拉框中选择串口号 → \rightarrow 在“波特率”下拉框中选择波特率 → \rightarrow “打开串口”。结果如下图所示
在这里插入图片描述
可以看到文本框中显示出了下位机发送上来的信息。

至此我们就完成了接收下位机数据这一功能。

4.关闭串口

在一个任务周期完成之后我们需要关闭串口。关闭串口的代码如下

configureCallback(app.ser,"off");
delete(app.ser);

第一行代码将回调函数关闭第二行代码将串口变量删除释放串口资源为连接其他串口提供空间。在这里我将关闭串口的代码写入另一个按钮的回调函数当中当我们按下按钮后串口关闭。完整代码如下

% Button pushed function: CloseSerialButton
function CloseSerialButtonPushed(app, event)
    configureCallback(app.ser,"off");
    delete(app.ser);
end

至此我们就走完了串口使用的整个流程。读者可以针对自己数据的具体需求在回调函数中添加自己的处理算法以实现特定的功能。

未完待续…

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: android