13.6.2 串口打开函数的实现
打开串口函数OpenSerialPort()将根据传入的参数打开相应的串口,并设置这个串口的属性,实现如下:
- 01 bool CMySerial::OpenSerialPort(CWnd* pParent, UINT portnr, UINT baud,
- 02 char parity, UINT databits, UINT stopbits,
- 03 DWORD dwCommEvents, UINT writebuffersize)
- 04 {
- 05 assert(portnr > 0 && portnr < 5);
- 06 assert(pParent != NULL);
- 07 if (m_bThreadAlive) //如果串口监控线程活动,则关闭它
- 08 {
- 09 do
- 10 {
- 11 SetEvent(m_hShutdownEvent);
- 12 } while (m_bThreadAlive);
- 13 TRACE("Thread ended\n");
- 14 }
- 15 if (m_ov.hEvent != NULL) //创建串口异步通信事件
- 16 ResetEvent(m_ov.hEvent);
- 17 else
- 18 m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- 19 if (m_hWriteEvent != NULL) //创建发送事件
- 20 ResetEvent(m_hWriteEvent);
- 21 else
- 22 m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- 23 if (m_hShutdownEvent != NULL) //创建关闭串口事件
- 24 ResetEvent(m_hShutdownEvent);
- 25 else
- 26 m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- 27 m_hEventArray[0] = m_hShutdownEvent; //具有最高的优先级
- 28 m_hEventArray[1] = m_ov.hEvent;
- 29 m_hEventArray[2] = m_hWriteEvent;
- 30 InitializeCriticalSection(&m_csCommunicationSync); //初始化临界资源
- 31 m_pParent = pParent; //保存串口操作窗口指针
- 32 if (m_szWriteBuffer != NULL) //为发送缓冲申请空间
- 33 delete [] m_szWriteBuffer;
- 34 m_szWriteBuffer = new char[writebuffersize];
- 35 m_nPortNr = portnr; //保存串口号
- 36 m_nWriteBufferSize = writebuffersize; //将要发送的数据
- 37 m_dwCommEvents = dwCommEvents; //串口事件
- 38 BOOL bResult = FALSE;
- 39 char *szPort = new char[50]; //数据缓冲区
- 40 char *szBaud = new char[50];
- 41 EnterCriticalSection(&m_csCommunicationSync); //锁定临界变量
- 42 if (m_hComm != NULL) //确保串口处于关闭状态
- 43 {
- 44 CloseHandle(m_hComm);
- 45 m_hComm = NULL;
- 46 }
- 47 sprintf(szPort, "COM%d", portnr); //串口状态信息
- 48 sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d",
- 49 baud, parity, databits, stopbits);
- 50 //打开串口
- 51 m_hComm = CreateFile( szPort, //串口号
- 52 GENERIC_READ | //读模式
- 53 GENERIC_WRITE, //写模式
- 54 0, //必须为0
- 55 NULL, //安全性属性结构
- 56 OPEN_EXISTING, //必须置为OPEN_EXISTING
- 57 FILE_FLAG_OVERLAPPED, //使用异步的I/O
- 58 NULL); //必须为NULL
- 59 if (m_hComm == INVALID_HANDLE_VALUE)
- 60 { //打开失败
- 61 delete [] szPort;
- 62 delete [] szBaud;
- 63 return FALSE;
- 64 }
- 65 //超时参数
- 66 m_CommTimeouts.ReadIntervalTimeout = 1000;
- 67 m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
- 68 m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
- 69 m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
- 70 m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
- 71 if (SetCommTimeouts(m_hComm, &m_CommTimeouts)) //设置串口参数
- 72 { //超时设置
- 73 if (SetCommMask(m_hComm, dwCommEvents))
- 74 { //事件设置
- 75 if (GetCommState(m_hComm, &m_dcb))
- 76 { //参数设置
- 77 m_dcb.EvtChar = 'q';
- 78 m_dcb.fRtsControl = RTS_CONTROL_ENABLE;
- 79 if (BuildCommDCB(szBaud, &m_dcb))
- 80 {
- 81 if (!SetCommState(m_hComm, &m_dcb))
- 82 ProcessErrorMessage("SetCommState()");
- 83 }
- 84 else //串口参数设置失败
- 85 ProcessErrorMessage("BuildCommDCB()");
- 86 }
- 87 else //串口参数获取失败
- 88 ProcessErrorMessage("GetCommState()");
- 89 }
- 90 else //串口事件设置失败
- 91 ProcessErrorMessage("SetCommMask()");
- 92 }
- 93 else //串口超时设置失败
- 94 ProcessErrorMessage("SetCommTimeouts()");
- 95 delete [] szPort; //清空数据缓冲区
- 96 delete [] szBaud;
- 97 PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |
- 98 PURGE_RXABORT | PURGE_TXABORT);
- 99 LeaveCriticalSection(&m_csCommunicationSync); //解锁临界变量
- 100 return TRUE;
- 101 }
【代码解析】
OpenSerialPort()函数的第7~14行判断串口监控线程是否活动,如是则将其关闭。第15~26行创建并启动串口的3个事件。第27~29行将创建的事件句柄保存到事件数组中。第30行初始化临界资源,方便后面的使用。第32、33行申请一段发送缓冲区。第34~36行保存传入的参数。第55行锁定临界资源。第42~44行确保串口已经被关闭。第51~58行打开串口。第59~64行判断是否打开串口成功,否则释放资源后返回。第66~70行设置串口通信超时参数。第71~92行将前面准备好的串口的所有属性设置到串口上,设置失败后调用ProcessErrorMessage()函数进行失败处理。第95、96行释放资源。第97、98行清空串口的缓冲区。第99行解锁临界资源,其他线程此后便可以使用这个临界资源。