stm32F1+HAL库+DMA+串口空闲中断
关于配置问题(F1的配置与F4的配置完全相同)
- DMA的设置 ,使用默认配置。注意接收数据的宽度统一,优先级可以不需要改变;
Memory的递增模式一定要配置。 - 串口设置 ,使用默认配置。注意与通信模块的波特率相同,注意使能串口中断;
- 其他设置 ,RCC的设置,根据单片机的外部晶振进行设置
(优先外部晶振,减小发生错误的概率);
关于代码问题(F1的代码与F4的代码相同)
F1的版本 main部分 存在问题版本
// An highlighted block
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_DMA_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
/* USER CODE END 2 */
while (1)
{
/* USER CODE END WHILE */
if(recv_end_flag ==1)
{
//printf("\nrx_len=%d\r\n",rx_len);
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);
for(uint8_t i=0;i<rx_len;i++)
rx_buffer[i]=0;
rx_len=0;
recv_end_flag=0;
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
}
}
/* USER CODE BEGIN 3 */
F1的版本 it部分 (存在问题版本)
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag = __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
if((tmp_flag != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
temp = huart1.Instance->SR;
temp = huart1.Instance->DR;
HAL_UART_DMAStop(&huart1);
temp = hdma_usart1_rx.Instance->CNDTR;
rx_len = BUFFER_SIZE - temp;
recv_end_flag = 1;
// printf("%s",rx_buffer);
// HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
F1的代码实验结果
串口发送:123123 接收:3(只接收最后一个发送的数据)
串口发送:3215 接收:5(只接收最后一个发送的数据)
1.只有正确收到发送数据的个数
所存在的问题:无法正确接收正确数据
错误原因
STM32 HAL库的DMA时钟配置跟串口,dma通道配置在两个文件里,结果先进行了串口配置,DMA通道配置,然后才是把DMA时钟打开了。导致DMA出现错误
根本原因:与cubemx的初始化顺序有关
具体相关链接:链接: https://blog.csdn.net/lutigers/article/details/103910090.
正确版本(main版本):
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
//HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
有人说main函数看起来好像没有意义?
可不可以把main函数的while(1)里面的部分进行省略,移植到串口中断函数里面?
根据建议修改后的版本:
修改版本+整合while(1)的内容(it文件):
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag = __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
if((tmp_flag != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
temp = huart1.Instance->SR;
temp = huart1.Instance->DR;
HAL_UART_DMAStop(&huart1);
temp = hdma_usart1_rx.Instance->CNDTR;
rx_len = BUFFER_SIZE - temp;
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);
for(uint8_t i=0;i<rx_len;i++)
{
rx_buffer[i]=0;
}
rx_len=0;
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
实践出真知,运行一下代码,会出现什么情况呢?
疯狂按串口助手的发送建?接收始终没有任何显示。
按下16进制显示,才发现无论我们像单片机发送什么,单片机始终只会回复0。
只有16进制显示下,才会显示。
分析目前的现象,按下发送键,有回复,回复为0.
有回复说明,串口空闲中断是正常运行的,但是回复不正常,说明是DMA又出现了问题
为什么会出现这样的错误?
flag_test =HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
(PS:在进行多次实验中,出现正确的代码也无法以运行的情况。解决办法:换个串口,插拔一下就可以了。)
我们利用标志位的返回值来判断,究竟是哪里出现了问题。
下次再写…
第一次写,希望大家见谅,写错的地方需要大家指正。。。。。。。