<linux+qt>使用thread监控串口通信(一)
最近做的项目需要使用到串口通信方面的知识,就这方面的内容加以总结和分享:(1)首先是串口的读写操作,都是在Linux下进行的操作1.1 串口的打开//打开串口/******************************************************************************* 函数名称:OpenSerialPort()* 功
最近做的项目需要使用到串口通信方面的知识,就这方面的内容加以总结和分享:
(1)首先是串口的读写操作,都是在Linux下进行的操作
1.1 串口的打开
//打开串口
/******************************************************************************
* 函数名称: OpenSerialPort()
* 功能描述: 打开串口
* 输入参数: int iComNum // 串口号(COM0,COM1,COM2等)
* 输出参数:
* 返回值: 打开的串口的文件描述符
* 其它说明:
* 修改历史:
******************************************************************************/
static int OpenSerialPort(int iComNum)// 串口号(COM1,COM2等)
{
/* 各变量的定义 */
int fd = -1; // 串口的文件描述符
if ( 1 == iComNum ) // 串口1
{
fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY);
if ( -1 == fd )
{
perror("Can't Open Serial Port 1");
return (-1);
}
}
else if ( 2 == iComNum ) // 串口2
{
fd = open("/dev/ttyS2", O_RDWR | O_NOCTTY | O_NDELAY);
if ( -1 == fd )
{
perror("Can't Open Serial Port 2");
return (-1);
}
}
else if ( 3 == iComNum ) // 串口3
{
fd = open("/dev/ttyS3", O_RDWR | O_NOCTTY | O_NDELAY);
if ( -1 == fd )
{
perror("Can't Open Serial Port 3");
return (-1);
}
}
//change by hss delete 0 add 4 serial port
else if ( 4 == iComNum ) // 串口4
{
fd = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY);
if ( -1 == fd )
{
perror("Can't Open Serial Port 4");
return (-1);
}
}
else
{
printf("system don't have Serial Port %d\n",iComNum);
return -1;
}
fcntl(fd, F_SETFL, O_NONBLOCK); //非阻塞
/* 测试是否为一个终端设备,以进一步确认串口是否正确打开 */
if( 0 == isatty(STDIN_FILENO) )
{
printf("standard input is not a terminal device.\n");
}
else
{
;// printf("is a tty success!\n");
}
// printf("fd-open = %d\n", fd);
return fd;
}
使用到的函数fcntl(fd, F_SETFL, 0); //此为阻塞方式
/******************************************************************************
* 函数名称: SetSerialPort()
* 功能描述: 配置串口参数
* 输入参数: int fd, // 串口的文件描述符
* int iSerialPortSpeed, // 串口速率(读写速率一致)
* int iBits, // 数据位 或 字符大小 ???
* char cParityCheck, // 奇偶校验位
* int iStop // 停止位
* 输出参数: 无
* 返回值: int
* 其它说明:
******************************************************************************/
int SetSerialPort(
int fd, // 串口的文件描述符
int iSerialPortSpeed, // 串口速率(读写速率一致)
int iBits, // 数据位 或 字符大小 ???
int iParityCheck, // 奇偶校验位
int iStop, // 停止位
int iFlowControl // 流控标志位
)
{
/* 各变量的定义 */
struct termios TNewSerialPortParam; // 新串口配置参数
struct termios TOldSerialPortParam; // 老串口配置参数
/* 各变量值的赋值和初始化 */
/* 函数任务开始 */
// 保存测试现有串口的参数设置,如果串口号等出错,则有相关出错信息
if ( 0 != tcgetattr( fd, &TOldSerialPortParam ) )
{
perror("SetupSerial 1");
return (-1);
}
// 新串口配置参数清零
bzero( &TNewSerialPortParam, sizeof(TNewSerialPortParam) );
// 激活本地连接和接收使能
TNewSerialPortParam.c_cflag |= CLOCAL | CREAD;
// 设置数据位
TNewSerialPortParam.c_cflag &= ~CSIZE;
switch ( iBits )
{
case 7:
TNewSerialPortParam.c_cflag |= CS7;
break;
case 8:
TNewSerialPortParam.c_cflag |= CS8;
break;
default: // 默认数据位为8
TNewSerialPortParam.c_cflag |= CS8;
break;
}// end of switch ( iBits )
// 设置波特率
switch ( iSerialPortSpeed )
{
case 2400:
同下
case 4800:
同下
case 9600:
cfsetispeed( &TNewSerialPortParam, B9600);
cfsetospeed( &TNewSerialPortParam, B9600);
break;
case 19200:
同上
case 38400:
同上
case 57600:
同上
case 115200:
cfsetispeed( &TNewSerialPortParam, B115200 );
cfsetospeed( &TNewSerialPortParam, B115200);
break;
case 460800:
同上
default:
cfsetispeed( &TNewSerialPortParam, B9600 );
cfsetospeed( &TNewSerialPortParam, B9600);
break;
}// end of switch ( iSerialPortSpeed )
// 设置奇偶校验位
switch ( iParityCheck )
{
case ODD_CHECK: // 奇校验
TNewSerialPortParam.c_cflag |= PARENB;
TNewSerialPortParam.c_cflag |= PARODD;
TNewSerialPortParam.c_iflag |= (INPCK | ISTRIP);
break;
case EVEN_CHECK: // 偶校验
TNewSerialPortParam.c_iflag |= (INPCK | ISTRIP);
TNewSerialPortParam.c_cflag |= PARENB;
TNewSerialPortParam.c_cflag &= ~PARODD;
break;
case NO_CHECK: // 无奇偶校验位
TNewSerialPortParam.c_cflag &= ~PARENB;
break;
default: // 默认无奇偶校验位
TNewSerialPortParam.c_cflag &= ~PARENB;
break;
}// end of switch ( cParityCheck )
// 设置停止位
switch ( iStop )
{
case 2: // 停止位为2,激活CSTOPB
TNewSerialPortParam.c_cflag |= CSTOPB;
break;
case 1: // 停止位为1,清除CSTOPB
TNewSerialPortParam.c_cflag &= ~CSTOPB;
break;
default: // 默认停止位为1
TNewSerialPortParam.c_cflag &= ~CSTOPB;
break;
}// end of switch ( iStop )
// 设置流控
switch ( iFlowControl )
{
case NO_FLOW_CTRL: // 无流控
TNewSerialPortParam.c_cflag &= ~CRTSCTS; // 关闭硬件流控
TNewSerialPortParam.c_iflag &= ~( IXON | IXOFF | IXANY );// 关闭软件流控
break;
case HARD_FLOW_CTRL: // 硬流控
TNewSerialPortParam.c_cflag |= CRTSCTS; // 开启硬件流控
TNewSerialPortParam.c_iflag &= ~( IXON | IXOFF | IXANY );// 关闭软件流控
break;
case SOFT_FLOW_CTRL: // 软流控
TNewSerialPortParam.c_cflag &= ~CRTSCTS; // 关闭硬件流控
TNewSerialPortParam.c_iflag |= ( IXON | IXOFF | IXANY );// 开启软件流控
break;
default: // 默认无流控
TNewSerialPortParam.c_cflag &= ~CRTSCTS; // 关闭硬件流控
TNewSerialPortParam.c_iflag &= ~( IXON | IXOFF | IXANY );// 关闭软件流控
break;
}// end of switch ( iFlowControl )
// 设置等待时间和最小接收字符
TNewSerialPortParam.c_cc[VTIME] = 0;
TNewSerialPortParam.c_cc[VMIN] = 0;
// 处理未接受字符
tcflush( fd, TCIFLUSH );
// 激活新配置
if ( 0 != tcsetattr(fd, TCSANOW, &TNewSerialPortParam) )
{
perror("com set error");
return (-1);
}
// printf("set done!\n");
/* 函数任务结束 */
return 0;
}
用以上两个函数,打开串口,并设置串口的各项属性,主要的有波特率等信息,设置错误即使打开串口也无法通信。
调用例子:
int di_s4b_comfd = OpenSerialPort();
SetSerialPort(di_s4b_comfd, //文件描述符
115200,//波特率
8,//数据位
0,//奇偶校验位
1,//停止位
0);//流控标志位
1.2 数据的写入
写操作较为简单,因为不需要一直监视串口,直接写到串口就可以,不完备的写操作大致如下:
/*
将ACK通过三号端口写出
*/
void writeMessage()
{
int comfd = sthread->retComfd();//由外部获得端口的文件描述符
const char array[]={'A','C','K'};
write(comfd,array,3);
qDebug("writeMessage done!");
}
主要使用的函数为write函数
ssize_t write(int fd, const void *buf, size_t count);
返回值为写入串口的数据长度,buf为写入的数据,count为数据长度
以上例子是一个不完备的写入情况,没有对写入不完全的情况进行处理,也没有考虑资源的保护和互斥的使用。
1.3 数据的读出
数据的读出较写入麻烦,原因在于对读取数据时机的判断,为在数据到达时立即得到通知,并把数据读出,需要时时对端口进行监控,同时主程序保持运行,此时就需要用到多线程,一个主线程,一个守护线程。此处先给出读数据的示例代码,多线程串口通信在下一节给出。
/*
子线程一直监视串口,在有数据时,将其读出
*/
void SThread::run()
{
while (1)
{
res = read(di_s4b_comfd, tosendstr, 4);
if (res >=4)
{
qDebug("abcd\n");
emit get(1);
}
}
qDebug("Serial done\n");
}
read函数原型
#include<unistd.h>
ssize_t read(intfd, void *buf, size_t count);
read返回为读取字符串的长度,fd为端口的文件描述符,buf为读取的数据,count为长度。
更多推荐
所有评论(0)