首页 > 系统相关 >Linux的串口非标准波特率设置更改

Linux的串口非标准波特率设置更改

时间:2023-01-03 15:34:22浏览次数:61  
标签:include cflag int 串口 break Linux 波特率 newttys1

用的是全志的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 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

 

 

参考资料

LINUX的串口非标准波特率更改 - 知乎 (zhihu.com)

标签:include,cflag,int,串口,break,Linux,波特率,newttys1
From: https://www.cnblogs.com/hylife/p/17022372.html

相关文章

  • Linux rbash Bypass
    rbash全称Restrictedbash,即受限制的bash 1.vi:setshell=/bin/bash:shell #设置环境变量exportPATH=/bin:/usr/bin:$PATHexportSHELL=/bin/bash:$SHE......
  • Linux基础知识(14)- GDB 调试器(二)| 普通断点、单步调试和查看变量
    在“Linux基础知识(13)-GDB调试器(一)|安装配置和基本使用方法”里我们完成了GDB的安装配置,并演示了GDB几个内部命令的基本使用方法,本文将演示普通断点、单步调试和查......
  • Linux上的Jenkins部署项目到另一台Linux服务器上
    一、说明jenkins配置ssh(A服务器-jenkins所在的服务器,B服务器-部署项目的Linux服务器)二、配置秘钥在A服务器首先生成密钥ssh-keygen–trsa或ssh-keygen-mPEM-......
  • hyper给linux扩容空间
    1.hyper操作(1)关机后,在设置中,查看硬盘驱动器中的虚拟磁盘及编号,(2)编辑磁盘->查找磁盘中选中刚才的编号磁盘(3)操作时扩容(大小填的不是增量,是扩容以后的空间)2.linux扩容,使......
  • Linux基础知识(13)- GDB 调试器(一)| 安装配置和基本使用方法
    GDB调试器(GNUSymbolicDebugger),是Linux平台下最常用的一款程序调试器。GDB编译器通常以gdb命令的形式在终端(Shell)中使用,它有很多选项。GDB调试器支持C、C++、Go、......
  • Linux 的apt 命令
    apt(AdvancedPackagingTool)是一个在Debian和Ubuntu中的Shell前端软件包管理器。apt命令提供了查找、安装、升级、删除某一个、一组甚至全部软件包的命令,而且命令简......
  • linux的shell的概述
    Shell教程Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。Shell是指一种应用程序,这个应用程序提供了一个界面......
  • WordPress网站成为Linux恶意软件目标: 19个插件和主题缺陷
    WordPress网站正成为一种以前未知的Linux恶意软件的目标,该恶意软件利用二十多个插件和主题中的缺陷来破坏易受攻击的系统。“如果网站使用此类附加组件的过时版本,缺乏关键......
  • Linux下安装nvidia驱动
     Linux查看显卡信息:lspci|grep-ivga或者lspci|grep-invidia下载驱动:https://www.nvidia.cn/Download/index.aspx?lang=cn屏蔽系统自带的nouveau......
  • 《DFZU2EG_4EV MPSoC之嵌入式Linux开发指南》第一章 Ubuntu系统安装​
    Ubuntu系统安装​Linux的开发需要在Linux系统下进行,这就要求我们的PC主机安装Linux系统,本书我们选择Ubuntu这个Linux发行版系统。本章讲解如何安装虚拟机,以及如何在虚拟机中......