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/RS232/RS485/RS-422笔记

    串口通讯详解笔记 串口通讯概述串口通讯传输数据帧的结构UARTRS232RS485RS 422RS 232 RS 422和RS 485的主要区别 xff08 重要 xff09 串口通讯概述 串口通讯是指数据按位 xff08 bit xff0
  • Jetson nano串口的使用——UART

    UART串口使用两条杜邦线就可以实现数据发送和接收 xff0c 可以很方便的与其他扩展进行数据连接 xff0c 比如微雪的L76X GPS HAT就可以直接连接40Pin的GPIO接口通过UART串口进行数据传递 接下来具体说明Jetson
  • UART、RS232 、RS485 区别

    UART RS232 RS485 区别 UART RS232 RS485这些物理层的串口通信 xff0c 它们都是在同一时间发送一位 RS232 RS485只是串口通讯的变种 xff0c 理解了UART串口通讯 xff0c 那么RS232和
  • 总线协议一(UART/RS232/RS485/IIC/SPI)

    目录 基础概述 xff1a 一 UART xff08 为串口通信方式 xff09 二 RS232协议 三 RS485协议 四 I2C总线协议 五 SPI总线 六 I2C和SPI的区别 基础概述 xff1a 总线的本质就是一根导线 xff0c
  • FPGA学习-UART串口发送单字节(UART时序分析+真正的FPGA设计看图写代码)

    首先看UART发送时序图 xff1a 要发送一个完整字节 xff0c 需要 1位起始位 43 8位数据位 43 1位停止位 xff0c 图上的第11位 xff0c 是确认一个字节发送完的一位 重点是每一位之间的发送时间需要保持一致 xff0
  • 【FPGA】UART串口通信

    文章目录 一 通信方式1 串行通信2 并行通信 二 UART串口通信1 模块设计与时序图2 代码实现 三 测试结果1 仿真结果2 上板验证 一 通信方式 1 串行通信 串行通信是指利用一条传输线将数据一位位地顺序传送 xff08 也就是说串
  • 串口通信UART

    串口基本概念 串口通讯 Serial Communication 是指外设和计算机间 xff0c 通过数据信号线 地线等 xff0c 按位进行传输数据的一种通讯方式 其通讯协议可分层为协议层和物理层 物理层规定通信协议中具有机械 电子功能的
  • 【verilog】UART串口发送(FPGA)

    简述核心代码仿真测试 简述 串口发送是以一定速率发送单bit数据 xff0c 通常一组数据为10bit 空闲状态为高电平 xff0c 起始位为0 xff0c 中间以低位在前的方式发送8bit数据 xff0c 终止位为1 采用计数器 cnt
  • ESP32+WiFi+UART数据传输测试

    刚开始使用ESP32芯片 xff0c 摸索着实现了一个数据传输的功能 xff0c 记录下来以免忘记 实现功能 使用ESP32在服务器与下位机之间传输数据 xff0c 整体的流程图如下所示 如图所示 xff0c 下位机与ESP通过串口连接 x
  • STM32 HAL UART 使用关键思路(无代码,但是很关键)

    1 到底使用哪种方式 xff0c 或者说有哪几种方式 xff1f STM32 中的 UART 允许使用不同的发送 TX 和接收 RX 模式进行配置 xff0c 有什么区别和优势 xff1f xff1a 轮询模式 xff08 简单来说就是无
  • 串口通信协议---UART

    串口通信的分类 UART属于串行 异步 全双工通信 串行通信与并行通信 根据传输数据的位宽 xff0c 串口通信可分为串行通信与并行通信 xff0c 串行通信是指设备之间通过少量数据信号线 一般是 8 根以下 xff0c 地线以及控制信号线
  • STM32 硬件UART接收超时检测设置

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

    串行通信基础 串行通信接口 异步串行通信 UART 常称为 串口 或SCI xff0c 在USB未普及之前 xff0c 是PC机必备通信接口之一 通信方式为单字节通信 xff0c 是最简单的串行通信方式 RS232 RS485 接线简单 x
  • 串口通信协议 UART+I2C+SPI

    UART 异步 串行 全双工 I2C SPI 不同通信协议比较 UART UART协议详解 UART通信 xff0c 接收与发送 xff08 详细版 xff0c 附代码 xff09 UART串行通信详解 待整理 UART是Universal
  • HAL_UART_IRQHandler(UART_HandleTypeDef *huart)里面的中断接收函数

    目录 前言1 UART Receive IT2 HAL UART Receive3 HAL UART Receive IT 前言 看了很长时间串口中断的HAL库 xff0c 最容易混淆的就是函数的名称 xff0c 主要集中在UART Rec
  • 4.RTT-UART-中断接收及轮询发送

    本期博客开始分享RTT的UART xff0c 利用战舰V3的uart2来输入输出一些字符串 UART xff08 Universal Asynchronous Receiver Transmitter xff09 通用异步收发传输器 xff
  • GD32E23x的USART被断点打断后重新运行,会一直进入中断的问题

    GD32E23x的USART被断点打断后重新运行 会一直进入中断的问题 GD32E230K8单片机USART0连接一个从机芯片 该芯片每100ms发来一串16Bytes的数据 MCU中断接收 没有开启FIFO 只开启了RBNE 接收缓存非空
  • 使用HAL库开发STM32:UART基础使用

    文章目录 目的 基础说明与初始化 基础说明 初始化 数据接收和发送 轮询方式 中断方式 DMA方式 其它说明 总结 目的 UART 异步串口 是单片机非常常用的一个功能 一般用作设备或模块间通讯的一种方式 通常所说的232或是485通讯从写
  • STM32CubeMX HAL库串口+DMA+IDLE空闲中断不定长度数据接收和发送

    本文开发环境 MCU型号 STM32F103ZET6 IDE环境 MDK 5 29 代码生成工具 STM32CubeMx 5 3 0 HAL库版本 STM32Cube FW F1 V1 8 0 STM32Cube MCU Package f
  • STM32F4-Discovery (STM32F429ZIT6) 上的 RS232 (UART) 与 HAL 库?

    背景 这是我的一些背景 以便你们知道我有或没有哪些相关知识 我完全是这种嵌入式系统的新手 而且我对电子产品一无所知 我是一个纯粹的软件人员 我唯一的嵌入式系统经验是Raspberry Pi 它与STM32F4 Discovery有很大不同

随机推荐