【转】Linux串口编程

2019-03-02  本文已影响0人  RonZheng2010

参考资料

嵌入式Linux 串口应用编程
http://www.hqyj.com/news/emb174.htm

1. termios 介绍

termios是在POSIX规范中定义的标准接口,表示终端设备,包括虚拟终端、串口等。串口通过termios进行配置。

struct termios
{
    unsigned short c_iflag;  // 输入模式标志
    unsigned short c_oflag;  // 输出模式标志
    unsigned short c_cflag;  // 控制模式标志
    unsigned short c_lflag;  // 本地模式标志
    unsigned char c_line;    // 线路规程
    unsigned char c_cc[NCC]; // 控制特性
    speed_t c_ispeed;        // 输入速度
    speed_t c_ospeed;        // 输出速度
}
tios.c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);

1.1 规范模式

1.2 非规范模式

非规范模式下,所有的输入即时有效,用户不需要另外输入行结束符,不能进行行编辑。

c_cc[VMIN](这里简称为MIN) 和 c_cc[VTIME](这里简称为TIMEOUT)的值决定read()的工作模式。TIMEOUT的单位是1/10秒。

MIN TIMEOUT 工作模式
=0 =0 read()立即返回。若有数据可读,则读取并返回读取的字节数,否则返回0。
>0 =0 read()被阻塞,直到 MIN 个字节数据可被读取。
=0 >0 若数据可读,或超过TIMEOUT无数据,则read()返回。
>0 >0 若MIN个字节可读,或者超过TIMEOUT无数据,则read()返回。

1.3 原始模式

原始模式是一种特殊的非规范模式。这种模式下,所有输入数据以字节为单位处理。

调用cfmakeraw()函数可将终端设置为原始模式。

2. 串口配置步骤

2.1 保存老配置

使用函数tcgetattr()得到原来的配置。该函数也可以测试该串口是否可用。

struct termios tios;
tcgetattr (fd, &tios);

2.2 设置一般控制选项

CLOCAL和CREAD分别用于本地连接和接收使能。如下代码激活这两个选项。

tios.c_cflag |= CLOCAL | CREAD;

2.3 设置波特率 Baudrate

cfsetispeed()和cfsetospeed()分别设置输入和输出方向的波特率。波特率是一组定义好的常量值。通常两个方向使用同样的值。

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

2.4 设置字符大小 Character Size

字符大小可以是CS5、CS6、CS7、和CS8。CSIZE是这些值的组合。一般的做法先清除再重新设置。

tios.c_cflag &= ~CSIZE;
tios.c_cflag |= CS8; 

2.5 设置奇偶校验位 Parity

分两步:

设置奇校验:

tios.c_cflag |= (PARODD | PARENB);
tios.c_iflag |= INPCK; 

设置偶校验:

tios.c_cflag |= PARENB;
tios.c_cflag &= ~PARODD;
tios.c_iflag |= INPCK; 

不校验:

tios.c_cflag &= ~PARENB;
tios.c_iflag &= ~INPCK; 

2.6 设置停止位 Stop Bits

设置c_cflag。

若停止位为两个bit,则激活CSTOPB:

tios.c_cflag |= CSTOPB;  

若停止位为一个bit,则清除CSTOPB:

tios.c_cflag &= ~CSTOPB; 

2.7 设置 MIN 和 TIMEOUT

这个取决于串口数据的特性。低延迟则需要设置一个较小的TIMEOUT;如果延时要求不高则可以设置较大TIMEOUT。MIN的值一般与最小数据包大小接近。

tios.c_cc[VTIME] = 0;
tios.c_cc[VMIN] = 0; 

2.8 清除数据缓冲

在启用新的设置之前,调用tcflush()清空缓存中的残留数据。

int tcflush (int fd, int queue_selector);

queue_selector 可能的取值有以下几种:

一般使用TCIOFLUSH:

tcflush (fd, TCIFLUSH);

2.9 激活新配置

使用tcsetattr()激活新配置。

tcsetattr (int fd, int optional_actions, const struct termios *termios_p);

optional_actions指定新配置生效的时机。可能的取值有以下几种:

tcsetattr (fd, TCSANOW, &tios);

3. 示例

如下的例子中,串口工作在非规范模式下工作。

int configSerialPort (int fd, unsigned int baudrate, unsigned int databits, char parity, 
                     unsigned int stopbits, unsigned int flowcntl)
{
    struct termios tis;
    int ret = 0;

    // get old terminos
    ret = tcgetattr (fd, &tis);
    if (ret < 0)
        return ret;
    
    tis.c_cflag |= (CLOCAL | CREAD);

    // baudrate
    cfsetispeed (&tis, baudrate);
    cfsetospeed (&tis, baudrate);

    // databits
    tis.c_cflag &= ~CSIZE;
    switch (databits)
    {
        case 5:  tis.c_cflag |= CS5;  break;
        case 6:  tis.c_cflag |= CS6;  break;        
        case 7:  tis.c_cflag |= CS7;  break;
        case 8:  tis.c_cflag |= CS8;  break;
        default:  return -1;
    }

    // parity
    switch (parity)
    {
        case 'n':
        case 'N':
            tis.c_cflag &= ~PARENB;
            tis.c_iflag &= ~INPCK;
            break;
        case 'o':
        case 'O':
            tis.c_cflag |= (PARODD | PARENB);
            tis.c_iflag |= INPCK;
            break;
        case 'e':
        case 'E':
            tis.c_cflag |= PARENB;
            tis.c_cflag &= ~PARODD;
            tis.c_iflag |= INPCK;
            break;
        default:
            return -1;
    }

    // stopbits
    switch (attr.stopbits)
    {
        case 1:  tis.c_cflag &= ~CSTOPB;  break;
        case 2:  tis.c_cflag |= CSTOPB;   break;
        default:  return -1;
    }

    // flow control
    switch (attr.flowcntl)
    {
        case FLOW_CNTL_NONE:  tis.c_cflag &= ~CRTSCTS;             break;
        case FLOW_CNTL_HW:    tis.c_cflag |= CRTSCTS;              break;
        case FLOW_CNTL_SW:    tis.c_cflag |= IXON | IXOFF | IXANY; break;
        default:            return -1;
    }

    //tis.c_oflag = 0;
    tis.c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);
    tis.c_cc[VTIME] = 0;
    tis.c_cc[VMIN] = 0;

    tcflush (fd, TCIFLUSH);

    ret = tcsetattr (fd, TCSANOW, &tis);
    if (ret < 0)
        return ret;
}
上一篇 下一篇

猜你喜欢

热点阅读