1.简介
之前在烽火集团实习的时候,开发串口通信程序用的都是纯C++。感觉串口程序开发很考验人的逻辑思考能力。不过,现在好了,科研工作中,一切已存在的“利器”都可以用来为自己的“idea”服务。在串口程序开发过程中,有两个很得力的助手——“CserialPort”和“MSCommon”。这里,仅尝试了利用MSCommon空间进行最基本的串口助手开发,也是受益匪浅。
2.一步一步开发程序
1.利用先前点击打开链接介绍的加载MSCommon控件的方法设计对话框面板,如下图所示:
2.改变各控件的ID号以及添加相应的空间变量:
3.初始化串口,设置MSComm控件的属性
OOL CSerialCommDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
///初始化代码///
m_ctrlComm.put_CommPort(1);//选择COM1
m_ctrlComm.put_InputMode(1); //设置输入方式为二进制方式
m_ctrlComm.put_InBufferSize(1024);//设置输入缓冲区大小
m_ctrlComm.put_OutBufferSize(512);//设置输出缓冲区大小
//通信协议:波特率9600 无校验 传输位数8 停止位1
m_ctrlComm.put_Settings(_T("9600,n,8,1"));//提示const char* 与 LPCTSTR不兼容
//打开串口
if (!m_ctrlComm.get_PortOpen())
m_ctrlComm.put_PortOpen(TRUE);
m_ctrlComm.put_RThreshold(1);//每当串口缓冲区又多于或等于1个字符的时候将
//引发一个接收数据的OnCommon事件
m_ctrlComm.put_InputLen(0); //设置当前接受区数据长度为0
m_ctrlComm.get_Input(); //先预读缓冲区以清除残留数据
return TRUE;
}
串口初始化部分其实就是三个过程:选择串口及开辟缓存区、设定通信协议、打开串口并监控串口线程消息。
4.添加串口消息处理函数OnComm()
void CSerialCommDlg::Oncomm()
{//接收串口数据并传递到显示窗口
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len, k;
BYTE rxdata[2048];
CString strtemp;
if (m_ctrlComm.get_CommEvent() == 2 ) //事件值为2表示接受缓冲区内有字符
{
variant_inp = m_ctrlComm.get_Input(); //读缓冲区
safearray_inp = variant_inp; //数据类型转换
len = safearray_inp.GetOneDimSize(); //得到有效数据长度
for (k = 0; k < len; k++)
safearray_inp.GetElement(&k, rxdata + k); //转换为BYTE型数组
for (k = 0; k < len; k++)
{
BYTE bt = *(char*)(rxdata + k); //字符型
strtemp.Format(_T("%c"),bt); //将字符送入临时变量中保存
//const char 与 const wchar_t不兼容
m_strEditRxData += strtemp;
}
}
UpdateData(FALSE);
}
MSComm控件一般就是用事件驱动方式从串口接收数据,也就是消息处理,当串口有事件发生时,程序调用消息消息函数来处理数据。该函数代码的主要任务是从串口接收数据并显示在接收编辑框中。
在这里不得不说的是我们会经常碰到的程序错误:“ const char* 与LPCTCTR类型不匹配 ”、“ const char 和 const wchar_t 类型不匹配”。在这里,我们利用“-T()”函数处理就好了。
5.发送消息设置
void CSerialCommDlg::OnClickedButtonManualsend()
{
UpdateData(TRUE);
m_ctrlComm.put_Output(COleVariant(m_strEditTxData));//发送数据
}
首先通过更新命令,实时更新成员变量值,然后利用串口对象将该数据发送出去。
6.双串口配置
利用虚拟串口软件Virtual Serial Ports Driver XP设置一对串口,如下图所示:
7.实验结果:
3.心得感受
1.利用先前点击打开链接介绍的加载MSCommon控件的方法设计对话框面板,如下图所示:
2.改变各控件的ID号以及添加相应的空间变量:
3.初始化串口,设置MSComm控件的属性
OOL CSerialCommDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
///初始化代码///
m_ctrlComm.put_CommPort(1);//选择COM1
m_ctrlComm.put_InputMode(1); //设置输入方式为二进制方式
m_ctrlComm.put_InBufferSize(1024);//设置输入缓冲区大小
m_ctrlComm.put_OutBufferSize(512);//设置输出缓冲区大小
//通信协议:波特率9600 无校验 传输位数8 停止位1
m_ctrlComm.put_Settings(_T("9600,n,8,1"));//提示const char* 与 LPCTSTR不兼容
//打开串口
if (!m_ctrlComm.get_PortOpen())
m_ctrlComm.put_PortOpen(TRUE);
m_ctrlComm.put_RThreshold(1);//每当串口缓冲区又多于或等于1个字符的时候将
//引发一个接收数据的OnCommon事件
m_ctrlComm.put_InputLen(0); //设置当前接受区数据长度为0
m_ctrlComm.get_Input(); //先预读缓冲区以清除残留数据
return TRUE;
}
串口初始化部分其实就是三个过程:选择串口及开辟缓存区、设定通信协议、打开串口并监控串口线程消息。
4.添加串口消息处理函数OnComm()
void CSerialCommDlg::Oncomm()
{//接收串口数据并传递到显示窗口
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len, k;
BYTE rxdata[2048];
CString strtemp;
if (m_ctrlComm.get_CommEvent() == 2 ) //事件值为2表示接受缓冲区内有字符
{
variant_inp = m_ctrlComm.get_Input(); //读缓冲区
safearray_inp = variant_inp; //数据类型转换
len = safearray_inp.GetOneDimSize(); //得到有效数据长度
for (k = 0; k < len; k++)
safearray_inp.GetElement(&k, rxdata + k); //转换为BYTE型数组
for (k = 0; k < len; k++)
{
BYTE bt = *(char*)(rxdata + k); //字符型
strtemp.Format(_T("%c"),bt); //将字符送入临时变量中保存
//const char 与 const wchar_t不兼容
m_strEditRxData += strtemp;
}
}
UpdateData(FALSE);
}
MSComm控件一般就是用事件驱动方式从串口接收数据,也就是消息处理,当串口有事件发生时,程序调用消息消息函数来处理数据。该函数代码的主要任务是从串口接收数据并显示在接收编辑框中。
在这里不得不说的是我们会经常碰到的程序错误:“ const char* 与LPCTCTR类型不匹配 ”、“ const char 和 const wchar_t 类型不匹配”。在这里,我们利用“-T()”函数处理就好了。
5.发送消息设置
void CSerialCommDlg::OnClickedButtonManualsend()
{
UpdateData(TRUE);
m_ctrlComm.put_Output(COleVariant(m_strEditTxData));//发送数据
}
首先通过更新命令,实时更新成员变量值,然后利用串口对象将该数据发送出去。
6.双串口配置
利用虚拟串口软件Virtual Serial Ports Driver XP设置一对串口,如下图所示:
利用MSComm进行串口程序开发大大提高了编程效率!关键在于串口消息的实时监控,并设定适当的消息处理函数。最典型的就是获得串口接收到的数据(当然了也包括这些数据的算法处理)。