linux驱动之终端控制体系与串口驱动程序设计

本文围绕Linux串口展开,介绍数据通信的并行与串行方式,异步通信规则及波特率概念。阐述Linux中TTY终端类型,包括控制台、串口和伪终端。详细说明TTY体系结构,以及串口驱动描述、注册、端口描述等内容,还给出串口驱动程序设计的操作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在介绍终端控制体系之前,要先普及 一下数据通信的基本方式。

数据通信

数据通信的基本方式可分为并行通信串行通信两种:

  • 并行通信:利用多条数据线将数据的各位同时传送。它的特点是传输速度快,适用于短距离通信。
  • 串行通信:利用一条数据线将数据一位位地顺序传送。特点就是通信线路简单,利用简单的线缆就能实现通信,低成本,适用于远距离通信。

异步通信

异步通信是以字符为传输单位,通信中两个字符间的时间间隔是不固定的,然而同一个字符中的两个相邻位之间的时间间隔是固定的。

通信协议:是指双方约定的一些规则。在使用异步串口发送一个字符的信息时,对数据格式有如下约定:规定有空闲位、起始位、资料位、奇偶校验位、停止位。
在这里插入图片描述
波特率:是衡量数据传送速率的指针。表示每秒钟传送的二进制位数。

传送方式

在这里插入图片描述

终端概述

在Linux中,TTY(终端)是一类字符设备的统称,包括了3种类型:控制台,串口和伪终端。

控制台

供内核使用的终端为控制台。控制台在Linux启动时,通过命令 console=… 指定,如果没有指定控制台,系统把第一个注册的终端(tty)作为控制台。

  • 控制台是一个虚拟的终端,它必须映射到真正的终端上。
  • 控制台可以简单的理解为 printk 输出的地方。
  • 控制台是个只输出的设备,功能很简单,只能在内核中访问。

伪终端

在这里插入图片描述

终端体系

在这里插入图片描述
在Linux中,TTY体系分为:TTY核心,TTY线路规程,TTY驱动三部分。TTY核心从用户获取要发送给TTY设备的数据,然后把数据传递给TTY线路规程,它对数据进行处理后,负责把数据传递到TTY驱动程序,TTY驱动程序负责格式化数据,并通过硬件发送出去。

在这里插入图片描述

终端体系—串口

在这里插入图片描述

数据流

在这里插入图片描述
读操作:
TTY驱动从硬件收到数据后,负责把数据传递到TTY核心,TTY核心将从TTY驱动收到的数据缓存到一个 tty_flip_buffer 类型的结构中。该结构包含两个数据数组。从tty设备接受到的数据被存储于第一个数组,当这个数组满,等待数据的用户将被通知。当用户从这个数组读数据时,任何从TTY驱动新来的数据被存储在第二个数组。当第二个数组存满后,数据再次提交给用户,并且驱动又开始填充第一个数组,以此交替。

串口驱动描述

Linux内核使用 uart_driver 描述串口驱动,它包含串口设备的驱动名、设备名、设备号等信息。

struct uart_driver
{
	struct module *owner;
	const char *driver_name;    //驱动名
	const char *dev_name;  //设备名
	int major;   //主设备号
	int minor;   //起始次设备号
	int nr;     //设备数
	struct console;  
	struct uart_state *state;
	struct tty_driver *tty_driver;
};

串口驱动注册

Linux 为串口驱动注册提供了如下接口:

int uart_register_driver(struct uart_driver *drv);

UART端口描述

uart_port 用于描述一个 UART 端口(一个串口)的地址、FIFI大小、端口等信息;

struct uart_port
{
	spinlock_t lock;  //端口锁
	unsigned int iobase;   //IO端口基地址
	unsigned char __iomem *membase;  //IO内存基地址
	unsigned int irq;  //中断号
	unsigned char fifosize;  //传输fifo大小
	const struct uart_ops *ops;
	......
};

操作串口

uart_ops 定义了针对串口的一系列操作,包括发送、接受及线路设置等。

struct uart_ops
{
	unsigned int(*tx_empty) (struct uart_port*);
	void (*set_mctrl) (struct uart_port *,unsigned int mctrl);
	void (*stop_tx) (struct uart_port*);  //停止发送
	void (*start_tx) (struct uart_port*);  //开始发送
	void (*send_xchar) (struct uart_port*,char ch);  //发送xchar
	void (*stop_rx) (struct uart_port*);  //停止接收
	......
};

添加端口

串口核心层提供如下函数来添加1个端口:

int uart_add_one_port(struct uart_driver *drv,struct uart_port *port);

串口驱动程序设计

操作流程

  1. 定义一个 uart_driver 的变量,并初始化;
  2. 使用 uart_register_driver 来注册这个驱动;
  3. 初始化 uart_port 和 ops 函数表;
  4. 调用 uart_add_one_port() 添加初始化好的 uart_port。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值