UART串口驱动代码编写及总结

2023-05-16

芯片内置UART接口,用于与外部进行异步串行通信。串口控制器有如下特征:1,内置波特率发生器,支持不同波特率的配置;2,数据位宽支持5/7/8bit;3 停止位可配置成1或2bit;4,可支持38Khz红外调制;5 , 支持自动波特率检测。

-每个UART口,芯片会分配16K的地址。每个UART相关的寄存器如下图:

寄存器名称作用
uart_ctluart控制寄存器
uart_bauduart波特率配置寄存器
uart_txduart发送数据寄存器
uart_rxduart接收数据寄存器

UART_CTRL寄存器的每个位的具体作用如下图:

uart_ctl 寄存器bit位具体bit位作用
bit0(EN)置1时模块使能
bit1(TXIN)置1时发送中断使能, 对应的是sta状态寄存器中的bit0)
bit2(RXIN)置1时接收数据中断使能,对应sta状态寄存器中的bit1
bit3(ERRIN)置1时,打开错误中断使能,对应sta状态寄存器的bit2-bit5
bit4(STOPS)置1时,设置为2bit的停止位;置0时,表示1bit的停止位
bit6-5(data_translen)控制数据传输时的bit位; 00: 5bit;01: 6bit;10:7bit;11:8bit
bit9-7(pars数据校验)000: 无校验;001:奇校验;010:偶校验;011:固定为0校验;100:固定为1校验

编写UART串口驱动程序时,需要从以下几个方面进行考虑。

  1. 串口时钟使能,GPIO时钟使能;
  2. 串口复位;
  3. GPIO端口模式配置;
  4. 串口参数初始化
  5. 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤);
  6. 使能串口;
  7. 编写中断处理函数。
//UART_rx口模式寄存器通过bitband映射到的地址
//UART_rx口数据寄存器通过bitband映射到的地址
//UART_tx口模式寄存器通过bitband映射到的地址
//UART_tx口数据寄存器通过bitband映射到的地址
#include <stdio.h>
#define  UART_rxgpio_mode  0x50000000     
#define  UART_rxgpio_data  0x50000004     
#define  UART_txgpio_mode  0x50000008     
#define  UART_txgpio_data  0x5000000C     
#define  UART_rstgpio_mode 0x50000012     
#define  UART_rstgpio_data 0x50000016
//适合所有GPIO口的通用的数据结构
#define	 uart_num          3//设备中uart通道的总个数是3个。

	struct gpio_t
	{
		int *gpio_data_out;//gpio数据寄存器,用来输出数据
		int *gpio_data_in;//gpio数据寄存器,用来输入数据
		int *gpio_mode;    //gpio模式寄存器,用来控制io口是输入还是输出的。
		void (*out_mode)       (int *gpio_mode);				  //gpio配置为输出模式
		void (*in_mode)        (int *gpio_mode);					  //gpio配置为输入模式
		void (*active_signal)  (int *gpio_data_out);		  //gpio的数据寄存器中,某一位输出有效位(打开功能)
		void (*non_active_signal)  (int *gpio_data_out);    //gpio的数据寄存器中,某一位输出无效位(关闭功能)
	};

	void out_mode (int *gpio_mode)
	{
		*gpio_mode = 1;//输入模式
	}

	void in_mode  (int *gpio_mode)
	{
		*gpio_mode = 1;//输入模式
	}
	void active_signal (int *gpio_data_out)
	{
		*gpio_data_out = 1;//这个要根据实际情况,看高电平有效还是低电平有效
	}

	void non_active_signal (int *gpio_data_out)
	{
		*gpio_data_out = 0;//这个要根据实际情况,看高电平有效还是低电平有效
	}
//一个UART口至少要包括TX和Rx,对于外设寄存器,芯片厂家一般会给出bitband,对数据和模式寄存器的地址进行映射到另外一片内存区域,进行位操作
	struct gpio_t  rx =
	{
		(int *)UART_rxgpio_data, //gpio通过bitband映射到的地址
		(int *)UART_rxgpio_data, //gpio通过bitband映射到的地址
	    (int *)UART_rxgpio_mode,
		out_mode,
		in_mode,
		active_signal,
		non_active_signal,
	};//uart的接收io口

	struct gpio_t  tx = 
	{
		(int *)UART_txgpio_data, //gpio通过bitband映射到的地址
		(int *)UART_txgpio_data, //gpio通过bitband映射到的地址
		(int *)UART_txgpio_mode,
		out_mode,
		in_mode,
		active_signal,
		non_active_signal,
	};  //uart的发送io口

	struct gpio_t  rst =
	{
		(int *)UART_rstgpio_data,   //gpio通过bitband映射到的地址
		(int *)UART_rstgpio_data,   //gpio通过bitband映射到的地址
		(int *)UART_rstgpio_mode,
		out_mode,
		in_mode,
		active_signal,
		non_active_signal,
	};  //uart的复位的io口
//对uart进行数据结构的定义
	struct uart_t
	{
		char     *name;//分清是哪个串口
		struct   gpio_t  *rx;
		struct   gpio_t  *tx;
		struct   gpio_t  *rst;
	};
	struct uart_t  remote_uart = 
	{
		"remote_uart",
		(int *)&rx,
		(int *)&tx,
		(int *)&rst,
	};
    //串口相关的配置
	struct uart_config_t
	{
		int baud_rate;  //波特率的配置
		int data_bits;  //数据位
		int parity;     //奇偶校验位
		int stop_bits;  //停止位
		int data_process_mode;//数据处理的方式,分为扫描和中断
	};

	enum  data_process_mode 
	{
		scan_mode  = 0,//扫描的方式
		invt_mode  //中断的方式
	};

	struct uart_config_t uart_config = 
	{
		9600,
		8,//8位数据位
		0,//无校验
		1,//1位停止位
		invt_mode,//中断的方式
	};
	 
	//芯片内部总的全局变量,用来控制各个外设工作的。
	struct sys_t
	{
		int  osc_ctl1;//系统OSC控制寄存器
		int  sys_mode;//系统模式切换寄存器
		int  sys_pd;  //系统掉电控制寄存器
		int  ADC_CTL; //ADC控制寄存器(电源控制)
		int  osc_ctl2;//系统osc2控制寄存器
		int  sys_rst; //系统复位寄存器
		int  map_ctl; //地址映射控制寄存器
		int  mode0_en;//模块使能0寄出器
		int  mode1_en;//模块使能1寄存器
		int  nvic_en; //nvic中断使能寄存器
		int  kbi_en;  //kbi使能寄存器
	}; 
	
	struct sys_t sys;

	struct uart_t_paramete_config_t
	{
		int ctrl;//控制寄存器
		int baud;//波特率配置寄存器
		int stat;//uart相关的状态寄存器
		int txd;//发送数据寄存器
		int rxd;//接收数据的寄存器
	};
	struct uart_t_paramete_config_t uart;

	//串口的状态
	struct uart_status_t
	{
		int reset_time_count;//达到这个固定的时间,就复位一下串口。防止串口彻底乱了
		int tx_time_out;//每次发送完时间的延时,超过这个时间,才允许再次发送
		int rx_time_out;//每次接收数据的时间延时计时。两帧之间只有大于这个时间,才允许继续读出来
	};
	struct uart_status_t uart_status[uart_num];

	struct fifo_t
	{
		int *fifo_buf;//uart串口通信的起始地址
		int rd; //读的指针
		int wd; //写的指针
		int buf_len;//uart串口总的数据长度
	};

	struct resource_driver_t;//编译这个参数时,会自动往下查找的。
	struct device_t
	{
		int device_id;//器件对应的id
		int trans_class;//总线传输类型:IIC,SPI,Uart
		void *bus_driver;//总线驱动(万能的void*,后面进行实例化时,可以进行强转)
		void *resource; //实际占用的硬件资源(IO等)
		void *resource_cfg;//硬件资源的配置:如控制灯如何闪烁间隔等
		struct resource_driver_t *resouce_driver;//器件资源控制驱动(初始化,读,写,控制的驱动)
	};

	//设备驱动的初始化,读,写,执行功能,需要用函数指针进行实例化
	struct resource_driver_t
	{
		int (init*)(struct device_t *device,int mode);//根据上电,下电,复位等情况时,对资源进行初始化操作
		int (*read)(int addr, int *buf, int len, struct device_t *device);//根据资源实际挂载的传输总线。进行查找里面的值
		int (*write)(int addr, int *buf, int len, struct device_t *device);
		int(*ioctrl)(int ctlid, struct device_t *device, int parameter);//根据传进来的参数进行实际控制设备

	};

	struct uart_buffer_t
	{
		struct fifo_t rx;//接收的缓存
		struct fifo_t tx;//发送数据的缓存
		struct device_t *device;//uart实际物理设备的地址
	};
	struct uart_buffer_t uart_buf[uart_num];

	void nvic_disable(int uart_nvic_index)
	{

	}
	void nvic_enable(int uart_nvic_index)
	{

	}
	void uart_init  (struct uart_config_t *uart_config, struct uart_t  *remote_uart)
	{
		//在芯片的上配置对应的时钟使能
		sys.mode0_en |= 1 << 5;    //使能远程通信串口的时钟
		//会根据配置的串口的数据位和校验位信息,进行改变ctrl里面寄存器的值
		if (uart_config->data_bits == 8)
		{
			uart.ctrl |= (uart_config->data_bits - 5) << 5;//将ctrl的bit5,6进行置位。
		}

		uart.baud = uart_config->baud_rate; //暂时用这个方法,实际上比这个复杂,具体根据芯片厂家来确定
		//根据配置的uart数据是扫描还是中断的方式,来确定系统的中断是否生效
		if (uart_config->data_process_mode == scan_mode) //配置为扫描的方式,则uart对应的系统中断失效
		{
			nvic_disable(0); //远程uart中断号失效,不在使用
		}
		else
		{
			nvic_enable(0);//将uart口的中断号生效
		}
	}

	int main()
	{
		struct gpio_t *txio = remote_uart.tx;
		struct gpio_t *rst  = remote_uart.rst;
		memset(sys,0);
		//uart的初始化,是在通信模块上电瞬间进行初始化的:根据实际的uart通道的个数,分别对每个uart进行初始化操作
		//1.首先uart底层驱动的buffer指向应用层实际的串口。

 //上电时,先设定好io口是输入还是输出的模式。输出模式时,模式寄存器对应的bit位为0;输入模式时,模式寄存器上对应的bit位为1
		remote_uart.tx->out_mode(txio->gpio_mode);//将rx配置为输出模式,由于电脑上0x50000008这个内存不能分配给使用,故会报错。嵌入式硬件上可以
		remote_uart.tx->out_mode(rst->gpio_mode);//将rst管脚配置为输出模式

		//根据配置好的uart相关io配置及串口通信相关的配置,对串口进行初始化。主要功能:修改UART相关寄存器里面的值
		uart_init(&uart_config, &remote_uart);
		//上电过程中通过文件系统,进行读,写,控制串口通信

		system("pause");
	}


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UART串口驱动代码编写及总结 的相关文章

  • UART、IIC、SPI、CAN通信的区别与应用

    文章目录 1 通信的基本知识1 1 数据通信的种类1 1 1 串行通信1 1 2 并行通信1 1 3 总结 1 2 数据通信的传输方向1 2 1 单工1 2 2 半双工1 2 3 全双工1 2 4 总结 1 3 数据通信的方式1 3 1 同
  • 【STM32】UART串口通信详解

    目录 一 数据通信方式 1 串行与并行通信2 全双工 半双工及单工通讯3 同步通讯与异步通讯 二 串口通讯协议 STM32串口简介1 物理层1 RS232标准2 USB转串口 重点 3原生的串口到串口2 协议层1 xff09 通讯的起始和停
  • Jetson Nano – UART

    There is a UART on the J41 GPIO Header of the NVIDIA Jetson Nano Developer Kit Useful when you need a little bit of extr
  • ESP32+WiFi+UART数据传输测试

    刚开始使用ESP32芯片 xff0c 摸索着实现了一个数据传输的功能 xff0c 记录下来以免忘记 实现功能 使用ESP32在服务器与下位机之间传输数据 xff0c 整体的流程图如下所示 如图所示 xff0c 下位机与ESP通过串口连接 x
  • UART通信中流控RTS和CTS的理解

    一 流控 xff0c 顾名思义就是流量控制的意思 目的是协调收发双方 xff0c 使数据不会丢失 如果UART只有RX TX两个信号 xff0c 要流控的话只能是软流控 xff1b 如果有RX xff0c TX xff0c CTS xff0
  • UART详解

    UART 通用异步收发传输器 xff08 Universal Asynchronous Receiver Transmitter xff0c 通常称作UART xff09 是一种串行异步收发协议 xff0c 应用十分广泛 UART工作原理是
  • STM32 硬件UART接收超时检测设置

    STM32 硬件UART接收超时检测设置 本文作者 智御电子 xff0c 期待与电子爱好者交流学习 应用场景 在uart应用中有时候需要进行双工通信 xff0c 主机需要对从机的数据进行接收超时检测 xff0c 例如modbus协议 xff
  • arduino学习——UART串口通信

    Serial begin 初始化串口 用作串口的启动 xff0c 常放置在setup xff08 xff09 中 原型 xff1a Serial begin speed Serial begin speed config 参数 xff1a
  • UART串口通信

    目录 一 通信特点二 通信应用三 接线示意图三 UART通信协议四 STM32F4 串口使用1 资源分布2 特性3 UART框图4 使用方法5 相关库函数6 函数实例 五 实战 上位机控制开发板小灯 一 通信特点 异步 串行 全双工 一般描
  • UART串口通信协议详解

    UART xff1a 通信异步收发器 xff0c 串行 异步通信总线 xff0c 两条数据线 xff08 收发 xff09 xff0c 全双工 xff08 可以同时接收和发送 xff09 一 UART帧格式 xff08 UART协议 xff
  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数

    目录 前言1 UART Receive IT2 HAL UART Receive3 HAL UART Receive IT 前言 看了很长时间串口中断的HAL库 xff0c 最容易混淆的就是函数的名称 xff0c 主要集中在UART Rec
  • Node.js笔记:SerialPort(串口)模块使用(基于9.x.x)

    文章目录 目的 模块安装 基础使用 扫描端口 打开端口 发送数据 接收数据 错误处理 数据解析器 SerialPort类 构造方法 属性 事件 方法 命令行工具 总结 目的 上位机与各种电路模块间常常采用串口进行通讯 Node js中可以使
  • 一起学nRF51xx 6 - uart

    前言 通用异步接收器 发送器提供快速 全双工 内置流量控制的异步串行通信 CTS RTS 在硬件方面支持高达1Mbps波特率 支持奇偶校验和第9位数据生成 用于每个UART接口线的GPIO可从芯片上的GPIO中任选 而且可独立配置 这使得芯
  • GD32E23x的USART被断点打断后重新运行,会一直进入中断的问题

    GD32E23x的USART被断点打断后重新运行 会一直进入中断的问题 GD32E230K8单片机USART0连接一个从机芯片 该芯片每100ms发来一串16Bytes的数据 MCU中断接收 没有开启FIFO 只开启了RBNE 接收缓存非空
  • ESP32-C3入门教程 基础篇(三、UART模块 — 与Enocean无线模块串口通信)

    测试第三课 ESP32 C3的串口通信测试 老样子 使用Enocean无线模块和ESP32 C3进行串口通信 目录 前言 1 UART示例测试 1 1 UART 基础测试 1 2 与Enocean无线模块串口通信测试 2 ESP32 C3
  • 启用并测试 UART 的本地环回

    我正在尝试进行 UART 内部环回测试并提出以下更改 include
  • IOError:[Errno 2]没有这样的文件或目录(当它确实存在时)Python [重复]

    这个问题在这里已经有答案了 我正在通过 python 中的 uart 传输文件文件夹 下面您可以看到简单的功能 但有一个问题 因为我收到如标题所示的错误 IOError Errno 2 No such file or directory 1
  • GATT 配置文件和 UART 服务

    我是开发通过蓝牙连接到外围设备的移动应用程序的新手 我搜索到 GATT 是用于蓝牙LE 通信的相关配置文件 但我们的客户建议我们使用 UART 服务 现在我很困惑 1 这两件事是如何关联的 2 我们是否必须选择其中之一 如果是的话 每一个的
  • 跨线程操作无效:从创建它的线程以外的线程访问控制“textBox1”[重复]

    这个问题在这里已经有答案了 我想使用 UART 将温度值从微控制器发送到 C 接口并显示温度Label Content 这是我的微控制器代码 while 1 key scan get value of temp if Usart Data
  • 如何检测来自 QNX 中 ncurses 的屏幕调整大小事件?

    我无法配置为接收有关使用 ncurses QNX Momentics 更改终端大小的事件 我使用Putyy作为终端 通过COM端口传输数据 我的问题是如何实现使用远程终端时接收屏幕变化事件 FILE fcons fopen dev ser1

随机推荐