首页 > 代码库 > 跨平台串口编程
跨平台串口编程
希望这套API可以帮助有需要的人!
如果您有异议,请给出理由,让我可以改善存在的问题,谢谢。
如果您在使用中发现问题,请及时联系我。
我承认在用C++写 C,纯粹为了封装方便,如果是这个原因要喷我,那我替您先喷了..
虽说是跨平台但我测试的平台有限。
windows7 x32使用vs2008编译运行成功
Ubuntu12.04 x32 使用gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 编译运行成功
arm-linux-gcc [ gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203) ] 交叉编译成功
关于Linux下使用欢迎参考我的一篇短文
http://my.oschina.net/mlgb/blog/300925
#ifndef SERIALPORT_H_ #define SERIALPORT_H_ #include <stddef.h> #ifdef _WIN32 #include <Windows.h> typedef HANDLE serial_t; #elif defined __linux__ typedef int serial_t; #endif enum COMPARAM { CHECK_NONE, //无校验 CHECK_ODD, //奇校验 CHECK_EVEN, //偶校验 STOP_1, //停止位1 STOP_1_5, //停止位1.5 STOP_2, //停止位2 DATA_7, //数据位7 DATA_8 //数据位8 }; enum COMIO { COM_IN, //输入选项 COM_OUT //输出选项 }; class SerialPort { public: SerialPort(void); ~SerialPort(void); /* *打开串口 *Param: * [IN]port COM端口 * [IN]opt Windows平台 是否启用重叠IO * Linux平台 是否启用非阻塞方式 * */ bool open(int port,bool opt = false); /* *关闭串口 * */ void close(); /* *设置串口属性 *Param: * [IN]rate 波特率 * [IN]check_bit 校验位 * [IN]stop_bit 停止位(linux无1.5) * [IN]data_bit 数据位 * */ bool set_attribute( size_t rate, COMPARAM check_bit = CHECK_NONE, COMPARAM stop_bit = STOP_1, COMPARAM data_bit = DATA_8); /* *设置超时 *Param: * [IN]write_ms 写超时(单位 毫秒) * [IN]read_ms 读超时(单位 毫秒) * [IN]flag Windows下指定间隔延迟 Linux下指定非规范模式的最小字符数 *Other * linux在非阻塞模式下设置超时无效 * 超时设置为0时“效果”等同于非阻塞模式 * read超时返回0 * */ bool set_timeout(size_t write_ms,size_t read_ms,int flag = 0); /* *发送数据 *Param: * [IN]sendBuf 发送数据缓存 * [IN]len 发送数据长度 */ int send(const char* sendBuf,size_t len); /* *接收数据 *Param: * [OUT]recvBuf 接收数据缓存 * [IN] len 接收数据长度 */ int recv(char* recvBuf,size_t len); /* *终止IO操作 *Param: * [IN]mode 指定需要操作的IO */ void abort(COMIO mode); /* *清空缓冲区数据 *Param: * [IN]mode 指定需要操作的IO */ void clear_buff(COMIO mode); /* *开放使用和平台相关的高级IO操作 *如: *LINUX下的select和poll模型 *WIN32下的Overlapped模型 * */ serial_t get_serial_handle(); #ifdef _WIN32 /* *获取接收缓冲区数据长度 */ size_t peek(); #endif #ifdef __linux__ /* *设置LINUX下串口阻塞方式 *Param: * [IN]isBlock 是否阻塞 */ bool set_block(bool isBlock); #endif private: serial_t m_hSerial;//串口句柄/描述符 }; #endif //SERIALPORT_H_
#include "SerialPort.h" #include <stdio.h> #ifdef _WIN32 #define INVALID_SERRAL INVALID_HANDLE_VALUE #elif defined __linux__ #include <unistd.h> #include <fcntl.h> //open close #include <termios.h>//struct termios #define INVALID_SERRAL -1 size_t t_raw_rate[] = { 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000 }; size_t t_unix_rate[] = { B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000 }; #endif SerialPort::SerialPort(void) { m_hSerial = INVALID_SERRAL; } SerialPort::~SerialPort(void) { this->close(); } bool SerialPort::open(int port,bool opt) { char com[16]={0}; #ifdef _WIN32 #ifdef WINCE sprintf(com,"COM%d:",port); #else sprintf(com,"COM%d",port); #endif DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; if(opt) { dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED; } m_hSerial = CreateFile(com, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); #elif defined __linux__ #ifdef __arm__ sprintf(com,"/dev/ttySAC%d",port-1); #else sprintf(com,"/dev/ttyS%d",port-1); #endif int flags = O_RDWR | O_NOCTTY; if(opt) { flags |= O_NDELAY; } m_hSerial = ::open(com,flags); #endif return (m_hSerial != INVALID_SERRAL)?true:false; } void SerialPort::close() { if(m_hSerial != INVALID_SERRAL) { #ifdef _WIN32 CloseHandle(m_hSerial); #elif defined __linux__ ::close(m_hSerial); #endif m_hSerial = INVALID_SERRAL; } } bool SerialPort::set_attribute( size_t rate, COMPARAM check_bit, COMPARAM stop_bit, COMPARAM data_bit) { if(m_hSerial == INVALID_SERRAL) return false; #ifdef _WIN32 DCB dcb = {0}; dcb.BaudRate = rate; dcb.fParity = TRUE; dcb.fBinary = FALSE; if(check_bit == CHECK_NONE) { dcb.fParity = FALSE; dcb.Parity = NOPARITY; } else if(check_bit == CHECK_ODD) { dcb.Parity = ODDPARITY; } else if(check_bit == CHECK_EVEN) { dcb.Parity = EVENPARITY; } if(stop_bit == STOP_1) { dcb.StopBits = ONESTOPBIT; } else if(stop_bit == STOP_1_5) { dcb.StopBits = ONE5STOPBITS;; } else if(stop_bit == STOP_2) { dcb.StopBits = TWOSTOPBITS; } if(data_bit == DATA_8) { dcb.StopBits = 8; } else if(data_bit == DATA_7) { dcb.StopBits = 7; } if( ! SetCommState(m_hSerial,&dcb) ) { return false; } SetupComm(m_hSerial,50/*IN BUF*/,50/*OUT BUFF*/); PurgeComm(m_hSerial,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); #elif defined __linux__ struct termios com_cfg = {0}; size_t raw_rate = 0; size_t i=0; for(i=0; i< sizeof(t_raw_rate)/sizeof(size_t) ; i++) { if(t_raw_rate[i] == rate) { raw_rate = t_unix_rate[i]; break; } } if(!raw_rate) { return false; } else { cfsetispeed(&com_cfg,raw_rate);//IN speend; cfsetospeed(&com_cfg,raw_rate);//OUT speend; } switch(check_bit) { case CHECK_NONE: com_cfg.c_cflag &= ~PARENB; com_cfg.c_iflag &= ~INPCK; break; case CHECK_ODD: com_cfg.c_cflag |= (PARODD|PARENB); com_cfg.c_iflag |= INPCK; break; case CHECK_EVEN: com_cfg.c_cflag |= PARENB; com_cfg.c_iflag &= ~PARODD; com_cfg.c_iflag |= INPCK; break; default: return false; } switch(stop_bit) { case STOP_1: com_cfg.c_cflag &= ~CSTOPB; break; case STOP_1_5: com_cfg.c_cflag &= ~CSTOPB;//Linux没有1.5停止位 break; case STOP_2: com_cfg.c_cflag |= CSTOPB; break; default: return false; } switch(data_bit) { case DATA_8: com_cfg.c_cflag &= ~CSIZE; com_cfg.c_cflag |= CS8; break; case DATA_7: com_cfg.c_cflag &= ~CSIZE; com_cfg.c_cflag |= CS7; break; default: return false; } tcflush(m_hSerial,TCIOFLUSH); com_cfg.c_cc[VTIME] = 0; com_cfg.c_cc[VMIN] = 1; if( tcsetattr(m_hSerial,TCSANOW,&com_cfg) ) { return false; } #endif return true; } bool SerialPort::set_timeout(size_t write_ms,size_t read_ms,int flag) { if(m_hSerial == INVALID_SERRAL) return false; #ifdef _WIN32 COMMTIMEOUTS to; memset(&to,0,sizeof(to)); /* 读间隔超时。 接收时,两字符间最大的时延。 * 将ReadIntervalTimeout设置为0, 则不使用间隔超时, 只考虑总超时设置 * */ to.ReadIntervalTimeout = flag; to.WriteTotalTimeoutMultiplier = 1;//写每字节的超时 to.WriteTotalTimeoutConstant = write_ms;//写串口数据的固定超时 // TIMEOUT = WriteTotalTimeoutMultiplier Bytecount + WriteTotalTimeoutConstant to.ReadTotalTimeoutMultiplier = 1; //读取每字节的超时 to.ReadTotalTimeoutConstant = read_ms; //读串口数据的固定超时 // TIMEOUT = ReadTotalTimeoutMultiplier * Bytecount + ReadTotalTimeoutConstant return (SetCommTimeouts(m_hSerial,&to) == TRUE)?true:false; #elif defined __linux__ struct termios com_cfg = {0}; tcgetattr(m_hSerial,&com_cfg);//get old setting com_cfg.c_cc[VTIME] = read_ms*0.01;//超时单位 百毫秒 com_cfg.c_cc[VMIN] = flag;//最少可读数据 超时有效必须是0 printf("[SET] VTIME(%d),VMIN(%d)\n",com_cfg.c_cc[VTIME],com_cfg.c_cc[VMIN]); return (!tcsetattr(m_hSerial,TCSANOW,&com_cfg) )?true:false; #endif } #ifdef __linux__ bool SerialPort::set_block(bool isBlock) { if(m_hSerial == INVALID_SERRAL) return false; if(isBlock) { printf("[SET] block mode\n"); return ( -1 == fcntl(m_hSerial,F_SETFL,0) )?false:true; } else { printf("[SET] no block mode\n"); return ( -1 == fcntl(m_hSerial,F_SETFL,FNDELAY) )?false:true; } return true; } #endif int SerialPort::send(const char* sendBuf,size_t len) { if(m_hSerial == INVALID_SERRAL) return 0; #ifdef _WIN32 DWORD write_len = 0; WriteFile(m_hSerial,sendBuf,len,&write_len,NULL); return write_len; #elif defined __linux__ return write(m_hSerial,sendBuf,len); #endif } int SerialPort::recv(char* recvBuf,size_t len) { if(m_hSerial == INVALID_SERRAL) return 0; #ifdef _WIN32 DWORD read_len = 0; ReadFile(m_hSerial,recvBuf,len,&read_len,NULL); return read_len; #elif defined __linux__ return read(m_hSerial,recvBuf,len); #endif } void SerialPort::abort(COMIO mode) { if(m_hSerial != INVALID_SERRAL) { if(mode == COM_IN) { #ifdef _WIN32 //中断所有读操作并立即返回,即使读操作还没有完成 PurgeComm(m_hSerial,PURGE_RXABORT); #elif defined __linux__ tcflush(m_hSerial,TCIOFF);//挂起输入 #endif } else if(mode == COM_OUT) { #ifdef _WIN32 //中断所有写操作并立即返回,即使写操作还没有完成 PurgeComm(m_hSerial,PURGE_TXABORT); #elif defined __linux__ tcflush(m_hSerial,TCOOFF);//挂起输出 #endif } } } void SerialPort::clear_buff(COMIO mode) { if(m_hSerial != INVALID_SERRAL) { if(mode == COM_IN) { #ifdef _WIN32 PurgeComm(m_hSerial,PURGE_RXCLEAR); #elif defined __linux__ tcflush(m_hSerial,TCIFLUSH); #endif } else if(mode == COM_OUT) { #ifdef _WIN32 PurgeComm(m_hSerial,PURGE_TXCLEAR); #elif defined __linux__ tcflush(m_hSerial,TCOFLUSH); #endif } } } serial_t SerialPort::get_serial_handle() { return m_hSerial; } #ifdef _WIN32 size_t SerialPort::peek() { if(m_hSerial == INVALID_SERRAL) { return 0; } DWORD dwErrorFlags; COMSTAT ComStat; ClearCommError( m_hSerial, &dwErrorFlags, &ComStat ); return ComStat.cbInQue; } #endif
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。