作为铁路院校毕业的学生,难免和铁路设备打交道。机车安全信息综合检测装置(简称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 <termios.h> |
002 |
#include <sys/ioctl.h> |
003 |
#include <stdio.h> /*标准输入输出定义*/ |
004 |
#include <stdlib.h> /*标准函数库定义*/ |
005 |
#include <unistd.h> /*Unix标准函数定义*/ |
006 |
#include <sys/types.h> /**/ |
007 |
#include <sys/stat.h> /**/ |
008 |
#include <fcntl.h> /*文件控制定义*/ |
009 |
#include <termios.h> /*PPSIX终端控制定义*/ |
010 |
#include <errno.h> /*错误号定义*/ |
011 |
#include <linux/serial.h> |
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 |
} |