完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
芯片:STM32L452RE
通过CubeMx生成工程文件,利用HAL库实现串口通信(DMA+空闲中断)任意长度的数据接收, 该程序不同于其它博客的写法,不用在主函数判断空闲中断再调用串口DMA接收函数,且解决第一次接收不到数据或数据不完整的情况。。 1.在STM32CubeMX里配置所需功能 1.1 时钟系统 建议选择MSI作为时钟输入源,HSI反应有Bug(没有去尝试过,暂时省略) 1.2 设置串口中断和DMA 这里不做详细介绍,网上有大量教程可以参考 1.3 生成工程文件(keil5) 不熟悉的同学可以参考其它博客,有写得很详细的。 2. 程序编写 不用在主函数里调用DMA接收函数,且解决第一次接收不到数据或数据不完整的情况(不用环形缓冲区)。 2.1设计思路 首先开启串口中断接收函数,允许接收中断 HAL_UART_Receive_IT(&huart1, (uint8_t *)&Buftemp, 1); 当接收到第一个字节时产生中断(非空闲中断),此时的中断会调用HAL_UART_RxCpltCallback(), 在该函数里开启空闲中断和DMA接收,由于第一个中断已向缓冲区写入一个字节,此时的DMA接收区需要调整(若不设置,第一次接收的数据会丢失第一个字节); 在stm32l4xx_it.c里,编写中断服务程序。如果有空闲中断,编写空闲中断处理函数(清除标志位,停止DMA传输),再开启DMA接收 main.c 主函数 unsigned char data[MAX_RCV_LEN]; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ printf("****start*****n"); HAL_Delay(1000); GetRcvData(&huart1 ,data, sizeof(data)); if(strlen(data)){ printf("recv: %s n",data); HAL_Delay(1000); } } /* USER CODE END 3 */ usart.h /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __usart_H #define __usart_H #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "stm32l4xx_hal.h" #include "main.h" /* USER CODE BEGIN Includes */ #include #include #include /* USER CODE END Includes */ extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart3; /* USER CODE BEGIN Private defines */ #define MAX_RCV_LEN 1024 extern uint8_t USART1RECV[MAX_RCV_LEN]; //串口1 /* USER CODE END Private defines */ extern void _Error_Handler(char *, int); void MX_USART1_UART_Init(void); void MX_USART2_UART_Init(void); void MX_USART3_UART_Init(void); /* USER CODE BEGIN Prototypes */ /* 清空*/ void USART_Clear(UART_HandleTypeDef *huart); extern void USART_IDLECallBack(void); uint16_t GetRcvNum(UART_HandleTypeDef *huart); extern void GetRcvData(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t rcv_len); void USART_Write(UART_HandleTypeDef *huart, uint8_t *Data, uint16_t len); /* USER CODE END Prototypes */ #ifdef __cplusplus } #endif #endif /*__ usart_H */ usart.c /* USER CODE BEGIN 0 */ uint8_t Buftemp; uint16_t usart1_recv_len; uint8_t USART1RECV[MAX_RCV_LEN]; /* USER CODE END 0 */ 在串口1的初始化程序里,开启串口接收中断 HAL_UART_Receive_IT(&huart1, (uint8_t *)&Buftemp, 1); void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } HAL_UART_Receive_IT(&huart1, (uint8_t *)&Buftemp, 1);//使能第一次中断 } 由第一次中断调用 HAL_UART_RxCpltCallback()函数,再开启空闲中断和DMA接收 /* USER CODE BEGIN 1 */ void USART_Clear(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { usart1_recv_len = 0; memset(USART1RECV, 0x0, sizeof(USART1RECV)); }else if(huart->Instance == USART2) { } } void USART_IDLECallBack(void) { unsigned int temp; __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位 temp = USART1->RDR; //清除状态寄存器RDR temp = temp; HAL_UART_DMAStop(&huart1); // } void GetRcvData(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t rcv_len) { if(huart->Instance == USART1) { if(buf){ memcpy(buf,USART1RECV, rcv_len); } USART_Clear(&huart1); }else if(huart->Instance == USART2){ } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { UNUSED(huart); if(huart->Instance == USART1) {//只有第一次中断会调用 if(usart1_recv_len==0){ USART1RECV[usart1_recv_len++]=Buftemp;//第一次中断的数据被写入USART1RECV[0]处 __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位 __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//使能空闲中断 HAL_UART_Receive_DMA(&huart1, USART1RECV+1, MAX_RCV_LEN); //设置第一次DMA接收缓冲区, } } } stm32l4xx_it.c 判断是否为空闲中断,如果是,调用空闲中断处理函数USART_IDLECallBack(),如果需要处理串口收到的数据可以再该函数里进行;; 最后,开启DMA接收(不用调整接收缓冲区); /** * @brief This function handles USART1 global interrupt. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) { USART_IDLECallBack(); HAL_UART_Receive_DMA(&huart1, USART1RECV, MAX_RCV_LEN); } /* USER CODE END USART1_IRQn 1 */ } 3 运行结果 完美的情况 失败的情况 第一次的数据丢失第一个字节,后面的都正常 相关资源已上传 STM32L4系列 串口通信 空闲中断+DMA 实现任意长度的数据接收 包含两种方式 1:不用在主函数调用DMA接收函数(推荐,非常实用) 2:许多教程的写法,需要在主函数调用判断空闲中断状态再调用DMA接收函数 https://download.csdn.net/download/sinat_37853238/10935731 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1816 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1631 浏览 1 评论
1098 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
739 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1691 浏览 2 评论
1950浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
754浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
585浏览 3评论
604浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
568浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 00:49 , Processed in 0.898478 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号