C++ 如何在Linux上将波特率设置为307200?
基本上,我使用以下代码设置串行端口的波特率:C++ 如何在Linux上将波特率设置为307200?,c++,c,linux,serial-port,baud-rate,C++,C,Linux,Serial Port,Baud Rate,基本上,我使用以下代码设置串行端口的波特率: struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); tcsetattr(fd, TCSANOW, &options); 这很有效。但是我知道我必须和一个波特率为307200的设备通信。我该怎么设置呢cfsetispeed(&options,B30
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
tcsetattr(fd, TCSANOW, &options);
这很有效。但是我知道我必须和一个波特率为307200的设备通信。我该怎么设置呢<代码>cfsetispeed(&options,B307200)代码>不起作用,未定义B307200
我使用MOXA Uport 1150(实际上是USB到串行转换器)和Intel主板的标准串行端口进行了尝试。我不知道后者的确切类型,setserial只是将其报告为16550A。对该速度的支持取决于系统。如果未定义
B307200
,则您的系统可能不支持它
下面是stty.c的源代码:
您可以看到,所有高速变量都是“ifdef”,因为对这些速度的支持因系统而异。在许多操作系统上,枚举值在数字上等于波特率。因此,只需跳过宏/枚举并传递所需的波特率,例如
cfsetispeed(&options, 307200);
当然,您应该检查返回代码,以确保此技巧实际起作用,而且并非所有UART都支持所有波特率
您还可以尝试使用
TIOCGSERIAL
和TIOCSSERIAL
ioctl代码设置选项。尝试ioctl调用-您可以指定任意波特率。就是
ioctl(串行文件描述符、IOSSIOSPEED和波特率)
打开串行端口:
// Open the serial like POSIX C
serialFileDescriptor = open(
"/dev/tty.usbserial-A6008cD3",
O_RDWR |
O_NOCTTY |
O_NONBLOCK );
// Block non-root users from using this port
ioctl(serialFileDescriptor, TIOCEXCL);
// Clear the O_NONBLOCK flag, so that read() will
// block and wait for data.
fcntl(serialFileDescriptor, F_SETFL, 0);
// Grab the options for the serial port
tcgetattr(serialFileDescriptor, &options);
// Setting raw-mode allows the use of tcsetattr() and ioctl()
cfmakeraw(&options);
// Specify any arbitrary baud rate
ioctl(serialFileDescriptor, IOSSIOSPEED, &baudRate);
// This selector will be called as another thread
- (void)incomingTextUpdateThread: (NSThread *) parentThread {
char byte_buffer[100]; // Buffer for holding incoming data
int numBytes=1; // Number of bytes read during read
// Create a pool so we can use regular Cocoa stuff.
// Child threads can't re-use the parent's autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// This will loop until the serial port closes
while(numBytes>0) {
// read() blocks until data is read or the port is closed
numBytes = read(serialFileDescriptor, byte_buffer, 100);
// You would want to do something useful here
NSLog([NSString stringWithCString:byte_buffer length:numBytes]);
}
}
uint8_t val = 'A';
write(serialFileDescriptor, val, 1);
io_object_t serialPort;
io_iterator_t serialPortIterator;
// Ask for all the serial ports
IOServiceGetMatchingServices(
kIOMasterPortDefault,
IOServiceMatching(kIOSerialBSDServiceValue),
&serialPortIterator);
// Loop through all the serial ports
while (serialPort = IOIteratorNext(serialPortIterator)) {
// You want to do something useful here
NSLog(
(NSString*)IORegistryEntryCreateCFProperty(
serialPort, CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault, 0));
IOObjectRelease(serialPort);
}
IOObjectRelease(serialPortIterator);
从串行端口读取:
// Open the serial like POSIX C
serialFileDescriptor = open(
"/dev/tty.usbserial-A6008cD3",
O_RDWR |
O_NOCTTY |
O_NONBLOCK );
// Block non-root users from using this port
ioctl(serialFileDescriptor, TIOCEXCL);
// Clear the O_NONBLOCK flag, so that read() will
// block and wait for data.
fcntl(serialFileDescriptor, F_SETFL, 0);
// Grab the options for the serial port
tcgetattr(serialFileDescriptor, &options);
// Setting raw-mode allows the use of tcsetattr() and ioctl()
cfmakeraw(&options);
// Specify any arbitrary baud rate
ioctl(serialFileDescriptor, IOSSIOSPEED, &baudRate);
// This selector will be called as another thread
- (void)incomingTextUpdateThread: (NSThread *) parentThread {
char byte_buffer[100]; // Buffer for holding incoming data
int numBytes=1; // Number of bytes read during read
// Create a pool so we can use regular Cocoa stuff.
// Child threads can't re-use the parent's autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// This will loop until the serial port closes
while(numBytes>0) {
// read() blocks until data is read or the port is closed
numBytes = read(serialFileDescriptor, byte_buffer, 100);
// You would want to do something useful here
NSLog([NSString stringWithCString:byte_buffer length:numBytes]);
}
}
uint8_t val = 'A';
write(serialFileDescriptor, val, 1);
io_object_t serialPort;
io_iterator_t serialPortIterator;
// Ask for all the serial ports
IOServiceGetMatchingServices(
kIOMasterPortDefault,
IOServiceMatching(kIOSerialBSDServiceValue),
&serialPortIterator);
// Loop through all the serial ports
while (serialPort = IOIteratorNext(serialPortIterator)) {
// You want to do something useful here
NSLog(
(NSString*)IORegistryEntryCreateCFProperty(
serialPort, CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault, 0));
IOObjectRelease(serialPort);
}
IOObjectRelease(serialPortIterator);
写入串行端口:
// Open the serial like POSIX C
serialFileDescriptor = open(
"/dev/tty.usbserial-A6008cD3",
O_RDWR |
O_NOCTTY |
O_NONBLOCK );
// Block non-root users from using this port
ioctl(serialFileDescriptor, TIOCEXCL);
// Clear the O_NONBLOCK flag, so that read() will
// block and wait for data.
fcntl(serialFileDescriptor, F_SETFL, 0);
// Grab the options for the serial port
tcgetattr(serialFileDescriptor, &options);
// Setting raw-mode allows the use of tcsetattr() and ioctl()
cfmakeraw(&options);
// Specify any arbitrary baud rate
ioctl(serialFileDescriptor, IOSSIOSPEED, &baudRate);
// This selector will be called as another thread
- (void)incomingTextUpdateThread: (NSThread *) parentThread {
char byte_buffer[100]; // Buffer for holding incoming data
int numBytes=1; // Number of bytes read during read
// Create a pool so we can use regular Cocoa stuff.
// Child threads can't re-use the parent's autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// This will loop until the serial port closes
while(numBytes>0) {
// read() blocks until data is read or the port is closed
numBytes = read(serialFileDescriptor, byte_buffer, 100);
// You would want to do something useful here
NSLog([NSString stringWithCString:byte_buffer length:numBytes]);
}
}
uint8_t val = 'A';
write(serialFileDescriptor, val, 1);
io_object_t serialPort;
io_iterator_t serialPortIterator;
// Ask for all the serial ports
IOServiceGetMatchingServices(
kIOMasterPortDefault,
IOServiceMatching(kIOSerialBSDServiceValue),
&serialPortIterator);
// Loop through all the serial ports
while (serialPort = IOIteratorNext(serialPortIterator)) {
// You want to do something useful here
NSLog(
(NSString*)IORegistryEntryCreateCFProperty(
serialPort, CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault, 0));
IOObjectRelease(serialPort);
}
IOObjectRelease(serialPortIterator);
列出可用串行端口:
// Open the serial like POSIX C
serialFileDescriptor = open(
"/dev/tty.usbserial-A6008cD3",
O_RDWR |
O_NOCTTY |
O_NONBLOCK );
// Block non-root users from using this port
ioctl(serialFileDescriptor, TIOCEXCL);
// Clear the O_NONBLOCK flag, so that read() will
// block and wait for data.
fcntl(serialFileDescriptor, F_SETFL, 0);
// Grab the options for the serial port
tcgetattr(serialFileDescriptor, &options);
// Setting raw-mode allows the use of tcsetattr() and ioctl()
cfmakeraw(&options);
// Specify any arbitrary baud rate
ioctl(serialFileDescriptor, IOSSIOSPEED, &baudRate);
// This selector will be called as another thread
- (void)incomingTextUpdateThread: (NSThread *) parentThread {
char byte_buffer[100]; // Buffer for holding incoming data
int numBytes=1; // Number of bytes read during read
// Create a pool so we can use regular Cocoa stuff.
// Child threads can't re-use the parent's autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// This will loop until the serial port closes
while(numBytes>0) {
// read() blocks until data is read or the port is closed
numBytes = read(serialFileDescriptor, byte_buffer, 100);
// You would want to do something useful here
NSLog([NSString stringWithCString:byte_buffer length:numBytes]);
}
}
uint8_t val = 'A';
write(serialFileDescriptor, val, 1);
io_object_t serialPort;
io_iterator_t serialPortIterator;
// Ask for all the serial ports
IOServiceGetMatchingServices(
kIOMasterPortDefault,
IOServiceMatching(kIOSerialBSDServiceValue),
&serialPortIterator);
// Loop through all the serial ports
while (serialPort = IOIteratorNext(serialPortIterator)) {
// You want to do something useful here
NSLog(
(NSString*)IORegistryEntryCreateCFProperty(
serialPort, CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault, 0));
IOObjectRelease(serialPort);
}
IOObjectRelease(serialPortIterator);
USB协商也有类似的问题。我为您找到了这个答案,也可以使用:
struct serial_struct ser_info;
ioctl(ser_dev, TIOCGSERIAL, &ser_info);
ser_info.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY;
ser_info.custom_divisor = ser_info.baud_base / CUST_BAUD_RATE;
ioctl(ser_dev, TIOCSSERIAL, &ser_info);
Linux对非标准波特率使用脏方法,称为“波特率别名”。基本上,您告诉串行驱动程序以不同的方式解释值
B38400
。这由serial\u struct
成员标志中的ASYNC\u SPD\u CUST
标志控制
您需要手动计算自定义速度的除数,如下所示:
// configure port to use custom speed instead of 38400
ioctl(port, TIOCGSERIAL, &ss);
ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST;
ss.custom_divisor = (ss.baud_base + (speed / 2)) / speed;
closestSpeed = ss.baud_base / ss.custom_divisor;
if (closestSpeed < speed * 98 / 100 || closestSpeed > speed * 102 / 100) {
sprintf(stderr, "Cannot set serial port speed to %d. Closest possible is %d\n", speed, closestSpeed));
}
ioctl(port, TIOCSSERIAL, &ss);
cfsetispeed(&tios, B38400);
cfsetospeed(&tios, B38400);
警告:我不确定这个方法是否可以在其他*nix版本之间移植。我使用termios2
和ioctl()
命令完成了这项工作
struct termios2 options;
ioctl(fd, TCGETS2, &options);
options.c_cflag &= ~CBAUD; //Remove current BAUD rate
options.c_cflag |= BOTHER; //Allow custom BAUD rate using int input
options.c_ispeed = 307200; //Set the input BAUD rate
options.c_ospeed = 307200; //Set the output BAUD rate
ioctl(fd, TCSETS2, &options);
之后,您应该能够查询端口设置并查看自定义波特率以及其他设置(可以使用stty
命令)。您可以使用“stty”设置此波特率吗?如果没有,我怀疑你能(对我来说似乎是一个模糊的速度);如果可以,请看一下它的代码。“速度”选项由termios.h中的八进制值定义,因此您可以通过分析这些值来假设推导出正确的值。Nostty
不起作用,因为它使用一些硬编码值检查波特率。有趣的是,serserserial
允许设置307200,并且不报告错误。但是当我尝试从串口读取数据时,它不起作用。你真的确定你的设备的波特率是307200吗?这不是无线电通信特有的东西吗?是的,我确信307200是正确的。-1这在Linux上是不正确的,请参阅/usr/include/bits/termios中的定义。佩恩说过这在Linux上不起作用吗cfsetispeed
需要一个八进制值。我试过使用0000022
,它应该是307200,但不起作用。0000022
=18
,我不知道“应该是307200”。你是对的,它应该是0000024。但这只是一个假设,因为9600被定义为0000015,19200被定义为0000016,38400被定义为0000017。@cairol:我发布了一些额外的信息。关于TIOCSSERIAL
的详细信息很难找到,您可能需要阅读源代码,但您可以通过这种方式获得非标准波特率。感谢链接。代码中定义了许多高速波特率,但不是307200。Linux上似乎不支持此波特率,因为它既不是在/usr/include/bits/termios.h
中定义的,也不是在另一个Bxy
中定义的。老式UNIX的速度为4位。可能VAX硬件在硬件中有类似的4位波特率。无论如何,现代硬件有一个“基本波特率”和一个约数,可以是16位,允许65536个不同的波特率。Linux内核保留旧接口的时间太长了。(大约二十年前,我就不再争论要改变它了)。内核的适当接口只需为请求的波特率设置一个整数。然后内核可以做任何必要的尝试和实现,用户空间libc可以模拟旧的行为。。。太久了,这个问题是关于Linux的,而不是关于BSD的。Linux支持不同的IOCTL,我想我已经在回答中列出了合适的IOCTL。如果你有一些关于TIOCSSERIAL
的示例代码,那会很有帮助,值得一试。这对我很有用。还有一个问题。还有一个与这个答案相关的问题。OMG。那只是。。。真可怕(有人在设计API之前完全忘了在早餐麦片粥上撒上抽象内容。@放松比你想象的更可怕,因为它的文档记录得很糟糕。我想这就是为什么3年前的这个答案仍然得到支持的原因:)这并不是所有的芯片都支持的。对于多产的PL2303,驱动程序不支持TIOCSSERIAL
ioctl
命令。我可以直接设置波特率(在我的例子中使用B921600
)。您必须在Linux中使用struct termios2
来设置波特率和相应的IOCTL。波特率实际上是307200吗?你量过了吗?实际最接近的波特率可能是230400和460800,也可能不是。@PeterMortensen我没有实际测量实际波特率,但我使用的是一个自定义微控制器,它以自定义波特率运行,似乎没有任何通信问题。确保您遵循了上述所有步骤