源码在这下载:https://github.com/luckypm/matlab-serial-GUI
最近为了方便监控IMU的地磁传感器(HMC5983)数据,用matlab的GUI做了一个简易的串口助手,可实时显示地磁传感器X Y Z三轴的数据,并动态的显示曲线图。
*1. 串口助手的GUI图如下:
[外链图片转存失败(img-7ZddnqFF-1565794912664)(http://i.imgur.com/A6btBmB.jpg)]
*2. 连接串口后的数据图如下(绘图时可勾选要显示的数据):
[外链图片转存失败(img-72ARahkP-1565794912665)(http://i.imgur.com/jG1MQ0A.jpg)]
*3. 我所使用的串口发送的数据格式是
sprintf(buff,"%8f %8f %8f\n",IMU_MAGX,IMU_MAGY,IMU_MAGZ);
*4. 现将最主要的“打开串口”按钮回调函数和串口的回调函数分享出来:
"打开串口"按钮的callback函数:
function open_serial_Callback(hObject, eventdata, handles)
% 【打开/关闭串口】按钮的回调函数
%% 定义一些全局变量并初始化
global XData; %定义一全局变量,坐标轴X轴的数据
global YData1;%坐标轴IMU_MAGX的数据
global YData2;%坐标轴IMU_MAGY的数据
global YData3;%坐标轴IMU_MAGZ的数据
global Xlim;%坐标轴X轴的范围
global L1;%用来存储IMU_MAGX线的句柄
global L2;%用来存储IMU_MAGY线的句柄
global L3;%用来存储IMU_MAGZ线的句柄
global Checkbox_x;%用来判定是否选中了IMU_MAGX复选框
global Checkbox_y;%用来判定是否选中了IMU_MAGY复选框
global Checkbox_z;%用来判定是否选中了IMU_MAGZ复选框
Checkbox_x = 0;%初始化为未选中
Checkbox_y = 0;
Checkbox_z = 0;
XData = 0;%初始化坐标轴的数据为0
YData1 = 0;
YData2 = 0;
YData3 = 0;
Xlim = 0;
%打开串口,并初始化相关参数
%% 若按下【打开串口】按钮,打开串口
if get(hObject,'value')
%% 获取串口的端口名
com_n = sprintf('com%d', get(handles.com, 'value'));
%% 获取波特率
rates = [9600 38400 115200];
baud_rate = rates(get(handles.baudrate, 'value'));
%% 获取校验位设置
switch get(handles.jiaoyan, 'value')
case 1
jiaoyan = 'none';
case 2
jiaoyan = 'odd';
case 3
jiaoyan = 'even';
end
%% 获取数据位个数
data_bits = 5 + get(handles.data_bit, 'value');
%% 获取停止位个数
stop_bits = get(handles.stop_bit, 'value');
%% 创建串口对象
scom = serial(com_n);
%% 配置串口属性,指定其回调函数
set(scom, 'BaudRate', baud_rate, 'Parity', jiaoyan, 'DataBits',...
data_bits, 'StopBits', stop_bits,...
'BytesAvailableFcnMode', 'Terminator', 'BytesAvailableFcn', {@my_callback, handles});
%% 将串口对象的句柄作为用户数据,存入窗口对象
set(handles.figure1, 'UserData', scom);
%% 尝试打开串口
try
fopen(scom); %打开串口
catch % 若串口打开失败,提示“串口不可获得!”
msgbox('串口不可获得!');
set(hObject, 'value', 0); %弹起本按钮
return;
end
%% 能够打开串口后,设定绘图的相关属性
if get(handles.checkbox1,'value')
Checkbox_x = 1;
L1 = plot(handles.axes,XData,YData1,'r','EraseMode','none','MarkerSize',5);
hold on;
end
if get(handles.checkbox2,'value')
Checkbox_y = 1;
L2 = plot(handles.axes,XData,YData2,'b','EraseMode','none','MarkerSize',5);
hold on;
end
if get(handles.checkbox3,'value')
Checkbox_z = 1;
L3 = plot(handles.axes,XData,YData3,'m','EraseMode','none','MarkerSize',5);
end
set(handles.axes,'XLim',[Xlim-400 Xlim+100],'YLim',[-2 +2]);%设定坐标轴的范围
grid on; %绘出网格
%% 设定其它按钮的属性
set(handles.pause_start,'enable','on');
set(hObject,'string','关闭串口');
set(handles.lamb,'backgroundcolor','g');
else %若关闭串口
%% 删除line对象
Linehandle = get(gca,'children');%获取坐标轴的子对象的句柄
delete(Linehandle);
%% 停止并删除串口对象
scoms = instrfind;
fclose(scoms);
delete(scoms);
set(hObject,'string','打开串口');
set(handles.lamb,'backgroundcolor','r');
set(handles.pause_start,'enable','off');
set(handles.pause_start,'string','暂停显示');
set(handles.pause_start,'value',0);
end
串口的回调函数:
function my_callback(obj,~,handles)
% 串口的BytesAvailableFcn回调函数
%% 定义一些全局变量
global XData;
global YData1;
global YData2;
global YData3;
global Xlim;
global L1;
global L2;
global L3;
global Checkbox_x;
global Checkbox_y;
global Checkbox_z;
%% 每运行一次本函数X轴的数据+1
Xlim = Xlim+1;
XData =[XData Xlim];
%% 接收串口发送过来的数据(这里有时会出现BUG,具体原因不详)
outdata = fscanf(obj);%接收串口发来的ASII数据,串口发过来的数据是字符串“IMU_MAGX IMU_MAGY IMU_MAGZ ”
YData = str2num(outdata);%将字符串转化成数值类型
YData1 = [YData1 YData(:,1)];%存储IMU_MAGX的数据
YData2 = [YData2 YData(:,2)];%存储IMU_MAGY的数据
YData3 = [YData3 YData(:,3)];%存储IMU_MAGZ的数据
%% 限定坐标轴X Y的数组长度不能超过500,防止数据过多时易导致内存消耗过大卡死
if (length(XData)) > 500
XData = XData(:,2:end);%数组长度一旦超过500就丢弃第1列的值
end
if (length(YData1)) > 500
YData1 = YData1(:,2:end);
end
if (length(YData2)) > 500
YData2 = YData2(:,2:end);
end
if (length(YData3)) > 500
YData3 = YData3(:,2:end);
end
%% 通过判定勾选的复选框的值来更新相应Y轴坐标的数据
if (~get(handles.pause_start,'value'))%如果点击了暂停显示,是停止更新Y轴的数据
if Checkbox_x
set(L1,'Xdata',XData,'YData',YData1);
end
if Checkbox_y
set(L2,'Xdata',XData,'YData',YData2);
end
if Checkbox_z
set(L3,'Xdata',XData,'YData',YData3);
end
end
%% 求出Y轴数据的最小最大值
min_1 = min(YData1(:));
min_2 = min(YData2(:));
min_3 = min(YData3(:));
max_1 = max(YData1(:));
max_2 = max(YData2(:));
max_3 = max(YData3(:));
%% 通过判定复选框的勾选值来采用相应的最小最大值,并求出整个Y轴数据的最小最大值
if Checkbox_x && Checkbox_y && Checkbox_z
min_array = [min_1 min_2 min_3];
max_array = [max_1 max_2 max_3];
elseif Checkbox_x && Checkbox_y
min_array = [min_1 min_2];
max_array = [max_1 max_2];
elseif Checkbox_y && Checkbox_z
min_array = [min_2 min_3];
max_array = [max_2 max_3];
elseif Checkbox_x
min_array = min_1;
max_array = max_1;
elseif Checkbox_y
min_array = min_2;
max_array = max_2;
elseif Checkbox_z
min_array = min_3;
max_array = max_3;
else
min_array = -2 + 0.2;
max_array = 2 + 0.2;
end
min_all = min(min_array);
max_all = max(max_array);
%% 更新坐标轴范围
if (~get(handles.pause_start,'value'))%如果点击了暂停显示,是停止更新坐标轴范围
set(handles.axes,'XLim',[Xlim-400 Xlim+100],'YLim',[min_all-0.2 max_all+0.2]);
end
%% 将数值数据格式化成字符串
IMU_MAGX = sprintf('%f',YData(:,1));
IMU_MAGY = sprintf('%f',YData(:,2));
IMU_MAGZ = sprintf('%f',YData(:,3));
%% 显示接收的字符串
if (~get(handles.pause_start,'value'))
set(handles.display_x,'string',IMU_MAGX);
set(handles.display_y,'string',IMU_MAGY);
set(handles.display_z,'string',IMU_MAGZ);
end
*5. 为方便大家阅读,我对代码进行了详细的注释,希望对有需要的人有所帮助;另我这代码写得并不简洁,希望大家能优化改进
参考书籍:《MATLAB GUI设计学习手记》罗华飞著