VC++实现串口通信的应用程序设计

本文介绍了一种基于Win32 API和C++类思想封装的串口通信类CSerialPort,通过具体实例展示了在VC++环境下如何实现串口通信。文章详细阐述了串口的初始化、读写操作及关闭过程,并通过串口调试工具验证了通信效果。

VC++实现串口通信的应用程序设计

                   

在 VS2013 下, 实现串口通信的方法有以下几种:

1) 使用 API 通信函数; 
2) 使用串口通信控件 MScomm; 
3) 使用微软提供的串口通信类 SerialPort类; 
4) 使用Remon Spekreijse写的开源类CSerialPort类; 
项目主要用CSerialPort类进行串口通信编程,接下来就以CSerialPort 介绍串口通信的实现。

 

 

      摘 要:本文介绍了结合了Win32 的API 函数和C++类的基本思想封装的一个串行通信类

CSerialPort 类。并通过具体的实例详细介绍其在VC++6.0 下的实现串口通信方法和过程。

关键词:VC++,串口通信,CSerialPort 类

1. 引言

    在控制领域的研发中,PC 机与外围控制设备的通讯方式有多种,如串行通信口、并行

通信口、一台网口(需要网卡支持)、USB 通信口或自制危机接口卡。而串口通信则是在

数据通信速率部是很高的情况下,开发者所采用的最常见、最简单、最通用的通信方式。并

且考虑到现在的PC 机标准配置都具备两个串口,因此利用串口资源来开发PC 机与外围控

制设备之间的通信应该是最方便快捷的[3]。

   在目前常用的各种开发环境(如VB、VC 和Delphi 等)下实现串口通信的方式有很多

种:

   首先,最简便的方法是采用Microsofe 公司提供的ActiveX 控件实现串口通信,即

MSComm 控件。实现串口通信的编程方法原理上比较简单,容易实现,但编程的灵活性稍差,

且应用程序运行时必须同时拷入与通信控件相关的文件。

   其次,使用Win32 的API 函数实现串口通信亦是很好的方法。利用 API 函数实现串口

通信的编程方法功能强大 ,灵活性好 ,但原理上比较复杂 ,需要编程人员对串口的硬件工作

原理有较深入的了解。

   最后,可以利用VC 运行时库的标准通信函数实现串口通信。其编程原理简单,但其使

用性和灵活性较差。

   总之,各种串口通信的实现方式在使用条件、灵活性和复杂程度等方面各有优缺点,分

别适合于各自不同的应用场合。而本文介绍一个结合了Win32 的API 函数和C++类的基本

思想封装了一个串行通信类CSerialPort 类,通过一个实例介绍,我们发现这个自定义的串

口通信类能够使得串口通信的实现更加灵活、方便。

2. 串口通信的实现

虽然实现串口通信方法很多,但是一般来说,串行通信程序的工作过程一般分四步[2]:

(1)打开串口:在此步骤中,我们可以实现打开通信资源、设置通信参数、设置通信

事件、创建读写事件以及等待串口接收中断等操作。

(2)读串口:在此步骤中,当有字符或干扰到达串口时发生EV_ RXCHAR 消息的发

送 ,响应函数接收到此消息后读取串口接收缓冲区。

(3)写串口:该步骤是负责将要发送的字符写入发送串口缓冲区。

(4)关闭串口。

2.1 CSerialPort 通信类的介绍

http://www.paper.edu.cn

- 2 -

2.1.1 CSerialPort 类的定义声明

class CSerialPort

{

public:

   void ClosePort();

   CSerialPort();

   virtual      ~CSerialPort();

BOOL      InitPort(CWnd* pPortOwner, UINT portnr = 1, UINT baud = 19200, char parity =

'            N', UINT databits = 8, UINT stopbits = 1, DWORD dwCommEvents =

             EV_RXCHAR, UINT writebuffersize = 1024);

HANDLE       m_hComm;

BOOL          StartMonitoring();

BOOL          RestartMonitoring();

BOOL          StopMonitoring();

DWORD        GetWriteBufferSize();

DWORD        GetCommEvents();

DCB           GetDCB();

void            WriteToPort(char* string);

Void            WriteToPort(char* string,int n);

Void            WriteToPort(LPCTSTR string);

void            WriteToPort(LPCTSTR string,int n);

protected:

void            ProcessErrorMessage(char* ErrorText);

static UINT      CommThread(LPVOID pParam);

static void        ReceiveChar(CSerialPort* port, COMSTAT comstat);

static void        WriteChar(CSerialPort* port);

CWinThread* m_Thread;

CRITICAL_SECTION          m_csCommunicationSync;

BOOL                        m_bThreadAlive;

HANDLE                     m_hWriteEvent;

HANDLE                      m_hShutdownEvent;

HANDLE                      m_hEventArray[3];

OVERLAPPED m_ov;

COMMTIMEOUTS              m_CommTimeouts;

DCB                           m_dcb;

CWnd*                         m_pOwner;

UINT                           m_nPortNr;

char*                            m_szWriteBuffer;

DWORD                        _dwCommEvents;

DWORD                        m_nWriteBufferSize;

};

2.1.2 CSerialPort 类的函数说明

     在构造函数 CSerialPort 中对该类的数据成员进行了初始化。InitPort 函数完成串口的初

始化工作,包括打开串口、设置 SPC 的参数、设置通信事件的时间、建立串口的设备控制

块。由于串口是一种临界资源,不允许多个线程或用户同时访问,因此在该函数中调用了两

http://www.paper.edu.cn

- 3 -

个Windows API 函数EnterCriticalSection 和LeaveCriticalSection,以实现对串口的互斥访问。

   A,串口操作函数:

StartMonitoring 函数调用Windows API 函数:AfxBeginThread 启动一个SPC 线程,打

开串口。

   RestartMonitoring 函数调用CwinThread 的成员函数:ResumeThread 重启SPC 线程,

重起串口;

    StopMonitoring 函数调用CwinThread 的成员函数:SuspendThread 停止SPC 线程,关

闭串口。

    B,串口读写函数:

    WriteChar 函数调用Windows API 函数:WriteFile 向串口写数据;

    ReceiveChar 函数调用 Windows API 函数:ReadFile 从串口读取数据。

    WriteToPort 函数:另外扩充函数,通过不同的变量参数,适应不同的写串口的需求。

    CommThread 函数是SPC 的线程,完成SPC 的消息循环。该函数调用了WaitCommEvent

函数来等待事件消息,然后进行消息的处理和分发。在消息的处理中调用了WriteChar 函数

和ReceiveChar 函数。另外在这个SPC 线程函数中还进行了必要的异常处理。

    C,其他的相关函数

    其它的几个函数 ProcessErrorMessage,GetDCB 和GetWriteBufferSize 则完成一些辅助

的功能。

2.2 CSerialPort 串口通信类的具体应用

    前面介绍了CSerialPort 类的声明以及其中一些重要的函数。下面介绍在VC++6.0 环境

下利用MFC 编写一个基于对话框的串口通信测试的应用程序[1]。定义实现串口通信的类为

CSerialPort。

2.2.1 串口初始化

     在我们的例子中,我们在CSerialPort.h 中声明一个串口类的对象:

     CSerialPort m_SerialPort;

     要实现串口首先需要对串口进行设置和初始化。打开串口后,才能对串口的状态进行监

控。其串口初始化函数如下:

     InitPort(this, nPort, band, checkbit, databits, stopbits,EV_RXFLAG | EV_RXCHAR,512);

     初始化串口的状态,每次只能初始化一个串口。其中参数nPort:端口号, band:波特率,

checkbit:校验位, databits:数据个数, stopbits:停止位均可以通过界面设置,也可以在初始

化串口时直接定义。

     初始化串口完毕后,需要通过StartMonitoring()启动串口通信线程函数CommThread,

即可立即对所定义的串口进行监听。

2.2.2 处理函数的定义

     在文件CSerialPort.h 类CSerialPort 的定义中声明自定义处理函数:

     afx_msg void OnComm(WPARAM ch, LPARAM port);

     在 CSerialPort.cpp 内添加函数OnComm()。实现了对接受到的数据的处理代码。

     在文件 CSerialPort.cpp 消息映射的BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP

之间添加自定义消息映射宏ON_MESSAGE(WM_COMM_RXCHAR, OnComm),即在接受

http://www.paper.edu.cn

- 4 -

到字节的情况下触发函数。这样就可以在串口上存在一个字节的时候就可以触发OnComm

()函数来处理消息。

2.2.3 写串口

    在处理完接受的消息的后,就需要将反馈的消息再次写到串口发送出来,从而完成串口

通信。在这里我们使用m_SerialPort.WriteToPort(char* string,int n)来完成写串口,其中定义

了写到串口的字符串和字符的个数。在CSerialPort 类中,我们补充了其他的WriteToPort 的

函数以满足其他情况下的需要,在使用的过程中大家可以根据需要选择合适的写串口函数,

也可以根据自己的需要来扩充其他的函数。

2.2.4 关闭串口

    在串口通信完毕用m_SerialPort.ClosePort()来关闭串口。

3. 测试

使用“串口调试工具”对编写的串口测试工具进行调试,用串口线将PC 机上的串口1 和

串口2 相连。将串口调试工具和串口测试工具的参数设置如下所示,其比特率,交验位,

数据位,停止位设置必须相同,其两个端口号分别选择为端口1,端口2。当两个端口同时

打开的时候,PC 机上的串口连接线将两个串口导通。当“串口调试工具”发送“this is a test

program!”信息时,在串口测试工具接受到该条信息。测试结果如下图所示:图1:串口调试

器发送信息;图2:串口测试工具接受信息。

图 1 串口调试器发送信息

图 2 串口测试工具接受信息

 

 

 

4. 结束语

    本文应用Win32 的API 函数和C++类的基本思想把对串口的操作封装成一个串口通信

类的CSeriaPort,采用该串口通信类对串口设备的“屏蔽”,增加对串口操作的透明度,提高

串口传输数据的可靠性,方便程序员的编程。另外,还可以根据自己的需求对CSeriaPort

类进行功能扩充。

http://www.paper.edu.cn

 

参考文献

[1] Kruglinski.《Visual C++ 技术内幕》[M].北京:电子工业出版社,1999.

[2] 李现勇.《Visual C+ +串口通信技术与工程实践》[M].北京:人民邮电出版社.

[3] 王颖.《用 VC6.0 实现串行通信的三种方法》[J].VC 知识库在线帮助期,http://www.vckbase.com/,

2000 第9 期:18-20.

Application design of serial communication based on VC++

Wang Zhen, Chen Yongtai

school of information engineering,Wuhan University of Technology, Wuhan, PRC (430070)

Abstract

This paper introduces a new Serial Port class, which is named CSerialPort and is comprised based on

Win32 API and some C++ classes. By introducing one example, we analysis the application of the

CSerialPort class in the serial communication based on VC++.

Keywords:VC++,Serial Communication,Class CSerialPort

概要:   DevCon 实用工具是一种命令行实用工具,可以替代设备管理器。使用 DevCon,您可以启用禁用、重新启动、更新、删除查询单个设备或一组设备。DevCon 提供与开发人员有关但无法在设备管理器中看到的信息。   您可以将 DevCon 用于 Windows 2000 、Windows XPWindows vista。不能将 Devcon 用于 Microsoft Windows 95、Windows 98、或 Windows Millennium Edition。   下载:http://download.microsoft.com/download/1/1/f/11f7dd10-272d-4cd2-896f-9ce67f3e0240/devcon.exe 用法及参数说明:   devcon.exe [-r] [-m:\\] [...]   -r 如果指定它,在命令完成后若需要则重新启动计算机。    是目标计算机的名称。    是将要执行的命令(如下所示)。   ... 是命令需要的一个或多个参数。   要获取关于某一特定命令的帮助,请键入:devcon.exe help   classfilter 允许修改类别筛选程序。   classes 列出所有设备安装类别。   disable 禁用与指定的硬件或实例 ID 匹配的设备。   driverfiles 列出针对设备安装的驱动程序文件。   drivernodes 列出设备的所有驱动程序节点。   enable 启用与指定的硬件或 实例 ID 匹配的设备。   find 查找与指定的硬件或 实例 ID 匹配的设备。   findall 查找设备,包括那些未显示的设备。   help 显示此信息。   hwids 列出设备的硬件 ID。   install 手动安装设备。   listclass 列出某一安装类别的所有设备。   reboot 重新启动本地计算机。   remove 删除与特定的硬件或 实例 ID 匹配的设备。   rescan 扫描以发现新的硬件。   resources 列出设备的硬件资源。   restart 重新启动与特定的硬件或 实例 ID 匹配的设备。   stack 列出预期的设备驱动程序堆栈。   status 列出设备的运行状态。   update 手动更新设备。   UpdateNI 手动更新设备,无用户提示   SetHwID 添加、删除更改根枚举设备的硬件 ID 的顺序。 示例:   devcon -m:\\test find pci\* 列出计算机 test 上的所有已知 PCI 设备。(通过使用 -m,您可以指定一个目标计算机。您必须使用“进程间通信”(IPC) 访问此计算机。)   devcon -r install Windows directory\Inf\Netloop.inf *MSLOOP 安装一个新的 Microsoft 环回适配器实例。这将创建一个新的根枚举设备节点,使用此节点您可以安装“虚拟设备”,如环回适配器。如果需要重新启动计算机,此命令还将以安静模式重启计算机。   devcon classes 列出所有已知的安装类别。输出结果包含短的未本地化的名称(例如,“USB”)描述性名称(例如,“通用串行总线控制器”)。 禁用启用网卡的步骤:   1.用devcon hwids PCI*命令得到所有以PCI开头的设备。这时会列出很多设备,那么哪个才是网卡对应的呢?   2.打开设备管理器,展开网络适配器,找到网卡的名称,然后记住到刚才得到的列表中找对应的Name,然后你会在下面看到好几个ID,随便挑一个就行   3.用devcon disable "PCI\VEN_11AB&DEV_4380&SUBSYS_301B17AA&REV_10"禁用网卡(启用的话讲disable换成enable就行了)   4.其实用PCI开头得到的几组设备中一般第一个就是网卡设备 sysdzw 16:01 2010-11-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值