linux下uart应用编程

喜夏-厌秋 提交于 2020-01-24 10:01:08

目的:在用户空间通过读写uart设备文件,控制uart串口发送和接收数据。

在用户空间设置uart波特率、奇偶校验使能等操作是通过termios结构体termios库函数完毕。须要在应用程序中包括termios.h头文件。

一、termios结构体定义

#define NCCS 17   // 控制字符数组的长度。
struct termios
{
unsigned long c_iflag;  // 输入模式标志
unsigned long c_oflag;  // 输出模式标志
unsigned long c_cflag;  // 控制模式标志
unsigned long c_lflag;  // 本地模式标志
unsigned char c_line;   // 线路规程(速率)
unsigned char c_cc[NCCS];  // 控制字符数组
};


c_iflag标记參数有:

#define IGNBRK 0000001  // 输入时忽略BREAK 条件
#define BRKINT 0000002  // 假设没有设置IGNBRK,则在BREAK 时产生SIGINT 信号
#define IGNPAR 0000004  // 忽略奇偶校验和帧错误
#define PARMRK 0000010  // 标记奇偶校验错,在INPCK被设置且IGNPAR未被设置时才实用
#define INPCK 0000020   // 使能帧和奇偶校验错误检查
#define ISTRIP 0000040  // 屏蔽字符第8位
#define INLCR 0000100   // 输入时将换行符NL映射成回车符CR
#define IGNCR 0000200   // 忽略回车符CR
#define ICRNL 0000400   // 在输入时将回车符CR 映射成换行符NL
#define IUCLC 0001000   // 在输入时将大写字符转换成小写字符
#define IXON 0002000    // 同意開始/停止(XON/XOFF)输出控制
#define IXANY 0004000   // 同意不论什么字符重新启动输出
#define IXOFF 0010000   // 同意開始/停止(XON/XOFF)输入控制
#define IMAXBEL 0020000  // 输入队列满时响铃

c_oflag标记參数有:

#define OPOST 0000001   // 使能输出处理。仅仅有这个标记设置了。c_oflag其它的设置才会有效
#define OLCUC 0000002   // 在输出时将小写字符转换成大写字符
#define ONLCR 0000004   // 在输出时将换行符NL 映射成回车-换行符CR-NL
#define OCRNL 0000010   // 在输出时将回车符CR 映射成换行符NL
#define ONOCR 0000020   // 在0列不输出回车符CR
#define ONLRET 0000040  // 换行符NL运行回车符的功能
#define OFILL 0000100   // 延迟时使用填充字符而不使用时间延迟
#define OFDEL 0000200   // 填充字符是ASCII 码DEL。假设未设置,则使用ASCII NULL
#define NLDLY 0000400   // 选择换行延迟
#define NL0 0000000     // 换行延迟类型0
#define NL1 0000400     // 换行延迟类型1
#define CRDLY 0003000   // 选择回车延迟
#define CR0 0000000   // 回车延迟类型0
#define CR1 0001000   // 回车延迟类型1
#define CR2 0002000   // 回车延迟类型2
#define CR3 0003000   // 回车延迟类型3
#define TABDLY 0014000  // 选择水平制表延迟
#define TAB0 0000000    // 水平制表延迟类型0
#define TAB1 0004000    // 水平制表延迟类型1
#define TAB2 0010000    // 水平制表延迟类型2
#define TAB3 0014000    // 水平制表延迟类型3
#define XTABS 0014000   // 将制表符TAB 换成空格。该值表示空格数
#define BSDLY 0020000   // 选择退格延迟
#define BS0 0000000     // 退格延迟类型0
#define BS1 0020000     // 退格延迟类型1
#define VTDLY 0040000  // 纵向制表延迟
#define VT0 0000000    // 纵向制表延迟类型0
#define VT1 0040000    // 纵向制表延迟类型1
#define FFDLY 0040000  // 选择换页延迟
#define FF0 0000000    // 换页延迟类型0
#define FF1 0040000    // 换页延迟类型1

c_cflag标记參数有:

#define CBAUD 0000017   // 传输速率位屏蔽码
#define B0 0000000      // 挂断线路 
#define B50 0000001     // 波特率 50
#define B75 0000002     // 波特率 75
#define B110 0000003    // 波特率 110
#define B134 0000004    // 波特率 134
#define B150 0000005    // 波特率 150
#define B200 0000006    // 波特率 200
#define B300 0000007    // 波特率 300
#define B600 0000010    // 波特率 600
#define B1200 0000011   // 波特率 1200
#define B1800 0000012   // 波特率 1800
#define B2400 0000013   // 波特率 2400
#define B4800 0000014   // 波特率 4800
#define B9600 0000015   // 波特率 9600
#define B19200 0000016  // 波特率 19200
#define B38400 0000017  // 波特率 38400
#define EXTA B19200     // 扩展波特率A
#define EXTB B38400     // 扩展波特率B
#define CSIZE 0000060 // 字符位宽度屏蔽码
#define CS5 0000000   // 每字符5 比特位
#define CS6 0000020   // 每字符6 比特位
#define CS7 0000040   // 每字符7 比特位
#define CS8 0000060   // 每字符8 比特位
#define CSTOPB 0000100   // 设置两个停止位
#define CREAD 0000200    // 字符接收使能。假设没有设置,仍然从port接收字符。可是这些字符都要被丢弃
#define CPARENB 0000400  // 开启输出时产生奇偶位、输入时进行奇偶校验
#define CPARODD 0001000  // 输入/输入校验是奇校验
#define HUPCL 0002000    // 最后进程关闭后挂断
#define CLOCAL 0004000   // 忽略调制解调器(modem)控制线路
#define CIBAUD 03600000  // 输入波特率(未使用)
#define CRTSCTS 020000000000 //流控制
#define PARENB CPARENB  // 开启输出时产生奇偶位、输入时进行奇偶校验
#define PARODD CPARODD  // 输入/输入校验是奇校验

c_lflag标记參数有:

#define ISIG 0000001    // 当收到字符INTR、QUIT、SUSP 或DSUSP,产生对应的信号
#define ICANON 0000002  // 开启规范模式(熟模式)
#define XCASE 0000004   // 若设置了ICANON,则终端是大写字符的
#define ECHO 0000010    // 回显输入字符
#define ECHOE 0000020   // 若设置了ICANON,则ERASE/WERASE 将擦除前一字符/单词
#define ECHOK 0000040   // 若设置了ICANON。则KILL 字符将擦除当前行
#define ECHONL 0000100  // 如设置了ICANON。则即使ECHO 没有开启也回显NL 字符
#define NOFLSH 0000200  // 当生成SIGINT 和SIGQUIT 信号时不刷新输入输出队列,当生成SIGSUSP 信号时。刷新输入队列
#define TOSTOP 0000400  // 发送SIGTTOU 信号到后台进程的进程组,该后台进程试图写自己的控制终端
#define ECHOCTL 0001000  // 若设置了ECHO,则除TAB、NL、START 和STOP 以外的ASCII控制信号将被回显成象^X 式样。X 值是控制符+0x40
#define ECHOPRT 0002000  // 若设置了ICANON 和IECHO。则字符在擦除时将显示
#define ECHOKE 0004000   // 若设置了ICANON。则KILL 通过擦除行上的全部字符被回显
#define FLUSHO 0010000   // 输出被刷新。通过键入DISCARD 字符,该标志被翻转
#define PENDIN 0040000   // 当下一个字符是读时,输入队列中的全部字符将被重显
#define IEXTEN 0100000   // 开启实现时定义的输入处理

c_line參数有:
#define TIOCM_LE 0x001   // 线路同意(Line Enable)
#define TIOCM_DTR 0x002  // 数据终端就绪(Data Terminal Ready)
#define TIOCM_RTS 0x004  // 请求发送(Request to Send)
#define TIOCM_ST 0x008   // 串行数据发送(Serial Transfer)
#define TIOCM_SR 0x010   // 串行数据接收(Serial Receive)
#define TIOCM_CTS 0x020  // 清除发送(Clear To Send)
#define TIOCM_CAR 0x040  // 载波监測(Carrier Detect)
#define TIOCM_RNG 0x080  // 响铃指示(Ring indicate)
#define TIOCM_DSR 0x100  // 数据设备就绪(Data Set Ready)
#define TIOCM_CD TIOCM_CAR
#define TIOCM_RI TIOCM_RNG

c_cc[NCCS]数组:

TO-DO

二、termios库函数

1、获取当前的操作模式參数

int tcgetattr (int fd, struct termios *termios_p)

2、使用*termios_p来设置操作模式參数

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

optional_actions的參数:

#define TCSANOW 0    // 改变马上发生
#define TCSADRAIN 1  // 改变在全部已写的输出被传输之后发生
#define TCSAFLUSH 2  // 改变在全部已写的输出被传输之后而且在全部接收到但还没有读取的数据被丢弃之后发生

3、获得*termios_p中的发送波特率

speed_t cfgetospeed (struct termios *termios_p)

4、获得*termios_p中的接收波特率

speed_t cfgetispeed (struct termios *termios_p)

5、设置*termios_p中的发送波特率

int cfsetospeed (struct termios *termios_p, speed_t speed)

6、设置*termios_p中的接收波特率

int cfsetispeed (struct termios *termios_p, speed_t speed)

7、等待全部输出数据都被发送

int tcdrain (int fd)

8、清空输入/输出缓冲区

int tcflush (int fd, int queue_selector)

queue_selector的參数:

#define TCIFLUSH 0  // 清空输入缓冲区(驱动程序已接收到。但用户程序尚未读取)
#define TCOFLUSH 1  // 清空输出缓冲区(用户程序已经写,但驱动尚未发送)
#define TCIOFLUSH 2  // 清空输入和输出缓冲区

9、对输入输出流进行控制

int tcflow (int fd, int action)

action的參数:

#define TCOOFF 0  // 挂起输出。
#define TCOON 1   // 重新启动被挂起的输出。
#define TCIOFF 2  // 系统传输一个STOP 字符,使设备停止向系统数据传输。
#define TCION 3   // 系统传输一个START 字符,使设备開始向系统数据传输。

10、发送break

int tcsendbreak (int fd, int duration)
在一个指定的时间区间内发送连续的二进位数0。若duration參数为0,则此种发送延续0,25~0.5秒。POSIX.1说明若duration非0。则发送时间依赖于实现。

三、编程实例

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

#define UART_DEVICE     "/dev/ttyPS0" //uart设备文件名称

int main(int argc, char *argv[])
{

    int    fd, res;
    struct termios  oldtio, newtio;
    char  ch;
    char buf[256] = {0};
	
//-----------打开uart设备文件------------------
    fd = open(UART_DEVICE, O_RDWR|O_NOCTTY);//没有设置O_NONBLOCK。所以这里read和write是堵塞操作
    if (fd < 0) {
        perror(UART_DEVICE);
        exit(1);
    }
    else
    	printf("Open %s successfully\n", UART_DEVICE);
    
//-----------设置操作參数-----------------------	
    tcgetattr(fd, &oldtio);//获取当前操作模式參数
    memset(&newtio, 0, sizeof(newtio));
	
	//波特率=115200 数据位=8 使能数据接收 
    newtio.c_cflag = B115200|CS8|CLOCAL|CREAD;
    newtio.c_iflag = IGNPAR; 
    //newtio.c_oflag = OPOST | OLCUC; //
    /* 设定为正规模式 */
    //newtio.c_lflag = ICANON;

    tcflush(fd, TCIFLUSH);//清空输入缓冲区和输出缓冲区
    tcsetattr(fd, TCSANOW, &newtio);//设置新的操作參数
	
//------------向urat发送数据-------------------
    res=write(fd, "\r\nBegin Uart tx", 16);
    while(1) {
    	//从控制台终端获取数据,然后通过uart发送出去,直到接收到!字符
        while((ch=getchar()) != '!') {
            buf[0]=ch;
            res=write(fd, buf, 1);
        }
      
        buf[0]=ch;
        buf[1]='\n';
        res = write(fd, buf, 2);
        break;
    }
//-------------从uart接收数据-------------------
    while(1) {
    	res = read(fd, buf, 255);//程序将在这里挂起,直到从uart接收到数据(堵塞操作)
    	if (res == 0) 
  			continue;
  		
  		buf[res] = '\0';
  		printf("res = %d, buf = %s\n", res, buf);//将uart接收到的字符打印出来
  		if (buf[0] == '!')//uart接收到!字符后退出while
  			break;
  	}
//------------关闭uart设备文件,恢复原先參数--------
    close(fd);
    printf("Close %s\n", UART_DEVICE);
    tcsetattr(fd, TCSANOW, &oldtio); //恢复原先的设置

    return 0;
}






易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!