封装uart串口类及测试
封装uart串口类及测试
文章目录
封装uart串口类及测试1.串口类2.串口类测试程序3.测试结果
(1)阻塞接收测试:(2)非阻塞接收测试:(3)发送测试
1.串口类
我们后续将使用c++来开发程序,因此有必要将串口模块功能移植为串口类,移植后的结果:
serial.cpp:
#include "serial.h"#include #include #include #include #include #define SPEED_NUM 8 //支持的可设置的波特率的数量serial::serial(){ printf("构造完成\n");}serial::~serial(){ printf("析构完成\n");}serial::serial(const serial &obj){ }int serial::open_serial(int fd,char* port){ int ret = 0; fd = open(port, O_RDWR|O_NDELAY|O_NOCTTY); if(-1 == fd) { return -1; } ret = fcntl(fd, F_SETFL, 0); if(ret < 0) ; if(!isatty(STDIN_FILENO)) ; return fd;}void serial::close_serial(int fd){ close(fd);}int serial::set_serial(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity){ int i; int ret = 0; int status; struct termios options_old, options_new; ret = tcgetattr(fd, &options_old); if(ret) { printf("file:%s,line:%d.Tcgetattr failed,tcgetattr(fd,&options_old)->%d\n",__FILE__,__LINE__,tcgetattr(fd,&options_old)); return -1; } bzero(&options_new, sizeof(options_new)); set_char_uart0_char_size(&options_new); if(set_baud_rate(speed, &options_new) < 0) return -2; if(set_flow_control(flow_ctrl, &options_new) < 0) return -3; if(set_data_bits(databits, &options_new) < 0) return -4; if(set_parity_check_bits(parity, &options_new) < 0) return -5; if(set_stop_bits(stopbits, &options_new) < 0) return -6; options_new.c_cc[VTIME] = 1; options_new.c_cc[VMIN] = 0; tcflush(fd,TCIFLUSH); ret = tcsetattr(fd, TCSANOW, &options_new); if(ret) { printf("file:%s,line:%d.Tcsetattr failed\n",__FILE__,__LINE__); return -7; } return 0;}int serial::block_read_from_serial(int fd, char *rcv_buf, int recv_len){ int len = 0; int ret = 0; int time_flag = 0; fd_set rd; FD_ZERO(&rd); FD_SET(fd, &rd); if(select(fd +1, &rd, NULL, NULL, NULL) < 0) ; else if(FD_ISSET(fd, &rd) > 0) { while((ret = read(fd, rcv_buf + len,recv_len - 1 - len)) >= 0) { len+=ret; if(ret < 16) { time_flag = 1; break; } } if(!time_flag) return -2; } return len;}int serial::unblock_read_from_serial(int fd, int wait_time, char *rcv_buf, int recv_len){ int len = 0; int ret = 0; int time_flag = 0; fd_set rd; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = wait_time * 1000000; FD_ZERO(&rd); FD_SET(fd, &rd); if(select(fd + 1, &rd, NULL, NULL, &tv) < 0) ; else if(FD_ISSET(fd, &rd) > 0) { while ((ret = read(fd, rcv_buf + len,recv_len - 1 - len)) >= 0) { len+=ret; if(ret < 16) { time_flag = 1; break; } } if(!time_flag) return -2; } return len;}int serial::write_to_serial(int fd, char *send_buf, int data_len){ int len = 0; len = write(fd, send_buf, data_len); if(len == data_len) return len; else return -1;}void serial::set_char_uart0_char_size(struct termios* options){ options->c_cflag |= (CLOCAL|CREAD); options->c_cflag &= ~CSIZE; return;}int serial::set_baud_rate(int speed, struct termios* options){ int speed_arr[SPEED_NUM] = {B115200,B38400,B19200,B9600,B4800,B2400,B1200,B300}; int name_arr[SPEED_NUM] = {115200,38400,19200,9600,4800,2400,1200,300}; int flag = 0; int i; for(i = 0;i < SPEED_NUM;i++) { if(speed == name_arr[i]) { cfsetispeed(options,speed_arr[i]); cfsetospeed(options,speed_arr[i]); flag = 1; } } if(!flag) { printf("file:%s,line:%d.unsupported baud rate.\n",__FILE__,__LINE__); return -1; } return 1;}int serial::set_flow_control(int flow_ctrl, struct termios* options){ 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: return -1; } return 1;}int serial::set_data_bits(int databits, struct termios* options){ 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: return -1; } return 0;}int serial::set_parity_check_bits(int parity, struct termios* options){ switch (parity) { case 'n': case 'N': options->c_cflag &= ~PARENB; options->c_iflag &= ~INPCK; break; case 'o': case 'O': options->c_cflag |= (PARODD | PARENB); options->c_iflag |= INPCK; break; case 'e': case 'E': options->c_cflag |= PARENB; options->c_cflag &= ~PARODD; options->c_iflag |= INPCK; break; default: return -1; } return 1;}int serial::set_stop_bits(int stopbits, struct termios* options){ switch(stopbits) { case 1: options->c_cflag &= ~CSTOPB; break; case 2: options->c_cflag |= CSTOPB; break; default: return -1; } return 1;}
serial.h:
/****************************************************************************** 版权所有 (C), 2017-2019, ZY ****************************************************************************** 文 件 名 : serial.h 版 本 号 : 初稿 作 者 : ZY 生成日期 : 2018年9月13日 星期四 最近修改 : 功能描述 : serial.cpp 的头文件 函数列表 : 修改历史 : 1.日 期 : 2018年9月13日 星期四 作 者 : ZY 修改内容 : 创建文件******************************************************************************//*----------------------------------------------* * 包含头文件 * *----------------------------------------------*//*----------------------------------------------* * 外部变量说明 * *----------------------------------------------*//*----------------------------------------------* * 外部函数原型说明 * *----------------------------------------------*//*----------------------------------------------* * 内部函数原型说明 * *----------------------------------------------*//*----------------------------------------------* * 全局变量 * *----------------------------------------------*//*----------------------------------------------* * 模块级变量 * *----------------------------------------------*//*----------------------------------------------* * 常量定义 * *----------------------------------------------*//*----------------------------------------------* * 宏定义 * *----------------------------------------------*/#ifndef __SERIAL_H__#define __SERIAL_H__#ifdef __cplusplus#if __cplusplusextern "C"{#endif#endif /* __cplusplus */#includeclass serial{ private: void set_char_uart0_char_size(struct termios* options); int set_baud_rate(int speed, struct termios* options); int set_flow_control(int flow_ctrl, struct termios* options); int set_data_bits(int databits, struct termios* options); int set_parity_check_bits(int parity, struct termios* options); int set_stop_bits(int stopbits, struct termios* options); public: serial(); ~serial(); serial(const serial &obj); int open_serial(int fd,char* port); void close_serial(int fd); int set_serial(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity); int block_read_from_serial(int fd, char *rcv_buf, int recv_len); int unblock_read_from_serial(int fd, int wait_time, char *rcv_buf, int recv_len); int write_to_serial(int fd, char *send_buf, int data_len);};#ifdef __cplusplus#if __cplusplus}#endif#endif /* __cplusplus */#endif /* __SERIAL_H__ */
2.串口类测试程序
test.cpp:
/****************************************************************************** 版权所有 (C), 2017-2019, ZY ****************************************************************************** 文 件 名 : test.cpp 版 本 号 : 初稿 作 者 : ZY 生成日期 : 2018年9月13日 星期四 最近修改 : 功能描述 : 測試串口類是否可用 函数列表 : 修改历史 : 1.日 期 : 2018年9月13日 星期四 作 者 : ZY 修改内容 : 创建文件******************************************************************************//*----------------------------------------------* * 包含头文件 * *----------------------------------------------*//*----------------------------------------------* * 外部变量说明 * *----------------------------------------------*//*----------------------------------------------* * 外部函数原型说明 * *----------------------------------------------*//*----------------------------------------------* * 内部函数原型说明 * *----------------------------------------------*//*----------------------------------------------* * 全局变量 * *----------------------------------------------*//*----------------------------------------------* * 模块级变量 * *----------------------------------------------*//*----------------------------------------------* * 常量定义 * *----------------------------------------------*//*----------------------------------------------* * 宏定义 * *----------------------------------------------*/#include #include "serial.h"#include #include int main(int argc,char *argv[]){ int fd = -1; int set_serial_res = -1; if(2 > argc) { printf("*******************************************************************************************************************\n"); printf("please run like:%s %s (explain:brs means block read serial,ubrs means unblock read serial,ws means write serial)\n",argv[0],"'brs' or 'ubrs' or 'ws'"); printf("if you want to write to serial, you can run like this:%s ws %s\n",argv[0],"hello serial!"); printf("*******************************************************************************************************************\n"); return -1; } //创建串口对象 serial serial_obj; //打开串口 fd = serial_obj.open_serial(fd, "/dev/ttyS1"); if(fd < 0) { printf("open com filed\n"); return -1; } printf("open serial ok!\n"); //设置串口 set_serial_res = serial_obj.set_serial(fd,38400,0,8,1,'N'); if(set_serial_res < 0) { printf("set serial failed!:%d\n",set_serial_res); return -1; } printf("set serial ok!\n"); char rcv_buf[100] = "\0"; int recv_res = 0; //发送数据到串口 if(!strcmp(argv[1],"ws")) { char send_buf[100] = "hello serial!"; int send_serial_res = 0; if(3 == argc && argv[2] != NULL) { memset(send_buf,'\0',sizeof(send_buf)); strcpy(send_buf,argv[2]); } send_serial_res = serial_obj.write_to_serial(fd, send_buf, sizeof(send_buf)); printf("发送结果:%d:%s\n",send_serial_res,send_buf); } //阻塞接收串口数据 if(!strcmp(argv[1],"brs")) { recv_res = serial_obj.block_read_from_serial(fd, rcv_buf, sizeof(rcv_buf)); printf("阻塞接收结果:%d:%s\n",recv_res,rcv_buf); } //非阻塞接收串口数据(这里等待时间的单位为s) if(!strcmp(argv[1],"ubrs")) { unsigned int wait_time = 3; if(3 == argc && argv[2] != NULL) wait_time = atoi(argv[2]); recv_res = serial_obj.unblock_read_from_serial(fd, wait_time, rcv_buf, sizeof(rcv_buf)); printf("非阻塞接收结果:%d:%s\n",recv_res,rcv_buf); } //关闭串口 serial_obj.close_serial(fd); return 0;}
编译脚本:
########################################################################## File Name: compile.sh# Author: loon# mail: 2453419889@qq.com# Created Time: 2018年09月13日 星期四 15时59分02秒##########################################################################!/bin/bashCC=mipsel-openwrt-linux-g++$CC -o test_serial test.cpp serial.cpp
3.测试结果
在开发板上测试时,我们需要将要测试的串口短接(RXD1和TXD1,我这里是ttyS1),然后运行程序,分别测试阻塞接收、非阻塞接收和发送。
(1)阻塞接收测试:
运行test_serial程序(这里使用了外部传参的方式运行程序,所以运行时需要传参brs,代表阻塞读取串口,之后程序会一直阻塞在那等待读取串口数据):
root@ZhuoTK:/# ./test_serial *******************************************************************************************************************please run like:./test_serial 'brs' or 'ubrs' or 'ws' (explain:brs means block read serial,ubrs means unblock read serial,ws means write serial)if you want to write to serial, you can run like this:./test_serial ws hello serial!*******************************************************************************************************************root@ZhuoTK:/# ./test_serial brs构造完成open serial ok!set serial ok!
然后可通过终端命令发送数据:
echo hello,serial>/dev/ttyS1
然后就会看到程序接收到数据后退出了(如果没有接收到数据则会一直阻塞):
root@ZhuoTK:/# ./test_serial brs构造完成open serial ok!set serial ok!阻塞接收结果:13:hello,serial析构完成
(2)非阻塞接收测试:
非阻塞接收即等待接收串口数据,如果一段时间后未接收到则该程序就结束了,等待的时间可以传入(测试程序中默认设置了三秒,三秒后未接收则程序退出,这期间接收到则直接打印,当然也可以外部传参的方式设置新的非阻塞读取等待时间):
root@ZhuoTK:/# ./test_serial ubrs构造完成open serial ok!set serial ok!非阻塞接收结果:0:析构完成
root@ZhuoTK:/# ./test_serial ubrs 5构造完成open serial ok!set serial ok!非阻塞接收结果:13:hello,serial析构完成
root@ZhuoTK:/# ./test_serial ubrs 5构造完成open serial ok!set serial ok!非阻塞接收结果:0:析构完成
(3)发送测试
发送测试可以结合minicom来测试。默认发送“hello serial”,也可以传参发送想要发送的数据。
root@ZhuoTK:/# ./test_serial ws构造完成open serial ok!set serial ok!发送结果:100:hello serial!析构完成
Welcome to minicom 2.7OPTIONS: Compiled on Jan 27 2016, 19:22:46.Port /dev/ttyS1, 19:13:32Press CTRL-A Z for help on special keyshello serial!
root@ZhuoTK:/# ./test_serial ws serial!hello构造完成open serial ok!set serial ok!发送结果:100:serial!hello析构完成
Welcome to minicom 2.7OPTIONS: Compiled on Jan 27 2016, 19:22:46.Port /dev/ttyS1, 19:23:23Press CTRL-A Z for help on special keyshello serial!serial!hello
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~