我正在尝试将串行端口(/ 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
答案 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串行适配器),则 会破坏您的一天,因此,您需要对其进行配置以使其远离您要使用的端口使用(或将其完全删除)。