说来惭愧,自己看别人的API说明,想要鼓捣出一个串口通讯界面,结果失败了,最后还是看的教程。。。。
使用MFC进行串口通讯的上位机的软件编程,教程网址如下,十分简单。
http://download.youkuaiyun.com/download/peter_jjh/9938549
1. 程序框架及代码分析:
1.1 程序框架:
(1) 初始化界面
(2) 打开串口 (读取串口号,初始化串口参数(波特率、校验位、数据位等),若串口已经打开则关闭串口)
(3) 发送数据 (更新控件状态,进入MSComm事件驱动函数,读缓冲区,数据转换,更新编辑框成员函数,更新编辑框内容)
(4) 退出界面 (检测串口是否开启,若开启则关闭串口,再进行退出)
1.2 关键代码分析:
(1)初始化界面:除却MFC自动生成的界面初始化代码,这里的关键在于初始化参数,在BOOL xxxxx:OnInitDialog()中添加部分代码
// 串口选择组合框
CString str;
int i;
for (i = 0; i<30; i++)
{
str.Format(_T("com %d"), i + 1);
m_ComNum.InsertString(i, str);
}
m_ComNum.SetCurSel(0);//预置COM口
//波特率选择组合框
CString str1[] = { _T("300"), _T("600"), _T("1200"), _T("2400"), _T("4800"), _T("9600"),
_T("19200"), _T("38400"), _T("43000"), _T("56000"), _T("57600"), _T("115200") };
for (int i = 0; i<12; i++) //使用AddString会无序排列,在Dialog中把这一ComboBox的Sorted改为False即可
{
int judge_tf = m_BaudRate.AddString(str1[i]);
if ((judge_tf == CB_ERR) || (judge_tf == CB_ERRSPACE))
MessageBox(_T("build baud error!"));
}
/*for (int i = 0; i<12; i++) //更换为使用InsertString
{
m_BaudRate.InsertString(i, str1[i]);
}*/
m_BaudRate.SetCurSel(5);//预置波特率为"9600"
(2) 打开串口:
void CComCommunicateDlg::OnBnClickedButtonOpen() //打开串口按钮
{
CString str, str1, n; //定义字符串
GetDlgItemText(IDC_BUTTON_OPEN, str);
CWnd *h1;
h1 = GetDlgItem(IDC_BUTTON_OPEN); //指向控件的caption
if (!m_mscom.get_PortOpen())
{
m_BaudRate.GetLBText(m_BaudRate.GetCurSel(), str1);//取得所选的字符串,并存放在str1里面
str1 = str1 + ',' + 'n' + ',' + '8' + ',' + '1'; //这句话很关键
m_mscom.put_CommPort((m_ComNum.GetCurSel() + 1)); //选择串口
m_mscom.put_InputMode(1); //设置输入方式为二进制方式
m_mscom.put_Settings(str1); //波特率为(波特率组Á合框)无校验,8数据位,1个停止位
m_mscom.put_InputLen(1024); //设置当前接收区数据长度为1024
m_mscom.put_RThreshold(1); //缓冲区一个字符引发事件
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); //改变按钮名称为打开串口
}
}
}
(3) 发送数据
void CComCommunicateDlg::OnBnClickedButtonSend()
{
UpdateData(true); //将控件的状态传给其关联的变量
m_mscom.put_Output(COleVariant(m_EditSend));//把发送编辑框的数据发送出去,跳转到OnCommMscomm1中
}
void CComCommunicateDlg::OnCommMscomm1() //事件驱动
{
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);
}
}
(4) 退出界面
void CComCommunicateDlg::OnBnClickedButtonClose()
{
if (m_mscom.get_PortOpen())
m_mscom.put_PortOpen(false); //先关闭串口再退出,否则串口一直被占用
CDialogEx::OnCancel();
}
2. 遇到的问题:
2.1 缺少Microsoft Communications Control 控件
MSComm 控件是一个串行通讯控件,作用为替程序员串口通讯编程节省时间,有关于MSComm空间的介绍可以参考这篇博客:串口通信-MSComm控件使用详解
这一问题的解决方式很简单,下载压缩包解压复制就可以,下载网址:
http://download.youkuaiyun.com/download/peter_jjh/9937696
1.解压缩压缩包内包含3个文件:
MSCOMM.SRG
MSCOMM32.DEP
mscomm32.ocx
2.复制文件到指定路径:
32位的系统,文件复制到C:\WINDOWS\SYSTEM32目录下;
64位的系统,文件复制到C:\Windows\SysWOW64目录下。
3.win+r输入cmd打开cmd窗口,在cmd中输入:
32位:regsvr32 C:\Windows\System32\mscomm32.ocx
64位:regsvr32 C:\Windows\SysWOW64\mscomm32.ocx
如果失败,请以管理员身份打开cmd,再进行步骤3。
2.2 error LNK2001: 无法解析的外部符号
在进行编译时,出现如上错误的原因有两个,分别是
(1)部分函数声明了却未定义
(2)部分动态链接库的编译方式未统一
针对第一种错误,只需要找到未定义的函数,注释掉或者删除就可以了,在我的测试程序中,这类问题主要出现在BoxEditor中,可能是由于我的误操作导致,添加了OnEnChangeEditRev函数,该OnEnChange***函数针对的是窗口中数据内容变化的响应函数,但是实际没有实现这个函数,所以导致了错误。
参考:http://tieba.baidu.com/p/2049736254
针对第二种错误,需要将 MFC使用 和 运行库 都进行统一。注意先将右上角的配置选为 所有配置, 具体选择如下:
参考:http://www.360doc.com/content/11/1031/14/4190063_160548608.shtml
附录:
在研究如何自动读取可用的串口号时,发现了一个十分完整的开源的串口通信项目。较为复杂,慢慢研究,该项目的地址如下:
结语:
本文存在诸多不足,希望大家多多指教!