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

来源:互联网 发布:网络协议抽象成软件 编辑:程序博客网 时间:2024/05/01 15:32

1 -

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

                   

      摘 要:本文介绍了结合了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


0 0