CSerialPort类解析

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!                CSerialPort
摘要由CSDN通过智能技术生成

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

CSerialPort类的功能及成员函数介绍

CSerialPort类是免费提供的串口累,Codeguru是一个非常不错的源代码网站

CSerialPort类支持线连接(非MODEM)的串口编程操作。

CSerialPort类是基于多线程的,其工作流程如下:首先设置好串口参数,再开启串口检测工作线程,串口检测工作线程检测到串口接收到的数据、流控制事件或其他串口事件后,就以消息方式通知主程序,激发消息处理函数来进行数据处理,这是对接受数据而言的,发送数据可直接向串口发送。

CSerialPort类定义的消息如表

消息名称

消息号

功能说明

WM_COMM_BREAK_DETECTED

WM_USER+1

检测到输入中断

WM_COMM_CTS_DETECTED

WM_USER+2

检测到CTS(清除发送)信号状态改变

WM_COMM_DSR_DETECTED

WM_USER+3

检测到DSR(数据设备准备就绪)信号状态改变

WM_COMM_ERR_DETECTED

WM_USER+4

发生线状态错误(包括CE_FRAME,CE_OVERRUN,和CE_RXPARITY)

WM_COMM_RING_DETECTED

WM_USER+5

检测到响铃指示信号

WM_COMM_RLSD_DETECTED

WM_USER+6

检测到RLSD(接收线信号)状态改变

WM_COMM_RXCHAR

WM_USER+7

接收到一个字符并已放入接受缓冲区

WM_COMM_RXFLAG_DETECTED

WM_USER+8

检测到接受到字符(该字符已放入接受缓冲区)事件

WM_COMM_TXEMPTY_DETECTED

WM_USER+9

检测到发送缓冲区最后一个字符已经被发送

介绍几个经常用到的函数:
1、串口初始化函数InitPort
BOOL CSerialPort::InitPort(CWnd *pPortOwner,    // the owner (CWnd) of the port (receives message)                            UINT  portnr,        // portnumber (1..4)                            UINT  baud,            // baudrate                            char  parity,        // parity                            UINT  databits,        // databits                            UINT  stopbits,        // stopbits                            DWORD dwCommEvents,    // EV_RXCHAR, EV_CTS etc                            UINT  writebuffersize)    // size to the writebuffer {     assert(portnr > 0 && portnr < 5);     assert(pPortOwner != NULL);      // if the thread is alive: Kill     if (m_bThreadAlive)     {         do         {             SetEvent(m_hShutdownEvent);         }         while (m_bThreadAlive);         TRACE("Thread ended\n");     }      // create events     if (m_ov.hEvent != NULL)         ResetEvent(m_ov.hEvent);     m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);      if (m_hWriteEvent != NULL)         ResetEvent(m_hWriteEvent);     m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);      if (m_hShutdownEvent != NULL)         ResetEvent(m_hShutdownEvent);     m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);      // initialize the event objects     m_hEventArray[0] = m_hShutdownEvent;    // highest priority     m_hEventArray[1] = m_ov.hEvent;     m_hEventArray[2] = m_hWriteEvent;      // initialize critical section     InitializeCriticalSection(&m_csCommunicationSync);      // set buffersize for writing and save the owner     m_pOwner = pPortOwner;      if (m_szWriteBuffer != NULL)         delete [] m_szWriteBuffer;     m_szWriteBuffer = new char[writebuffersize];      m_nPortNr = portnr;      m_nWriteBufferSize = writebuffersize;     m_dwCommEvents = dwCommEvents;      BOOL bResult = FALSE;     char *szPort = new char[50];     char *szBaud = new char[50];      // now it critical!     EnterCriticalSection(&m_csCommunicationSync);      // if the port is already opened: close it     if (m_hComm != NULL)     {         CloseHandle(m_hComm);         m_hComm = NULL;     }      // prepare port strings     sprintf(szPort, "COM%d", portnr);     sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);      // get a handle to the port     m_hComm = CreateFile(szPort,                        // communication port string (COMX)                          GENERIC_READ | GENERIC_WRITE,    // read/write types                          0,                                // comm devices must be opened with exclusive access                          NULL,                            // no security attributes                          OPEN_EXISTING,                    // comm devices must use OPEN_EXISTING                          FILE_FLAG_OVERLAPPED,            // Async I/O                          0);                            // template must be 0 for comm devices      if (m_hComm == INVALID_HANDLE_VALUE)     {         // port not found         delete [] szPort;         delete [] szBaud;          return FALSE;     }      // set the timeout values     m_CommTimeouts.ReadIntervalTimeout = 1000;     m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;     m_CommTimeouts.ReadTotalTimeoutConstant = 1000;     m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;     m_CommTimeouts.WriteTotalTimeoutConstant = 1000;      // configure     if (SetCommTimeouts(m_hComm, &m_CommTimeouts))     {         if (SetCommMask(m_hComm, dwCommEvents))         {             if (GetCommState(m_hComm, &m_dcb))             {                 m_dcb.fRtsControl = RTS_CONTROL_ENABLE;        // set RTS bit high!                 if (BuildCommDCB(szBaud, &m_dcb))                 {                     if (SetCommState(m_hComm, &m_dcb))                         ; // normal operation... continue                     else                         ProcessErrorMessage("SetCommState()");                 }                 else                     ProcessErrorMessage("BuildCommDCB()");             }             else                 ProcessErrorMessage("GetCommState()");         }         else             ProcessErrorMessage("SetCommMask()");     }     else         ProcessErrorMessage("SetCommTimeouts()");      delete [] szPort;     delete [] szBaud;      // flush the port     PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);      // release critical section     LeaveCriticalSection(&m_csCommunicationSync);      TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr);      return TRUE; } 

这个函数是用来初始化串口的,即设置串口的通信参数:需要打开的串口号、波特率、奇偶校验方式、数据位、停止位,这里还可 以用来进行事件的设定。

如果串口初始化成功,就返回TRUE,若串口被其他设备占用、不存在或存在其他股占,就返回FALSE,编程者可以在这儿提示串口操作是否成功。

如果在当前主串口调用这个函数,那么pPortOwner可用this指针表示,串口号在函数中做了限制,只能用1,2,3和4四个串口号,而事实上在编程时可能用到更多串口号,可以通过通过注释掉本函数中的“assert(portur>0&&portnr<5)”语句取消对串口号的限制。

2、启动串口通信监测线程函数StartMonitoring()

串口初始化成功后,就可以调用BOOL StartMonitoring()来启动串口检测线程,线程启动成功,发挥TRUE

BOOL CSerialPort::StartMonitoring() 

if (!(m_Thread = AfxBeginThread(CommThread, this))) 

return FALSE; 

TRACE("Thread started\n"); 

return TRUE; 

3、暂停或停止监测线程函数StopMonitoring()

该函数暂停或停止串口检测,要注意的是,调用该函数后,串口资源仍然被占用
// Suspend the comm thread 
// 
BOOL CSerialPort::StopMonitoring() 

     TRACE("Thread suspended\n"); 
     m_Thread->SuspendThread(); 
     return TRUE; 

4、关闭串口函数ClosePort()

该函数功能是关闭串口,释放串口资源,调用该函数后,如果要继续使用串口,还需要调用InitPort()函数

5、通过串口发送字符/写串口函数WriteToPort()

该函数完成写串口功能,即向串口发送字符。

// Write a string to the port 

void CSerialPort::WriteToPort(char *string) 

{

assert(m_hComm != 0); 

memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer)); 

strcpy(m_szWriteBuffer, string); 
 

// set event for write 

SetEvent(m_hWriteEvent); 


以上是常用的函数介绍,熟悉该类的使用后,可以仔细看看其他函数,对上面介绍的函数,在对串口资源的使用上要记住一下三点:

l 打开串口用调用InitPort()和StartMonitoring();关闭串口用StopMonitoring()和ClosePort()而且以上函数的调用顺序不能乱

l 通过串口发送字符调用函数WriteToPort()

l 接受串口收到的字符需要自己编写WM_COMM_RXCHAR消息处理函数,需要手工添加。

操作:

首先,需要操作一个串口,所以只需要定义1个类对象就可以了,如要操作多个串口,则要为每个串口均定一个类对象,这可以通过数据方式来实现,这里定义的类对象为m_SerialPort,再定义一个布尔变量m_bSerialPortOpened用来标志串口是否打开。

在CserialPort类中有多个串口事件可以响应,在一般串口编程中,只需要处理WM_COMM_RXCHAR消息就可以了,该类所有的消息均需要人工添加消息处理函数,将处理函数名定义为OnComm(),首先在SerialPortTestDlg.h(头文件)中添加串口字符接受消息WM_COMM_RXCHAR(串口接受缓冲区内有一个字符)的响应函数声明:

//Generated message map funnctions 
//{ {AFX_MSG(CSCportTestView) 
afx_msg   long  OnComm(WPARAM ch, LPARAM port); 
//}}AFX_MSG 
 

然后在,SerilPortTestDlg.cpp文件中进行WM_COMM_RXCHAR消息映射

BEGIN_MESSAE_MAP(CSerialPortTestDlg, CDialog)s 
//{ {AFX_MSG_MAP(CSerialPortTestDlg) 
ON_MESSAGE(WM_COMM_RXCHAR, OnComm) 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
  接着,在 SerialPortTestDlg.cpp文件中加入函数OnComm()的实现,并在其中完成对节诶受到的字符的处理,将接收到的字符显示在接受编辑框中:

long  CSerialPortTestDlg::OnComm(WPARAM ch, LPARAM port) 
    m_strEditReceiveMsg += ch; 
    UpdateData(FLASE); //将接收到的字符显示在接受编辑框中 
    returne  0 ; 

说明:WPARAM、LPARAM类型是多态数据类型,在WIN32中为32位,支持多种数据类型,根据需要自动适应,这样,程序有很强的适应性,再次,我们可以分贝理解为char和integer类型数据,每当串口接受缓冲区内有一个字符时,就会产生一个WM_COMM_RXCHAR消息,除法OnComm()函数,这时就可以在函数中进行数据处理,所以,这个消息就是整个程序的源头。


虽然CSerialPort类是一个非常好的类,但毕竟只是集中了作者一个人的智慧和经验,他也有许多缺陷,

n 原类只能发送字符(ASCII文本)不能处理二进制发送(也就是不能发送0X00)

n 该类不能很好的释放串口

n 存在内存泄漏

可以进行如下改进

改进一、ASCII文本和二进制数据发送方式兼容

CSerialPort类中只有一个发送函数WriteToPort()

// 
// Write a string to the port 
// 
void  CSerialPort::WriteToPort( char  *string) 
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值