最近做的项目需要使用到串口通信方面的知识,就这方面的内容加以总结和分享:
(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 portelse 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: // 默认数据位为8TNewSerialPortParam.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,激活CSTOPBTNewSerialPortParam.c_cflag |= CSTOPB;break;case 1: // 停止位为1,清除CSTOPBTNewSerialPortParam.c_cflag &= ~CSTOPB;break;default: // 默认停止位为1TNewSerialPortParam.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为长度。
什么是串口监控 串口监控怎么使用
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Dtrace脚本监控串口 串口监控原理
目录一、定义 应用场景: 连接方式: 帧格式:二、代码编写 初始化串口 串口工
Dtrace脚本监控串口 单片机 stm32 物联网 串口