https://blog.csdn.net/jinhongdu/article/details/43413071
 对于非标准的任意波特率需要用ioctl(fd, TIOCGSERIAL,  p)和ioctl(fd, TIOCSSERIAL, p)的配合,ioctl的最后一个参数是struct serial_struct  *类型,在linux/serial.h中定义。
 
 其中baud_base是基准晶振频率/16,通常是115200,你需要设的是custom_divisor这个值,最终的波特率为baud_base/custom_divisor,比如你需要28800,因为115200/4=28800,所以要设置custom_divisor=4,。
 具体过程为,先设置波特率设为38400(tcsetattr),然后用TIOCGSERIAL得到当前的设置,将flags设置ASYNC_SPD_CUST位,设置custom_divisor,最后用TIOCSSERIAL设置。
 
 使用setserial其实就是利用上述方法,来设置baud_base, custom_divisor等, 其内部实现就是使用ioctl来进行设置。
 
 网上的东西真的是参差不齐,希望能呈现完善的正确的Blog给大家。
 由于是测试代码,只是保证可以运行。另外推荐一个串口调试助手AccessPort,可以提供28800的串口比特率作为测试。
#include <termios.h>
#include <sys/ioctl.h>
#include <stdio.h>      /*标准输入输出定义*/
#include <stdlib.h>     /*标准函数库定义*/
#include <unistd.h>     /*Unix标准函数定义*/
#include <sys/types.h>  /**/
#include <sys/stat.h>   /**/
#include <fcntl.h>      /*文件控制定义*/
#include <termios.h>    /*PPSIX终端控制定义*/
#include <errno.h>      /*错误号定义*/
#include <linux/serial.h>
#define TRUE 1
#define FALSE 0
/*
*功能:用于测试非标准波特率串口。
*此代码仅限于运行在X86架构的环境下,其他架构并未测试。在arm下未测试
*请在root下编译此代码
*如有问题,联系我:靳小都 hellojinhongdu#126.com
*/
struct serial_t {
    int     fd;
    char    *device;/*/dev/ttyS0,...*/
    int     baud;
    int     databit;/*5,6,7,8*/
    char    parity;/*O,E,N*/
    int    stopbit;/*1,2*/
    int    startbit;/*1*/
    struct termios    options;
};
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
        B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300,
        38400,  19200,  9600, 4800, 2400, 1200,  300, };
void set_speed(int fd, int speed)
{
  int   i;
  int   status;
  struct termios   Opt;
  tcgetattr(fd, &Opt);
  for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
   {
    if  (speed == name_arr[i])
    {
        tcflush(fd, TCIOFLUSH);
        cfsetispeed(&Opt, speed_arr[i]);
        cfsetospeed(&Opt, speed_arr[i]);
        status = tcsetattr(fd, TCSANOW, &Opt);
        if  (status != 0)
            perror("tcsetattr fd1");
        return;
        }
   tcflush(fd,TCIOFLUSH);
   }
}
//设置为特诉波特率,比如28800
int serial_set_speci_baud(struct serial_t *tty,int baud)
{
    struct serial_struct ss,ss_set;
    tcgetattr(tty->fd,&tty->options);
    cfsetispeed(&tty->options,B38400);
    cfsetospeed(&tty->options,B38400);
    tcflush(tty->fd,TCIFLUSH);/*handle unrecevie char*/
    tcsetattr(tty->fd,TCSANOW,&tty->options);
    if((ioctl(tty->fd,TIOCGSERIAL,&ss))<0){
        printf("BAUD: error to get the serial_struct info:%s\n",strerror(errno));
        return -1;
    }
    ss.flags = ASYNC_SPD_CUST;
    ss.custom_divisor = ss.baud_base / baud;
    printf("ss.custom_divisor = %d \r\n",ss.custom_divisor);
    if((ioctl(tty->fd,TIOCSSERIAL,&ss))<0){
        printf("BAUD: error to set serial_struct:%s\n",strerror(errno));
        //return -2;
    }
    ioctl(tty->fd,TIOCGSERIAL,&ss_set);
    printf("BAUD: success set baud to %d,custom_divisor=%d,baud_base=%d\n",
            baud,ss_set.custom_divisor,ss_set.baud_base);
    return 0;
}
/*get serial's current attribute*/
static int serial_get_attr(struct serial_t *tty)
{
    if(tcgetattr(tty->fd,&tty->options) != 0){
        printf("SERIAL: can't get serial's attribute\n");
        return -1;
}
    return 0;
}
/*update serial's attrbute*/
static int serial_attr_update(struct serial_t *tty)
{
    tcflush(tty->fd,TCIFLUSH);/*handle unrecevie char*/
    if((tcsetattr(tty->fd,TCSANOW,&tty->options)) < 0){
        return -1;
}
    return 0;
}
static int serial_init_databit(struct serial_t *tty)
{
    if(serial_get_attr(tty)<0)
        return -1;
    tty->options.c_cflag &= ~CSIZE;
    switch(tty->databit){
        case 5: tty->options.c_cflag |= CS5;break;
        case 6: tty->options.c_cflag |= CS6;break;
        case 7: tty->options.c_cflag |= CS7;break;
        case 8: tty->options.c_cflag |= CS8;break;
        default:
            printf("SERIAL: unsupported databit %d\n",tty->databit);
            return -2;    
}
    if(serial_attr_update(tty) < 0)
        return -3;
    printf("SERIAL: set databit to %d\n",tty->databit);
    return 0;
}
static int serial_init_parity(struct serial_t *tty)
{
    if(serial_get_attr(tty)<0)
        return -1;
    /*ignore framing and parity error*/
    tty->options.c_iflag = IGNPAR;
    switch (tty->parity){
        case 'n':
        case 'N':
            /* Clear parity enable */
            tty->options.c_cflag &= ~PARENB;
            /* Enable parity checking */
            tty->options.c_iflag &= ~INPCK;
            break;
        case 'o':
        case 'O':
            /* 设置为奇校检*/
            tty->options.c_cflag |= (PARODD|PARENB);
            /* Disnable parity checking */
            tty->options.c_iflag |= (INPCK|ISTRIP);
            break;
        case 'e':
        case 'E':
            /* Enable parity */
            tty->options.c_cflag |= PARENB;
            /* 转换为偶效验*/
            tty->options.c_cflag &= ~PARODD;
            /* Disnable parity checking */
            tty->options.c_iflag |= (INPCK|ISTRIP);  
            break;
        default:
            printf("SERIAL: unsupported parity %c\n",tty->parity);
            return -2;
}
    if(serial_attr_update(tty) < 0)
        return -3;
    printf("SERIAL: set parity to %c\n",tty->parity);
    return 0;
}
static int serial_init_stopbit(struct serial_t *tty)
{
    if(serial_get_attr(tty)<0)
        return -1;
    switch(tty->stopbit){
        case 1:
            tty->options.c_cflag &= ~CSTOPB;break;
        case 2:
            tty->options.c_cflag |= CSTOPB;break;
        default:
            printf("SERIAL: unsupported stopbit %d\n",tty->stopbit);  
            return -2;    
}
    if(serial_attr_update(tty) < 0)
        return -3;
    printf("SERIAL: set stopbit to %d\n",tty->stopbit);
    return 0;
}
/**
*@brief   设置串口数据位,停止位和效验位
*@param  fd     类型  int  打开的串口文件句柄*
*@param  databits 类型  int 数据位   取值 为 7 或者8*
*@param  stopbits 类型  int 停止位   取值为 1 或者2*
*@param  parity  类型  int  效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd,int databits,int stopbits,int parity)
{
    struct termios options;
 if  ( tcgetattr( fd,&options)  !=  0)
  {
    perror("SetupSerial 1");
    return(FALSE);
  }
  options.c_cflag &= ~CSIZE;
  switch (databits) /*设置数据位数*/
  {
    case 7:
        options.c_cflag |= CS7;
        break;
    case 8:
        options.c_cflag |= CS8;
        break;
    default:
        fprintf(stderr,"Unsupported data size\n");
        return (FALSE);
    }
  switch (parity)
    {
    case 'n':
    case 'N':
        options.c_cflag &= ~PARENB;   /* Clear parity enable */
        options.c_iflag &= ~INPCK;     /* Enable parity checking */
        break;
    case 'o':
    case 'O':
        options.c_cflag |= (PARODD | PARENB);  /* 设置为奇效验*/
        options.c_iflag |= INPCK;             /* Disnable parity checking */
        break;
    case 'e':
    case 'E':
        options.c_cflag |= PARENB;     /* Enable parity */
        options.c_cflag &= ~PARODD;   /* 转换为偶效验*/
        options.c_iflag |= INPCK;       /* Disnable parity checking */
        break;
    case 'S':
    case 's':  /*as no parity*/
        options.c_cflag &= ~PARENB;
        options.c_cflag &= ~CSTOPB;
        break;
    default:
        fprintf(stderr,"Unsupported parity\n");
        return (FALSE);
        }
  /* 设置停止位*/
  switch (stopbits)
    {
    case 1:
        options.c_cflag &= ~CSTOPB;
        break;
    case 2:
        options.c_cflag |= CSTOPB;
        break;
    default:
        fprintf(stderr,"Unsupported stop bits\n");
        return (FALSE);
    }
  /* Set input parity option */
  if (parity != 'n')
        options.c_iflag |= INPCK;
    options.c_cc[VTIME] = 150; // 15 seconds
    options.c_cc[VMIN] = 0;
  tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
  if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        perror("SetupSerial 3");
        return (FALSE);
    }
  return (TRUE);
 }
//用法:只要指定serial_t的baud就可以了
static struct serial_t __seri_conf[] = {
    [0] = {//connect with b board, ttyS0
        .device = "/dev/ttyS1",
        .baud = 28800,
        .databit = 8,
        .parity = 'N',
        .stopbit = 1,
    },
};
/**
*@breif     main()
*/
int main(int argc, char **argv) {
    int fd;
    int nread;
    char buff[512];
    fd = open(__seri_conf->device, O_RDWR | O_NOCTTY | O_NONBLOCK);
    __seri_conf->fd = fd;
    serial_set_speci_baud(__seri_conf, __seri_conf->baud);
    /*
    if (set_Parity(__seri_conf->fd, 8, 1, 'N') == FALSE)
        {
            printf("Set Parity Error\n");
        }
    */
    if(serial_init_databit(__seri_conf)<0)
        printf("serial_init_databit error\n");
    if(serial_init_parity(__seri_conf)<0)
        printf("serial_init_parity error\n");
    if(serial_init_stopbit(__seri_conf)<0)
        printf("serial_init_stopbit error\n");
    //struct termios opt;
    tcgetattr(__seri_conf->fd,&__seri_conf->options);
    __seri_conf->options.c_iflag &=~(BRKINT|ICRNL|INPCK|ISTRIP|IXON);
    __seri_conf->options.c_lflag &=~(ICANON|ECHO|ECHOE|ECHONL|ISIG|IEXTEN);
    __seri_conf->options.c_oflag &=~(OPOST);
    if(tcsetattr(__seri_conf->fd,TCSANOW,&__seri_conf->options)!=0)
        printf("error");
    while (1) {
        char ct[10] = "hello";
        write(__seri_conf->fd, ct, 10);
        puts("hello world 28800 test 8888!\n");
        sleep(1);
        nread = read(__seri_conf->fd,buff,256);
        if(nread>0)
        {
            printf("recv :%d ***%s\r\n",nread,buff);           
        }
    }
    close(fd);
}

【转】Linux C下非特定波特率的配置和使用的更多相关文章

  1. Linux(Ubuntu)下MySQL的安装与配置

    转自:http://www.2cto.com/database/201401/273423.html 在Linux下MySQL的安装,我一直觉得挺麻烦的,因为之前安装时就是由于复杂的配置导致有点晕.今 ...

  2. linux系统下tomcat应用开机自启动 配置

    linux系统下tomcat应用开机自启动 配置 相对简单的方式是将tomcat添加为系统服务第一步  复制文件将 $Tomcat_Home/bin目录下的 catalina.sh脚本文件复制到目录/ ...

  3. Linux Centos下MySQL主从Replication同步配置(一主一从)

    MySQL 主从复制概念MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点.MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据 ...

  4. linux 系统下java开发环境的配置

    在安装之前,确保你的linux系统下有 jdk,jboss等相关软件 一.配置JDK环境变量 步骤: 解压缩JDK文件: unzip jdk1.6.0_31.zip 目录下显示文件夹jdk1.6.0_ ...

  5. Linux虚拟机下mysql 5.7安装配置方法图文教程

    一. 下载mysql5.7 http://mirrors.sohu.com/mysql/MySQL-5.7/ Linux下载: 输入命令:wget http://mirrors.sohu.com/my ...

  6. Linux环境下卸载、安装及配置MySQL5.1

    Linux环境下卸载原有MySQL5.1数据库,并重新安装MySQL数据库的示例记录. 一.卸载MySQL 查看主机中是否安装了MySQL数据库: [root@RD-viPORTAL- ~]# rpm ...

  7. Linux系统下安装jdk及环境配置(两种方法)

    https://blog.csdn.net/qq_42815754/article/details/82968464 这里介绍两种linux环境下jdk的安装以及环境配置方法在windows系统安装j ...

  8. CentOS Linux系统下安装Redis过程和配置参数说明

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/102.html?1455869303 安装过程: 代码如下: wget h ...

  9. Oracle Enterprise Linux 64-bit 下Oracle11g的监听配置修改及测试步骤

    测试环境:Oracle Enterprise Linux 64-bit (5.8版本) + Oracle 11g 64位 相关说明: Oracle11g64位软件的安装位置为/u01/app/orac ...

随机推荐

  1. Random Maze HDU - 4067(预定义状态建边(贪心建边))

    Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  2. C# 成员默认访问权限(public、private、protected、internal)

    C# 成员默认访问权限(public.private.protected.internal) 来源 https://www.cnblogs.com/yezongjie/p/20181121Access ...

  3. [NOIP提高组2011day1t2]选择客栈

    我看到有人用线段树来写而且想法和我的差不多,但是代码有一点复杂,所以我就贴一下我的做法. 思路 首先一定知道纯暴力50分差不多了,所以看到k非常的小,那么就从k入手. 不知道有没有人和我一样是先枚举颜 ...

  4. 20165223《JAVA程序设计》第二周学习总结

    20165223 <JAVA程序设计>第二周学习总结 教材学习内容总结 第二章要点 标识符与关键字 基本数据类型 类型转换运算 输入输出数据 数组 第三章要点 运算符与表达式 语句概述 i ...

  5. 使用BlockQueue实现生产者和消费者模式

    数据 package cn.lonecloud.procum; /** * @author lonecloud * @version v1.0 * @date 上午11:00 2018/5/7 */ ...

  6. 编写高质量代码:改善Java程序的151个建议 --[78~92]

    编写高质量代码:改善Java程序的151个建议 --[78~92] HashMap中的hashCode应避免冲突 多线程使用Vector或HashTable Vector是ArrayList的多线程版 ...

  7. (1)Phonics自然拼读 英语动画 Fun with Phonics 国际主流英语教学法

    Phonics(拼音英语)是目前国际主流的英语教学法,我国香港和台湾地区2000年就已引进此教学法,并已进入大规模推广和普及阶段.它之所以风靡全球,是因为这种教学法简单高效,符合人类学习语言的规律,尤 ...

  8. Gnome添加Open with Code菜单

    解决方法 测试环境: Manjaro Linux Rolling at 2018-08-31 19:04:49 Microsoft Visual Stdio Code 1.26.1 Bulid: 20 ...

  9. Manjaro下带供电的USB Hub提示error -71

    问题描述 这款USB Hub是绿联出的1转7带供电的白色款. 在lsusb中显示为 Bus 004 Device 023: ID 05e3:0616 Genesys Logic, Inc. hub B ...

  10. MVC aspx

    客户端服务器---Model(模型)---View(视图)---Control(控制器) 1.ASP.NET  MVC 2.新建项目引擎选aspx.在Controllers创建控制器,默认启动Home ...