⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serialport.cpp

📁 串口通信类编程中必不可少的一个类 定义了类函数
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "stdAfx.h"
#include "SerialPort.h"
#include <assert.h>

//构造函数
CSerialPortEx::CSerialPortEx()
{
    //初始化overlapped结构
	m_ov.Offset = 0;
	m_ov.InternalHigh = 0;

	//初始化事件句柄

	m_ov.hEvent =NULL;
	m_hWriteEvent = NULL;
    m_hShutdownEvent = NULL;

    //初始化其他成员
    m_hComm = NULL;
    m_szWriteBuffer = NULL;
    m_bThreadAlive = FALSE;     //默认使用ReadChar 模式读取数据
    m_bBlockRead = FALSE;
}
CSerialPortEx::~CSerialPortEx()
{
	do
    {
		SetEvent(m_hShutdownEvent);
    }while(m_bThreadAlive);
    delete[]m_szWriteBuffer;
}

//初始化串口,可以是从串口1到串口4
BOOL CSerialPortEx::InitPort(CWnd*pPortOwner,                 //父窗口(接收消息)
                             UINT portnr,                     //串口号(1...4)
                             UINT baud,                       //数据转输率
                             char parity,                     //校验位
                             UINT databits,                    //数据位
                             UINT stopbits,                   //停止位
                             DWORD dwCommEvents,               //串口状态事件
                             UINT writebuffersize)             //输出缓冲区大小
{
	assert(portnr>0 && portnr<5);
    assert(pPortOwner != NULL);
     
    //若当前监视统线程正在运行,则先Kill该线程
    if(m_bThreadAlive)
    {
		do
        {
			SetEvent(m_hShutdownEvent);
        }while(m_bThreadAlive);
	}
    //创建事件
	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);

    //初始化监视事件对象
    m_hEventArray [0] = m_hShutdownEvent;      //最高优先级
    m_hEventArray[1] = m_ov.hEvent;
    m_hEventArray[2] = m_hWriteEvent;

    //初始化临界区
    InitializeCriticalSection(&m_csCommunicationSync);
	    
    //保存父窗口与串口号
    m_pOwner = pPortOwner;
    m_nPortNr =portnr;
 
    //创建输出缓冲区
    if(m_szWriteBuffer != NULL)
		delete[] m_szWriteBuffer;
    m_szWriteBuffer = new BYTE[writebuffersize];
	m_nWriteBufferSize = writebuffersize;

    //保存串口状态事件
    m_dwCommEvents = dwCommEvents;
   
    BOOL bResult = FALSE;
    char *szPort = new char[50];
    char *szBaud = new char[50];

	//进入临界区
    EnterCriticalSection(&m_csCommunicationSync);

	//若串口已经打开,则先关闭
    if(m_hComm != NULL)
	{	
		CloseHandle(m_hComm);
        m_hComm=NULL;
	}
    //准备串口设置
    sprintf(szPort,"COM%d",portnr);
    printf(szBaud,"baud = %d parity =%c data = %d stop = %d",baud,parity,databits,stopbits);

    //打开串口
    HANDLE m_hComm = CreateFile(szPort,                      //串口名称字符串,如“COM1"
                            GENERIC_READ||GENERIC_WRITE,       //读写
                            0,                                //以独占方式打开
                            NULL,                              //未设置安全属性
                            OPEN_EXISTING,                     //串口设备必须设置该值
                            FILE_FLAG_OVERLAPPED,              //使用异步I/O
                            0);                                //串口设备该参数必须设为0
	if(m_hComm == INVALID_HANDLE_VALUE)
	{
		//出错处理
		delete[] szPort;
        delete[] szBaud;
        return FALSE;
    }
    //设置超时时间
    m_CommTimeouts.ReadIntervalTimeout = 1000;      
	m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;   
	m_CommTimeouts.ReadTotalTimeoutConstant = 1000;   
	m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;   
	m_CommTimeouts.WriteTotalTimeoutConstant = 1000;   
        
    //配置串口
    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;

	//清空串口数据
	PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|
		                                         PURGE_TXABORT);

	//离开临界区
	LeaveCriticalSection(&m_csCommunicationSync);

	return TRUE;
	}


	//创建串口主(监 视)线程
	BOOL CSerialPortEx::StartMonitoring()
	{
		if(!(m_Thread = AfxBeginThread(CommThread,this)))
		      return FALSE;
		return TRUE;
	}
	//重新开始串口主线程
	BOOL CSerialPortEx::RestartMonitoring()
	{
		TRACE("Thread resumed\n");
		m_Thread -> ResumeThread();
		return TRUE;
	}
	//中止串口主线程
	BOOL CSerialPortEx::StopMonioring()
	{
		TRACE("Thread suspended\n");
		if(m_bThreadAlive)
		{
			m_Thread ->SuspendThread();
			m_bThreadAlive = FALSE;
		}
		return TRUE;
	}
	//串口主(监视)线程
	UINT CSerialPortEx::CommThread(LPVOID pParam)
	{
		CSerialPortEx *port = (CSerialPortEx*)pParam;

		//表示当前监视线程正在运行
		port ->m_bThreadAlive = TRUE;

		DWORD BytesTransfered = 0;
		DWORD Event = 0;
		DWORD CommEvent = 0;
		DWORD dwError = 0;
		COMSTAT comstat;
		BOOL bResult = TRUE;

		//清空串口缓冲区
		if(port ->m_hComm)
			PurgeComm(port ->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |PURGE_RXABORT
			                                                        |PURGE_RXABORT);
		//开始无限循环,当该线程Alive时该循环一直进行
		for(;;)
		{
			//检测线路状态,等待SetCommMask 指定事件之一发生,事实上因为CSerialPortEx
			//以异步方式操作串口,所以该调用将立刻返回
			bResult = WaitCommEvent(port->m_hComm,&Event,&port->m_ov);
			if(!bResult)
			{
				switch(dwError = GetLastError())
				{
				case ERROR_IO_PENDING:
					{
						//串口没数据时的正常返回值
						break;
					}
				case 87:
					{
						//在Windows NT下,该值将会返回,原因不明,但它是正常返回值
						break;
					}
				default:
					{
						//其他返回值表示有错误发生
						port->ProcessErrorMessage("WaitCommEvent()");
						break;
					}
				}
			}
			else 
			{
				//WaitCommEvent 以后,要用ClearCommError清除事件的Flag,以便进行下一轮
				//WaitCommEvent,同时这个API可以获得更详细的事件信息
				bResult = ClearCommError(port->m_hComm,&dwError,&comstat);
				//确认串口中无字符则无须进入主监视过程,重新开始循环
				if(comstat.cbInQue == 0)
					continue;
			}   //end if bResult
			//主监视函数,该函数将阻塞本线程直至等待的某一事件发生
			Event=WaitForMultipleObjects(3,port->m_hEventArray,FALSE,INFINTTE);

			switch(Event)
			{
			case 0:
				{                                            //将中止本线程
					port->m_bThreadAlive = FALSE;
					AfxEndThread(100);
					break;
				}
			case 1:                                    //处理串口状态事件
				{
					GetCommMask(port ->m_hComm,&CommEvent);
					//处理串口状态事件
					if(CommEvent & EV_CTS)
						::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_CTS_DELECTED,
						              (WPARAM)0,(LPARAM)port->m_nPortNr);
					if(CommEvent & EV_RXFLAG)
						::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RXFLAG_DELECTED,
           			                (WPARAM)0,(LPARAM)port ->m_nPortNr);
                    if(CommEvent & EV_BREAK)
                        ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_BREAK_DETECTED,
                                                               (WPARAM)0,(LPARAM) port->m_nPortNr);   
                    if(CommEvent & EV_ERR)
						::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_ERR_DELECTED,
                                                                (WPARAM)0,(LPARAM) port->m_nPortNr);                  
                    if(CommEvent & EV_RING)
                        ::SendMessage(port->m_pOwner->m_hWnd,WM_COMM_RING_DELECTED,
                                                                (WPARAM)0,(LPARAM) port->m_nPortNr);    
					if(CommEvent & EV_RXCHAR)
						if(!port->m_bBlockRead)   //检测是ReadBlock还是ReadChar模式
							ReceiveChar(port,comstat);
                            break;
				}
			case 2:
				{
					WriteChar(port);
                    break;
                }//end switch
			} //结束串口主循环
                return 0;
		}
	}
	
//ReceiveChar 不需用户调用,串口主线程在有数据到达串口时自动调用该函数。
//它将读取到的数据通过自定义消息WM_COMM_RXCHAR发送给父窗口m_pOwner,
//调用者只需在该窗口内处理WM_COMM_RXCHAR消息即可。
void CSerialPortEx::ReceiveChar(CSerialPortEx* port,COMSTAT comstat)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -