【问题标题】:Specifying non-standard baud rate for FTDI virtual serial port under LinuxLinux下为FTDI虚拟串口指定非标准波特率
【发布时间】:2010-07-07 06:43:06
【问题描述】:

我有一个 USB 设备,我正试图通过 ftdi_sio 内核模块提供的虚拟串行端口与之通信。但是,我在将端口的波特率设置为 14400 时遇到了一些问题:

  • termios.h 没有为 14400 指定常量,所以我不能使用 cfsetispeedcfsetospeed
  • 在 ftdi_sio 内核模块的源代码中,波特基设置为 24000000,似乎没有办法改变它。这意味着我无法将自定义除数与 TIOCSSERIAL ioctl 一起使用,从而获得 14400 的波特率。
  • 模块源有一条评论,听起来好像将端口的tty_struct 结构的alt_speed 成员设置为14400 可以满足我的要求,但似乎没有任何方法可以将其设置为14400 给定现有接口。

有人对此有任何想法吗?通过破解内核模块很容易解决这个问题,但我真的在寻找一种不需要更改内核的解决方案。

【问题讨论】:

  • ISTR 在 Dave Grohl 担任 Nirvana 的鼓手时,使用 14400 波特调制解调器和 19200 波特的端口速度 - 您的设备在 19200 下无法工作吗?
  • 不,不幸的是,它是 14400 或半身像。
  • 由 baudbase / divisor 产生的波特率不是确切的波特率是很常见的事情。这通常不是问题。如果您的串行硬件晶体无法提供,您将无法获得准确的波特率。尤其是像 ftdi 这样的硬件,我怀疑你可以改变波特基。

标签: linux serial-port virtual-serial-port


【解决方案1】:

你不能改变波特基,我想它与硬件有关。所以弄乱模块对你没有任何好处。在您的第三点中,您只讨论了设置自定义波特率的第一种方法,您需要访问tty->alt_speed。似乎没有直接从用户空间设置 tty 结构的接口,至少没有使用 ftdi_sio 驱动程序。
但是,cmets 中解释了另一种方法:

     * 3. You can also set baud rate by setting custom divisor as follows
     *    - set tty->termios->c_cflag speed to B38400
     *    - call TIOCSSERIAL ioctl with (struct serial_struct) set as
     *      follows:
     *      o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
     *      o custom_divisor set to baud_base / your_new_baudrate

你试过了吗?

【讨论】:

  • 我试过了,但是 custom_divisor 是一个整数类型,所以虽然我可以得到 14405 或 14397,但 14400 是不可能的。波特基旋转对我来说看起来很有用,因为它似乎只用于导出您提到的第三种情况中使用的实际波特率。但是,我刚刚注意到 ftdi_sio.h 中与 FTDI_SIO_SET_BAUDRATE 相关的 cmets - 我必须检查是否可以使用它来以有用的方式旋转除数。
  • 啊哈!根据您上面的评论(不完全是 14.4k),我最后仔细研究了 get_ftdi_divisor 函数 - 使用 1666 的除数(即 14405 波特)就可以了,因为这会导致相同的值在 USB 控制消息中发送到设备,该消息设置实际的串行波特率,为 14400 发送。谢谢一百万!
  • 这些比率都在任何合理的保证金误差范围内,应该可以工作。另一台设备很难生成足够精确的波特率,以便在以 14,405 或 13,397 与另一台设备通话时检测到故障。误差很小。
【解决方案2】:

Shodanex 的解决方案适用于 Linux 下的 NDI Polaris Spectra(波特率为 1.2mbps)。按照说明,用B38400打开串口设备(/dev/ttyUSB0),

int port = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);
tcgetattr(port,&g_initialAtt);// save this to restore later
newAtt=g_initialAtt;
newAtt.c_cflag = B38400 | CS8 | CLOCAL | CREAD; 
cfmakeraw(&newAtt);
tcsetattr(port,TCSANOW,&newAtt);

然后执行:

if(ioctl(port, TIOCGSERIAL, &sstruct) < 0){
    printf("Error: could not get comm ioctl\n"); 
    exit(0); 
}
sstruct.custom_divisor = custDiv;
//sstruct.flags &= 0xffff ^ ASYNC_SPD_MASK; NO! makes read fail.
sstruct.flags |= ASYNC_SPD_CUST; 
if(ioctl(port, TIOCSSERIAL, &sstruct) < 0){
    printf("Error: could not set custom comm baud divisor\n"); 
    exit(0); 
}

【讨论】:

猜你喜欢
  • 2019-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 2011-11-30
  • 1970-01-01
相关资源
最近更新 更多