【编程】Linux下非特定波特率(如28800)的配置和使用

作为铁路院校毕业的学生,难免和铁路设备打交道。机车安全信息综合检测装置(简称TAX箱)就是这样一个奇葩的设备,数据输出的波特率为28800.而通用的串口波特率设置方法并没有配置成这个波特率的方法。没有办法,只能查资料。各种搜索引擎尝试了之后,发现也有同僚遇到这种问题,但是基本所有的搜索条目都指向了同一个帖子,或者其复制品。而这个帖子只给出了思路和部分代码,没有给出可运行的程序,无奈,只能自己去尝试,去修改,去完善,最终成功搞定,记录一下,供后来人使用,如需转载,请注明出处,谢谢。www.datouinfo.com。

http://www.datouinfo.com/?p=1254

对于非标准的任意波特率需要用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的串口比特率作为测试。

查看源代码
打印 帮助
001 #include
002 #include
003 #include       /*标准输入输出定义*/
004 #include      /*标准函数库定义*/
005 #include      /*Unix标准函数定义*/
006 #include   /**/
007 #include    /**/
008 #include       /*文件控制定义*/
009 #include     /*PPSIX终端控制定义*/
010 #include       /*错误号定义*/
011 #include
012  
013 #define TRUE 1
014 #define FALSE 0
015  
016 /*
017 *功能:用于测试非标准波特率串口。
018 *此代码仅限于运行在X86架构的环境下,其他架构并未测试。在arm下未测试
019 *请在root下编译此代码
020 *如有问题,联系我:靳小都 hellojinhongdu#126.com
021 */
022  
023 struct serial_t {
024     int     fd;
025     char    *device;/*/dev/ttyS0,...*/
026     int     baud;
027     int     databit;/*5,6,7,8*/
028     char    parity;/*O,E,N*/
029     int    stopbit;/*1,2*/
030     int    startbit;/*1*/
031     struct termios    options;
032 };
033  
034  
035 int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,
036         B38400, B19200, B9600, B4800, B2400, B1200, B300, };
037 int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300,
038         38400,  19200,  9600, 4800, 2400, 1200,  300, };
039  
040 void set_speed(int fd, int speed)
041 {
042   int   i;
043   int   status;
044   struct termios   Opt;
045   tcgetattr(fd, &Opt);
046   for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
047    {
048     if  (speed == name_arr[i])
049     {
050         tcflush(fd, TCIOFLUSH);
051         cfsetispeed(&Opt, speed_arr[i]);
052         cfsetospeed(&Opt, speed_arr[i]);
053         status = tcsetattr(fd, TCSANOW, &Opt);
054         if  (status != 0)
055             perror("tcsetattr fd1");
056         return;
057         }
058    tcflush(fd,TCIOFLUSH);
059    }
060 }
061  
062 //设置为特诉波特率,比如28800
063 int serial_set_speci_baud(struct serial_t *tty,int baud)
064 {
065     struct serial_struct ss,ss_set;
066     tcgetattr(tty->fd,&tty->options);
067     cfsetispeed(&tty->options,B38400);
068     cfsetospeed(&tty->options,B38400);
069  
070     tcflush(tty->fd,TCIFLUSH);/*handle unrecevie char*/
071     tcsetattr(tty->fd,TCSANOW,&tty->options);
072     if((ioctl(tty->fd,TIOCGSERIAL,&ss))<0){
073         printf("BAUD: error to get the serial_struct info:%s\n",strerror(errno));
074         return -1;
075     }
076     ss.flags = ASYNC_SPD_CUST;
077     ss.custom_divisor = ss.baud_base / baud;
078  
079     printf("ss.custom_divisor = %d \r\n",ss.custom_divisor);
080  
081     if((ioctl(tty->fd,TIOCSSERIAL,&ss))<0){
082         printf("BAUD: error to set serial_struct:%s\n",strerror(errno));
083         //return -2;
084     }
085     
086     ioctl(tty->fd,TIOCGSERIAL,&ss_set);
087     printf("BAUD: success set baud to %d,custom_divisor=%d,baud_base=%d\n",
088             baud,ss_set.custom_divisor,ss_set.baud_base);
089              
090     return 0;
091 }
092  
093 /*get serial's current attribute*/
094 static int serial_get_attr(struct serial_t *tty)
095 {
096   
097     if(tcgetattr(tty->fd,&tty->options) != 0){
098   
099         printf("SERIAL: can't get serial's attribute\n");
100         return -1;
101       
102 }
103   
104     return 0;
105   
106 }
107   
108 /*update serial's attrbute*/
109 static int serial_attr_update(struct serial_t *tty)
110 {
111   
112     tcflush(tty->fd,TCIFLUSH);/*handle unrecevie char*/
113   
114     if((tcsetattr(tty->fd,TCSANOW,&tty->options)) < 0){
115   
116         return -1;
117       
118 }
119   
120     return 0;
121   
122 }
123  
124 static int serial_init_databit(struct serial_t *tty)
125 {
126   
127     if(serial_get_attr(tty)<0)
128         return -1;
129   
130     tty->options.c_cflag &= ~CSIZE;
131     switch(tty->databit){
132   
133         case 5: tty->options.c_cflag |= CS5;break;
134         case 6: tty->options.c_cflag |= CS6;break;
135         case 7: tty->options.c_cflag |= CS7;break;
136         case 8: tty->options.c_cflag |= CS8;break;
137         default:
138             printf("SERIAL: unsupported databit %d\n",tty->databit);
139             return -2;    
140       
141 }
142   
143     if(serial_attr_update(tty) < 0)
144         return -3;
145   
146     printf("SERIAL: set databit to %d\n",tty->databit);
147     return 0;
148   
149 }
150   
151 static int serial_init_parity(struct serial_t *tty)
152 {
153   
154     if(serial_get_attr(tty)<0)
155         return -1;
156   
157     /*ignore framing and parity error*/
158     tty->options.c_iflag = IGNPAR;
159   
160     switch (tty->parity){
161   
162         case 'n':
163         case 'N':
164             /* Clear parity enable */
165             tty->options.c_cflag &= ~PARENB;
166             /* Enable parity checking */
167             tty->options.c_iflag &= ~INPCK;
168             break;
169         case 'o':
170         case 'O':
171             /* 设置为奇校检*/
172             tty->options.c_cflag |= (PARODD|PARENB);
173             /* Disnable parity checking */
174             tty->options.c_iflag |= (INPCK|ISTRIP);
175             break;
176         case 'e':
177         case 'E':
178             /* Enable parity */
179             tty->options.c_cflag |= PARENB; 
180             /* 转换为偶效验*/
181             tty->options.c_cflag &= ~PARODD;
182             /* Disnable parity checking */
183             tty->options.c_iflag |= (INPCK|ISTRIP);  
184             break;
185         default:
186             printf("SERIAL: unsupported parity %c\n",tty->parity); 
187             return -2;
188

你可能感兴趣的:(Linux)