1、在众多网友的支持下,串口调试助手从 2001 年 5 月 21 日发布至今,短短一个月,在全国各地累计下载量近 5000 人次,在近 200 多个电子邮件中,20 多人提供了使用测试意见,更有 50 多位朋友提出要串口调试助手的源代码,为了答谢谢朋友们的支持,公开推出我最初用 VC 控件 MSComm 编写串口通信程序的源代码,并写出详细的编程过程,姑且叫串口调试助手源程序 V1.0 或 VC 串口通讯源程序吧,我相信,如果你用 VC 编程,那么有了这个代码,就可以轻而易举地完成串口编程任务了。(也许本文过于详细,高手就不用看)开始吧:1.建立项目:打开 VC6.0,建立一个基于对话框的 MF
2、C 应用程序 SCommTest(与我源代码一致,等会你会方便一点);2.在项目中插入 MSComm 控件 选择 Project 菜单下 Add To Project 子菜单中的 Components and Controls选项,在弹出的对话框中双击 Registered ActiveX Controls 项(稍等一会,这个过程较慢),则所有注册过的 ActiveX 控件出现在列表框中。 选择 Microsoft Communications Control, version 6.0,单击 Insert 按钮将它插入到我们的 Project 中来,接受缺省的选项。(如果你在控件列表中看不到
3、Microsoft Communications Control, version 6.0,那可能是你在安装 VC6 时没有把 ActiveX 一项选上,重新安装 VC6,选上 ActiveX 就可以了),这时在 ClassView 视窗中就可以看到 CMSComm 类了,(注意:此类在 ClassWizard 中看不到,重构 clw 文件也一样),并且在控件工具栏 Controls 中出现了电话图标(如图 1 所示),现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。3.利用 ClassWizard 定义 CMSComm 类控制对象 打开 ClassWizardMemb
4、er Viariables 选项卡,选择CSCommTestDlg 类,为 IDC_MSCOMM1 添加控制变量:m_ctrlComm,这时你可以看一看,在对话框头文件中自动加入了/AFX_INCLUDES() #include “mscomm.h“ /AFX_INCLUDES (这时运行程序,如果有错,那就再从头开始)。4.在对话框中添加控件 向主对话框中添加两个编辑框,一个用于接收显示数据 ID 为IDC_EDIT_RXDATA,另一个用于输入发送数据,ID 为 IDC_EDIT_TXDATA,再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其 ID 设为 IDC_BUTTO
5、N_MANUALSEND。别忘记了将接收编辑框的PropertiesStyles 中把 Miltiline 和 Vertical Scroll 属性选上,发送编辑框若你想输入多行文字,也可选上 Miltiline。再打开 ClassWizardMember Viariables 选项卡,选择 CSCommTestDlg 类, 为 IDC_EDIT_RXDATA 添加CString 变量 m_strRXData, 为 IDC_EDIT_TXDATA 添加 CString 变量 m_strTXData。说明: m_strRXData和 m_strTXData 分别用来放入接收和发送的字符数据。休息
6、一会吧?我们天天与电脑打交道,要注意保重,我现在在单杠上做引体向上可以来 40 次,可我都 32 了,佩服吗? 。好了,再接着来,下面是关键了:5.添加串口事件消息处理函数 OnComm() 打开 ClassWizardMessage Maps,选择类 CSCommTestDlg,选择 IDC_MSCOMM1,双击消息 OnComm,将弹出的对话框中将函数名改为 OnComm,(好记而已)OK。这个函数是用来处理串口消息事件的,如每当串口接收到数据,就会产生一个串口接收数据缓冲区中有字符的消息事件,我们刚才添加的函数就会执行,我们在 OnComm()函数加入相应的处理代码就能实现自已想要的功能
7、了。请你在函数中加入如下代码:void CSCommTestDlg:OnComm() / TODO: Add your control notification handler code hereVARIANT variant_inp;COleSafeArray safearray_inp;LONG len,k;BYTE rxdata2048; /设置 BYTE 数组 An 8-bit integerthat is not signed.CString strtemp;if(m_ctrlComm.GetCommEvent()=2) /事件值为 2 表示接收缓冲区内有字符 /以下你可以根据自己的
8、通信协议加入处理代码variant_inp=m_ctrlComm.GetInput(); /读缓冲区safearray_inp=variant_inp; /VARIANT 型变量转换为 ColeSafeArray 型变量len=safearray_inp.GetOneDimSize(); /得到有效数据长度for(k=0;kMessage Maps,选择类 CSCommTestDlg,选择 IDC_BUTTON_MANUALSEND,双击 BN_CLICKED 添加OnButtonManualsend()函数,并在函数中添加如下代码:void CSCommTestDlg:OnButtonMan
9、ualsend() / TODO: Add your control notification handler code hereUpdateData(TRUE); /读取编辑框内容m_ctrlComm.SetOutput(COleVariant(m_strTXData);/发送数据运行程序,在发送编辑框中随意输入点什么,单击发送按钮,啊!看看,在另一端的串口调试助手(或别的调试工具)接收框里出现了什么。如果你真是初次涉猎串口编程,又一次成功,那该说声谢谢我了,因为我第一次做串口程序时可费劲了,那时网上的资料也不好找。开开玩笑,谢谢你的支持,有什么好东西别忘了给我寄一份。最后说明一下,由于用到
10、 VC 控件,在没有安装 VC 的计算机上运行时要从 VC 中把mscomm32.ocx、msvcrt.dll、mfc42.dll 拷到 Windows 目录下的 System 子目录中(win2000 为System32)并再进行注册设置,请参考如何手工注册 MSComm 控件。龚建伟 2001.6.208.发送十六进制字符在主对话框中加入一个复选接钮,ID 为 IDC_CHECK_HEXSEND Caption: 十六进制发送,再利用ClassWizard 为其添加控制变量:m_ctrlHexSend;在 ClassView 中为 SCommTestDlg 类添加以下两个 PUBLIC 成
11、员函数,并输入相应代码;/由于这个转换函数的格式限制,在发送框中的十六制字符应该每两个字符之间插入一个空隔/如:A1 23 45 0B 00 29/CByteArray 是一个动态字节数组,可参看 MSDN 帮助int CSCommTestDlg:String2Hex(CString str, CByteArray int hexdatalen=0;int len=str.GetLength();senddata.SetSize(len/2);for(int i=0;i=len)break;lstr=stri;hexdata=ConvertHexChar(hstr);lowhexdata=Co
12、nvertHexChar(lstr);if(hexdata=16)|(lowhexdata=16)break;else hexdata=hexdata*16+lowhexdata;i+;senddatahexdatalen=(char)hexdata;hexdatalen+;senddata.SetSize(hexdatalen);return hexdatalen;/这是一个将字符转换为相应的十六进制值的函数/好多 C 语言书上都可以找到/功能:若是在 0-F 之间的字符,则转换为相应的十六进制字符,否则返回-1char CSCommTestDlg:ConvertHexChar(char c
13、h) if(ch=0)else return (-1);再将 CSCommTestDlg:OnButtonManualsend()修改成以下形式:void CSCommTestDlg:OnButtonManualsend() / TODO: Add your control notification handler code hereUpdateData(TRUE); /读取编辑框内容if(m_ctrlHexSend.GetCheck()CByteArray hexdata;int len=String2Hex(m_strTXData,hexdata); /此处返回的 len 可以用于计算发送
14、了多少个十六进制数m_ctrlComm.SetOutput(COleVariant(hexdata); /发送十六进制数据else m_ctrlComm.SetOutput(COleVariant(m_strTXData);/发送 ASCII 字符数据现在,你先将串口线接好并打开串口调试助手 V2.1,选上以十六制显示,设置好相应串口,然后运行我们这个程序,在发送框中输入 00 01 02 03 A1 CC 等十六进制字符,并选上以十六进制发送,单击手动发送,在串口调试助手的接收框中应该可以看到 00 01 02 03 A1 CC 了。9.在接收框中以十六进制显示这就容易多了: 在主对话框中加
15、入一个复选接钮,IDC_CHECK_HEXDISPLAY Caption: 十六进制显示,再利用 ClassWizard 为其添加控制变量:m_ctrlHexDiaplay。 然后修改 CSCommTestDlg:OnComm()函数:void CSCommTestDlg:OnComm() / TODO: Add your control notification handler code hereVARIANT variant_inp;COleSafeArray safearray_inp;LONG len,k;BYTE rxdata2048; /设置 BYTE 数组 An 8-bit in
16、tegerthat is not signed.CString strtemp;if(m_ctrlComm.GetCommEvent()=2) /事件值为 2 表示接收缓冲区内有字符variant_inp=m_ctrlComm.GetInput(); /读缓冲区safearray_inp=variant_inp; /VARIANT 型变量转换为 ColeSafeArray 型变量len=safearray_inp.GetOneDimSize(); /得到有效数据长度for(k=0;klen;k+)safearray_inp.GetElement(/转换为 BYTE 型数组for(k=0;kle
17、n;k+) /将数组转换为 Cstring 型变量BYTE bt=*(char*)(rxdata+k); /字符型if(m_ctrlHexDisplay.GetCheck()strtemp.Format(“%02X “,bt); /将字符以十六进制方式送入临时变量 strtemp 存放,注意这里加入一个空隔else strtemp.Format(“%c“,bt); /将字符送入临时变量 strtemp 存放m_strRXData+=strtemp; /加入接收编辑框对应字符串 UpdateData(FALSE); /更新编辑框内容测试:在串口调试助手发送框中输入 00 01 02 03 A1
18、CC 等十六进制字符,并选上以十六进制发送,单击手动发送,在本程序运行后选上以十六进制显示,在串口调试助手中单击手动发送或自动发送,则在本程序的接收框中应该可以看到 00 01 02 03 A1 CC 了。10.如何设置自动发送最简单的设定自动发送周期是用 SetTimer()函数,这在数据采集中很有用,在控制中指令的传送也可能用到定时发送。方法是:在 ClassWizard 中选上 MessageMap 卡,然后在 Objects IDs 选中 CSCommTestDlg 类,再在Messages 框中选上 WM_TIMER 消息,单击 ADD_FUNCTION 加入 void CSComm
19、TestDlg:OnTimer(UINT nIDEvent) 函数,这个函数是放入“时间到”后要处理的代码:void CSCommTestDlg:OnTimer(UINT nIDEvent) / TODO: Add your message handler code here and/or call defaultOnButtonManualsend();CDialog:OnTimer(nIDEvent);再在在主对话框中加入一个复选接钮,ID 为 IDC_CHECK_AUTOSEND Caption: 自动发送(周期 1 秒),再利用 ClassWizard 为其添加 BN_CLICK 消息
20、处理函数 void CSCommTestDlg:OnCheckAutosend():void CSCommTestDlg:OnCheckAutosend() / TODO: Add your control notification handler code herem_bAutoSend=!m_bAutoSend;if(m_bAutoSend)SetTimer(1,1000,NULL);/时间为 1000 毫秒elseKillTimer(1); /取消定时其中:m_bAutoSend 为 BOOL 型变量,在 CLASSVIEW 中为 CSCommTestDlg 类加入,并在构造函数中初始化
21、:m_bAutoSen=FALSE;现在可以运行程序测试了。11.什么是 VARIANT 数据类型?如何使用 VARIANT 数据类型?不知如何使用 VARIANT 数据类型, 有不少朋友对 VARIANT 这个新的数据类型大感头疼。SetOutput()函数中 需要的 VARIANT 参数还可以使用 COleVariant 类的构造函数简单生成,现在 GetInput()函数的返回值也成了 VARIANT 类型,那么如何从返回的值中提取有用的内容。 VARIANT 及由之而派生出的COleVariant 类主要用于在 OLE 自动化中传递数据。实际上 VARIANT 也只不过是一个新定义的结
22、构罢了,它的主要成员包括一个联合体及一个变量。该联合体由各种类型的数据成员构成, 而该变量则用来指明联合体中目前起作用的数据类型。我们所关心的接收到的数据就存储在该联合体的某个数据成员中。 该联合体中包含的数据类型很多,从一些简单的变量到非常复杂的数组和指针。由于通过串口接收到的内容常常是一个字节串,我们将使用其中的某个数组或指针来访问接收到的数据。这里推荐给大家的是指向一个 SAFEARRAY(COleSafeArray)类型变量。新的数据类型 SAFEARRAY 正如其名字一样,是一个“安全数组”,它能根据系统环境自动调整其 16 位或 32 位的定义,并且不会被 OLE 改变(某些类型如
23、 BSTR 在 16位或 32 位应用程序间传递时会被 OLE 翻译从而破坏其中的二进制数据)。大家无须了解 SAFEARRAY 的具体定义,只要知道它是另外一个结构,其中包含一个 (void *)类型的指针 pvData,其指向的内存就是存放有用数据的地方。 简而言之,从 GetInput()函数返回的 VARIANT 类型变量中,找出 parray 指针,再从该指针指向的 SAFEARRAY 变量中找出 pvData 指针,就可以向访问数组一样取得所接收到的数据了。具体应用请参见 void CSCommTestDlg:OnComm()函数。大概我现在也说不清这个问题,我自己从第一次接触这个东西,到现在还是给别人讲不清。另:二进制收发设置请参考 MSComm 控件说明。