1 引言
串行通迅较之并行通讯,虽然技术相对复杂一点,但其成本低、操作方便、可靠性高、传输距离长的特点使其应用广泛。它实现了计算机与外部串行设备(如打印机、CRT终端设备、传真机以及远程数据采集设备等)之间的数据传 输。利用VC中的MSComm控件可以快速方便的开发出具有个性化的通信软件以满足不同的要求。该应用程序支持常用的300~115200bps波特率, 能设置校验、数据位和停止位,能接收或发送二进制,十六进制数据或字符,可以任意设定自动发送周期等,使用非常方便。
2 基于VC的串口通信实现途径
Visual C++(version 6.0)的功能十分强大,提供了多种方法来实现计算机间的串口通迅。
2.1 标准通信函数编程
VC++中的标准通信函数_inp、 _inpw、_inpd、_outp、_outpw、_outpd等,可以对串口进行操作,对UART内部寄存器进行读出或写入操作。函数使用较为简单,但串口通迅设置比较复杂,需对硬件电路的结构工作原理十分熟悉,才能进行通信。
2.2 Windows通信API
通信API是 Windows的32位应用程序编程接口,是一系列很复杂的函数,消息和结构,是Windows的一种通信机制。Windows API不用对计算机硬件进行操作,使用范围较广。但其函数体庞大、结构复杂,实际编译完成后的程序不易阅读、继承性差。使用者同时需要对Windows的 结构体系具有一定的认识,有基础的专业人员才能熟练进行编程。
2.3 面向对象编程设计
VC可以调用专门用于串行通信的串口类,可以 根据对象的不同进行功能定做,并可由该类派生出具有特殊功能的类。但串口类只完成对底层串口通讯的封装,在使用的时候仍然要进行大量的编程完善,使用并不便捷。
2.4 调用Active 控件(MSComm)
MSComm(Microsoft CommuNIcation control)控件是Microsoft公司提供的简化Windows下串行接口收发数据的简便方法。它包装了类的成员函数可以访问组件接口的属性,形 成接口类,提供了一系列标准通讯命令的使用接口,不需要对硬件进行操作,参数属性设置便捷。 MSComm控件在多种开发平台中都可方便调用,运行稳定,串口通迅操作相当简便。
3 通讯程序的开发
3.1 在vc中新建工程并添加控件
如图1所示:

3.2 MSComm处理数据的方法—事件驱动法:
MSComm处理数据是通过检查MSComm控件的CommEvent属性的值来判断所发生的事件或者错误。当有事件或错误发生的时候,事件OnComm由MSComm控件解发,被执行程序捕捉后,依据CommEvent属性的 值,系统就可以知道如端口状态改变,新字符到达,发生错误等所发生的事件。通常所说的查询法,同样是通过检查CommEvent属性的值来确定事件和发生 的错误。只不过后者是在执行一段程序,经过一定时间后才检查CommEvent属性的值从而做出响应,而前者是即时查阅即时处理,二者只是程序设计上的不 同无本质区别。事件驱动法的优点是程序响应及时、可靠性高、应用广泛。
3.3 MSComm控件属性:
该控件有很多属性,可通过它的属 性窗口或程序进行设置。
CommPort:设置串口号,类型 short:1-comm1 2-comm2;
Settings:设置串 口通讯参数,类型CString;
PortOpen:设置或返回串口状态,类型BOOL:TURE-打开FALSE-关闭;
InputMode: 设置从接收缓冲区读取数据的格式,类型 long:0-文本1-二进制;
Input:从接收缓冲区读取数据类型VARIANT;
InBufferSize: 接收缓冲区的大小,类型:short;
Output:向发送缓冲区写入数据,类型:VARIANT;
OutBufferSize:发送缓 冲区的大小,类型:short;
CommEvent:串口事件,类型:short;
RThreshold:设置并返回的要接收的字符数, 类型: short;
SThreshold:设置并返回传输缓冲区中允许的最小字符数,类型:short。
3.4 主程序设计
程序的流程如图2和图3所示:

a为控件Combo Box分别添加函数:
void CMyDlg::OnSelSerialport()
{
int nRow=m_Serialport.GetCurSel();
//获取选项改变的消息
if (nRow!=CB_ERR)
{m_Serialport.GetLBText(nIndex,m_StrSerial);}
// 获取所选项内容放入相应变量
}
b为消息m_OnComm添加函数Oncomm,并添加程序代码如下:
void CMyDlg::OnComm()
{
m_Oncomm.SetCommPort(atoi(m_StrSerial));
// 强制类型转换,响应参数设置
m_Oncomm.SetSettings("atoi(m_StrBaud),m_StrChcek,atoi(m_StrData),atoi(m_StrStop)");
m_Oncomm.SetInBufferSize(atoi(m_StrInbuffersize));
m_Oncomm.SetOutBufferSize(atoi(m_StrOutbuffersize));
m_Oncomm.SetRThreshold(1);
// 接收缓冲区有1或1个以上字符时触发接收Oncomm事件
m_Oncomm.SetInputLen(0);
// 0:全部读取数据缓冲区内容
VARIANT Strvari;
COleSafeArray Strsafearray;
long Strlen,i;
BYTE Strrx[4096];
CString strtemp;
if (m_Oncomm.GetCommEvent()==2)
// 事件值等于2表示接收区内有字符
{
Strvari =m_Oncomm.GetInput();
//将缓冲区数据转换成VARIANT型变量
Strsafearray = Strvari;
//VARIANT型变量转变成COleSafeArray型变量
Strlen= Strsafearray.GetOneDimSize();
// 获得数据长度
for(i=0;i
Strsafearray.GetElement(&i,Strrx+i);
// 转换为位型数组
for(i=0;i
{
BYTE Strrx=*(char*)(Strrx+i);
// 转化为字符数组
strtemp.Format("%c",bt);
// 将字符送入临时变量strtemp中存放
m_Receivedata+=strtemp;
//送入接收框显示
}
}
UpdateData(FALSE);
//更新编辑框的内容显示
}
c范围命令处理机制:
MFC中消息是通过一种消息映 射机制来处理的。宏命令为消息和处理函数构建映射,同时分析处理映射过程,使得函数功能得以实现。
在添加Radio Button控件程序代码的时候,可以遵循传统的方法逐一增加函数然,写入代码。但当同样类型的控件数目较多,功能相似并且每个功能函数的程序代码很少的时候,这样做就使得程序的结构不够紧凑、工作效率低下。所以可利用范围命令处理机制统一对相关按钮命令进行管理,即相关命令按钮的消息可以在同一消息处理 函数中进行操作。同时添加相应的更新消息处理函数及时检测并更新按钮的状态,这样不但结构紧凑而且维护特别方便。
范围命令处理机制只能通过手工注 册方式来完成(Class Wizard不支持),如下:
(1) 将按钮ID设置成连续值.:IDC_TYPE_0, IDC_TYPE_1, IDC_TYPE_2;ID值必须连续。
(2) 在.h文件类定义中加入消息处理函数的函数原型(函数声明)
protected:
UINT iChoose;
// 定义类中数据成员
// Generated message-map functions
//{{AFX_MSG(CMyDlg)
afx_msg void OnType(UINT nID);
//消息处理函数声明
afx_msg void OnUpdateType(CCmdUI* pUpdate);
//更新消息函数声明
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
UINT 型参数nID,提供当前命令的ID值,是处理单一命令的消息处理函数所没有的。
(3) 在.cpp文件类的消息映射表中加入相应的消息映射入口项。
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_COMMAND_RANGE(ID_ IDC_TYPE_0, IDC_TYPE_2,OnType);
ON_UPDATE_COMMAND_UI_RANGE(IDC_TYPE_0, IDC_TYPE_2,OnUpdateType);
//}}AFX_MSG_MAP
END_MESSAGE_MAP( )
宏ON_COMMAND_RANGE 把一定范围内的命令ID 映射到相应的函数上来实现从命令消息IDC_TYPE_0到 IDC_TYPE_2都由OnType一个消息函数处理.宏ON_UPDATE_COMMAND_UI_RANGE把该范围内的用户接口的更新命令消息映射到相应的函数上实现更新消息。
(4) 在类的实现文件中加入消息处理函数及更新函数的函数体。
void CMyDlg::OnType(UINT nID)
{
iChoose=nID- IDC_TYPE_0;
switch(iChoose)
{
case 0: m_Oncomm.SetInputMode(1); break;
// 传输二进制数据
case 1: m_Oncomm.SetInputMode(0); break;
// 以文本形式传输十六进制数据
case 2: m_Oncomm.SetInputMode(0); break;
// 传输文本数据




