串行端口上不常见的波特率 - Linux
Uncommon baud rate on serial port - Linux
我目前正在尝试编写一个程序来读取串行端口。在这个端口上我收到了波特率为875000的数据。这种情况确实不常见,我没有成功修改它。我已经编写了一个小 C 程序来执行此操作,但它不适用于 875000...这里是串口编程的部分代码:
#include <stdio.h>
#include <stdlib.h>
#include <asm/termios.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "test.h"
void read_Serial_Port(const char* DEVICE_PORT)
{
int file;
struct ktermios options;
unsigned int nCountMax = 60;
bool b;
file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY);
if(file == -1){perror("Unable to open the serial port\n");}
//printf("Serial port open successful !\n");
int speed = atoi("875000");
ioctl(file, TCGETS2, &options);
options.c_ispeed = speed;
options.c_ospeed = speed;
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CBAUD;
options.c_cflag |= BOTHER;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
ioctl(file, TCSETS2, &options);
//printf("Reading serial port ...\n\n");
b = readMessage(file, nCountMax);
if (b == 0){printf("Error while reading serial port\n");}
//else printf("\nSerial port read successful\n");
close(file);
//printf("Serial port closed\n");
};
最后我在 Whosebug 上找到了另一个主题,它已经完成并解决了我的问题:How to set baud rate to 307200 on Linux?
这是我修改后的代码:
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);
B(2000000);B(2500000);B(3000000);B(3500000);B(4000000);
default: return 0;
}
#undef B
}
int Custom_Baudrate(const char* Device, int rate)
{
/*Declaration of all the variables needed*/
struct termios2 options;
struct serial_struct serinfo;
int file=-1;
int speed = 0;
int r=rate;
/* Open and configure serial port */
file = open(Device,O_RDWR|O_NOCTTY);
if(file==-1){printf("\nERROR : Unable to open the serial port\n\n");return 1;}
speed = rate_to_constant(r);
/*Find best Baudrate*/
if (speed == 0) {
/* Custom divisor */
serinfo.reserved_char[0] = 0;
if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
serinfo.flags &= ~ASYNC_SPD_MASK;
serinfo.flags |= ASYNC_SPD_CUST;
serinfo.custom_divisor = ((serinfo.baud_base + (r / 2)) / r);
if (serinfo.custom_divisor < 1)
serinfo.custom_divisor = 1;
if (ioctl(file, TIOCSSERIAL, &serinfo) < 0) file=-1;
if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
if (serinfo.custom_divisor * r != serinfo.baud_base) {
warnx("actual baudrate is %d / %d = %f",
serinfo.baud_base, serinfo.custom_divisor,
(float)
serinfo.baud_base / serinfo.custom_divisor);
}
}
/*Set the best Baudrate (if desired baudrate is unvailable, it's set automatically at 38400)*/
fcntl(file, F_SETFL, 0);
tcgetattr(file, &options);
cfsetispeed(&options, speed ?: B38400);
cfsetospeed(&options, speed ?: B38400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
if (tcsetattr(file, TCSANOW, &options) != 0) file=-1;
/*Read the serial port*/
communicate_Serial_Port(file);
close(file);
return 1;
}
在此代码中,您只需精确确定所需的波特率,它就会找到您可以使用的最接近的值。该值基于您设备的 "base baudrate",它会搜索一个除数以设置最佳波特率。但是,某些波特率应该始终不可用,因此该程序会将 38400 作为基础(这是一个选择)。
我用几个波特率测试它,它总是有效。
我是 Whosebug 的新手,我希望这个 post 能正确完成问题。
不幸的是,对于自定义波特率,您有时需要自定义硬件,或者至少需要自定义驱动程序。 Linux 处理的标准波特率非常有限,但现代 UART 通常可以达到更多,因为波特率发生器的时钟频率比 30-40 年前高得多,此外还经常支持小数分频器。一个例子:
https://assets.maxlinear.com/web/documents/xr17v358.pdf
它可以使用125MHz 或62.5MHz 作为参考,在125MHz 时,875000 的波特率需要8 和15/16 的分频器。为此,您必须使用自定义 exar_serial 驱动程序而不是通常的 Linux 串行子系统。
在较旧的硬件上,通常会找到一个不同的 crystal 来获得您想要的频率,甚至经常使用可变或可选振荡器。
我目前正在尝试编写一个程序来读取串行端口。在这个端口上我收到了波特率为875000的数据。这种情况确实不常见,我没有成功修改它。我已经编写了一个小 C 程序来执行此操作,但它不适用于 875000...这里是串口编程的部分代码:
#include <stdio.h>
#include <stdlib.h>
#include <asm/termios.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "test.h"
void read_Serial_Port(const char* DEVICE_PORT)
{
int file;
struct ktermios options;
unsigned int nCountMax = 60;
bool b;
file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY);
if(file == -1){perror("Unable to open the serial port\n");}
//printf("Serial port open successful !\n");
int speed = atoi("875000");
ioctl(file, TCGETS2, &options);
options.c_ispeed = speed;
options.c_ospeed = speed;
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CBAUD;
options.c_cflag |= BOTHER;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
ioctl(file, TCSETS2, &options);
//printf("Reading serial port ...\n\n");
b = readMessage(file, nCountMax);
if (b == 0){printf("Error while reading serial port\n");}
//else printf("\nSerial port read successful\n");
close(file);
//printf("Serial port closed\n");
};
最后我在 Whosebug 上找到了另一个主题,它已经完成并解决了我的问题:How to set baud rate to 307200 on Linux?
这是我修改后的代码:
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);
B(2000000);B(2500000);B(3000000);B(3500000);B(4000000);
default: return 0;
}
#undef B
}
int Custom_Baudrate(const char* Device, int rate)
{
/*Declaration of all the variables needed*/
struct termios2 options;
struct serial_struct serinfo;
int file=-1;
int speed = 0;
int r=rate;
/* Open and configure serial port */
file = open(Device,O_RDWR|O_NOCTTY);
if(file==-1){printf("\nERROR : Unable to open the serial port\n\n");return 1;}
speed = rate_to_constant(r);
/*Find best Baudrate*/
if (speed == 0) {
/* Custom divisor */
serinfo.reserved_char[0] = 0;
if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
serinfo.flags &= ~ASYNC_SPD_MASK;
serinfo.flags |= ASYNC_SPD_CUST;
serinfo.custom_divisor = ((serinfo.baud_base + (r / 2)) / r);
if (serinfo.custom_divisor < 1)
serinfo.custom_divisor = 1;
if (ioctl(file, TIOCSSERIAL, &serinfo) < 0) file=-1;
if (ioctl(file, TIOCGSERIAL, &serinfo) < 0) file=-1;
if (serinfo.custom_divisor * r != serinfo.baud_base) {
warnx("actual baudrate is %d / %d = %f",
serinfo.baud_base, serinfo.custom_divisor,
(float)
serinfo.baud_base / serinfo.custom_divisor);
}
}
/*Set the best Baudrate (if desired baudrate is unvailable, it's set automatically at 38400)*/
fcntl(file, F_SETFL, 0);
tcgetattr(file, &options);
cfsetispeed(&options, speed ?: B38400);
cfsetospeed(&options, speed ?: B38400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
if (tcsetattr(file, TCSANOW, &options) != 0) file=-1;
/*Read the serial port*/
communicate_Serial_Port(file);
close(file);
return 1;
}
在此代码中,您只需精确确定所需的波特率,它就会找到您可以使用的最接近的值。该值基于您设备的 "base baudrate",它会搜索一个除数以设置最佳波特率。但是,某些波特率应该始终不可用,因此该程序会将 38400 作为基础(这是一个选择)。 我用几个波特率测试它,它总是有效。
我是 Whosebug 的新手,我希望这个 post 能正确完成问题。
不幸的是,对于自定义波特率,您有时需要自定义硬件,或者至少需要自定义驱动程序。 Linux 处理的标准波特率非常有限,但现代 UART 通常可以达到更多,因为波特率发生器的时钟频率比 30-40 年前高得多,此外还经常支持小数分频器。一个例子: https://assets.maxlinear.com/web/documents/xr17v358.pdf
它可以使用125MHz 或62.5MHz 作为参考,在125MHz 时,875000 的波特率需要8 和15/16 的分频器。为此,您必须使用自定义 exar_serial 驱动程序而不是通常的 Linux 串行子系统。
在较旧的硬件上,通常会找到一个不同的 crystal 来获得您想要的频率,甚至经常使用可变或可选振荡器。