近几天需要用linux的串口,在网上找了一些例子,随后又自己改成了一个类
可以发送,接收未测试。
头文件:
#ifndef MYSERIAL_H
#define MYSERIAL_H
class MySerial
{
public:
MySerial()
{};
int UART_open(const char *portName);
int UART_open(int uartNum);
int UART_set(int baud = 115200,int flow_ctrl = 0,int databits = 8,int stopbits = 1,int parity = 0);
int UART_init(int baud = 115200,int flow_ctrl = 0,int databits = 8,int stopbits = 1,int parity = 0);
int UART_recv(unsigned char *rcv_buf,int data_len);
int UART_send(unsigned char *send_buf,int data_len);
~MySerial();
private:
int fd; //串口设备描述符
};
#endif
cpp:
/****************************************************************
* FileName: mySerial.cpp
* Author: sfy
* Description: linux串口类
****************************************************************/
#include <iostream>
#include <unistd.h> //Unix 标准函数定义
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <string>
#include <vector>
#include <utility>
#include <sstream>
#include "mySerial.h"
using namespace std;
/***********************************************************************
* 名称: UART_open
* 功能: 打开指定串口并返回状态
* 入口参数: portName:串口号(ttyUSB0,ttyUSB1,ttyUSB2)
* 返回值: 正确打开返回0 错误返回-1
************************************************************************/
int MySerial::UART_open(const char *portName)
{
fd = open(portName,O_RDWR|O_NOCTTY|O_NDELAY);//非阻塞模式打开
if(fd == -1)
{
cout << "Can't open serial port" << *portName << endl;
return -1;
}
//判断串口的状态是否为阻塞状态
int BOOL = fcntl(fd,F_SETFL,0);
if(BOOL < 0)
{
cout << "fcntl failed" << endl;
return -1;
}
else
{
printf("fcntl=%d\n",BOOL);
}
//测试是否为终端设备
if(!isatty(STDIN_FILENO))
{
cout << "standard input is not a terminal device" << endl;
return -1;
}
else
{
cout << "isatty success!" << endl;
}
//cout << "fd->open" << fd << endl;
return 0;
}
/***********************************************************************
* 名称: UART_open
* 功能: 打开串口并返回状态
* 入口参数: uartNum:串口号 自动打开0-uartNum之间的一个串口号
* 返回值: 正确返回0 错误返回-1
************************************************************************/
int MySerial::UART_open(int uartNum)
{
stringstream stream;
string uartName = "/dev/ttyUSB";
string str;
bool BOOL;
for(int i = 0;i <= uartNum; ++i)
{
stream.clear();
stream << i;
stream >> str;
str = uartName + str;
fd = open(str.c_str(),O_RDWR|O_NOCTTY|O_NDELAY);//非阻塞模式打开
if(fd != -1)
{
cout << "open serial port " << str << " successed" << endl;
break;
}
cout << "open serial port " << str << " failed" << endl;
if(i == uartNum)
{
return -1;
}
}
//判断串口的状态是否为阻塞状态
BOOL = fcntl(fd,F_SETFL,0);
if(BOOL < 0)
{
cout << "fcntl failed" << endl;
return -1;
}
else
{
printf("fcntl=%d\n",BOOL);
}
//测试是否为终端设备
if(!isatty(STDIN_FILENO))
{
cout << "standard input is not a terminal device" << endl;
return -1;
}
else
{
cout << "isatty success!" << endl;
}
//cout << "fd->open" << fd << endl;
return 0;
}
/***************************************************************************
* 名称: UART_set
* 功能: 设置串口数据位,停止位,校验位
* 入口参数: baud 波特率 2400 4800 9600 115200
* flow_ctrl 数据流控制 0 1 2
* databits 数据位 7或8
* stopbits 停止位 1或2
* parity 校验类型 0 1 2
* 返回值: 正确返回0 错误返回-1
*****************************************************************************/
int MySerial::UART_set(int baud ,int flow_ctrl ,int databits ,int stopbits ,int parity )
{
typedef std::pair< int,int> Baud;
vector<Baud> baud_list;
baud_list.push_back(Baud(2400,B2400));
baud_list.push_back(Baud(4800,B4800));
baud_list.push_back(Baud(9600,B9600));
baud_list.push_back(Baud(115200,B115200));
struct termios options;
/*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将他们保存与options,该函数还可以测试配置是否正确,
该串口是否可用等,若调用成功,函数返回0,若调用失败,返回-1 */
if(tcgetattr(fd,&options) !=0)
{
cout << "设置串口失败" <<endl;
return -1;
}
for(vector< Baud >::iterator iter=baud_list.begin();iter!=baud_list.end();++iter)
{
if(iter->first == baud)
{
cfsetispeed(&options,iter->second);
cfsetospeed(&options,iter->second);
}
}
//修改控制模式 保证程序不会占用串口
options.c_cflag |= CLOCAL;
//修改控制模式 使得能够从串口中读输入数据
options.c_cflag |= CREAD;
//设置数据流控制
switch (flow_ctrl)
{
case 0 : //不使用流控制
options.c_cflag &= ~CRTSCTS;
break;
case 1 : //使用硬件流控制
options.c_cflag |= CRTSCTS;
break;
case 2 : //使用软件流控制
options.c_cflag |= IXON |IXOFF |IXANY;
break;
default :
cout << "数据流参数错误" << endl;
return -1;
}
//设置数据位
options.c_cflag &= ~CSIZE; //屏蔽其他标志位
switch(databits)
{
case 5 :
options.c_cflag |= CS5;
break;
case 6 :
options.c_cflag |= CS6;
break;
case 7 :
options.c_cflag |= CS7;
break;
case 8 :
options.c_cflag |= CS8;
break;
default :
cout << "数据位参数错误" << endl;
return -1;
}
//设置校验位
switch(parity)
{
case 0 : //无奇偶校验位
options.c_cflag &= ~PARENB;
//options.c_iflag &= ~INPCK;
break;
case 1 : //奇校验
options.c_cflag |= (PARODD | PARENB);
//options.c_iflag |= INPCK;
break;
case 2 : //偶校验
options.c_cflag &= ~PARENB;
options.c_cflag &= ~PARODD;
//options.c_iflag |= INPCK;
break;
case 3 : //设置为空格
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default :
cout << "校验位参数错误" << endl;
return -1;
}
//设置停止位
switch(stopbits)
{
case 1 :
options.c_cflag &= ~CSTOPB;
break;
case 2 :
options.c_cflag |= CSTOPB;
break;
default :
cout << "停止位参数错误" << endl;
return -1;
}
//修改输出模式 原始数据输出
options.c_oflag &= ~OPOST;
//设置等待时间和最小接受字符
options.c_cc[VTIME] = 1; // 读取一个字符等待1*(1/10)s
options.c_cc[VMIN ] = 1; // 读取字符的最小个数为1
//如果发生数据溢出,接受数据,但是不再读取
tcflush(fd,TCIFLUSH);
//将修改后的数据设置写入串口
if(tcsetattr(fd,TCSANOW,&options) != 0) //立即生效
{
cout << "com set error" << endl;
return -1;
}
return 0;
}
/**********************************************************
* 名称: USRT_init()
* 功能: 串口初始化
* 入口参数: fd 文件描述符
* baud 串口波特率
* flow_ctrl 数据流控制
* databits 数据位 7或8
* stopbits 停止位 1或2
* parity 检验类型 N E O S
* 返回值: 正确返回0 ,错误返回-1
*************************************************************/
int MySerial::UART_init(int baud ,int flow_ctrl ,int databits ,int stopbits ,int parity )
{
//设置串口数据帧格式
if(UART_set(baud,flow_ctrl,databits,stopbits,parity) != 0)
{
cout << "set uart error" << endl;
return -1;
}
return 0;
}
/**********************************************************************
* 名称: UART_recv
* 功能: 接受串口数据
* 入口参数: rcv_buf 数据缓存区
* data_len 一帧数据的长度
* 返回值: 正确返回实际接受字符数 错误返回-1
*************************************************************************/
int MySerial::UART_recv(unsigned char *rcv_buf,int data_len)
{
int len,fs_sel;
fd_set fs_read;
struct timeval time;
FD_ZERO(&fs_read);
FD_SET(fd,&fs_read);
time.tv_sec = 10;
time.tv_usec = 0;
//使用select实现串口的多路通信
fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);
if(fs_sel)
{
len = read(fd,rcv_buf,data_len);
return len;
}
return -1;
}
/******************************************************************************
* 名称: UART_send
* 功能: 发送数据
* 入口参数: send_buf 发送缓存区
* data_len 一帧数据个数
* 返回值: 正确返回实际发送字符数 错误返回-1
*******************************************************************************/
int MySerial::UART_send(unsigned char *send_buf, int data_len)
{
int len = 0;
len = write(fd,send_buf,data_len); //返回实际串口发送字符数
if(len == data_len)
{
return len;
}
tcflush(fd,TCOFLUSH);
return -1;
}
/********************************************************************************
* 名称: ~MySerial
* 功能: 析构函数 关闭串口
* 入口参数: void
* 返回值: void
*********************************************************************************/
MySerial::~MySerial()
{
close(fd);
}
使用例子:
#include "mySerial.h"
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
unsigned char send_buf[20] = "1234567891";
MySerial serial;
bool BOOL =serial.UART_open(5);
if(BOOL !=0)
{
return -1;
}
serial.UART_init(115200,0,8,1,0);
while(1)
{
int len = serial.UART_send(send_buf,20);
if(len > 0)
cout << "send data successful" << endl;
else
cout << "send datafailed" << endl;
sleep(1);
}
return 0;
}