STM32H750在使用串口外设配合DMA,和其他不带高速数据缓冲区的MCU差别就是,在调用DMA收发函数时,如果开启了数据高速缓存区,需要对将要调用的数据存储区域进行缓存清空处理。因为DMA传输的数据不在高速缓冲区范围内。如果不是调用DMA相关收发函数,就不需要此操作。
开启缓冲区
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
清除指定缓冲区方法
SCB_CleanDCache_by_Addr((uint32_t *)UART_RX_STA, UART_RX_LEN);
SCB_CleanInvalidateDCache_by_Addr ((uint32_t *)UART_RX_STA, UART_RX_LEN);//或者
如果开启了MPU功能,需要注意所定义的变量存储位置在可读写范围内,不是定义在MPU内存保护区地址内,否则无法存储所接收的数据。
串口接收事件中断回调(HAL_UARTEx_RxEventCallback )和接收完成中断回调(HAL_UART_RxCpltCallback )差异说明
HAL_UARTEx_RxEventCallback 和 HAL_UART_RxCpltCallback 是两个不同的回调函数,它们在STM32的HAL库中用于处理UART(通用异步收发传输器)的接收事件。
HAL_UART_RxCpltCallback: 这个回调函数在UART接收完成时被调用。当UART接收到指定数量的数据(通常是一个字节或一个数据包)后,DMA(直接内存访问)传输完成,此时会触发这个回调函数。
◦ 它通常用于处理接收到的数据,例如将数据存储到缓冲区或进行进一步的处理。
HAL_UARTEx_RxEventCallback: 这个回调函数在UART接收到数据时被调用,而不仅仅是在接收完成时。它可以在接收到每个字节或每个数据包时被触发,具体取决于UART的配置。与 HAL_UART_RxCpltCallback 不同,HAL_UARTEx_RxEventCallback 提供了更细粒度的控制,可以在数据接收的过程中进行实时处理。
总结:
• HAL_UART_RxCpltCallback 在UART接收完成时调用,用于处理接收到的完整数据。
• HAL_UARTEx_RxEventCallback 在UART接收到数据时调用,可以在数据接收的过程中进行实时处理。
采用不同的接收回调函数,决定了中断处理内容的不同。具体使用哪种方式,可以根据具体的实际需求来设定中断回调。
STM32CubeMX工程配置
串口外设的基本配置:无特殊要求,默认参数即可
串口DMA配置参数
使能串口全局中断
业务代码完善
开启串口DMA接收
HAL_UART_Receive_DMA(&huart1,UART_RX_BUF,UART_RX_LEN);//开启DMA串口接收
开启空闲中断
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//空闲中断
串口中断处理函数
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) // 空闲中断标记被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); // 清除中断标记
HAL_UART_DMAStop(&huart1); // 停止DMA接收
UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx); // 总数据量减去未接收到的数据量为已经接收到的数据量
UART_RX_BUF[UART_RX_STA] = 0; // 添加结束符
UART_RX_STA |= 0X8000; // 标记接收结束
HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN); // 重新启动DMA接收
}
/* USER CODE END USART1_IRQn 1 */
}
串口接收完成,数据处理内容:
if(UART_RX_STA & 0X8000)
{
SCB_CleanDCache_by_Addr((uint32_t *)UART_RX_STA, UART_RX_LEN);
// SCB_CleanInvalidateDCache_by_Addr ((uint8_t *)UART_RX_STA, UART_RX_LEN);//或者
HAL_UART_Transmit_DMA(&huart1,(uint8_t *)UART_RX_BUF, UART_RX_STA & 0X7FFF);//配合上面的函数一起使用
// HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100); // 将接收到的数据发送回去
UART_RX_STA = 0; // 清除标记
}
接收事件回调实现方法
在中断处理函数中添加:
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 */
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,UART_RX_BUF,UART_RX_LEN); //重新开启串口空闲中断和DMA接收,一定要放在这里
/* USER CODE END USART1_IRQn 1 */
}
添加接收事件回调函数处理内容:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == USART1)
{
UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx); // 总数据量减去未接收到的数据量为已经接收到的数据量
UART_RX_BUF[UART_RX_STA] = 0; // 添加结束符
UART_RX_STA |= 0X8000; // 标记接收结束
__HAL_UNLOCK(huart);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,UART_RX_BUF,UART_RX_LEN) ;
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_12 ) ;
}
}
main串口接收空闲中断初始化
在main外设初始化后,添加:
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,UART_RX_BUF,UART_RX_LEN) ;
接收数据回调事件,数据处理内容:
if(UART_RX_STA & 0X8000)
{
SCB_CleanDCache_by_Addr((uint32_t *)UART_RX_STA, UART_RX_LEN);
// SCB_CleanInvalidateDCache_by_Addr ((uint32_t *)UART_RX_STA, UART_RX_LEN);//或者
HAL_UART_Transmit_DMA(&huart1,(uint8_t *)UART_RX_BUF, UART_RX_STA & 0X7FFF);//配合上面的函数一起使用
// HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100); // 将接收到的数据发送回去
UART_RX_STA = 0; // 清除标记
}
————————————————
本文为Perseverance52博主原创文章,未经博主允许,不得转载!
原文链接:https://blog.csdn.net/weixin_42880082/article/details/143470897
|