linux下uart应用编程

目的:在用户空间通过读写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    // 字符接收使能。如果没有设置,仍然从端口接收字符,但是这些字符都要被丢弃
#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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 09:34:38

linux下uart应用编程的相关文章

Linux下C++的编程——开偏介绍

C++是一个功能强大而又应用广泛的计算机语言,就应用领域而言,几乎无所不在,因为有操作系统的地方就会有C++的存在,热门程序而言,也就仅次于C和Java.而C与C++又有天然的血缘关系. 从事C++开发近两年,虽然开发的产品都是跨平台的,但个人直接接触到的编程工程还是更偏重于Windows平台(至少开发环境更多的是在Windows平台,还写过"带你玩转Visual Studio"系列的博文),而现在要自己独立地带领一个项目的开发,还是一个跨平台的项目,也就有必要到Linux下C++的编

Linux下C++的编程——开发环境搭建与第一个程序

上一篇文章Linux下C++的编程--开偏介绍中我们已经介绍了GUN.GCC.G++等一些重要的概念,现在应该开始动手实践了! 开发工具的安装 环境 Distributions版本:CentOS 6.7 Linux内核片:2.6.32-573.3.1.el6.i686 一般Linux安装完之后默认就已经安装了GCC(GNU Compiler Collection),你可以查看一下gcc和g++的版本号检查gcc和g++是否已经安装. [luowf@luoweifu ~]$ gcc -v gcc

LINUX下C语言编程基础

实验二 Linux下C语言编程基础 一.实验目的 1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用gdb调试技术 6. 熟悉makefile基本原理及语法规范 7. 掌握静态库和动态库的生成 二.实验步骤 1. 快捷键 Ubuntu中: 2. vim VIM是一个非常好的文本编辑器,很多专业程序员使用VIM编辑代码,即使以后你不编写程序,只要跟文本打交道,都应该学学VIM,可以浏览参考一下普通人

Linux下C++的编程——GDB进行程序调试

GDB简介 我们在Linux下C++的编程--开偏介绍一文中已经简单介绍了GDB的功能,是类Unix系统的主要调试工具,可进行断点调试,跟踪程序,动态改变执行环境等功能. 从一个程序开始调试 下面我们就从一个程序开始讲解一下GDB的简单用法.假设我们有如下的程序: GDBTest1.cpp #include <iostream> int Accumulation(int n) { int result = 0; for(int i = 0; i < n; i ++) { result +

Linux下的shell编程入门

通常情况下,我们从命令行输入命令每输入一次就能够得到系统的一次响应.一旦需要我们一个接着一个的输入命令而最后才得到结果的时候,这样的做法显然就没有效率.要达到这样的目的,通常我们利用shell程序或者shell脚本来实现. 一.简介 Shell编程有很多类似C语言和其他程序语言的特征,但是又没有编程语言那样复杂.Shell程序就是放在一个文件中的一系列Linux命令和实用程序,在执行的时候,通过Linux一个接着一个地解释和执行每个命令. 下面我们来看一个简单的shell程序: 1.首先建立一个

linux下的bash编程简要学习

linux下的bash编程简要学习     1.bash是什么: linux运行时系统只会运行系统运行所需要的运行脚本即系统守护进程,一般根据用户自己需求设定和实现的服务需要手动启动,这种服务进程通常由bash启动,脚本中的命令通常被按照一定规则被bash读取视作参数,因此在脚本头部要申明运行的bash类型,bash命令分为内建命令及外部命令,外部命令通过PATH进行依次查找. bash读取命令后将其启动(fork)成为一个进程,依次启动服务     2.bash控制语句:         本地

Linux 下IO端口编程访问

以前写的一篇笔记,偶尔翻出来了,放在这里做个纪念 Linux 下IO端口编程访问 这里记录的方法是在用户态访问IO端口,不涉及驱动程序的编写. 首先要包含头文件 /usr/include/asm/io.h ioperm() 在 unistd.h 中声明.用来打开对IO端口的访问权限,要求程序执行时必须有root 权限.只可以打开0x00到0x3ff 这一地址段的IO端口. ioperm( from, num, turn_on) 比如: #include<asm/io.h> #include&l

Linux下C语言编程基础学习记录

VIM的基本使用  LINUX下C语言编程 用gcc命令编译运行C语言文件 预处理阶段:将*.c文件转化为*.i预处理过的C程序. 编译阶段:将*.i文件编译为汇编代码*.s文件. 汇编阶段:将*.s文件转化为*.o的二进制目标代码文件. 链接阶段:将*.o文件转化为可执行文件. 生成可执行文件:将*.o转换为可执行文件. 执行可执行C语言文件. gcc常用选项列表 -c      只编译不链接,生成目标文件“.o” -S      只编译不汇编,生成编码代码 -E      只进行预编译,不做

Linux下TCP网络编程与基于Windows下C#socket编程间通信

一.linux下TCP网络编程基础,需要了解相关函数 Socket():用于套接字初始化. Bind():将 socket 与本机上的一个端口绑定,就可以在该端口监听服务请求. Listen():使socket处于被动的监听模式,并为该  socket  建立一个输入数据队列,将到达的服务器, 请求保存在此队列中,直到程序处理他们. Accept():让服务器接收客户的连接请求. Connect():客户端使用connect函数来配置 socket并与远端服务器建立一个 TCP 连接. Clos