将/ dev / ttyS0波特率设置为> 115200

时间:2016-01-07 18:34:54

标签: linux uart baud-rate

我正在尝试将串行端口(/ dev / ttyS0)的波特率设置为1Mb(1000000)。我尝试使用cfsset {i | o} speed()+ tc {g | s} etattr()编写代码。任何> 115200将被忽略。

#include <termio.h>
#include <fcntl.h>
#include <err.h>
#include <linux/serial.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static int rate_to_constant(int baudrate) 
{
#define B(x) case x: return B##x
  switch(baudrate) {
    B(50);     B(75);     B(110);    B(134);    B(150);
    B(200);    B(300);    B(600);    B(1200);   B(1800);
    B(2400);   B(4800);   B(9600);   B(19200);  B(38400);
    B(57600);  B(115200); B(230400); B(460800); B(500000); 
    B(576000); B(921600); B(1000000);B(1152000);B(1500000);

  default: return 0;
  }
#undef B
}    

/* Open serial port in raw mode, with custom baudrate if necessary */
int serial_open(const char *device, int rate)
{
  struct termios options;
  struct termios options1;
  struct serial_struct serial;
  int fd;
  int speed = 0;

  /* Open and configure serial port */
  if ((fd = open(device, O_RDWR | O_NOCTTY)) == -1)
    return -1;

  speed = rate_to_constant(rate);
  warnx("speed: %d", speed);

  fcntl(fd, F_SETFL, 0);

  if (speed == 0)
    {
      warnx("speed == 0");

      /* Custom divisor */
      memset(&serial, 0, sizeof(struct serial_struct));

      serial.reserved_char[0] = 0;

      if (ioctl(fd, TIOCGSERIAL, &serial) < 0) return -1;

      warnx("serial.baud_base: %d", serial.baud_base);

            serial.flags &= 
      serial.flags &= ~ASYNC_SPD_MASK;
      serial.flags |= ASYNC_SPD_CUST;

      serial.custom_divisor = (serial.baud_base + (rate / 2)) / rate;

      warnx("serial.custom_divisor: %d", serial.custom_divisor);

      if (serial.custom_divisor < 1)
    serial.custom_divisor = 1;

      if (ioctl(fd, TIOCSSERIAL, &serial) < 0)
    return -1;

      if (ioctl(fd, TIOCGSERIAL, &serial) < 0)
    return -1;

      if (serial.custom_divisor * rate != serial.baud_base)
        {
          warnx("actual baudrate is %d / %d = %f",
                serial.baud_base, serial.custom_divisor,
                (float)(serial.baud_base) / serial.custom_divisor);
        }
    }

  memset(&options, 0, sizeof(struct termios));
  tcgetattr(fd, &options);
  cfmakeraw(&options);

  cfsetispeed(&options, speed ?: B38400);
  cfsetospeed(&options, speed ?: B38400);

  options.c_cflag |= (CLOCAL | CREAD);
  options.c_cflag &= ~CRTSCTS;

  if (tcsetattr(fd, TCSANOW, &options) != 0)
    return -1;

  memset(&options1, 0, sizeof(struct termios));
  tcgetattr(fd, &options1);
  warn("options1.speeds: %d and %d", cfgetispeed(&options1), cfgetospeed(&options1));

  return fd;
}

int main(int argc, char *argv[])
{
  int fd;

  //fd = serial_open("/dev/ttyS0", 115200);
  fd = serial_open("/dev/ttyS0", 460800);

  warnx("END");

  close(fd);
}

这基于:How to set baud rate to 307200 on Linux?

我尝试在命令行上使用stty和setserial ......结果相同。

stty -F /dev/ttyS0 1000000

1)我是否需要更改内核代码(serial_core.c或2850.c或2850_pci.c等)?

2)是否有用户空间代码?

Elżbieta

1 个答案:

答案 0 :(得分:1)

如果您要设置的比特率是在<asm/termbits.h>中定义的(包含在<termios.h>中),那么就很麻烦了,不需要遍历所有自定义除数的混搭(始终是特定于设备的):

struct termios ttycfg;
int            fd;

fd = open ("/dev/ttyS0", O_RDWR | O_NOCTTY);
tcgetattr (fd, &ttycfg);
cfsetspeed (&ttycfg, B961200);
tcsetattr (fd, TCSANOW, &ttycfg);

请注意,如果可以执行任何项所请求的更改,tcsetattr()将返回成功,因此,如果要更改多个设置,则应跟进另一个{{1} },看看哪些已成功应用。


此外:默认情况下,许多基于Debian的系统都安装了名为tcgetattr()的软件包,该软件包的目的是通过打开它可以找到的每个串行端口,大喊AT指令并检查响应来检测和管理调制解调器。 (JTAG适配器只是对它们做了<-em> :-/)。如果您要处理的是可热插拔的串行端口(例如USB串行适配器),则 会破坏您的一天,因此,您需要对其进行配置以使其远离您要使用的端口使用(或将其完全删除)。