版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
由于项目需要,最近在写一个简单的串口通信,基于MFC框架,写完之后特此回顾记录一下学习的过程:
串口通信主体框架
(1) 初始化界面(自动获取全部可用串口)
(2) 打开串口 (读取串口号,初始化串口参数(波特率、校验位、数据位等),若串口已经打开则关闭串口)
(3) 发送数据 (更新控件状态,进入MSComm事件驱动函数,读缓冲区,数据转换,更新编辑框成员函数,更新编辑框内容)
(4) 退出界面 (检测串口是否开启,若开启则关闭串口,再进行退出)
- 在MFC中建立对话框的基础上,添加两个控件CComBox和Button控件,CComBox负责扫描所有可用串口,Button用于打开和关闭串口,然后右键鼠标,点击插入ActiveX控件,选择控件,出现如控件(电话图标),则表示插入控件成功
- 给控件添加变量,变量名为m_mscom,之后项目中会出现对应.h和.cpp文件
- 加Eidit Control控件用于接受消息,绑定变量m_EditReveive,然后添加串口控件事件处理处理程序
点击添加编辑按钮(第一次添加会是添加编辑,再次添加的话会是编辑代码按钮),会出现如下代码:
void CCommTestDlg::OnCommMscomm2()
{
// TODO: 在此处添加消息处理程序代码
}
添加自动接收代码(项目中通信协议是测试结果自动上传),并直接显示在接收控件中,代码如下:
-
-
void CComCommunicateDlg::OnCommMscomm2()
//事件驱动
-
{
-
if (m_mscom.get_CommEvent() ==
2)
//事件值为2表示接收缓冲区内有字符
-
{
-
char str[
1024] = {
0 };
-
long k;
-
VARIANT InputData = m_mscom.get_Input();
//读缓冲区
-
COleSafeArray fs;
-
fs = InputData;
//VARIANT型变量转换为COleSafeArray型变量
-
for (k =
0; k<fs.GetOneDimSize(); k++)
-
fs.GetElement(&k, str + k);
//转换为BYTE型数组
-
-
m_EditReveive += str;
// 接收到编辑框里面
-
//SetTimer(1,10,NULL); //延时10ms
-
UpdateData(
false);
//更新到控件
-
}
-
}
-
-
- 由于项目比较简单,就将串口参数写死了,若想修改参数可以在源代码里修改,打开/关闭串口代码实现如下:
-
-
void CComCommunicateDlg::OnBnClickedButtonOpen()
//打开串口按钮
-
{
-
CString str, n;
//定义字符串
-
GetDlgItemText(IDC_BUTTON_OPEN, str);
//获取给定控件的文本
-
CWnd *h1;
-
h1 = GetDlgItem(IDC_BUTTON_OPEN);
//指向控件的caption
-
-
if (!m_mscom.get_PortOpen())
-
{
-
try
-
{
-
m_mscom.put_CommPort(num);
//选择串口
-
}
-
catch (CException* e)
-
{
-
m_mscom.put_OutBufferCount(
0);
-
-
AfxMessageBox(L
"打开串口 失败");
-
return;
-
}
-
m_mscom.put_InputMode(
1);
//设置输入方式为二进制方式
-
m_mscom.put_Settings(_T(
"115200,n,8,1"));
//设置串口参数,波特率,无奇偶校验,位停止位,位数据位
-
m_mscom.put_InputLen(
1024);
//设置当前接收区数据长度为1024
-
m_mscom.put_RThreshold(
1);
//接收缓冲区有1个及1个以上字符时,触发OnComm事件
-
m_mscom.put_RTSEnable(
1);
//设置RT允许
-
-
-
m_mscom.put_PortOpen(
true);
//打开串口
-
-
if (m_mscom.get_PortOpen())
-
{
-
str = _T(
"关闭串口");
-
UpdateData(
true);
-
h1->SetWindowText(str);
//改变按钮名称为‘’关闭串口”
-
}
-
}
-
else
-
{
-
m_mscom.put_PortOpen(
false);
//关闭串口
-
if (str != _T(
"打开串口"))
-
{
-
str = _T(
"打开串口");
-
UpdateData(
true);
//将控件的状态传给其关联的变量
-
h1->SetWindowText(str);
//改变按钮名称为打开串口
-
}
-
}
-
}
-
-
- 最后是选择串口下拉框,起初用的比较笨的方法,添加在ComBox添加1-8个串口,然后到设备管理器中查看串口信息,再打开串口。后来改用自动扫描已打开端口号,其功能封装在GetCom()函数里,在初始化的时候运行即可。代码如下
-
void CComCommunicateDlg::GetCom()
-
{
-
//程序启动时获取全部可用串口
-
HANDLE hCom;
-
int i, k;
-
CString str;
-
BOOL flag;
-
-
((CComboBox *)GetDlgItem(IDC_COMBO1))->ResetContent();
-
flag =
FALSE;
-
num =
0;
-
for (i =
1; i <=
16; i++)
-
{
//此程序支持16个串口
-
str.Format(L
"\\\\.\\COM%d", i);
-
hCom = CreateFile(str,
0,
0,
0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
0);
-
if (INVALID_HANDLE_VALUE != hCom)
-
{
//能打开该串口,则添加该串口
-
CloseHandle(hCom);
-
str = str.Mid(
4);
-
((CComboBox *)GetDlgItem(IDC_COMBO1))->AddString(str);
-
if (flag ==
FALSE)
-
{
-
flag =
TRUE;
-
num = i;
-
}
-
}
-
}
-
i = ((CComboBox *)GetDlgItem(IDC_COMBO1))->GetCount();
-
if (i ==
0)
-
{
//若找不到可用串口则禁用“打开串口”功能
-
((CComboBox *)GetDlgItem(IDC_COMBO1))->EnableWindow(
FALSE);
-
-
}
-
else
-
{
-
k = ((CComboBox *)GetDlgItem((IDC_COMBO1)))->GetCount();
-
((CComboBox *)GetDlgItem(IDC_COMBO1))->SetCurSel(k -
1);
-
//mCom.BindCommPort(num);
-
}
-
}
- 最终软件运行页面,串口通信消息的发送暂时没有用到,以后用到了再进行记录