Linux的串口非标准波特率设置更改
用的是全志的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 = %d\n",ret);
//ret = cfsetospeed(&newttys1, 0020001);
//printf("reto = %d\n",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 2\n");
return -1;
}
baud = atoi(argv[1]);
printf("baud =%d\n",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 error\n");
return -1;
} for(i =0 ;i<100;i++)
{
buff[i] =0x55;
} while(1)
{
n = write(fd, buff, len);
printf("n =%d\n",n);
if(n < 0)
{
printf("send write error\n");
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 = %d\n",ret);
//ret = cfsetospeed(&newttys1, 0020001);
//printf("reto = %d\n",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 -c baud_test.c 生成 baud_test.o
arm-openwrt-linux-gcc -c uart_oper.c 生成 uart_oper.o
arm-openwrt-linux-gcc -o 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
参考资料
LINUX的串口非标准波特率更改 - 知乎 (zhihu.com)
Linux的串口非标准波特率设置更改的更多相关文章
- 【转】Linux C下非特定波特率的配置和使用
https://blog.csdn.net/jinhongdu/article/details/43413071 对于非标准的任意波特率需要用ioctl(fd, TIOCGSERIAL, p)和i ...
- Linux串口中的超时设置
在Linux下使用串口通信时,默认的阻塞模式是不实用的.而采用select或epoll机制的非阻塞模式,写代码有比较麻烦.幸好Linux的串口自己就带有超时机制. Linux下使用termios.h中 ...
- linux下串口的阻塞和非阻塞操作
有两个可以进行控制串口阻塞性(同时控制read和write):一个是在打开串口的时候,open函数是否带O_NDELAY:第二个是可以在打开串口之后通过fcntl()函数进行控制. 阻塞的定义: 对于 ...
- (笔记)linux增加非标波特率的方法
1.内核修改 涉及到的内核文件包括driver/char/tty_ioctl.c和arch/xx/include/asm/termbits.h 在linux内核中,struct ktermios结构的 ...
- Linux BSP非标准HDMI分辨率
Linux BSP非标准HDMI分辨率 Intrinsyc公司发布了它的一个新的Linux BSP软件的发布 打开-Q820 开发套件基于Linux内核版本.支持的软件功能包括HDMI输出,可以支持标 ...
- Linux centosVMware MySQL常用操作设置更改root密码、连接mysql、mysql常用命令
一.设置更改root密码 启动mysql /usr/local/mysql/bin/mysql -uroot 更改环境变量PATH,增加mysql绝对路径 使mysql -uroot永久生效需要编辑, ...
- Linux下串口编制【转】
串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调 ...
- Linux下串口配置初步探寻
一.在struct termios结构体中,对串口进行基本配置(如波特率设置,校验位和停止位设置 等). (一): struct termios //串口的设置主要是设置struct termio ...
- Linux下串口编程入门
简介: Linux操作系统从一开始就对串行口提供了很好的支持,本文就Linux下的串行口通讯编程进行简单的介绍. 串口简介 串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用 ...
- linux下串口通信与管理
linux下的串口与windows有一些区别,下面将介绍一下linux下串口通信管理 查看是否支持USB串口: #lsmod | grep usbserial 如果没有信息:sudo apt-get ...
随机推荐
- 齐博x1where 标签动态变量查询/where 实现条件筛选与数据关联
大家可能对union参数不太习惯的话,也可以用where语句加入动态变量查询,比如 where="fid=$fid&uid=$info[uid]&pid>=$info. ...
- 14.api根路由
我们可以通过使用超链接来提高我们APi的内聚力和可发现性 一.为我们的API创建一个根路径 我们的视图有很多个url,但是没有一个入口点,可以使用@api_view创建一个根路径 #views.p ...
- 驱动开发:内核运用LoadImage屏蔽驱动
在笔者上一篇文章<驱动开发:内核监视LoadImage映像回调>中LyShark简单介绍了如何通过PsSetLoadImageNotifyRoutine函数注册回调来监视驱动模块的加载,注 ...
- dns隧道攻击原理及常用工具流量分析
DNS协议是一种请求应答协议,也是一种可用于应用层的隧道技术.虽然DNS流量的异常变化可能会被发现,但是在基于传统socket隧道已经濒临淘汰,TCP.UDP通信大量被安全设备拦截的大背景下,DNS. ...
- Python的几种lambda排序方法
1.对单个变量进行排序 #lst = [[5,8],[5,3],[3,1]] lst.sort(key = lambda x : x[1]) #lst = [[3,1],[5,8],[5,3]] 以元 ...
- 5种GaussDB ETCD服务异常实例分析处理
摘要:一文带你细数几种ETCD服务异常实例状态. 本文分享自华为云社区<[实例状态]GaussDB ETCD服务异常>,作者:酷哥 . 首先确认是否是虚拟机.网络故障 虚拟机故障导致ETC ...
- 16、有n个正数,使得前面每个数依次后移m个位置,最后m个数变成最前面m个数
/* 有n个正数,使得前面每个数依次后移m个位置,最后m个数变成最前面m个数 */ #include <stdio.h> #include <stdlib.h> #define ...
- vcenter密码设置永不过期
由于机房断电,原本的vcenter重启后web页面出现报错,为尽快恢复vcenter管理机,直接停用了旧的vcenter虚机,重新安装了一台vcenter,两个月后,页面开始报警密码即将到期: 经查阅 ...
- 【云原生 · Kubernetes】Jenkins+Gitlab+Rancher+Docker 实现自动构建镜像的 CI 平台(一)
1 准备 Jenkins+Gitlab 实验环境 1.1 准备实验环境:恢复到以一下快照:该环境已经配置好 jenkins+gitlab+sonar-配置通 主机角色: IP 地址 运行的服务 硬件配 ...
- C温故补缺(五):main函数的参数
main()的参数 main()函数的参数,用于在外部执行时传入参数,类似windows的bat脚本或linux的sh脚本.在bat脚本中传入参数,用%接收.sh脚本的参数用$接收. c语言编译成可执 ...