STM32CubeMX生成代码学习笔记(三)串口DMA不定长收发+串口打印(更新:空闲中断队列式收发解决方案+持续接收数据后串口死机BUG优化)

1. 配置CubeMX工程USART

首先配置时钟,配置同学习笔记二
配置USART1:选择串口模式为Asynchronous(异步):
在这里插入图片描述

配置波特率,字节位数,校验方式和停止位:
在这里插入图片描述
配置DMA:点击Add添加串口1接收中断发送中断,DMA模式为普通
在这里插入图片描述
配置中断优先级:
在NVIC页面勾选串口1中断
在这里插入图片描述

点击系统查看中的NVIC
在这里插入图片描述
在NVIC设置区中选中USART1中断,在红圈中设置优先级,注意不要与其他外设的优先级产生冲突
在这里插入图片描述
设置完成后生成代码,打开工程

2. 添加用户代码

在USART.C及USART.h中分别加入要用到的外部变量

USART.c中:

/* USER CODE BEGIN 0 */
volatile uint8_t Usart1_RX_Cnt;//串口1接收的列表计数
volatile uint8_t Usart1_RX_Pro;//串口1接收已处理的列表计数
volatile uint8_t Usart1_TX_Cnt;//串口1发送的列表计数
volatile uint8_t Usart1_TX_Pro;//串口1发送已处理的列表计数
uint8_t	USART1_Tx_Temp[USART1_TxBuffer_Size];//串口1数据发送缓存
uint8_t	USART1_Tx_Buffer[USART1_List_Size][USART1_TxBuffer_Size];	//串口1数据发送缓存数组
uint8_t	USART1_Rx_Buffer[USART1_List_Size][USART1_RxBuffer_Size]; //串口1数据接收缓存数组
uint16_t	USART1_Rx_Lenth[USART1_List_Size];//串口1数据接收长度
uint16_t	USART1_Tx_Lenth[USART1_List_Size];//串口1数据发送长度
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
/************************************************
*函数名:my_printf
*函数功能:字符串打印重定向
*输入:目标指针,字符串
*输出:字符串长度
************************************************/
uint16_t my_printf(char* buf,char* fmt,...)
{
	va_list ap; 
	va_start(ap,fmt);
	vsprintf((char*)buf,fmt,ap);
	va_end(ap);
	return	strlen((const char*)buf);		//此次发送数据的长度
}
/************************************************
*函数名:USART_Init
*函数功能:串口初始化
*输入:无
*输出:无
************************************************/
void	USART_Init(void)
{
	HAL_UARTEx_ReceiveToIdle_DMA(&huart1,USART1_Rx_Buffer[Usart1_RX_Cnt],USART1_RxBuffer_Size);//USART1使用DMA传输
	__HAL_UART_ENABLE_IT(&huart1,UART_IT_ERR);//USART1开启错误处理中断
}
/************************************************
*函数名:USART1_MsgToQueue
*函数功能:将USART1_Tx_Temp数据传入USART1发送队列
*输入:数据长度
*输出:无
************************************************/
void	USART1_MsgToQueue(uint8_t*	Sendbuffer,uint16_t lenth)
{
	USART1_Tx_Lenth[Usart1_TX_Cnt] = lenth;
	for(uint16_t i=0;i<lenth;i++)
	{
		USART1_Tx_Buffer[Usart1_TX_Cnt][i] = Sendbuffer[i];
	}
	if(Usart1_TX_Cnt==(USART1_List_Size-1))Usart1_TX_Cnt=0;
	else	Usart1_TX_Cnt++;
}
/************************************************
*函数名:USART1_MsgSend
*函数功能:USART1数据发送
*输入:无
*输出:无
************************************************/
void	USART1_MsgSend(void)
{
	if(Usart1_TX_Pro !=	Usart1_TX_Cnt)
	{
		HAL_UART_Transmit_DMA(&huart1,USART1_Tx_Buffer[Usart1_TX_Pro],USART1_Tx_Lenth[Usart1_TX_Pro]);//按队列顺序输出
		if(Usart1_TX_Pro==(USART1_List_Size-1))Usart1_TX_Pro=0;
		else	Usart1_TX_Pro++;
	}
}
/************************************************
*函数名:USART1_Recv
*函数功能:USART1接收数据处理
*输入:无
*输出:无
************************************************/
void	USART1_Recv(void)
{
	uint16_t Lenth;
	if(Usart1_RX_Cnt	!=	Usart1_RX_Pro)
	{
		Lenth = my_printf((char*)USART1_Tx_Temp,"\r\nUsart1_RX_LEN=%d\r\n接收数据:",USART1_Rx_Lenth[Usart1_RX_Pro]);//打印接收长度
		USART1_MsgToQueue(USART1_Tx_Temp,Lenth);
		USART1_MsgToQueue(USART1_Rx_Buffer[Usart1_RX_Pro],USART1_Rx_Lenth[Usart1_RX_Pro]);
		if(Usart1_RX_Pro==(USART1_List_Size-1))Usart1_RX_Pro=0;
		else	Usart1_RX_Pro++;
	}
}
/* USER CODE END 1 */

USART.h中:

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "stdarg.h"
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
	

#define	USART1_List_Size	32					//队列深度
#define	USART1_RxBuffer_Size	255				//接收数组大小
#define	USART1_TxBuffer_Size	255				//接收数组大小
/* USER CODE END Private defines */
/* USER CODE BEGIN Prototypes */
extern	volatile uint8_t Usart1_RX_Cnt;//串口1接收的列表计数
extern		volatile uint8_t Usart1_RX_Pro;//串口1接收已处理的列表计数
extern		volatile uint8_t Usart1_TX_Cnt;//串口1发送的列表计数
extern		volatile uint8_t Usart1_TX_Pro;//串口1发送已处理的列表计数
extern		uint8_t	USART1_Tx_Temp[USART1_TxBuffer_Size];//串口1数据发送缓存
extern		uint8_t	USART1_Tx_Buffer[USART1_List_Size][USART1_TxBuffer_Size];	//串口1数据发送缓存数组
extern		uint8_t	USART1_Rx_Buffer[USART1_List_Size][USART1_RxBuffer_Size]; //串口1数据接收缓存数组
extern		uint16_t	USART1_Rx_Lenth[USART1_List_Size];
extern		uint16_t	USART1_Tx_Lenth[USART1_List_Size];
void	USART_Init(void);
uint16_t my_printf(char* buf,char* fmt,...);
void	USART1_MsgToQueue(uint8_t*	Sendbuffer,uint16_t lenth);
void	USART1_MsgSend(void);
void	USART1_Recv(void);
/* USER CODE END Prototypes */

在stm32f1xx_it.c中插入代码:

/* USER CODE BEGIN Includes */
#include "usart.h"
/* USER CODE END Includes */
/************************************************
*函数名:HAL_UARTEx_RxEventCallback
*函数功能:串口接收回调
*输入:UART_HandleTypeDef *huart, uint16_t Size
*输出:无
************************************************/
void	HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	
	/************ USART1接收 ************/
	if(huart->Instance	==	USART1)
	{
		USART1_Rx_Lenth[Usart1_RX_Cnt] = Size;
		if(Usart1_RX_Cnt==(USART1_List_Size-1))Usart1_RX_Cnt=0;
		else	Usart1_RX_Cnt++;
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,USART1_Rx_Buffer[Usart1_RX_Cnt],USART1_RxBuffer_Size);//USART1使用DMA传输
	}
}
/************************************************
*函数名:HAL_UART_ErrorCallback
*函数功能:串口错误中断回调
*输入:UART_HandleTypeDef *huart
*输出:无
************************************************/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance	==	USART1)
	{
		__HAL_UART_CLEAR_OREFLAG(huart);
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,USART1_Rx_Buffer[Usart1_RX_Cnt],USART1_RxBuffer_Size);//USART1使用DMA传输
	}
}

在main.c中初始化部分插入开启USART1空闲中断和DMA传输:

/* USER CODE BEGIN 2 */
	USART_Init();
/* USER CODE END 2 */

3. 测试代码

在主循环中加入:

 while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    USART1_Recv();			//接收处理
    USART1_MsgSend();		//发送处理
    HAL_Delay(50);//处理速度
  }
  /* USER CODE END 3 */

测试效果(未更新):
在这里插入图片描述

4.遇到的问题:

一开始调试代码都写好了怎么调试都不通!!!!!!!!
最后发现是口插错了==
以后贴片器件还是画在Bottom层吧==

5.更新日志

在后面的项目中总结出了效率更高、更稳定等串口使用方法,故更新。
测试demo:https://download.csdn.net/download/weixin_44087298/87671515。

参考文章:

打印函数:https://www.cnblogs.com/hjf-log/p/12522796.html
其他函数:https://blog.csdn.net/qq_33728095/article/details/97778147

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

食熊鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值