26.UART串口接收过程与配置

2023-10-27

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.串口接收流程(配置步骤)

① 编程USARTx_CR1的M位来定义字长。
② 编程USARTx_CR2的STOP位来定义停止位位数。
③ 编程USARTx_BRR寄存器确定波特率。
④ 使能USARTx_CR1的UE位使能USARTx。
⑤ 如果进行多缓冲通信,配置USARTx_CR3的DMA使能(DMAT)。具体请参考后面DMA实验。
⑥ 使能USARTx_CR1的RE位为1使能接收器。
⑦ 如果要使能接收中断(接收到数据后产生中断),使能USARTx_CR1的RXNEIE位为1。

2.当串口接收到数据时

① USARTx_SR(ISR)的RXNE位置1。表明移位寄存器内容已经传输到RDR(DR)寄存器。已经接收到数据并且等待读取。
② 如果开启了接收数据中断(USARTx_CR1寄存器的RXNEIE位为1),则会产生中断。(程序上会执行中断服务函数)
③ 如果开启了其他中断(帧错误等),相应标志位会置1。
④ 读取USARTx_RDR(DR)寄存器的值,该操作会自动将RXNE位清零,等待下次接收后置位。

3.串口接收流程(HAL库)

1)配置过程
  • 接收配置步骤①~⑥和发送流程一样,调用HAL_UART_Init函数
	HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);
  • 步骤⑦开启接收中断:
	HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size);
2)接收数据过程
  • 步骤①获取状态标志位通过标识符实现:
	__HAL_UART_GET_FLAG //判断状态标志位
	__HAL_UART_GET_IT_SOURCE //判断中断标志位

**注意:**这里USART表示同步进行,UART表示异步进行

  • 步骤②~③中断服务函数:
	void USARTx_IRQHandler(void) ;//(x=1~3,6)
	void UARTx_IRQHandler(void) ;//(x=4,5,7,8)

在启动文件startup_stm32fxxx.s中查找。

  • 步骤④读取接收数据:
	HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

4.串口接收中断程序配置过程(HAL库)

① 初始化串口相关参数,使能串口:HAL_UART_Init();
② 串口相关IO口配置,复用配置:在HAL_UART_MspInit中调用HAL_GPIO_Init函数。
③ 串口接收中断优先级配置和使能:
HAL_NVIC_EnableIRQ(); //使能中断通道
HAL_NVIC_SetPriority(); //设置抢占优先级和响应优先级
④ 使能串口接收中断:HAL_UART_Receive_IT();
⑤ 编写中断服务函数:USARTx_IRQHandler

  • 经过上面6个步骤,我们就可以写完整的串口接收实验。我们就可以在中断服务函数中编写中断处理过程。
    HAL库提供了详细的中断处理函数
    HAL_UART_IRQHandler
    我们在中断服务函数中会调用此函数处理中断。
    在这里插入图片描述

  • 串口接收中断流程
    在这里插入图片描述

5.串口中断服务函数执行流程

① 串口中断服务函数中调用HAL库串口中断通用处理函数:

	HAL_UART_IRQHandler();
该函数会对中断来源进行分析,调用相应函数。

② 对于不同的中断类型,我们只需要编写最终的中断处理函数:

	void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
	void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
	void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
	void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
	void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);

二、串口接收实验

实验目标:
通过电脑的串口小程序向单片机串口1发送数据,在单片机接收数据后同时在发送相同的数据给电脑。

步骤
① 初始化串口相关参数,使能串口:HAL_UART_Init();
② 串口相关IO口配置,复用配置:在HAL_UART_MspInit中调用HAL_GPIO_Init函数。
③ 串口接收中断优先级配置和使能:
HAL_NVIC_EnableIRQ(); //使能中断通道
HAL_NVIC_SetPriority(); //设置抢占优先级和响应优先级
④ 使能串口接收中断:HAL_UART_Receive_IT();
⑤ 编写中断服务函数:USARTx_IRQHandler

  • 上一讲串口发送实验代码如下,我们在此基础上进行更改:
#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)					//如果是串口1,进行串口1 MSP初始化
	{
		__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);
	}
}

1.串口接收中断优先级配置和使能

首先要进行串口接收中断优先级配置,这里要针对串口一来进行操作
需要使用HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)函数
位置:工程文件-HALLIB-stm32f4xx_hal_cortex.c里面
在这里插入图片描述

函数HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)可以看到有三个入口参数:

1)IRQn_Type IRQn (使能哪个项目)

查看定义有
在这里插入图片描述
在这里插入图片描述

里面列举了所有IRQn可以使用的变量名,我们这里使用USART1_IRQn

2)uint32_t PreemptPriority (抢占优先级)和uint32_t SubPriority(响应优先级)

这里可以看到其定义的都是32为数字,按照前面所学,数字越大其级别越小,故这里我们把级别设小一点,其中抢占优先级为3;响应优先级为3

所以HAL_NVIC_SetPriority函数设置代码和位置如下

HAL_NVIC_SetPriority(USART1_IRQn,3,3)

加粗样式

2.使能中断通道

使能中断通道问哦们要调用HAL_NVIC_EnableIRQ函数
函数体HAL_NVIC_EnableIRQ(IRQn_Type IRQn),只有一个变量
位置:工程文件-HALLIB-stm32f4xx_hal_cortex.c里面
在这里插入图片描述

函数体中只有一个变量IRQn_Type IRQn,意思是使能哪个中断通道,这里我们使用USART1_IRQn
代码和位置如下:

HAL_NVIC_EnableIRQ(USART1_IRQn);

在这里插入图片描述

3.使能串口接收中断:HAL_UART_Receive_IT();

这里我们要使用HAL_UART_Receive_IT();函数
位置:工程文件-HALLIB-stm32f4xx_hal_uart.c里面
在这里插入图片描述

函数体:HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
有三个入口参数:和上一小节串口发送函数很像
UART_HandleTypeDef *huart(串口句柄)
uint8_t *pData(接收的数据)
uint16_t Size(接收的数据大小)

  • 串口句柄设置为&usart1_handler(同上一小节串口发送的句柄一样)
  • 接收的数据,我们在前面新定义一个数组用来存放接收来的数据:u8 rdata 所以第二个入口参数为刚刚定义的数组名rdata
  • 接收的数据大小,我们选择自适应rdata的数据大小,设置为sizeof(rdata)

函数体最终设置代码和位置为

u8 rdata[1];
int main(void)
{
HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata ));
}

在这里插入图片描述
在这里插入图片描述

4. 编写中断服务函数:USARTx_IRQHandler

在main.c里面添加中断服务函数:USARTx_IRQHandler,并在里面调用官方HAL库的中断服务函数HAL_UART_IRQHandler(&usart1_handler);
位置:工程文件-HALLIB-stm32f4xx_hal_uart.c里面
在这里插入图片描述

在HAL_UART_IRQHandler函数内部,会对中断的类型进行判断如果执行的是接收中断,它会调用UART_Receive_IT函数
在这里插入图片描述

查看UART_Receive_IT函数定义如下
在这里插入图片描述

在这个函数内部,MCU每接收到一个数据都会执行这个函数,然后把接收到的数据保存到变量pRxBuffPtr中

在接收完数据后,需要继续使能接收中断,所以加入使能接收中断函数HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata ));

最终中断服务函数代码和位置如下

void USART1_IRQHandler(void)			//中断服务函数
{
	HAL_UART_IRQHandler(&usart1_handler);		//调用官方HAL库的中断服务函数
	HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata ));			//使能接收中断
}

在这里插入图片描述

5.编写接收中断完成函数:HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

在main.c里面添加接收中断完成函数:HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
在这里插入图片描述

我们在函数体中编写上图框起来的部分的代码

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)		//接收中断完成函数
{
	u8 receive;
	if(huart->Instance ==USART1)				//如果是串口1,
	{
		receive=*((huart->pRxBuffPtr)-1);			//把接收到的数据赋值给receive
		//或使用receive=rdata[0];
	}
}

在这里插入图片描述

6.改写发送程序

这里我们要发送接收到的数据,即rdata[1]数组中的数据也是receive的地址中的数据
在中断完成函数里面编写串口发送函数HAL_UART_Transmit(&usart1_handler,&receive,1,1000);
代码和位置如下:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)		//接收中断完成函数
{
	u8 receive;
	if(huart->Instance ==USART1)				//如果是串口1,
	{
		receive=*((huart->pRxBuffPtr)-1);			//把接收到的数据赋值给receive
		//或使用receive=rdata[0];
		HAL_UART_Transmit(&usart1_handler,&receive,1,1000);		//使能发送中断
	}
}

在这里插入图片描述

7.把上一小节的发送函数注释掉

如图
在这里插入图片描述

因为库函数里面对串口接收和发送已经定义好了,在位置:工程文件-SYSTEM-usart.c文件里面,这里我们想要使用自己编写的代码,需要把usart.c文件删除
在这里插入图片描述

不删掉的话会报错说重复定义
在这里插入图片描述

8.main.c全部代码

#include "sys.h"
#include "delay.h"
#include "usart.h"

u8 rdata[1];			//定义一个数组,用于存放要接收的数据

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);		//初始化刚刚定义的结构体变量,调用官方HAL库的初始化函数
}

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
	GPIO_InitTypeDef  GPIO_Initure;			//初始化GPIO结构体
	
	if(huart->Instance ==USART1)				//如果是串口1,进行串口1 MSP初始化
	{
		__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
		
		HAL_NVIC_SetPriority(USART1_IRQn,3,3);	//串口1.抢占优先级3,响应优先级3
		HAL_NVIC_EnableIRQ(USART1_IRQn);		//使能中断通道1
	}
}

void USART1_IRQHandler(void)			//中断服务函数
{	
	HAL_UART_IRQHandler(&usart1_handler);		//调用官方HAL库的中断服务函数
	HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata ));			//使能接收中断
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)		//接收中断完成函数
{
	u8 receive;
	if(huart->Instance ==USART1)				//如果是串口1,
	{
		receive=*((huart->pRxBuffPtr)-1);			//把接收到的数据赋值给receive
		//或使用receive=rdata[0];
		HAL_UART_Transmit(&usart1_handler,&receive,1,1000);		//使能发送中断
	}
}

int main(void)
{
    //u8 data[]="-Apollo by wire-   ";			//定义一个数组,用于存放要发送的数据
	
    HAL_Init();                     //初始化HAL库    
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
	delay_init(180);				//初始化延时函数
	uart1_init();					//调用前面写的初始化函数
	
	HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata ));			//使能接收中断
	
	while(1)
	{
		//HAL_UART_Transmit(&usart1_handler,data,sizeof(data),1000);		//使能发送中断
		//delay_ms(300);
	}
}

9.下载程序到开发板

下载程序到开发板,打开串口调试助手,点击发送数据a,观察现象
在这里插入图片描述

在前面编写的数组rdata[1]中,只定义了一个数据位,那么接下来我们发送更多数据试试,写发送数据apollo,得到结果如下
在这里插入图片描述

MCU也返回了apollo,其实他是一个一个返回的,apollo六个字母,系统返回了六次

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

26.UART串口接收过程与配置 的相关文章

  • python监视mysql最大连接数

    usr local bin python3 5import pymysqlimport time sum 0 while True open db connection db pymysql connect localhost root a
  • You can‘t specify target table ‘XXXX‘ for update in FROM clause mysql错误解决方法

    mysql数据库同时对一个表进行查询和删改操作时 会报 You can t specify target table XXXX for update in FROM clause 错误 无法执行 错误提示的意思是 不能在 FROM 子句中指
  • 2022年度回顾

    2022年接近尾声 驻足回看行业这一年的跌宕起伏 无论是技术的突破 应用的创新 还是生态的兴衰 皆成为了行业发展的历史注脚 如往年一样 万向区块链于年末推出重磅年度回顾系列文章 公链技术篇 应用篇 和 监管篇 以期记录当前行业发展的缩影 下

随机推荐

  • Java快捷键(学到会慢慢更新)

    大家都知道快捷键的重要性 尤其在代码中 懂得运用快捷键的小伙伴写代码速度就是快 目前我学Java还不是很久 之前学c的 所以所知道的快捷键比较少 后续会一直更新这条博文 第一个快捷键 psvm 回车 这是main函数快速生成快捷键 具体还是
  • 顺序表的基本操作

    目录 一 实验要求 二 代码实现 三 运行结果 一 实验要求 1 验证性实验 实现顺序表的基本操作 实验内容 编写一个程序sqlist cpp 或 c 实现顺序表的各种基本运算和整体建表算法 假设顺序表的内容类型ElemType为char
  • Git-常用命令

    系列文章 Git 入门小结 Git 分支 Git 常用命令 Git 注册远程仓库 1 提交代码到暂存区 git add 添加当前目录的所有文件到缓存区 git add file1 file2 添加指定文件到缓存区 git rm file1
  • 1分钟学会在C++中将图像转换为Word文档,快速入手光学字符处理控件Aspose.OCR

    图像和扫描的文档可能包含您可能需要进一步处理的文本信息 可能已经使用智能手机拍摄了文本文档的图片 并将其转换为可编辑的文档 为此 对图像执行 OCR 可以证明是有帮助的 使用 OCR 可以将图像转换为可搜索和可编辑的 Word 文档 为此
  • c 语言软链接函数,C++/C链接过程详解

    头文件可以被多个编译单元包含 如果头文件里有定义 那么每个包含这个头文件的编译单元就都会对同一个符号 进行定义 如果该符号为外部链接 则会导致duplicated external simbols 因此如果头文件里要定义 必须保证定义的符号
  • 刷题day51:重新安排行程 ***

    题意描述 给你一份航线列表 tickets 其中 tickets i fromi toi 表示飞机出发和降落的机场地点 请你对该行程进行重新规划排序 所有这些机票都属于一个从 JFK 肯尼迪国际机场 出发的先生 所以该行程必须从 JFK 开
  • pip install 出现HHTP链接有问题

    Could not fetch URL https pypi org simple seaborn There was a problem confirming the ssl certificate HTTPSConnectionPool
  • linux 命令执行的判断依据

    linux 命令执行的判断依据 一 指令与指令中间利用分号 来隔开 分号前的指令执行完后就会立刻接着执行后面的指令了 二 和 每个指令执行结束后 都会有一个指令回传值 如果指令执行正确 返回0 如果执行错误 则返回错误的对应数字 和 会通过
  • 2218. Maximum Value of K Coins From Piles

    There are n piles of coins on a table Each pile consists of a positive number of coins of assorted denominations In one
  • HTML 制作表格案例

    1 运行要求 2 示例代码 table align center border 1 cellspacing 0 tr th 排名 th th 趋势 th th 关键词 th th 今日搜索 th tr table
  • 彻底理解NodeJs中的回调(Callback)函数

    究竟什么是回调函数 Callback 网上有许许多多的文章 大部分看得人云里雾外 这些文章大概分成两类 第一类堆砌了太多的术语 基本上不明白术语就没法看 另一类反过来 不讲术语 完全是举一些脱离编程的生活化例子来类比 看的人更加晕头转向 作
  • Ubuntu 20.04 下Fabric V2.2.0 和 V1.1.0 运行及配置说明(均可运行)

    ubuntu 20 04 下Fabric V2 2 0 和 V1 1 0 运行及配置说明 ubuntu 20 04 下Fabric运行及配置说明 注 本文是对 hyperledger fabric 区块链快速入门教程 错误解决 良好用户体验
  • 趣图丨前端后端接口联调的时候……

    是不是感觉数据永远都对不上 看完此文 你有什么想法或观点呢 欢迎在留言区留言评论 更多精彩
  • 华为录屏全攻略,从入门到高手

    求助 华为录屏在哪里呀 找了一上午了 平时的时候也看见过 就没在意 现在需要用到了 就找不到了 真的离谱 有没有人知道的 教教我 在智能手机时代 录制屏幕成为了我们生活中必不可少的一部分 无论是录制游戏过程 在线课程还是演示教程 录屏功能都
  • [大模型] LLaMA系列大模型调研与整理-llama/alpaca/lora(部分)

    文章目录 LLaMA大模型及其衍生模型 1 LLaMA 2 stanford alpaca 3 ChatDoctor 4 alpaca lora 5 Chinese LLaMA Alpaca 6 BELLE 大模型综述 A Survey o
  • 深度学习模型部署学习一

    深度学习模型部署 学习链接 模型部署入门教程 一 模型部署简介 写在前面 本文档为学习上述链接的相关记录 基本内容一致 仅用于学习用途 若侵权请联系我删除 目 录 深度学习模型部署 1 为什么需要部署 2 部署难题 3 部署流程 4 实战模
  • js实现右键弹出自定义的菜单

    js实现右键弹出自定义的菜单 实现的步骤 1 首先阻止右键弹出系统默认的菜单 2 自定义菜单并隐藏 3 点击右键弹出自定义菜单 4 点击桌面除菜单任意位置 菜单隐藏 点击菜单 菜单不隐藏
  • MySQL——数据库、表的操作

    文章目录 数据库的操作 创建数据库 创建数据库例子 字符集和校验规则 查看数据库支持的字符集 查看默认的字符校验规则 校验规则对数据库的影响 查看数据库 显示详细的创建数据库语句 修改数据库 删除数据库 查看连接情况 表的操作 创建表 显示
  • Python格式化输出之format函数

    format函数是Python中一个很强大的格式化输出函数 使用花括号 来占位 下面结合代码来讲述format函数的用法 一 匹配顺序 print 姓名 年龄 format 张三 25 运行结果 姓名 张三 年龄 25 可以看出 forma
  • 26.UART串口接收过程与配置

    UART串口接收过程与配置 参考资料 STM32Fx中文参考手册 第26章 通用同步异步收发器章节 开发板配套教程 STM32Fx开发指南 串口实验章节 笔记基于正点原子官方视频 视频连接https www bilibili com vid