UART串口及Linux实现
UART,全称Universal Asynchronous Receiver Transmitter,通用异步收发器,俗称串口。作为最常用的通信接口之一,从8位单片机到64位SoC,一般都会提供UART接口。
UART的常规构成及特性
芯片内部的UART模块,一般由波特率发生器、发送和接收FIFO、硬件流控、中断源等组件构成。常见特性如下:
全双工通信
硬件流控
可编程的字长(5/6/7/8比特)
可编程的停止位(1/1.5/2比特)
奇偶校验
可编程的FIFO中断触发水位
可编程的波特率
UART硬件信号及应用
| 信号脚 |
方向 |
用途 |
| TXD |
输出 | 串行数据输出 |
| RXD | 输入 |
串行数据输入 |
| CTSN | 输入 |
流控脚,允许发送,由对端设备控制,控制己方UART是否可以发送数据。低电平时,UART可以发送数据出去,高电平时,UART停止发送数据。 |
| RTSN | 输出 |
流控脚,请求发送,连接到对端设备的CTSN脚上,通知对端设备是否可以发送数据。低电平时,通知对端设备可以发送,高电平时,通知对端设备停止发送。 |
图1 带硬件流控的UART连接
图2 不带硬件流控的UART连接
UART通信协议
UART通信时序图如下
图3 UART时序
数据线的空闲电平为逻辑“1”,要传输数据时:
起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。
数据位:实际要传输的数据,数据位数可以是5、6、7、8,数据是从最低有效位(LSB)开始。
校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。上图中没有特意标明。
停止位:数据的结束标志。可以是1/1.5/2位的空闲电平。Linux串口设备编程接口并不支持设置1.5位。
UART通信是异步的,并没有单独的时钟来做同步,通信双方需要约定好相同的波特率。UART中的波特率可以认为是比特率,即每秒传输的位数。一般波特率有9600,115200,460800等选项。
Linux中的UART驱动
Linux UART驱动框架如下图所示,UART在用户空间会生成名为/dev/ttyS*的设备(ttyS名称是驱动给出的,可能因驱动而异),应用程序通过读写设备就可以进行UART通信。Linux内核实现了tty层和serial core,serial core会调用tty层的接口,注册tty driver,同时提供了底层uart的抽象:
定义struct uart_driver、struct uart_port、struct uart_ops等结构来描述底层uart驱动;
提供相应接口 uart_register_driver、uart_add_one_port 等。
图4 UART驱动框架
重点看一下struct uart_ops定义,如下图所示,定义了UART硬件能完成的操作。
UART控制器驱动会定义uart_ops结构并实现对应的函数功能,当然并不是所有函数都需要实现,最为关键的几个函数如下表所示。
| 函数 |
意义 |
| tx_empty |
查询TX FIFO是否为空,为空则返回1,否则返回0 |
| stop_tx |
停止发送 |
| start_tx |
启动发送 |
| stop_rx |
停止接收 |
| startup |
开启UART |
| shutdown |
关闭UART |
| set_termios |
设置UART属性,比如波特率、数据位数、停止位数、奇偶校验、流控等。 |
struct uart_driver指代一个UART驱动,struct uart_port指代一个具体UART端口,它们与struct uart_ops的关系大致如下图。
下面以某厂商的UART控制器驱动为例,看看驱动实现的整体流程。
UART控制器驱动,以platform_driver的形式呈现。
关键的uart_ops结构定义如下,uart_ops会关联到一个或多个uart_port上。
UART控制器驱动的probe函数,完成初始化uart_port,并添加到serial core中。
Linux上串口的常规操作工具
Linux上,除了一些串口工具比如minicom, cutecom可以操作串口外,也可以用如下命令行工具进行基本的操作。
| 目的 | 操作方法(以/dev/ttyS0为例) |
| 查询串口 |
stty -F /dev/ttyS0 |
| 设置串口 |
stty -F /dev/ttyS0 speed 115200 cs8 -parenb -cstopb 115200波特率 8数据位 1停止位 无校验 |
| 读取数据 |
cat /dev/ttyS0 |
| 发送数据 |
echo "test data" > /dev/ttyS0 |
用户空间的串口编程
打开/读/写串口,与普通字符设备一样,open/read/write系统调用,不再赘述。如何设置串口属性,Linux提供了专门的API。
struct termios options;//获取参数tcgetattr(fd, &options);//波特率cfsetispeed(&options, B115200);cfsetospeed(&options, B115200);//8位数据位options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;//无校验options.c_cflag &= ~PARENB;//1位停止位options.c_cflag &= ~CSTOPB;//设置参数tcsetattr(fd, TCANOW, &options);
内核空间的UART外设编程?
从以上介绍可以看到,UART最终是以用户空间的tty设备来呈现,应用程序可以操作tty设备完成UART通信。但是如果需要在内核中调用UART驱动呢,有没有相关接口?
假设有一个UART接口的按键扩展芯片,既要通过UART获取设备数据,又要将这些数据上报给input子系统。由于input子系统位于内核空间,那么通过UART获取数据的操作也应该在内核空间完成。那这个时候如何操作UART?如果最底层实现的UART操作函数有与tty和serial core解耦,那倒是可以考虑直接调用这些接口,但现实情况是一般都没有完全解耦。如果是专门针对该应用场景重构UART底层驱动,那也是一种方法,也确实有人这样做。
其它总线驱动,比如I2C驱动,针对挂在I2C总线上的设备,有i2c_driver框架实现设备驱动,有i2c_transfer函数接口来实现I2C通信。SPI驱动也是类似,有spi_driver框架和相应的SPI传输函数。所以在内核空间编写I2C/SPI设备驱动很方便。
针对UART,如果是4.14之前的内核,那么可以通过serio驱动来实现某设备与tty设备的挂钩,进而可以调用tty层的读写函数,tty层的读写函数最后会调用到UART底层驱动。
serio是个抽象的总线,并不专指UART,而是Serial IO的统称。serio驱动代码用struct serio_bus表示serio总线,用struct serio表示serio控制器,用struct serio_drvier表示serio设备驱动。详情可参考代码:
drivers/input/serio/*drivers/input/touchscreen/touchit213.c
如果是4.14版本以后的内核,已经新增了serail dev bus,并提供了相应的设备驱动注册函数:
serdev_device_driver_register(struct serdev_device_driver *, struct module *);
使用方法可参考蓝牙驱动:
drivers/bluetooth/hci_bcm.c
------ END ------
作者:bigfish99
博客:https://www.cnblogs.com/bigfish0506/
公众号:大鱼嵌入式

UART串口及Linux实现的更多相关文章
- linux UART串口驱动开发文档
转:http://www.360doc.com/content/10/0417/18/829197_23519037.shtml linux UART串口驱动开发文档时间:2010-01-09 14: ...
- Linux下使用putty进行UART串口调试【转】
本文转载自:http://blog.csdn.net/xzongyuan/article/details/11593101 版权声明:本文为博主原创文章,未经博主允许不得转载. 使用putty进行串口 ...
- Linux下读写UART串口的代码
Linux下读写UART串口的代码,从IBM Developer network上拿来的东西,操作比較的复杂,就直接跳过了,好在代码能用,记录一下- 两个实用的函数- //////////////// ...
- (三) UART 串口通讯
UART : university asynchronous receiver and transmitter UART // 通用异步接收器和发送器 为什么要有串口:因为许多嵌入式设备没有显示屏 ...
- 【C51】UART串口通信
我们常需要单片机和其他模块进行通信,数据传输,常用的方式就是串口通信技术. 常用来 单片机<-->电脑, 单片机<-->单片机之间通信. 串行通信 versus 并行通信 并 ...
- Uart串口与RS232串口的区别
Uart指的是TTL电平的串口:RS232指的是RS232电平的串口. TTL电平是3.3V的,而RS232是负逻辑电平,它定义+5~+12V为低电平,而-12~-5V为高电平. Uart串口的RXD ...
- uart串口协议
uart串口协议 /* USART Word Length ---------------------------------------------------------*/ US ...
- RTC实时时间系统学习笔记(一)---------------UART串口
临近研三了,自己倾向于要找数字IC方面的工作,苦于教研室的项目一直都是调板子调板子调板子,真正用到FPGA的很少,,本着"工欲善其事必先利其器"的原则,在网上搜寻如何自学FPGA, ...
- Uart串口
title: Uart串口 tags: ARM date: 2018-10-20 16:38:28 --- Uart串口 和单片机的应用没什么区别,首先设置IO复用,设置波特率和数据位,以及中断相关的 ...
随机推荐
- 面试问题之计算机网络:TCP滑动窗口
滑动窗口协议是传输层进行流量控制的一种措施,接收方通过通知发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的,并且滑动窗口分为接收窗口和发送窗口.TC ...
- Python - 本地文件读写(初级)
- 攻防世界 ics-06
ics-06 进入题目有点吓人,不过我都点了一下发现只有报表中心可以进去 进入报表中心在url中发现?id=1,一开始以为是sql注入结果啥也没探测到,这题脑洞有点,没有任何提示直接爆破id即可获得f ...
- 7_线性控制器设计(Linear Controller Design)
开环系统中 状态方程,其中A的特征值将决定这个系统的表现(稳定性或者收敛速度:特征值小于0时系统稳定) 如果开环系统特征值大于0时(即系统不稳定时): 可以引入输入量U时(U是关于状态变量X的函数), ...
- Node自动重启工具 nodemon
为什么要使用 在编写调试Node.js项目,修改代码后,需要频繁的手动close掉,然后再重新启动,非常繁琐.现在,我们可以使用nodemon这个工具,它的作用是监听代码文件的变动,当代码改变之后,自 ...
- vue实现省市区三级联动
npm 安装 npm install v-distpicker --save Vue全局引入组件 import Distpicker from 'v-distpicker' Vue.component ...
- 关于页面中css某些情况下出现不知原因的隔断解决办法
第一种方法:body{margin:0px;padding:0px position:absolute; top:0px;left:0px;} html{ width:100%; overflow-x ...
- Docker入门(windows版),利用Docker创建一个Hello World的web项目
Docker 当大家点开这篇博客的时候,相信大家对docker多多少少也有些认识了,最近学习docker这门技术,略微有些心得,写篇文章记录一下学习过程并帮大家跳过一些坑. docker的核心有两个, ...
- Thinkphp3.2.3 where注入 浅分析漏洞原理及修复
0x01引子 0x02分析 找到截断方法 找到_parseType的入口 找到生成sql语句的代码 0x03 poc链 0x04 利用示范 payload: http://localhost:3000 ...
- Installing github.com/mdempsky/gocode FAILED ----vscode安装go插件中的一些坑
问题前景: 最近在使用vscode,编写一些go的代码,但发现调试的时候,会需要安装很多插件,但通过vscode之间安装的话,会出现如下的错误: Installing github.com/mdemp ...