首先定义一些变量
uint8_t rx_len=0;
uint8_t recv_end_flag=0;
uint8_t rx_buffer[200];
然后在串口初始化之后添加IDLE中断相关函数
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//开启IDLE中断
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)==RESET)
{}
HAL_UART_Receive_DMA(&huart1,rx_buffer,200);//开启DMA接收
recv_end_flag=0;
串口中断函数
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 = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_DMAStop(&huart1);
rx_len = 200 - temp;
recv_end_flag = 1;
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
串口中断函数中,清除中断,获取接收到的长度,置接收完成标志recv_end_flag=1
while函数中判断recv_end_flag进行处理
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(recv_end_flag ==1)
{
printf("接收到的数据长度为%drn",rx_len);
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);//将接收到的数据发送出去
for(uint8_t i=0;i
{
rx_buffer
=0;//清空
}
rx_len=0;//清0
recv_end_flag=0;//清0
HAL_UART_Receive_DMA(&huart1,rx_buffer,200);
}
}
以上完成了串口IDLE+DMA接收不定长数据
但是实际调试中发现一个问题,串口初始化完毕,使能IDLE中断,开启DMA接收,会产生一次IDLE中断,程序会进入中断处理函数,置位recv_end_flag,进入while后便会串口打印出:接收到的数据长度为0,
就是说初始化过程之后,会进入一次IDLE中断,在网上看到一篇类似文章找出了解决办法
http://news.eeworld.com.cn/mcu/2015/1029/article_23375.html
就是说UART会发送一个空闲帧,猜想初始化进入IDLE中断也许与此类似
便添加了
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)==RESET)
{}
或者使用延时函数进行一段延时也可以
等待IDLE标志位清0,不过,依然会进入中断,后面需要将recv_end_flag=0,这样程序可以正常的接收不定长数据,不会出现上电复位,第一次就打印接收数据长度为0。
(解决办法是:这样还是会进中断,通过recv_end_flag=0,解决第一次打印问题)
另外接收不定长数据页可以使用定时器进行不定长接收
大概流程是:串口接收到数据后,开启定时器,将接收到的数据存储起来,定时器大概定3ms左右的定时,每次进入串口中断,定时器清0 ,当完成一帧接收,不再进入中断,定时器产生中断,然后置flag值,while函数判断flag值执行相关操作(之前使用STM8弄过一次)
在使用SMT32F103和STM32F412过程中没有出现过上电复位就进入IDLE中断的现象。(猜测STM32H750_400M频率,SMT32F103_72M,H750代码执行的更快,使用__HAL_UART_GET_FLAG获取IDLE的状态,H750会出现1,而F103没有,猜测要么可能与HAL底层的库的问题,要么可能与硬件威廉希尔官方网站
有关,或者就是与空闲帧有关)
或者应该在接收之后打开空闲中断,具体没去试过。
MY_QuinTA的笔记
首先定义一些变量
uint8_t rx_len=0;
uint8_t recv_end_flag=0;
uint8_t rx_buffer[200];
然后在串口初始化之后添加IDLE中断相关函数
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//开启IDLE中断
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)==RESET)
{}
HAL_UART_Receive_DMA(&huart1,rx_buffer,200);//开启DMA接收
recv_end_flag=0;
串口中断函数
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 = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
HAL_UART_DMAStop(&huart1);
rx_len = 200 - temp;
recv_end_flag = 1;
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
串口中断函数中,清除中断,获取接收到的长度,置接收完成标志recv_end_flag=1
while函数中判断recv_end_flag进行处理
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(recv_end_flag ==1)
{
printf("接收到的数据长度为%drn",rx_len);
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);//将接收到的数据发送出去
for(uint8_t i=0;i
{
rx_buffer
=0;//清空
}
rx_len=0;//清0
recv_end_flag=0;//清0
HAL_UART_Receive_DMA(&huart1,rx_buffer,200);
}
}
以上完成了串口IDLE+DMA接收不定长数据
但是实际调试中发现一个问题,串口初始化完毕,使能IDLE中断,开启DMA接收,会产生一次IDLE中断,程序会进入中断处理函数,置位recv_end_flag,进入while后便会串口打印出:接收到的数据长度为0,
就是说初始化过程之后,会进入一次IDLE中断,在网上看到一篇类似文章找出了解决办法
http://news.eeworld.com.cn/mcu/2015/1029/article_23375.html
就是说UART会发送一个空闲帧,猜想初始化进入IDLE中断也许与此类似
便添加了
while(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)==RESET)
{}
或者使用延时函数进行一段延时也可以
等待IDLE标志位清0,不过,依然会进入中断,后面需要将recv_end_flag=0,这样程序可以正常的接收不定长数据,不会出现上电复位,第一次就打印接收数据长度为0。
(解决办法是:这样还是会进中断,通过recv_end_flag=0,解决第一次打印问题)
另外接收不定长数据页可以使用定时器进行不定长接收
大概流程是:串口接收到数据后,开启定时器,将接收到的数据存储起来,定时器大概定3ms左右的定时,每次进入串口中断,定时器清0 ,当完成一帧接收,不再进入中断,定时器产生中断,然后置flag值,while函数判断flag值执行相关操作(之前使用STM8弄过一次)
在使用SMT32F103和STM32F412过程中没有出现过上电复位就进入IDLE中断的现象。(猜测STM32H750_400M频率,SMT32F103_72M,H750代码执行的更快,使用__HAL_UART_GET_FLAG获取IDLE的状态,H750会出现1,而F103没有,猜测要么可能与HAL底层的库的问题,要么可能与硬件威廉希尔官方网站
有关,或者就是与空闲帧有关)
或者应该在接收之后打开空闲中断,具体没去试过。
MY_QuinTA的笔记
举报