Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Basically I'm using the following code to set the baud rate of a serial port:

struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
tcsetattr(fd, TCSANOW, &options);

This works very well. But know I have to communicate with a device that uses a baud rate of 307200. How can I set that? cfsetispeed(&options, B307200); doesn't work, there is no B307200 defined.

I tried it using a MOXA Uport 1150 (that's actually a USB-to-serial converter) and the standard serial port of an Intel motherboard. I don't know the exact kind of the latter, setserial just reports it as 16550A.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
543 views
Welcome To Ask or Share your Answers For Others

1 Answer

Linux uses a dirty method for non-standard baud rates, called "baud rate aliasing". Basically, you tell the serial driver to interpret the value B38400 differently. This is controlled with the ASYNC_SPD_CUST flag in serial_struct member flags.

You need to manually calculate the divisor for the custom speed as follows:

// 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) {
    fprintf(stderr, "Cannot set serial port speed to %d. Closest possible is %d
", speed, closestSpeed));
}

ioctl(port, TIOCSSERIAL, &ss);

cfsetispeed(&tios, B38400);
cfsetospeed(&tios, B38400);

Of course, you need a serial driver with suitable baud_base and divisor settings. The preceding snippet allows for 2% deviation, which should be ok for most purposes.

And to tell the driver to interpret B38400 as 38400 baud again:

ioctl(mHandle, TIOCGSERIAL, &ss);
ss.flags &= ~ASYNC_SPD_MASK;
ioctl(mHandle, TIOCSSERIAL, &ss);

As a word of caution: I'm not sure if this method is portable between other *nix flavors.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...