25.UART串口发送过程与配置

UART串口收发过程与配置

参考资料
《STM32Fx中文参考手册》第26章:通用同步异步收发器章节
开发板配套教程《STM32Fx开发指南》 串口实验章节

笔记基于正点原子官方视频
视频连接https://www.bilibili.com/video/BV1Wx411d7wT?p=71&spm_id_from=333.1007.top_right_bar_window_history.content.click
如有侵权,联系删除

一、串口发送过程配置流程概述

1.HAL库中串口寄存器定义文件

在stm32f429xx.h 文件(位置:工程文件-HALLIB-stm32f4xx_hal.c-stm32f429xx.h)中,就有关于串口寄存器定义的结构体
在这里插入图片描述

	typedef struct
	{
		__IO uint32_t SR; 
		__IO uint32_t BRR; 
		__IO uint32_t CR1; 
		__IO uint32_t CR2; 
		__IO uint32_t CR3; 
		__IO uint32_t GTPR;
	} USART_TypeDef
2.HAL库中串口函数声明定义文件

位置:工程文件-HALLIB-stm32f4xx_hal_uart.c和工程文件-HALLIB-stm32f4xx_hal_usart.c
stm32f4xx_hal_uart.c / stm32f4xx_hal_uart.c
stm32f4xx_hal_usart.c / stm32f4xx_hal_usart.c
在这里插入图片描述

3.串口字节发送流程

① 编程USARTx_CR1的M位来定义字长。
② 编程USARTx_CR2的STOP位来定义停止位位数。
③ 编程USARTx_BRR寄存器确定波特率。
④ 使能USARTx_CR1的UE位使能USARTx。
⑤ 如果进行多缓冲通信,配置USARTx_CR3的DMA使能(DMAT)。具体请参考后面DMA实验。
⑥ 使能USARTx_CR1的TE位使能发送器。
⑦ 向发送数据寄存器TDR写入要发送的数据(对于M3,发送和接收共用DR寄存器)。
⑧ 向TRD寄存器写入最后一个数据后,等待状态寄存器USARTx_SR(ISR)的TC位置1,传输完成。

注:①-⑥为配置步骤;⑦-⑧为发送数据步骤

  • 配置步骤①~⑥:配置字长,停止位,奇偶校验位,波特率等:
    位置:工程文件-HALLIB-stm32f4xx_hal_uart.c中
    在这里插入图片描述
	HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

该函数内部会引用标识符__HAL_USART_ENABLE使能相应串口。

  • 步骤⑦~⑧发送数据和等待发送完成:
    位置:工程文件-HALLIB-stm32f4xx_hal_uart.c中
    在这里插入图片描述
	HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *husart, uint8_t *pTxData, uint16_t Size, uint32_t Timeout);

二、串口发送预备

1.__Weak关键字
函数前面加__weak修饰符,我们称之为弱函数。对于弱函数,用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候会选择用户定义的函数。如果用户没有定义,那么函数内容就是弱函数定义的内容。
  • 函数声明
	void HAL_UART_MspInit(UART_HandleTypeDef *huart);
  • 函数定义(弱函数)
    在这里插入图片描述
    函数内部为空,即我们可以在里面编写相关弱函数
		__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
	{
	}
  • 若函数被重新定义
	void HAL_UART_MspInit(UART_HandleTypeDef *huart)
	{
		…//内容
	}

** __Weak关键字的好处**

  • 对于事先已经定义好的一个流程,我们只希望修改流程中的某部分与用户相关的代码,这个时候我们可以采用弱函数定义一个空函数,然后让用户自行定义该函数。这样做的好处是我们不会对既有程序流程做任何修改。
  • HAL库中大量使用__weak关键字修饰外设回调函数。
  • 外设回调函数供用户编写MCU相关程序,大大提高程序的通用性移植性。
2.串口发送程序配置过程(HAL库):

① 初始化串口相关参数,使能串口:HAL_UART_Init();
② 串口相关IO口配置,复用配置:在HAL_UART_MspInit中调用HAL_GPIO_Init函数。
③ 发送数据,并等待数据发送完成:HAL_UART_Transmit()函数;

二、串口发送具体步骤

1.主函数

打开工程模板,把主函数清理成下图样子,并初始化延时函数
在这里插入图片描述

2.初始化串口参数

我定义一个uart1,在里面初始化HAL_UART_Init,因为HAL_UART_Init(UART_HandleTypeDef *huart)里面是一个结构体变量(UART_HandleTypeDef),我们查看结构体变量的内容如下图:
在这里插入图片描述

其中1号框内每一个参数都有自己的定义,里面定义了可以选择哪些数据区表示2号框里的内容,具体可以右键-查看定义来查看
在这里插入图片描述
在这里插入图片描述

	typedef struct
	{
		USART_TypeDef			 *Instance; 
		UART_InitTypeDef 			 Init; 
		uint8_t 							*pTxBuffPtr; 
		uint16_t 							TxXferSize; 
		uint16_t 							TxXferCount; 
		uint8_t 							*pRxBuffPtr; 
		uint16_t 							RxXferSize; 
		uint16_t 							RxXferCount; 
		DMA_HandleTypeDef		 *hdmatx; 
		DMA_HandleTypeDef 	*hdmarx; 
		HAL_LockTypeDef			 Lock; 
		__IO HAL_UART_StateTypeDef			 State; 
		__IO uint32_t 											ErrorCode; 
	}UART_HandleTypeDef
3.初始化串口参数步骤
1)初始化UART_HandleTypeDef的第一个变量usart1_handler.Instance

查看HAL_UART_Init下面关于Instance的定义,如下图
在这里插入图片描述
在这里插入图片描述

可见到Instance可以赋值的内容这里我们选择USART1,即写入代码

usart1_handler.Instance=USART1;
2)初始化usart1_handler.Init

查看Init相关定义,发现Init也是一个结构体,里面有7个变量,如图,也就说里面的7个变量也要进行逐一定义。
在这里插入图片描述
在这里插入图片描述

	typedef struct
	{
		uint32_t 	 	 BaudRate; 			//波特率
		uint32_t 	  	 WordLength; 		//字长
		uint32_t 		 StopBits; 			//
		uint32_t		 Parity; 				//
		uint32_t		 Mode; 				//
		uint32_t 		HwFlowCtl; 			//
		uint32_t 		OverSampling; 	//
	}UART_InitTypeDef;

(1)定义波特率为115200,代码如下

usart1_handler.Init.BaudRate=115200; //定义波特率

(2)定义字长WordLength,查看定义如下
**小技巧:**这里问我们需要查看WordLength的定义,我们就可以把WordLength复制下来,在总的初始化函数里面查找。
在这里插入图片描述

然后查看编号4的定义就可以了,如下图
在这里插入图片描述
在这里插入图片描述

可以看到字长有8位和9位两种,这我们选择8位,代码如下:

usart1_handler.Init.WordLength=UART_WORDLENGTH_8B;

(3)定义停止位StopBits
在这里插入图片描述
在这里插入图片描述

可以看到,StopBits可以选择1位或2位,这里我们选择1位,代码如下

usart1_handler.Init.StopBits=UART_STOPBITS_1;

(4)定义硬件流HwFlowCtl
查看定义有如下选项,这里我们选择关闭,代码如下:
在这里插入图片描述

usart1_handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; 

(5)定义模式Mode(开启发送还是接收或者都打开)
查看定义如下
在这里插入图片描述

在这个文件夹下继续搜索Mode,这里选择都打开,代码如下
在这里插入图片描述

usart1_handler.Init.Mode=UART_MODE_TX_RX;

(6)定义奇偶校验位Parity
查看定义如下,选择不使用校验位,代码如下:
在这里插入图片描述

usart1_handler.Init.Parity=UART_HWCONTROL_NONE;

到这里usart1_handler.Init结构体初始化完毕!!

3)注释掉usart.c函数

位置在:工程模板-SYSTEM-usart.c,
因为usart.c库函数中已经对串口发送和接收定义好了,这里我们要使用自己写的程序,则需要把下面代码注释掉
在这里插入图片描述

4)对弱函数进行重新编写

找到弱函数位置,复制其函数名,在main函数中进行重新编写,
在这里插入图片描述
在这里插入图片描述

我们常把外设的复用映射GPIO串口初始化中断优先级设置放在里面
代码如下:
在这里插入图片描述

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef  GPIO_Initure;			//初始化GPIO结构体
	
	if(huart->Instance ==USART1)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
		__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
		
		GPIO_Initure.Pin=GPIO_PIN_9;			//PA9
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;		//高速
		GPIO_Initure.Alternate=GPIO_AF7_USART1;	//复用为USART1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9

		GPIO_Initure.Pin=GPIO_PIN_10;			//PA10
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10
	}
5)串口发送程序编写

编写程序发送函数,如图,并查看定义:
在这里插入图片描述
在这里插入图片描述

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
其中UART_HandleTypeDef *huart为句柄(前文已解释)
uint8_t *pData为需要发送的数据
uint16_t Size为需要发送多少个字节的数据
uint32_t Timeout为超时时间
所以设置好的代码为

 	u8 data[]="-Apollo by wire-   ";			//定义一个数组,用于存放要发送的数据(数据为-Apollo by wire-   )
	while(1)
	{
		HAL_UART_Transmit(&usart1_handler,data,sizeof(data),1000);
		delay_ms(300);
	}
6)串口发送程序main.c代码
#include "sys.h"
#include "delay.h"
#include "usart.h"

UART_HandleTypeDef usart1_handler;		//定义结构体变量

void uart1_init()						//初始化uart1
{
	usart1_handler.Instance=USART1;
	usart1_handler.Init.BaudRate=115200; 				//定义波特率
	usart1_handler.Init.WordLength=UART_WORDLENGTH_8B;  //定义字长位8位
	usart1_handler.Init.StopBits=UART_STOPBITS_1;		//定义停止位
	usart1_handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;  //定义硬件流
	usart1_handler.Init.Mode=UART_MODE_TX_RX;			//定义模式
	usart1_handler.Init.Parity=UART_HWCONTROL_NONE;		//定义奇偶校验位
	
	HAL_UART_Init(&usart1_handler);		//初始换刚刚定义的结构体变量
}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef  GPIO_Initure;			//初始化GPIO结构体
	
	if(huart->Instance ==USART1)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
		__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
		
		GPIO_Initure.Pin=GPIO_PIN_9;			//PA9
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;		//高速
		GPIO_Initure.Alternate=GPIO_AF7_USART1;	//复用为USART1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9

		GPIO_Initure.Pin=GPIO_PIN_10;			//PA10
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10
	}
}

int main(void)
{
    u8 data[]="-Apollo by wire-   ";			//定义一个数组,用于存放要发送的数据
    HAL_Init();                     //初始化HAL库    
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
	delay_init(180);				//初始化延时函数
	uart1_init();					//调用前面写的初始化函数
	
	while(1)
	{
		HAL_UART_Transmit(&usart1_handler,data,sizeof(data),1000);
		delay_ms(300);
	}
}
4.编译程序,烧录进开发板

编译程序并烧录进开发板,
打开串口调试助手,位置:H:\3.开发板学习\STM32WorkFile\000.串口调试助手\XCOM(正点原子推荐)
在这里插入图片描述

然后设置好接口和波特率,打开串口接收即可看到数据在持续输出。
在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值