Linux下串口非标准波特率——使用termios2结构体修改波特率

方法一

在usb转ttl硬件模块为ch340,解析sbus协议不用修改串口为偶校验、2停止位。
使用FT4392 usb to uart 是需要修改串口为偶校验、2停止位,这时该方法下,接收的数据错误,使用方法二可以一劳永逸的解决。

注意事项

  1. linux的x86和arm64架构下均测试通过。
  2. 程序包含的两个头文件<termios.h> 和<asm/termbits.h>都定义了struct termios,需要将<asm/termbits.h>中的注释掉
  3. 先以标准波特率打开串口,再通过termios2 配合ioctrl修改自定义波特率。
  4. 确保打开串口权限 sudo chmod 777 /dev/ttyUSB0

c++代码

使用SerialInit(int &fd, const char* devname, int baude)完成串口打开与波特率自定义。

  1. uart.hpp
#ifndef UART_HPP_
#define UART_HPP_
//sys include
#include <termios.h> /*PPSIX 终端控制定义*/
#include <linux/serial.h>
class Uart{
public:
    Uart(){}
    ~Uart(){}
    int SerialInit(int &fd, const char* devname, int baude);
private:
    struct termios uart;
    int baude_changed(int &fd,int speed);
     int serial_set_speci_baud(int &fd,int baude);
     int setCustomBaudRate(int&fd,int baude);
};
#endif
  1. uart.cpp
#include <iostream>
#include <errno.h> /*错误号定义*/
#include <fcntl.h>   /*文件控制定义*/
#include <sys/ioctl.h>
#include <asm/termbits.h>//以修改源码
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "uart.hpp"

int Uart::SerialInit(int &fd, const char* devname, int baude){
    fd = open(devname, O_RDWR | O_NOCTTY | O_NDELAY);//以只读形式、不将此终端作为此进程的终端控制器、非阻塞的形式打开串口
    if (-1 == fd)
    {
        printf("Open %s Error!\n",devname);
        perror("\n");
        return -1;
    }
    if ((fcntl(fd, F_SETFL, 0)) < 0)//设置串口非阻塞,因为这里是以非阻塞形式打开的,所以第三个参数为0,
    {
        perror("Fcntl F_SETFL Error!\n");
        return -1;
    }
    if (tcgetattr(fd, &uart) != 0)
    {
        perror("tcgetattr error!\n");
        return -1;
    }
    cfmakeraw(&uart); //将终端设置为原始模式,该模式下全部的输入数据以字节为单位被处理
    //set speed
/***********************普通设置波特率****************************/
    cfsetispeed(&uart, B115200);
    cfsetospeed(&uart, B115200);
    uart.c_cflag |= CLOCAL | CREAD;//本地连接和接受使能
    uart.c_iflag &= ~ICRNL;    //禁止将输入中的回车翻译为新行 (除非设置了 IGNCR)
    uart.c_iflag &= ~ISTRIP;   //禁止将所有接收的字符裁减为7比特
    uart.c_cflag &= ~PARENB;   //禁止奇偶校验码的生成和检测功能
    uart.c_cflag &= ~CSTOPB;   //设置1停止位
    uart.c_cflag &= ~CSIZE;    //清除数据位设置
    uart.c_cflag |=  CS8;      //设置为8数据位
    uart.c_cflag &= ~CRTSCTS;  //禁止硬件流控
    uart.c_cc[VTIME] = 0;      //指定所要读取字符的最小数量
    uart.c_cc[VMIN] = 1;       //指定读取第一个字符的等待时间,时间的单位为n*100ms
                                //假设设置VTIME=0,则无字符输入时read()操作无限期的堵塞
    tcflush(fd, TCIFLUSH);     //清空终端未完毕的输入/输出请求及数据。

    if (tcsetattr(fd, TCSANOW, &uart) != 0) //激活配置
    {
        perror("tcsetattr Error!\n");
        return -1;
    }
    baude_changed(fd,baude);
    return 1;
}

int Uart::setCustomBaudRate(int &fd,int baude){
    // struct serial_struct currentSerialInfo;
    // if (ioctl(fd, TIOCGSERIAL, &currentSerialInfo) == -1)
    //     perror("\n");
    // printf("baud_base :%d\n",currentSerialInfo.baud_base);
    // if (currentSerialInfo.baud_base % baude != 0)
    //     // perror("\n");

    // currentSerialInfo.flags &= ~ASYNC_SPD_MASK;
    // currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
    // currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / baude;
    // if (currentSerialInfo.custom_divisor == 0)
    //     // perror("\n");
    // if (ioctl(fd, TIOCSSERIAL, &currentSerialInfo) == -1)
    //     perror("\n");
    // cfsetispeed(&uart, B38400);
    // cfsetispeed(&uart, B38400);
}

int Uart::serial_set_speci_baud(int &fd,int baude){
    // struct serial_struct ss, ss_set;
    // tcgetattr(fd, &uart);
    // cfsetispeed(&uart, B38400);
    // cfsetospeed(&uart, B38400);
    // tcflush(fd, TCIFLUSH);/*handle unrecevie char*/
    // tcsetattr(fd, TCSANOW, &uart);
    // if((ioctl(fd, TIOCGSERIAL, &ss)) < 0)
    // {
    //     printf("BAUD: error to get the serial_struct info:%s\n", strerror(errno));
    //     return -1;
    // }
    // ss.flags |= ASYNC_SPD_CUST| ASYNC_LOW_LATENCY;
    // ss.flags &= ~ASYNC_SPD_MASK;
    // ss.custom_divisor = ss.baud_base / baude;
    // if((ioctl(fd, TIOCSSERIAL, &ss)) < 0)
    // {
    //     printf("BAUD: error to set serial_struct:%s\n", strerror(errno));
    //     return -2;
    // }
    // ioctl(fd, TIOCGSERIAL, &ss_set);
    // printf("BAUD: success set baud to %d,custom_divisor=%d,baud_base=%d\n",
    //     baude, ss_set.custom_divisor, ss_set.baud_base);
    // return 0;
}

/*先使用标准波特率打开串口,再使用该接口修该波特率*/
int Uart::baude_changed(int &fd,int speed)
{
	struct termios2 tio = {0};
	tio.c_cflag = BOTHER | CS8 | CLOCAL | CREAD;
	tio.c_iflag = IGNPAR;
	tio.c_oflag = 0;
	tio.c_ispeed = speed;
	tio.c_ospeed = speed;
	return ioctl(fd, TCSETS2, &tio);
}

linux实现100k波特率的SBUS协议10通道解析

在这里插入图片描述

方法二(2021.9.10补充)

只使用termios2结构体

int Uart::Sbusinit(const char* _device)
 {
     /**
      * open the serial port
      */
     fd= open(_device, O_RDWR | O_NONBLOCK | O_CLOEXEC);
     if (-1 == fd) {
         printf("Open SBUS input %s failed, status %d \n", _device,
             (int) fd);
         fflush(stdout);
         return -1;
     }
     struct termios2 tio { };
     if (0 != ioctl(fd, TCGETS2, &tio)) {
         close(fd);
         fd= -1;
         return -1;
     }
     /**
      * Setting serial port,8E2, non-blocking.100Kbps
      */
     tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL
              | IXON);
     tio.c_iflag |= (INPCK | IGNPAR);
     tio.c_oflag &= ~OPOST;
     tio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
     tio.c_cflag &= ~(CSIZE | CRTSCTS | PARODD | CBAUD);
     /**
      * use BOTHER to specify speed directly in c_[io]speed member
      */
     tio.c_cflag |= (CS8 | CSTOPB | CLOCAL | PARENB | BOTHER | CREAD);
     tio.c_ispeed = 100000;
     tio.c_ospeed = 100000;
     tio.c_cc[VMIN] = 25;
     tio.c_cc[VTIME] = 0;
     if (0 != ioctl(fd, TCSETS2, &tio)) {
         close(fd);
         fd= -1;
         return -1;
     }
     return 0;
 }

参考px4的linux_sbus库函数

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值