- A+
用的是全志的R528 SDK,Linux内核是5.4,新增加一个250000的非标准波特率
参考网络大神文档,实践并记录宝贵的经验。
方法:
1、修改内核的/include/uapi/asm-generic/termbits.h文件
这个CBAUD原来是0010017改为0030017,是用来做掩码计算的。
图1
这两个是新加的
图2
这个头文件一共更改这三个地方。先说为什么增加波特率使用0020001而不在B4000000后面递增使用0010020,这是因为这个低位的20已经被占用了,
如下图3,所以找了没被占用的位置,0020000的中2这个bit位置在c_cflag中没被占用(c_cflag是用于设置波特率和其他一些信息的)。
第一处的0030017也是这个原因,就是将波特率使用的这些宏定义包含进去。
图3
2、/drivers/tty/tty_baudrate.c文件
这个文件就是获取波特率具体数值的文件,应用端的数据传入到内核,内核解析并获得250k波特率这个数值就是在这个文件,
先在文件
头部的波特率列表中增加所需数值,如图4,其中的250000和B250000为新增加。
图4
修改函数speed_t tty_termios_baud_rate(struct ktermios *termios),图5
图5
其中圈起来的地方是新加的,这就是根据刚才新加的部分进行波特率修改,新的0020001,与CBAUDEX2进行运算判断高位位置,
之所以cbaud+=30是因为前面已经有了30个波特率了,见图5。这样内核就修改完了。
最后重新编译内核, 重新烧录系统镜像。
3、应用程序测试验证
应用端的配置,应用端通常使用tcsetattr这个函数进行配置,在使能之前,对齐c_cflag进行赋值就可
struct termios , termios_new;
termios_new.c_cflag |= 0020001;
(其余配置省略)
tcsetattr(fdcom, TCSANOW, &termios_new);
这里说一下为什么不能使用cfsetispeed、cfsetospeed 函数。
因为这两个函数只能指定原来标准的波特率,设置我们非标准的0020001的时候就会设置失败
//ret = cfsetispeed(&newttys1, 0020001); //printf("reti = %dn",ret); //ret = cfsetospeed(&newttys1, 0020001); //printf("reto = %dn",ret);
应用层测试代码
baud_test.c #include<stdio.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "uart_oper.h" #define UART1_DEV_NAME "/dev/ttyS1" /*需根据实际端口修改*/ #define BUF_LEN 100 int main(int argc,char const * argv[]) { int fd =-1,ret =-1; char buff[BUF_LEN]={0}; int i =0; int n =0; int len = BUF_LEN; int baud = 0; if(argc !=2) { printf("arg is not 2n"); return -1; } baud = atoi(argv[1]); printf("baud =%dn",baud); fd = open(UART1_DEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY); if(fd < 0) { perror("Can't open uart1 port"); return(void *)"uart1 dev error"; } ret = set_serial(fd,baud, 8, 'N', 1); /*可能需要根据情况调整*/ // ret = set_serial(fd, 115200, 8, 'N', 1); /*可能需要根据情况调整*/ if(ret < 0) { printf("set_serial errorn"); return -1; } for(i =0 ;i<100;i++) { buff[i] =0x55; } while(1) { n = write(fd, buff, len); printf("n =%dn",n); if(n < 0) { printf("send write errorn"); sleep(1); return -1; } sleep(1); } return 0; } uart_oper.c #include <stdio.h> #include <errno.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include "uart_oper.h" /** *@brief 配置串口 *@param fd:串口文件描述符. nSpeed:波特率, nBits:数据位 7 or 8, nEvent:奇偶校验位, nStop:停止位 *@return 失败返回-1;成功返回0; */ int set_serial(int fd, int nSpeed, int nBits, char nEvent, int nStop) { struct termios newttys1, oldttys1; /*保存原有串口配置*/ if(tcgetattr(fd, &oldttys1) != 0) { perror("Setupserial 1"); return - 1; } memset(&newttys1, 0, sizeof(newttys1)); /*CREAD 开启串行数据接收,CLOCAL并打开本地连接模式*/ newttys1.c_cflag |= (CLOCAL | CREAD); newttys1.c_cflag &=~CSIZE; /*设置数据位*/ switch(nBits) /*数据位选择*/ { case 7: newttys1.c_cflag |= CS7; break; case 8: newttys1.c_cflag |= CS8; break; default:break; } switch(nEvent) /*奇偶校验位*/ { case '0': newttys1.c_cflag |= PARENB; /*开启奇偶校验*/ newttys1.c_iflag |= (INPCK | ISTRIP); /*INPCK打开输入奇偶校验,ISTRIP 去除字符的第八个比特*/ newttys1.c_cflag |= PARODD; /*启动奇校验(默认为偶校验)*/ break; case 'E': newttys1.c_cflag |= PARENB; /*开启奇偶校验*/ newttys1.c_iflag |= (INPCK | ISTRIP); /*INPCK打开输入奇偶校验,ISTRIP 去除字符的第八个比特*/ newttys1.c_cflag &= ~PARODD; /*启动偶校验*/ break; case 'N': newttys1.c_cflag &= ~PARENB; /*无奇偶校验*/ break; default:break; } switch(nSpeed) /*设置波特率*/ { case 2400: cfsetispeed(&newttys1, B2400); cfsetospeed(&newttys1, B2400); break; case 4800: cfsetispeed(&newttys1, B4800); cfsetospeed(&newttys1, B4800); break; case 9600: cfsetispeed(&newttys1, B9600); cfsetospeed(&newttys1, B9600); break; case 115200: cfsetispeed(&newttys1, B115200); cfsetospeed(&newttys1, B115200); break; case 250000: //ret = cfsetispeed(&newttys1, 0020001); //printf("reti = %dn",ret); //ret = cfsetospeed(&newttys1, 0020001); //printf("reto = %dn",ret); newttys1.c_cflag |= 0020001; break; default : cfsetispeed(&newttys1, B9600); cfsetospeed(&newttys1, B9600); break; } /*设置停止位*/ /*停止位为1,则清除CSTOPB,如停止位为2,则激活CSTOPB*/ if(nStop == 1) { newttys1.c_cflag &= ~CSTOPB; /*默认为停止位1*/ } else if(nStop == 2) { newttys1.c_cflag |= CSTOPB; } /*设置最少字符和等待时间,对于接收字符和等待时间没有特别的要求时*/ newttys1.c_cc[VTIME] = 0; /*非规范模式读取时的超时时间*/ newttys1.c_cc[VMIN] = 0; /*非规范模式读取时的最小字符数*/ /*tcflush 清空终端未完成的输入、输出请求及数据 TCIFLUSH表示清空正接收到的数据,且不读取出来*/ tcflush(fd, TCIFLUSH); /*激活配置使其生效*/ if((tcsetattr(fd, TCSANOW, &newttys1)) != 0) { perror("usart set error"); return - 1; } return 0; } uart_oper.h #ifndef __UART_OPER_H__ #define __UART_OPER_H__ int set_serial(int fd, int nSpeed, int nBits, char nEvent, int nStop); #endif
编译
arm-openwrt-linux-gcc baud_test.c 生成 baud_test.o
arm-openwrt-linux-gcc uart_oper.c 生成 uart_oper.o
arm-openwrt-linux-gcc tt baud_test.o uart_oper.o 连接到一起生成tt测试程序
备注当直接执行arm-openwrt-linux-gcc baud_test.c -o tt 的时候报错,找不到uart_oper.h中的函数。
将tt 拷贝到系统中。
终端执行tt 250000
之后用示波器测串口发出的波形。
波特率传送速率计算:
一、波特率为9600表示的是串口每秒钟可以传输9600bit,每传输1bit所需时间:
1 s / 9600 b i t = 1000000 ( u s ) / 9600 ( b i t ) = 1000 / 9.6 = 104.1667 u s 1s/9600bit = 1000000(us)/9600(bit) =1000/9.6 =104.1667us1s/9600bit=1000000(us)/9600(bit)=1000/9.6=104.1667us
那么8bit就是 104.1667 ∗ 8 = 833.3336 u s 104.1667*8 =833.3336us104.1667∗8=833.3336us
实际项目中,串口通信时数据格式是:起始位+8位数据+奇偶校验位+停止位 ,一般都没有奇偶校验位,所以是10位
也就是一个字节的时间为 104.1667 ∗ 10 = 1041.667 u s 104.1667*10 =1041.667us104.1667∗10=1041.667us
二、波特率为19200每传输1bit所需时间:
1 s / 19200 b i t = 1000000 ( u s ) / 19200 ( b i t ) = 1000 / 19.2 = 52.0833 u s 1s/19200bit=1000000(us)/19200(bit) =1000/19.2 =52.0833us1s/19200bit=1000000(us)/19200(bit)=1000/19.2=52.0833us
三、波特率115200每传输1bit所需时间:
1 s / 115200 b i t = 1000000 ( u s ) / 115200 ( b i t ) = 1000 / 115.2 = 8.6806 u s ; 1s/ 115200bit = 1000000 (us)/ 115200(bit)= 1000/115.2 = 8.6806us;1s/115200bit=1000000(us)/115200(bit)=1000/115.2=8.6806us;
四、波特率为250000每传输1bit所需时间:
1 s / 250000 b i t = 1000000 ( u s ) / 250000( b i t ) = 1000 / 250 = 4 u s ;
从测试结果看是成功的。
4、终端命令行执行设置串口的命令
查询串口配置命令
uart0:
cat /sys/bus/platform/drivers/uart/2500000.uart/ctrl_info
uart 1:
cat /sys/bus/platform/drivers/uart/2500400.uart/ctrl_info
查询
root@TinaLinux:/# stty -a -F /dev/ttyS1
speed 9600 baud;stty: /dev/ttyS1
设置
stty -F /dev/ttyS1 ispeed 115200 ospeed 115200 cs8
参考资料