1、准备开发板
这里我选用了一块网红开发板:”小熊派“,这款板子的人气比较高,还是全国大学生物联网设计竞赛(华为杯)的华为竞赛开发板,我个人也比较喜欢用这款板子,这款板子在放在纸箱吃灰半年之后,被我重新拿了起来,并想借此写博客的机会,整理一下自己的代码。
开发板功能区分布图

开发板俯视图

2、STM32CubeMX生成代码

搜索并选择芯片型号

配置系统时钟

配置时钟树
STM32L4的最高主频可达到80M,最后使HCLK = 80Mhz即可:


配置串口



生成工程设置
代码生成配置

生成代码

生成成功

3、在MDK中编写代码
在usart.h下的用户代码区编写以下代码
/* USER CODE BEGIN Includes */
#if defined ( __CC_ARM )
#pragma anon_unions
#endif
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
#define RX_BUF_MAX_LEN 256 //最大接收缓存字节数
typedef struct
{
unsigned short dataLenPre; //上一次的长度数据,用于比较
union{
unsigned short InfAll;
struct
{
unsigned short dataLen : 15; //接收数据长度
unsigned short finishFlag : 1; //接收完成标志
}InfBit;
};
unsigned char rxBuf[RX_BUF_MAX_LEN]; //接收缓存
} USART_INFO_STRUCT;
#define REC_OK 1 //接收完成标志
#define REC_WAIT 0 //接收未完成标志
extern USART_INFO_STRUCT usart1Info;
/* USER CODE END Private defines */
/* USER CODE BEGIN Prototypes */
void USART_Interupt_Enable(void);
void USER_UartDMAHandler(UART_HandleTypeDef* huart,USART_INFO_STRUCT* usartInfo);
/* USER CODE END Prototypes */
在usart.c下的用户代码区编写以下代码
/* USER CODE BEGIN 0 */
#include <stdio.h>
USART_INFO_STRUCT usart1Info;
int fputc(int ch, FILE *stream)
{
/* 堵塞判断串口是否发送完成 */
while((USART1->ISR & 0X40) == 0);
/* 串口发送完成,将该字符发送 */
USART1->TDR = (uint8_t) ch;
return ch;
}
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
void USART_Interupt_Enable(void)
{
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //空闲中断使能
__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE); //接收中断使能
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除串口空闲中断标志位
}
void USER_UartDMAHandler(UART_HandleTypeDef* huart,USART_INFO_STRUCT* usartInfo)
{
uint32_t ucCh;
if(huart->Instance == USART1)
{
if(__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET) //触发空闲中断
{
__HAL_UART_CLEAR_IDLEFLAG(huart); //清除串口2空闲中断标志位
HAL_UART_DMAStop(huart); //关闭DMA
ucCh = huart->Instance->ISR; //清除SR状态寄存器
ucCh = huart->Instance->RDR; //读取DR数据寄存器 用来清除中断
ucCh = hdma_usart1_rx.Instance->CNDTR; //获取DMA中未传输的数据个数
usartInfo->InfBit.dataLen = RX_BUF_MAX_LEN - ucCh; //总计数减去未传输的数据个数,得到已经接收的数据个数
usartInfo->InfBit.finishFlag = REC_OK; //标志接收成功
}
}
HAL_UART_Receive_DMA(huart,usartInfo->rxBuf,RX_BUF_MAX_LEN); //使能DMA接收到buf1
}
/* USER CODE END 1 */
在stm32l4xx_it.c中的USART1_IRQHandler函数的用户代码区编写以下代码
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
USER_UartDMAHandler(&huart1,&usart1Info); //用户中断代码
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
在main.c下的main函数下的用户代码区编写以下代码
/* USER CODE BEGIN 2 */
USART_Interupt_Enable(); //使能串口接收中断和空闲中断
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(usart1Info.InfBit.finishFlag == REC_OK) //如果接收成功
{
usart1Info.rxBuf[usart1Info.InfBit.dataLen++] = '\0'; //在数组最后添加\0,这样可以截断字符串
printf("usart1Info.rxBuf:%s\r\n",usart1Info.rxBuf); //打印字符串
usart1Info.InfBit.finishFlag = REC_WAIT; //将标志位设置成等待接收状态
usart1Info.InfBit.dataLen = 0; //将接收的数据长度设置为0
}
}
/* USER CODE END 3 */
4、配置烧录器


5、烧录代码

6、实验现象
串口助手向单片机发送数据,单片机会将接收到的数据再发送到串口助手

:03.串口收发DMA+空闲中断&spm=1001.2101.3001.5002&articleId=118736529&d=1&t=3&u=713fa69f88544340a99638a6377e4c06)
314

被折叠的 条评论
为什么被折叠?



