imuncle / imuncle.github.io

大叔的个人小站
https://imuncle.github.io/
78 stars 17 forks source link

MATLAB串口通信GUI程序 #43

Open imuncle opened 5 years ago

imuncle commented 5 years ago

最近上的材料测试方法课程有一个大作业,要求根据原理做一种材料分析仪器的演示装置。像这种大制作的东西,毫无疑问我承担了其中的编程部分。在“产品经理”的强烈要求下,我用MATLAB写了一个串口通信的程序,可以获取STM32发送的数据,并绘制出曲线。

MATLAB GUI

之前也没用过MATLAB GUI,这次是因为时间比较紧,技术比较菜,MATLAB代码量挺少的,就选择了MATLAB,之前一直用的Qt,本来也想尝试electron的,但是好像它不能访问USB设备。

所以现学了一波MATLAB GUI操作,实在是很简单,正所谓MATLAB一时爽,一直MATLAB一直爽。

首先在命令行输入'guide'新建一个空白GUI。

>> guide

image

然后简单添加,效果如下图所示:

image

其中下拉菜单我一直添加到了COM23口,可谓是丧心病狂。

实现逻辑

其实GUI开发很简单,全程写回调函数就行了,界面设计又是图形化拖动,简直没难度有木有。

我这里只有一个下拉菜单,两个按钮,所以有三个回调函数,再加上一个串口接收中断回调函数,一共四个函数。

下拉菜单回调函数

% --- Executes on selection change in ListMenu_COM_Port.
function ListMenu_COM_Port_Callback(hObject, eventdata, handles)
% hObject    handle to ListMenu_COM_Port (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
str = get(hObject, 'String');
val = get(hObject, 'Value');
% Set current data to the selected data set.
switch str{val};
    case 'COM1'
        fprintf('Select COM1\n');
        handles.device_port_current = serial('COM1');
    case 'COM2'
        fprintf('Select COM2\n');
        handles.device_port_current = serial('COM2');
    case 'COM3'
        fprintf('Select COM3\n');
        handles.device_port_current = serial('COM3');
    case 'COM4'
        fprintf('Select COM4\n');
        handles.device_port_current = serial('COM4');
    case 'COM5'
        fprintf('Select COM5\n');
        handles.device_port_current = serial('COM5');
    case 'COM6'
        fprintf('Select COM6\n');
        handles.device_port_current = serial('COM6');
    case 'COM7'
        fprintf('Select COM7\n');
        handles.device_port_current = serial('COM7');
    case 'COM8'
        fprintf('Select COM8\n');
        handles.device_port_current = serial('COM8');
    case 'COM9'
        fprintf('Select COM9\n');
        handles.device_port_current = serial('COM9');
    case 'COM10'
        fprintf('Select COM10\n');
        handles.device_port_current = serial('COM10');
    case 'COM11'
        fprintf('Select COM11\n');
        handles.device_port_current = serial('COM11');
    case 'COM12'
        fprintf('Select COM12\n');
        handles.device_port_current = serial('COM12');
    case 'COM13'
        fprintf('Select COM13\n');
        handles.device_port_current = serial('COM13');
    case 'COM14'
        fprintf('Select COM14\n');
        handles.device_port_current = serial('COM14');
    case 'COM15'
        fprintf('Select COM15\n');
        handles.device_port_current = serial('COM15');
    case 'COM16'
        fprintf('Select COM16\n');
        handles.device_port_current = serial('COM16');
    case 'COM17'
        fprintf('Select COM17\n');
        handles.device_port_current = serial('COM17');
    case 'COM18'
        fprintf('Select COM18\n');
        handles.device_port_current = serial('COM18');
    case 'COM19'
        fprintf('Select COM19\n');
        handles.device_port_current = serial('COM19');
    case 'COM20'
        fprintf('Select COM20\n');
        handles.device_port_current = serial('COM20');
    case 'COM21'
        fprintf('Select COM21\n');
        handles.device_port_current = serial('COM21');
    case 'COM22'
        fprintf('Select COM22\n');
        handles.device_port_current = serial('COM22');
    case 'COM23'
        fprintf('Select COM23\n');
        handles.device_port_current = serial('COM23');

end
guidata(hObject, handles); %保存配置

“打开串口”按钮回调函数

% --- Executes on button press in OpenCom.
function OpenCom_Callback(hObject, eventdata, handles)
% hObject    handle to OpenCom (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
set(handles.device_port_current, 'BaudRate',115200,'Parity','none','stopbits',1,'databits',8,'FlowControl','none'); %配置串口波特率,停止位,校验位,字节长度等
handles.device_port_current.BytesAvailableFcnCount = 1; %配置每接收到一个字节就产生一次中断
handles.device_port_current.BytesAvailableFcnMode = 'byte';
handles.device_port_current.BytesAvailableFcn = { @ReceiveBytesAvailableFcn, handles}; %配置接收回调函数

handles.output = hObject;
guidata(hObject, handles);

fopen(handles.device_port_current); %打开串口
set(handles.OpenCom, 'enable', 'off'); %打开串口后,“打开串口”按钮变灰
set(handles.ListMenu_COM_Port, 'enable', 'off');%打开串口后,禁止使用下拉菜单
set(handles.CloseCom, 'enable', 'on'); %打开串口后,使能“关闭串口”按钮
CurrentPortName = handles.device_port_current.name;
fprintf(CurrentPortName);
fprintf(' is open!\n');

“关闭串口”按钮回调函数

% --- Executes on button press in CloseCom.
function CloseCom_Callback(hObject, eventdata, handles)
% hObject    handle to CloseCom (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
CurrentPortName = handles.device_port_current.name;
fclose(handles.device_port_current); %关闭串口
set(handles.OpenCom, 'enable', 'on');
set(handles.ListMenu_COM_Port, 'enable', 'on');
set(handles.CloseCom, 'enable', 'off');
fprintf(CurrentPortName);
fprintf(' is closed!\n');

串口接收中断函数

%接收回调函数
function ReceiveBytesAvailableFcn(hObject, eventdata, handles)
ReceiveData = fread(handles.device_port_current, 1, 'int8');
persistent data_count;
persistent stm32_data;
if(isempty(data_count))
    data_count = 1;
end
if(isempty(stm32_data))
    stm32_data = 0;
end
stm32_data(data_count) = ReceiveData;
data_count = data_count + 1;
if(stm32_data(1) ~= 125)
    data_count = 1;
    return;
end
if(data_count < 5)
    return;
end
if(stm32_data(4) ~= 120)
    data_count = 1;
    return;
end
persistent h1;
persistent h2;
persistent count;
if(isempty(count))
    count = 0;
end
if(isempty(h1))
    h1 = animatedline('Color','r','LineWidth',2);
end
if(isempty(h2))
    h2 = animatedline('Color','b','LineWidth',2);
end
addpoints(h1,count,stm32_data(2));
addpoints(h2,count,stm32_data(3));
count = count + 1;
%set(handles.axes1,'XLim',[0 count],'YLim', [-1000 1000]);
drawnow limitrate;
data_count = 1;

这里是整个GUI程序最重要的地方,通信协议如下:

帧头 数据1 数据2 帧尾
125 data1 data2 120

接收到数据之后,使用animatedlineaddpoints来动态绘制函数。

初始化函数

初始化函数是MATLAB自动添加好的,我在其中添加了几句:

% --- Executes just before COM is made visible.
function COM_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to COM (see VARARGIN)

% Choose default command line output for COM
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

%初始化按钮
set(handles.OpenCom, 'enable', 'on');
set(handles.ListMenu_COM_Port, 'enable', 'on');
set(handles.CloseCom, 'enable', 'off');
handles.device_port_current = serial('COM1');
% UIWAIT makes COM wait for user response (see UIRESUME)
% uiwait(handles.figure1);

最终效果

最终效果

pinocchiolhw commented 5 years ago

太强了吧