function varargout = serial_1(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @serial_1_OpeningFcn, ...
'gui_OutputFcn', @serial_1_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
function serial_1_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
%% 初始化参数
hasData = false; %表征串口是否接收到数据
isShow = false; %表征是否正在进行数据显示,即是否正在执行函数dataDisp
isStopDisp = false; %表征是否按下了【停止显示】按钮
isHexDisp = false; %表征是否勾选了【十六进制显示】
isHexSend = false; %表征是否勾选了【十六进制发送】
numRec = 0; %接收字符计数
numSend = 0; %发送字符计数
strRec = ''; %已接收的字符串
%% 将上述参数作为应用数据,存入窗口对象内
setappdata(hObject, 'hasData', hasData);
setappdata(hObject, 'strRec', strRec);
setappdata(hObject, 'numRec', numRec);
setappdata(hObject, 'numSend', numSend);
setappdata(hObject, 'isShow', isShow);
setappdata(hObject, 'isStopDisp', isStopDisp);
setappdata(hObject, 'isHexDisp', isHexDisp);
setappdata(hObject, 'isHexSend', isHexSend);
guidata(hObject, handles); %更新handles
function varargout = serial_1_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
function com_Callback(hObject, eventdata, handles)
function com_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function rate_Callback(hObject, eventdata, handles)
function rate_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function jiaoyan_Callback(hObject, eventdata, handles)
function jiaoyan_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function data_bits_Callback(hObject, eventdata, handles)
function data_bits_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function stop_bits_Callback(hObject, eventdata, handles)
function stop_bits_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function start_serial_Callback(hObject, eventdata, handles)
% 【打开/关闭串口】按钮的回调函数
% 打开串口,并初始化相关参数
%% 若按下【打开串口】按钮,打开串口
if get(hObject, 'value') %get(hObject, 'value')值为1,表示按下按钮,用的Toggle Button
%% 获取串口的端口名
com_n = sprintf('com%d', get(handles.com, 'value'));
%% 获取波特率
rates = [300 600 1200 2400 4800 9600 19200 38400 43000 56000 57600 115200];
baud_rate = rates(get(handles.rate, '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_bits, 'value');
%% 获取停止位个数
stop_bits = get(handles.stop_bits, 'value');
%% 创建串口对象
scom = serial(com_n);
%% 配置串口属性,指定其回调函数
set(scom, 'BaudRate', baud_rate, 'Parity', jiaoyan, 'DataBits',...%BaudRate数据位传输的速率;Parity奇偶校验,用于检测传输的错误;DataBits传送数据的位数
data_bits, 'StopBits', stop_bits, 'BytesAvailableFcnCount', 10,...%StopBits数据传送的停止位位数;BytesAvailableFcnCount串口可读取的字节数达到该值后执行BytesAvailableFcn
'BytesAvailableFcnMode', 'byte', 'BytesAvailableFcn', {@bytes, handles},...%BytesAvailableFcnMode指定BytesAvailableFcn基于字节模式还是终止符模式,byte字节模式;BytesAvailableFcn当串口可读取的字节数达到设定值后执行的回调函数
'TimerPeriod', 0.05, 'timerfcn', {@dataDisp, handles});%TimerPeriod定时周期,单位为秒;timerfcn当定时周期到来时执行的回调函数
%% 将串口对象的句柄作为用户数据,存入窗口对象
set(handles.figure1, 'UserData', scom);
%% 尝试打开串口
try
fopen(scom); %打开串口
catch % 若串口打开失败,提示“串口不可获得!”
msgbox('串口不可获得!');
set(hObject, 'value', 0); %弹起本按钮
return;
end
%% 打开串口后,允许串口发送数据,清空接收显示区,点亮串口状态指示灯,
%% 并更改本按钮文本为“关闭串口”
set(handles.period_send, 'Enable', 'on'); %启用【自动发送】按钮
set(handles.manual_send, 'Enable', 'on'); %启用【手动发送】按钮
set(handles.xianshi, 'string', ''); %清空接收显示区,xianshi表示数据接收区
set(hObject, 'String', '关闭串口'); %设置本按钮文本为“关闭串口”
else %若关闭串口
%% 停止并删除定时器
t = timerfind; %查找内存中可见的定时器对象
if ~isempty(t)
stop(t); %停止定时器
delete(t); %从内存中删除定时器
end
%% 停止并删除串口对象
scoms = instrfind; %返回从内存到MATLAB工作空间的串口对象
stopasync(scoms); %停止异步读写操作
fclose(scoms); %断开串口对象和设备的连接
delete(scoms); %从内存清除串口对象
%% 禁用【自动发送】和【手动发送】按钮,熄灭串口状态指示灯
set(handles.period_send, 'Enable', 'off', 'value', 0); %禁用【自动发送】按钮
set(handles.manual_send, 'Enable', 'off'); %禁用【手动发送】按钮
set(hObject, 'String', '打开串口');%设置本按钮文本为“打开串口”
end
function dataDisp(obj, event, handles) %obj为定时器对象的句柄
% 串口的TimerFcn回调函数
% 串口数据显示
%% 获取参数
hasData = getappdata(handles.figure1, 'hasData'); %串口是否收到数据
strRec = getappdata(handles.figure1, 'strRec'); %串口数据的字符串形式,定时显示该数据
numRec = getappdata(handles.figure1, 'numRec'); %串口接收到的数据个数
%% 若串口没有接收到数据,先尝试接收串口数据
if ~hasData
bytes(obj, event, handles); %定义函数bytes,串口的BytesAvailableFcn回调函数
end
%% 若串口有数据,显示串口数据
if hasData
%% 给数据显示模块加互斥锁
%% 在执行显示数据模块时,不接受串口数据,即不执行BytesAvailableFcn回调函数
setappdata(handles.figure1, 'isShow', true);
%% 若要显示的字符串长度超过10000,清空显示区
if length(strRec) > 10000
strRec = '';
setappdata(handles.figure1, 'strRec', strRec);
end
%% 显示数据
set(handles.xianshi, 'string', strRec); %xianshi表示数据接收区
%% 更新接收计数
set(handles.rec,'string', numRec); %rec表示显示接收数据个数的文本框
%% 更新hasData标志,表明串口数据已经显示
setappdata(handles.figure1, 'hasData', false);
%% 给数据显示模块解锁
setappdata(handles.figure1, 'isShow', false);
end
function bytes(obj, ~, handles)
% 串口的BytesAvailableFcn回调函数
% 串口接收数据
%% 获取参数
strRec = getappdata(handles.figure1, 'strRec'); %获取串口要显示的数据
numRec = getappdata(handles.figure1, 'numRec'); %获取串口已接收数据的个数
isStopDisp = getappdata(handles.figure1, 'isStopDisp'); %是否按下了【停止显示】按钮
isHexDisp = getappdata(handles.figure1, 'isHexDisp'); %是否十六进制显示
isShow = getappdata(handles.figure1, 'isShow'); %是否正在执行显示数据操作
%% 若正在执行数据显示操作,暂不接收串口数据
if isShow
return;
end
%% 获取串口可获取的数据个数
n = get(obj, 'BytesAvailable');
%% 若串口有数据,接收所有数据
if n
%% 更新hasData参数,表明串口有数据需要显示
setappdata(handles.figure1, 'hasData', true);
%% 读取串口数据
a = fread(obj, n, 'uchar'); %从设备读进二进制数据
%% 若没有停止显示,将接收到的数据解算出来,准备显示
if ~isStopDisp
%% 根据进制显示的状态,解析数据为要显示的字符�