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 ...
随机推荐
- 解决springboot+vue+mybatis中,将后台数据分页显示在前台,并且根据页码自动跳转对应页码信息
文章目录 先看效果 1.要考虑的问题,对数据进行分页查询 2.前端和后台的交互 先看效果 1.要考虑的问题,对数据进行分页查询 mapper文件这样写 从每次开始查询的位置,到每页展示的条数, < ...
- while循环条件不成立却无法跳出死循环的问题
在进入循环的时候,实际上是将A从内存加载到寄存器里面运行的,在整个循环中,A这个变量都只是在读取寄存器里面的值. 而当进入中断的时候,中断里面会从内存加载A到寄存器,修改完之后又存到内存里,然后退出中 ...
- C. 连锁商店(状压dp)
C. 连锁商店 time limit per test 1 second memory limit per test 512 megabytes input standard input output ...
- ironic组件硬件自检服务——ironic-inspector
介绍 ironic-inspector是一个用于硬件自检的辅助型服务,它可以对被ironic组件管理的裸金属节点进行硬件自检,通过在裸金属节点上运行内存系统,发现裸金属节点的硬件信息,例如CPU数量和 ...
- Node.js 的学习(四)分别连接MongoDB与MySQL数据库,实现增删查改功能
一.Node.js 访问MongoDB 数据库 MongoDB 对许多平台都提供驱动可以访问数据库,如C#.Java.Node.js等. 1.1.安装MongoDB访问驱动 命令如下: 全局安装驱动: ...
- 2022-11-09 Acwing每日一题
本系列所有题目均为Acwing课的内容,发表博客既是为了学习总结,加深自己的印象,同时也是为了以后回过头来看时,不会感叹虚度光阴罢了,因此如果出现错误,欢迎大家能够指出错误,我会认真改正的.同时也希望 ...
- 2022春每日一题:Day 8
题目:[HNOI2003]激光炸弹 二维前缀和,扫大小为m*m的矩形,取最大即可. 代码: #include <cstdio> #include <cstdlib> #incl ...
- iOS逆向之某多多App抓包
阅读此文档的过程中遇到任何问题,请关注公众号[移动端Android和iOS开发技术分享]或加QQ群[309580013] 1.目标 由于某多多App现使用longlink进行数据传输,使用charle ...
- Android Studio打开时报错if you already hava 64-bit JDK installed,define a JAVA_HOME
出现这个问题不知道改了什么导致的,卸载了重新安装也是不行. 以及到高级设置中进行配置jdk也是无效, 解决方法为需要在路径 C:\Users\你自己的用户名\AppData\Roaming\Googl ...
- Axios +Vue + themeleay
1.pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId& ...