为什么使用HAL_UART_Receive不能持续接收到数据?
我是接收GPS模组的数据,可以确认GPS模组那边是一直有数据输出的。我的UART初始化函数如下:
static void MX_LPUART1_UART_Init(void)
{
Lpuart1.Instance = LPUART1;
Lpuart1.Init.BaudRate = 9600;
Lpuart1.Init.WordLength = UART_WORDLENGTH_8B;
Lpuart1.Init.StopBits = UART_STOPBITS_1;
Lpuart1.Init.Parity = UART_PARITY_NONE;
Lpuart1.Init.Mode = UART_MODE_TX_RX;
Lpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
Lpuart1.Init.OverSampling = UART_OVERSAMPLING_16;
Lpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
Lpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&Lpuart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
然后就循环调用下面的语句接收,结果总是只能接收一次,之后就一直返回Timeout,应该RXNE一直为零,不知为何?请高手指教,多谢!
HAL_UART_Receive(&Lpuart1, DataBuf, DataLen, 10000);
13 个回复
江浩生
赞同来自: Yeinestim
接受完一次,中断后调用的函数会把RXNEIE清零,关掉中断。要重新初始化
shine2018
赞同来自: Yeinestim
多谢,重新初始化是要调哪些函数,从HAL_UART_Init全部执行一遍?
还是说__HAL_UART_ENABLE就可以了?
我看RXNEIE是在HAL_UART_Receive_IT设置的,我又不需要中断传输,不能调啊
江浩生
赞同来自:
抱歉,你使用的是Polling方式吧?我用STM32L053R8 NUCLEO板子,用其固件库的例程ComPolling例子,串口模拟GPS数据发送不断往USART1发送数据,并不会出现你说的会返回timeout,除非停止发送。
而且就第一次可以的情况看,RXNE的置1和清零的情况是正常的。会不会是其他问题。如果可以贴上更完整的HAL_UART_Receive(&Lpuart1, DataBuf, DataLen, 10000);程序源码来分析会更好。
shine2018
赞同来自:
非常感谢您的帮助,我考虑到效率问题,还成了DMA方式,代码如下。结果总是无法收到任何数据,不知道问题出在哪里,帮忙看看~~
int main(void)
{
MX_GPIO_Init();
MX_DMA_Init();
MX_LPUART1_UART_Init();
HAL_UART_Receive_DMA(&Lpuart1,DataBuf,32);
}
static void MX_LPUART1_UART_Init(void)
{
Lpuart1.Instance = LPUART1;
Lpuart1.Init.BaudRate = 9600;
Lpuart1.Init.WordLength = UART_WORDLENGTH_8B;
Lpuart1.Init.StopBits = UART_STOPBITS_1;
Lpuart1.Init.Parity = UART_PARITY_NONE;
Lpuart1.Init.Mode = UART_MODE_TX_RX;
Lpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
Lpuart1.Init.OverSampling = UART_OVERSAMPLING_16;
Lpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
Lpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&Lpuart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
printf("enter rx callback\r\n");
if(huart->Instance == LPUART1)
{
HAL_UART_Receive_DMA(&Lpuart1,DataBuf,512);
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(huart->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspInit 0 */
/* USER CODE END USART2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART2_MspInit 1 */
/* USER CODE END USART2_MspInit 1 */
} else if(huart->Instance==LPUART1)
{
/* USER CODE BEGIN LPUART1_MspInit 0 */
/* USER CODE END LPUART1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_LPUART1_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> LPUART1_TX
PA3 ------> LPUART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_LPUART1;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
hdma_lpuart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_lpuart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_lpuart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_lpuart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_lpuart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_lpuart1_rx.Init.Mode = DMA_NORMAL;
hdma_lpuart1_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_lpuart1_rx.Init.Request = DMA_REQUEST_5;
hdma_lpuart1_rx.Instance = DMA1_Channel3;
if (HAL_DMA_Init(&hdma_lpuart1_rx) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(huart, hdmarx, hdma_lpuart1_rx);
__HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);
HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(LPUART1_IRQn);
printf("LPUART1 init\r\n");
/* USER CODE BEGIN LPUART1_MspInit 1 */
/* USER CODE END LPUART1_MspInit 1 */
}
}
void RNG_LPUART1_IRQHandler(void)
{
UART_IDLE_Callback(&Lpuart1);
HAL_UART_IRQHandler(&Lpuart1);
}
void DMA1_Channel2_3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_lpuart1_rx);
}
江浩生
赞同来自:
说些无关的东西
我也是刚接触STM32串口收发不就,DMA方式不熟,抱歉。
功能你是自己全部重新写的吗?有没有成功的实现功能,就是相应的收发功能,集成到接收GPS数据之前。如果没有成功就集成进来,自然有很多问题。而且之前的没有通过DMA的都没有实现,添加新的模块也会有问题,之前我也尝试过使用DMA,但是因为还没有完全理解而增加了问题,所以最近都是用IT中断来实现。
粗略观察你的主函数,竟然初始化完就结束了
一般至少在最后面加一个死循环吧
其实你发的代码还有一些地方不清楚的,比如printf是输出到串口的重新定义的函数吗?
一天下来,才解决了用IT方式,实现单个字节的收发。如果不是自己的代码,找起来更是难上加难,因此如果能够做当清晰地提问,提供必要的内容,会好得多。
拙见
chaojie
赞同来自: 月夜叉-yaksa
试试把cubemx的串口中断中断勾上
shine2018
赞同来自:
@chaojie把串口中断给打开后确实就好了,多谢指点。
现在又遇到相同的问题,DMA只进了一次中断,在中断中也调用了HAL_UART_Receive_DMA()函数,HAL这种函数是不是都需要自己在中断函数中再次打开DMA中断啊?
chaojie
赞同来自: 月夜叉-yaksa
cubemx里把dma设置成循环接收
shine2018
赞同来自:
谢谢大家,我通过增加了IDLE IRQ的方式实现了这个功能。RXNE IQR + IDLE IRQ + DMA结合起来,效果不错。
Blue Romance
赞同来自:
我是这样去接收的,暂时没用到DMA,因为数据量不大
HAL_UART_Receive( &huart1 , DEBUG_UART_RXBuffer , 1 , 10 );//因为我用的ESP8266,上电会有乱码,所以先接收掉当前的DR寄存器内的数据
__HAL_UART_ENABLE_IT( &huart1 , UART_IT_RXNE ); //下一次RXNE触发的时候,就是开始接收数据的时候,会触发中断
//USART1中断处理
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
UART_IRQHandler_EX( &huart1 );
}
//自己写的串口中断处理函数
void UART_IRQHandler_EX( UART_HandleTypeDef * huart )
{
if( __HAL_UART_GET_FLAG( huart , UART_FLAG_RXNE ) == SET ) //如果是RXNE触发的中断
{
__HAL_UART_DISABLE_IT( huart , UART_IT_RXNE ); //暂时关闭RXNE中断
UART_RXNECallback( huart ); //调用RXNE回调函数
}
//RXNE回调函数
void UART_RXNECallback( UART_HandleTypeDef * huart )
{
if( huart == &huart1 ) //如果是串口1触发的RXNE回调函数
{
HAL_UART_Receive( &huart1 , DEBUG_UART_RXBuffer , 100 , 20 );
//触发这个中断是因为接收到了一个字节数据,那么应该继续接收,接收量为100是因为接收的一帧数据不可能超过100,这个根据实际情况。
//直到超时20ms,此次接收结束,DEBUG_UART_RXBuffer 中存放的就是一帧的数据了
//当然如果下一次接收的数据短了些,这一次接收的数据的多出来的部分还是会留在那里,需要去清除掉,我用memset发现不能给数组的第2个元素赋值,头都大了...
__HAL_UART_ENABLE_IT( &Debug_Uart , UART_IT_RXNE ); //重新打开RXNE中断,准备接收下一帧数据
}
}
ZMCX
赞同来自:
串口发送一帧数据下来 我用HAL_UART_Receive先接收第一个数据 再用HAL_UART_Receive接收剩下的数据 接收不到 这是为什么?
周星星
赞同来自:
我也用cube lpuart 一直卡死在 __HAL_UART_ENABLE_IT(&hlpuart1, UART_IT_IDLE);这是为什么?
hongsenlin8
赞同来自:
竟然解决了,使用函数SCB_InvalidateDCache_by_Addr做接收缓冲区无效化。参考硬汉哥的一段代码,他是解决DMA收发问题,竟然同样适用于非dma的连续接收
if(g_ucRecieveFlag == 1)
{
g_ucRecieveFlag = 0;
bsp_LedToggle(3);
/* 设置新的接收,并将接收到发送回去 */
/* CPU访问前,将Cache对应的区域无效化 */
SCB_InvalidateDCache_by_Addr ((uint32_t *)aRxBuffer, 5);
HAL_UART_Transmit_DMA(&UartHandle, aRxBuffer, 5);
HAL_UART_Receive_DMA(&UartHandle, aRxBuffer, 5);
}