Windows串口类
2016-02-29 09:07
274 查看
最近又需要Windows下的串口,为了体验一下造轮子的乐趣,自己又写了一个串口类。
头文件:
头文件:
#ifndef MYSERIAL_H #define MYSERIAL_H #include <Windows.h> #include <iostream> #include <thread> class MySerial { public: MySerial():hCom(INVALID_HANDLE_VALUE),listenThreadClose(false) {} ~MySerial() { std::cout << "已调用析构函数" << std::endl; CloseHandle(hCom); listenThreadClose = true; Sleep(10); } const int ESC = 27; const int SPACE = 16; int open(int com_num, int input_buffer = 1024, int ouput_buffer = 1024, int baud = 115200, int byte_size = 8,int parity = 0, int stopbits = 0); int auto_open(int input_buffer = 1024, int ouput_buffer = 1024, int baud = 115200, int byte_size = 8,int parity = 0, int stopbits = 0); int send(unsigned char *send_buf,unsigned long data_len) const; void openListenThread(); void receive(const int data_len); private: HANDLE hCom; std::thread::id listenThreadID; bool listenThreadClose; int init(int input_buffer, int ouput_buffer, int baud, int byte_size,int parity, int stopbits) const; int open_file(LPCWSTR file_name, int input_buffer, int ouput_buffer, int baud, int byte_size, int parity, int stopbits); }; #endifcpp:
//c++标准库 #include <iostream> #include <sstream> #include <string> #include <thread> //windows平台库 #include <Windows.h> #include <conio.h> //获取键盘操作 //用户头文件 #include "mySerial.h" using namespace std; /************************************************* * 函数名称 : open_file * 函数功能 : 打开指定的串口并初始化 * 形参 : file_name 串口号 input_buffer 接收缓冲区 默认1024 ouput_buffer 发送缓冲区 默认1024 baud 波特率 默认115200 byte_size 字节长 默认8 parity 检验位 默认无 stopbits 停止位 默认1 * 返回值 : 0 成功 -1 失败 ****************************************************/ int MySerial::open_file(LPCWSTR file_name, int input_buffer, int ouput_buffer, int baud, int byte_size, int parity, int stopbits) { hCom = CreateFile(file_name, GENERIC_READ | GENERIC_WRITE, //允许读写 0, //此项必须为0 NULL, //no security attrs OPEN_EXISTING, //设置产生方式 FILE_FLAG_OVERLAPPED, //异步通信 FILE_FLAG_OVERLAPPED NULL); if (hCom == INVALID_HANDLE_VALUE) { std::cout << "串口打开失败" << std::endl; return -1; } int rec = init(input_buffer, ouput_buffer, baud, byte_size, parity, stopbits); if (rec == -1) { std::cout << "串口设置失败" << std::endl; return -1; } return 0; } /************************************************* * 函数名称 : open * 函数功能 : 打开指定的串口 * 形参 : com_num 串口编号 input_buffer 接收缓冲区 默认1024 ouput_buffer 发送缓冲区 默认1024 baud 波特率 默认115200 byte_size 字节长 默认8 parity 检验位 默认无 stopbits 停止位 默认1 * 返回值 : 0 成功 -1 失败 ****************************************************/ int MySerial::open(int com_num, int input_buffer, int ouput_buffer, int baud, int byte_size, int parity, int stopbits) { const std::wstring str = L"COM"; std::wstringstream stream; stream.clear(); stream << com_num; std::wstring com_name; stream >> com_name; com_name = str + com_name; int rec = open_file(com_name.c_str(), input_buffer, ouput_buffer, baud, byte_size, parity, stopbits); if (rec == -1) { while (1) { int key = _getch(); if (key == ESC) { this->~MySerial(); std::exit(0); } } } return 0; } /************************************************* * 函数名称 : auto_open * 函数功能 : 自动搜索串口打开 * 形参 : input_buffer 接收缓冲区 默认1024 ouput_buffer 发送缓冲区 默认1024 baud 波特率 默认115200 byte_size 字节长 默认8 parity 检验位 默认无 stopbits 停止位 默认1 * 返回值 : 0 成功 -1 失败 ****************************************************/ int MySerial::auto_open(int input_buffer, int ouput_buffer, int baud, int byte_size, int parity, int stopbits) { int i = 0; TCHAR port_name[25] = { 0 }; unsigned char sz_port_name[25] = { 0 }; long status = ERROR_SUCCESS; unsigned long dw_index = 0; unsigned long dw_long; unsigned long dw_sizeof_port_name; unsigned long type; HKEY hKey; LPCTSTR data_Set = L"HARDWARE\\DEVICEMAP\\SERIALCOMM\\"; //LPCTSTR data_Set = L"HARDWARE\\DEVICEMAP\\SERIALCOMM"; dw_long = sizeof(port_name); dw_sizeof_port_name = sizeof(sz_port_name); bool success_or_not = 0; long ret0 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, //打开主键名称 data_Set, //打开的子键 0, //保留值 必须为0 KEY_READ, // 访问权限 &hKey); //返回的串口句柄 //打开一个制定的注册表键 成功返回ERROR_SUCCESS if (ret0 == ERROR_SUCCESS) //调用成功 { while (status == ERROR_SUCCESS) { status = RegEnumValue(hKey, dw_index++, port_name, &dw_long, NULL, &type, sz_port_name, &dw_sizeof_port_name); //读取键值 if (status == ERROR_SUCCESS ) { //open(LPCTSTR(&sz_port_name)); int rec = open_file(LPCTSTR(sz_port_name), input_buffer, ouput_buffer, baud, byte_size, parity, stopbits); if (rec == 0) { success_or_not = 1; std::cout << "已打开:"; for (unsigned long i = 0; i != dw_sizeof_port_name; ++i) { if (sz_port_name[i] == '\0') //奇怪 得到的se_port_name是'C''\0''O''\0''M''\0''4' 这种形式的 continue; std::cout << sz_port_name[i]; } std::cout << std::endl; } } dw_index = sizeof(port_name); dw_sizeof_port_name = sizeof(sz_port_name); } RegCloseKey(hKey); } if(success_or_not == 0) { std::cout << "串口未打开! QAQ" << std::endl << "ESC键退出" << std::endl; while(1) { int key = _getche(); if (key == ESC) { this->~MySerial(); std::exit(0); } ///*if (key == SPACE) //{ // std::cout << "串口未打开" << std::endl; // break; //}*/ } } return 0; } /************************************************* * 函数名称 : init * 函数功能 : 设置串口参数 * 形参 : input_buffer 接收缓冲区 默认1024 ouput_buffer 发送缓冲区 默认1024 baud 波特率 默认115200 byte_size 字节长 默认8 parity 检验位 默认无 stopbits 停止位 默认1 * 返回值 : 0 成功 -1 失败 ****************************************************/ int MySerial::init(int input_buffer, int ouput_buffer, int baud , int byte_size ,int parity , int stopbits ) const { //输入缓冲区和输出缓冲区 SetupComm(hCom, input_buffer, ouput_buffer); //设置事件驱动类型 SetCommMask(hCom, EV_RXCHAR); COMMTIMEOUTS time_outs; //设定读超时 time_outs.ReadIntervalTimeout = MAXWORD; time_outs.ReadTotalTimeoutConstant = 0; time_outs.ReadTotalTimeoutMultiplier = 0; //设定写超时 time_outs.WriteTotalTimeoutConstant = 2000; time_outs.WriteTotalTimeoutMultiplier = 50; SetCommTimeouts(hCom, &time_outs); DCB dcb; GetCommState(hCom, &dcb); switch (baud) { case 2400: case 4800: case 9600: case 115200: case 38400: dcb.BaudRate = baud; break; default: std::cout << "波特率参数错误" << std::endl; return -1; } switch (byte_size) { case 4: case 5: case 6: case 7: case 8: dcb.ByteSize = byte_size; break; default: std::cout << "字节数参数错误" << std::endl; return -1; } switch (parity) { case 0: dcb.Parity = NOPARITY; //无校验 break; case 1: dcb.Parity = ODDPARITY; //奇校验 break; case 2: dcb.Parity = EVENPARITY; //偶检验 break; case 3: dcb.Parity = MARKPARITY; //标记校验 break; default: std::cout << "校验位参数错误" << std::endl; return -1; } switch (stopbits) { case 0: dcb.StopBits = ONESTOPBIT; //一位停止位 break; case 1: dcb.StopBits = ONE5STOPBITS; //1.5位停止位 break; case 2: dcb.StopBits = TWOSTOPBITS; //2位停止位 break; default: std::cout << "停止位参数错误" << std::endl; return -1; } SetCommState(hCom, &dcb); //写入参数 PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); //清干净输入、输出缓冲区 return 0; } /************************************************* * 函数名称 : send * 函数功能 : 发送数据 * 形参 : senf_buf 发送数据 data_len 数据长度 * 返回值 : 0 成功 -1 失败 ****************************************************/ int MySerial::send(unsigned char *send_buf,unsigned long data_len) const { DWORD errorFlags; COMSTAT comStat; DWORD numOfBytesWritten; //实际写入的数据字节数 OVERLAPPED wOverlapped = { 0,0,0,0,NULL }; // memset(&wOverlapped, 0, sizeof(OVERLAPPED)); wOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ClearCommError(&wOverlapped, &errorFlags, &comStat); WriteFile(hCom, send_buf, data_len, &numOfBytesWritten, &wOverlapped); if (WaitForSingleObject(wOverlapped.hEvent, 20) == WAIT_OBJECT_0) //等待的对象变为已通知状态 { return 0; } return -1; } /************************************************* * 函数名称 : openListenThread * 函数功能 : 打开监听线程 接收数据 * 形参 : 无 * 返回值 : 无 ****************************************************/ void MySerial::openListenThread() { thread listenThread(&MySerial::receive,this,5); listenThreadID = listenThread.get_id(); listenThread.detach(); } /************************************************* * 函数名称 : receive * 函数功能 : 接收数据 * 形参 : rcv_buf 接收数据缓存区 data_len 接收数据长度 * 返回值 : 0 成功 -1 失败 ****************************************************/ void MySerial::receive(const int data_len) { unsigned char receiveBuffer[100] = { 0 }; unsigned char receiveData[20] = { 0 }; //输入缓冲区 //接收到的正确数据 DWORD commEvtMask = 0; OVERLAPPED rOverlapped; DWORD error; COMSTAT comStat; DWORD numOfBytesRead; //实际读入的数据字节数 memset(&rOverlapped, 0, sizeof(OVERLAPPED)); rOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); while (!listenThreadClose) { ResetEvent(rOverlapped.hEvent); DWORD rec = WaitCommEvent(hCom, &commEvtMask, &rOverlapped); if (!rec) { continue; } else { rec = ClearCommError(hCom, &error, &comStat); if (comStat.cbInQue == 0) continue; } WaitForSingleObject(rOverlapped.hEvent, INFINITE); // rec = ClearCommError(hCom, &error, &comStat); if (comStat.cbInQue == 0) continue; ReadFile(hCom, receiveBuffer, comStat.cbInQue, &numOfBytesRead, &rOverlapped); int receiveFlag = 0; int j = 0; for (int i = 0; i != 100; ++i) { if (receiveBuffer[i] == 0xFF && receiveBuffer[i+1] == 0xDD) receiveFlag = 1; if (receiveFlag == 1) { receiveData[j] = receiveBuffer[i]; if (j == data_len + 2) { unsigned char checkNum = 0; for (int k = 0; k < data_len + 2; ++k) { checkNum += receiveData[k]; } if (checkNum == receiveData[j]) { receiveFlag = 2; break; } else { receiveFlag = 0; break; } } j++; } } PurgeComm(hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); memset(&receiveBuffer, 0, 100 * sizeof(unsigned char)); memset(&receiveData, 0, 20 * sizeof(unsigned char)); } } /************************************************* * 函数名称 : * 函数功能 : * 形参 : * 返回值 : 0 成功 -1 失败 ****************************************************/
相关文章推荐
- 开源 java CMS - FreeCMS2.4 模型管理
- 《基于MFC的OpenGL编程》Part 6 Animation
- 51nod 1042:数字0-9的数量
- 不同文本模型的选择之ROC曲线
- Linux学习方法之以始为终—Linux工作分类
- sql server 2008误操作 恢复数据库的方法--日志尾部备份
- 2016.2.29 工作笔记
- 机房重构——存储过程详解
- 十个看似无用实则逆天的数据应用小段子
- 当宽字节遇到了搜索型注入还能注入么?
- LeetCode:Roman to Integer
- Android LogUtil(log工具类)
- 冒泡排序
- 市场需求调研-待续
- nginx upstream timed out 10060错误解决
- DialogFragment
- acm系统开发笔记
- Maven配置
- Android客户端性能优化(魅族资深工程师毫无保留奉献)
- 机器学习入门方法