这几天一直再看串口相关知识,对于其总结为以下串口类:ide
头文件声明以下:函数
1 #pragma once 2 3 // 声明当串口接收到线程的时候调用的函数指针 4 // 参数: 1,接收到的数据; 2,数据长度; 3,发送的目标地址 5 typedef void (*DataArriveProc)(char *data, int len, DWORD dest); 6 7 /*********************************** 8 1,实现一个串口类,用于进行串口的通讯; 9 2,其中的特性是,主动发送数据,被动接受 10 作出响应,其中开辟一个线程进型串口读取; 11 3,线程函数响应时,应该将接受到的数据转 12 发给使用此串口的上层应用; 13 ************************************/ 14 class CSerialPort 15 { 16 public: 17 CSerialPort(void); 18 virtual ~CSerialPort(void); 19 20 // 串口操做函数 21 BOOL OpenPort(LPCTSTR portName, DWORD baudRate, int dataBits, int stopBits, int parity, DataArriveProc proc, DWORD dest); 22 BOOL ClosePort(); // 关闭串口 23 DWORD WritePort(char *data, DWORD size); // 往串口写数据 24 25 // 串口读操做线程的操做函数 26 static UINT AFX_CDECL ReadPortProc(LPVOID lpParam);// 往串口读数据的线程函数 27 BOOL Activate(); // 激活串口的读操做 28 BOOL Deactivate(); // 取消串口的读操做 29 BOOL IsActivate(); // 窗口是否已经准备好进行读操做 30 31 private: 32 HANDLE m_hPortHandle; // 串口句柄 33 HANDLE m_hReadThread; // 读线程 34 BOOL m_bReading; // 读线程是否处于工做状态 35 DCB m_dcbPort; // 串口的工做参数 36 COMMTIMEOUTS m_tmOut; // 串口通讯超时参数 37 38 DataArriveProc m_pDataArriveProc; // 接收到数据后的调用的方法 39 DWORD m_dwDestAddress; // 数据发送的目的地址 40 };
源文件定义以下:测试
1 #include "StdAfx.h" 2 #include "SerialPort.h" 3 #include "Resource.h" 4 5 CSerialPort::CSerialPort(void) 6 { 7 m_hPortHandle = INVALID_HANDLE_VALUE; 8 m_hReadThread = INVALID_HANDLE_VALUE; 9 m_bReading = FALSE; 10 } 11 12 CSerialPort::~CSerialPort(void) 13 { 14 if(INVALID_HANDLE_VALUE != m_hPortHandle){ 15 ClosePort(); 16 } 17 if(INVALID_HANDLE_VALUE != m_hReadThread){ 18 Deactivate(); 19 } 20 } 21 22 // 打开串口 23 // 1,打开串口文件; 24 // 2,设置串口属性 25 // 3,完成操做; 26 BOOL CSerialPort::OpenPort(LPCTSTR portName, DWORD baudRate, int dataBits, int stopBits, int parity, DataArriveProc proc, DWORD dest) 27 { 28 if(INVALID_HANDLE_VALUE != m_hPortHandle){ 29 // 串口已经打开 30 return TRUE; 31 } 32 33 CString temp; 34 35 // 保存数据到达后的响应地址,及目的地 36 m_pDataArriveProc = proc; 37 m_dwDestAddress = dest; 38 39 // 1, 打开串口文件 40 m_hPortHandle = ::CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 41 if(INVALID_HANDLE_VALUE == m_hPortHandle){ 42 temp.LoadString(IDS_OPENPORT_FAIL); 43 AfxMessageBox(temp); 44 return FALSE; 45 } 46 47 // 2, 获取串口的工做参数并从新赋值 48 GetCommState(m_hPortHandle, &m_dcbPort); 49 m_dcbPort.BaudRate = baudRate; // 设置波特率(外部设置) 50 m_dcbPort.ByteSize = dataBits; // 通讯字节位数 51 m_dcbPort.fParity = 1; // 奇偶校验使能,1能够 52 m_dcbPort.Parity = parity; // 校验方式:外设 53 m_dcbPort.StopBits = stopBits;// 中止位 54 m_dcbPort.fBinary = 1; 55 m_dcbPort.fDtrControl = 0; 56 m_dcbPort.fRtsControl = 0; 57 m_dcbPort.fOutX= m_dcbPort.fInX= m_dcbPort.fTXContinueOnXoff=0; 58 59 // 3,设置一组监视串口设备的事件,什么信息到达时通知 60 SetCommMask(m_hPortHandle, EV_RXCHAR); 61 // 4,设置串口的通讯参数,主要是缓冲区大小 62 SetupComm(m_hPortHandle, 10240, 10240); 63 // 5,设置工做参数 64 if(!SetCommState(m_hPortHandle, &m_dcbPort)){ 65 temp.LoadString(IDS_SETSTATE_FAIL); 66 AfxMessageBox(temp); 67 ClosePort(); 68 return FALSE; 69 } 70 71 // 6,获取通讯超时信息并从新设置 72 GetCommTimeouts(m_hPortHandle, &m_tmOut); 73 m_tmOut.ReadIntervalTimeout = 100; 74 m_tmOut.ReadTotalTimeoutConstant = 100; 75 m_tmOut.ReadTotalTimeoutMultiplier = 100; 76 m_tmOut.WriteTotalTimeoutMultiplier = 100; 77 m_tmOut.WriteTotalTimeoutConstant = 100; 78 if(!SetCommTimeouts(m_hPortHandle, &m_tmOut)){ 79 temp.LoadString(IDS_SETTTMOUT_FAIL); 80 AfxMessageBox(temp); 81 ClosePort(); 82 return FALSE; 83 } 84 85 // 7,清空串口缓冲区 86 PurgeComm(m_hPortHandle, PURGE_RXCLEAR | PURGE_TXCLEAR); 87 return TRUE; 88 } 89 // 关闭串口 90 // 1,清空通讯设备监听事件; 91 // 2,清空串口缓冲区; 92 // 3,关闭串口文件句柄; 93 BOOL CSerialPort::ClosePort() 94 { 95 if(INVALID_HANDLE_VALUE != m_hPortHandle){ 96 SetCommMask(m_hPortHandle, 0); 97 PurgeComm(m_hPortHandle, PURGE_RXCLEAR | PURGE_TXCLEAR); 98 CloseHandle(m_hPortHandle); 99 m_hPortHandle = INVALID_HANDLE_VALUE; 100 return TRUE; 101 } 102 103 return TRUE; 104 } 105 106 // 往串口写数据 107 // 1,首先检查串口是否处于工做状态; 108 // 2,向串口写入内容; 109 // 3,返回写入的内容大小; 110 DWORD CSerialPort::WritePort(char *data, DWORD size) 111 { 112 if(INVALID_HANDLE_VALUE == m_hPortHandle){ 113 return 0; 114 } 115 116 DWORD writeLen = 0; 117 BOOL ret = FALSE; 118 119 ret = WriteFile(m_hPortHandle, data, size*sizeof(char), &writeLen, NULL); 120 121 return writeLen; 122 } 123 124 // 激活串口的读操做 125 // 1,判断串口是否已经打开; 126 // 2,判断串口读线程是否已经建立; 127 // 3,设置成员变量; 128 BOOL CSerialPort::Activate() 129 { 130 if(INVALID_HANDLE_VALUE == m_hPortHandle){ 131 return FALSE; 132 } 133 134 if(!m_bReading){ 135 m_hReadThread = AfxBeginThread(ReadPortProc, this); 136 m_bReading = TRUE; 137 } 138 139 if(INVALID_HANDLE_VALUE !=m_hReadThread){ 140 // ResumeThread(m_hReadThread); 141 return TRUE; 142 }else{ 143 m_bReading = FALSE; 144 return FALSE; 145 } 146 147 return FALSE; 148 } 149 // 取消串口的读操做 150 // 1, 判断串口是否已经打开; 151 // 2,判断读线程是否已经建立; 152 // 3,设置成员变量; 153 BOOL CSerialPort::Deactivate() 154 { 155 if(INVALID_HANDLE_VALUE == m_hPortHandle){ 156 return FALSE; 157 } 158 159 if(INVALID_HANDLE_VALUE == m_hReadThread){ 160 return FALSE; 161 } 162 163 if(m_bReading){ 164 WaitForSingleObject(m_hReadThread, INFINITE); 165 CloseHandle(m_hReadThread); 166 m_hReadThread = INVALID_HANDLE_VALUE; 167 m_bReading = FALSE; 168 return TRUE; 169 } 170 171 return FALSE; 172 } 173 // 窗口是否已经准备好进行读操做 174 BOOL CSerialPort::IsActivate() 175 { 176 return m_bReading; 177 } 178 179 // 往串口读数据的线程函数 180 // 对于线程处理函数须要是一个全局的或者静态的 181 // 因此你须要知道你当前须要知道你用的是哪一个串口 182 // 实例,顾此函数参数为串口实例指针 183 UINT CSerialPort::ReadPortProc(LPVOID lpParam) 184 { 185 // 1, 变量准备 186 CSerialPort *pPort = (CSerialPort*)lpParam; 187 CString temp; 188 char *buffer = NULL; 189 int buferSize = 512; 190 DWORD dwRead = 0; 191 BOOL bRead = FALSE; 192 193 // 2,基本条件判断 194 buffer = new char[buferSize]; 195 while((pPort->m_hPortHandle != INVALID_HANDLE_VALUE) && (pPort->m_bReading)){ 196 bRead = ReadFile(pPort->m_hPortHandle, buffer, buferSize, &dwRead, NULL); 197 if(!bRead){ 198 temp.LoadString(IDS_READFILE_FAIL); 199 AfxMessageBox(temp); 200 }else{ 201 if(0 != dwRead) 202 pPort->m_pDataArriveProc(buffer, buferSize, pPort->m_dwDestAddress); 203 } 204 } 205 206 return 0; 207 }
对于上述代码已编译经过,可是具体的还未测试,等后续完善!this
谢谢支持!spa