How to set baud rate to 307200 on Linux?

后端 未结 6 2018
走了就别回头了
走了就别回头了 2020-11-28 10:36

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

struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options,         


        
相关标签:
6条回答
  • 2020-11-28 11:18

    I accomplished this using termios2 and ioctl() commands.

    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);
    

    After that, you should be able to query the port settings and see your custom BAUD rate, as well as the other settings (possible with stty commands).

    0 讨论(0)
  • 2020-11-28 11:18

    Try the ioctl call - you can specify an arbitrary baud rate. That is,

    ioctl(serialFileDescriptor, IOSSIOSPEED, &baudRate);

    To open the serial port:

    // 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);
    

    To read from the serial port:

    // 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]);
        }
    }
    

    To write to the serial port:

    uint8_t val = 'A';
    write(serialFileDescriptor, val, 1);
    

    To list availble serial ports:

    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);
    
    0 讨论(0)
  • 2020-11-28 11:26

    On many OSes, the enumerated values are numerically equal to the baud rate. So just skip the macro/enumeration and pass the baud rate you want, e.g.

    cfsetispeed(&options, 307200);
    

    Of course you should check the return code to make sure this trick actually worked, furthermore not all baud rates are supported by all UARTs.

    You can also try setting the options in struct serial_struct using the TIOCGSERIAL and TIOCSSERIAL ioctl codes.

    0 讨论(0)
  • 2020-11-28 11:28

    Support for that speed is system dependent. If B307200 isn't defined, then your system likely doesn't support it.

    Here's the source code for stty.c: http://www.koders.com/c/fid35874B30FDEAFEE83FAD9EA9A59F983C08B714D7.aspx

    You can see that all of the high-speed variables are #ifdef'd, because support for those speeds varies by system.

    0 讨论(0)
  • USB Negotiation has a similar issue. I found this answer for you which might be used as well:

    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);
    
    0 讨论(0)
  • 2020-11-28 11:34

    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) {
        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);
    

    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.

    0 讨论(0)
提交回复
热议问题