hal库 dma 中断发送接收过程(真心没有标准库好用)
dma中断定长发送本来很简单的一个问题让hal搞的头大,调来调去的,说好的彻底封装呢,确实很彻底啊,不废话了,实测之后说说的理解吧,不对的话请大佬指正。
hal_uart_transmit_dma如果配置好了dam,开启了通道,直接用这个函数。那么这个函数里面是个啥样的。
函数主体:
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
uint32_t *tmp;
/* Check that a Tx process is not already ongoing */
if(huart->gState == HAL_UART_STATE_READY)
{
if((pData == NULL ) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(huart);
huart->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size;
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Set the UART DMA transfer complete callback */
huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
/* Set the UART DMA Half transfer complete callback */
huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
/* Set the DMA error callback */
huart->hdmatx->XferErrorCallback = UART_DMAError;
/* Set the DMA abort callback */
huart->hdmatx->XferAbortCallback = NULL;
/* Enable the UART transmit DMA Stream */
tmp = (uint32_t*)&pData;
HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t*)tmp, (uint32_t)&huart->Instance->DR, Size);
/* Clear the TC flag in the SR register by writing 0 to it */
__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);
/* Process Unlocked */
__HAL_UNLOCK(huart);
/* Enable the DMA transfer for transmit request by setting the DMAT bit
in the UART CR3 register */
SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
除了相关的初始化外,只要的就是HAL_DMA_Start_IT,很熟悉吧,对了就是势能一次dma,然后__HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);清除一下串口接收完成标志(不知道如果开启了串口中断的话是个什么鬼情况,按道理应该是优先级的问题)再然后最后一步就是启动一次dma传输SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);据说hal库里面没有相关函数所有得用寄存器了。
当然在hal_dma_start_it里面是势能了所有接收/发送的相关句柄的中断情况的。
那么调用了hal_uart_transmit_dma,他的回调函数在哪里呢,我是真的让这个东西看哭了,看手册发现这个回调函数还是串口发送的回调函数 HAL_UART_Receive_DMA(&huart1,(uint8_t *)aRxMessage,10);
实测代码:
//stm32f1xx_it.c中的DMA中断句柄
void DMA1_Channel5_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel5_IRQn 0 */
/* USER CODE END DMA1_Channel5_IRQn 0 */
printf(“here DMA1_Channel5_IRQHandler”);
HAL_DMA_IRQHandler(&hdma_usart1_rx);//串口接收DMA通道
/* USER CODE BEGIN DMA1_Channel5_IRQn 1 */
/* USER CODE END DMA1_Channel5_IRQn 1 */
}
//在main.c中通过重载来处理DMA接收的数据
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
//printf("%c",aRxBuffer[ss]);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_UART_RxCpltCallback can be implemented in the user file
*/
for (i=0;i<100;i++){
printf("%c",aRxMessage[i]);
}
HAL_UART_Receive_DMA(&huart1,(uint8_t *)aRxMessage,10);
//HAL_UART_Transmit(&huart1, (uint8_t *)aRxBuffer, 10,0xFFFF);
}
/* USER CODE END 4 */
使用串口DMA接收数据,即使不使用“接收一半数据中断”,在接收一半数据后,也会触发相应的DMA通道中断句柄,全部数据接收完成后,又触发相应的DMA通道中断句柄,通过DMA通道中断句柄,而DMA中断句柄最终还是会调用串口接收中断回调函数,所以最终接收的数据可以通过重载串口接收中断回调函数来处理
在stm32f1xx_it.c中的与串口接收相关的DMA通道中断句柄函数,注意这个中断句柄与接收或发送相对应,也就是说发送和接收是2个不同DMA通道中断句柄。比如使用 HAL_UART_Receive_DMA(&huart1,(uint8_t *)aRxMessage,6) 在下面的代码中,我接收到3个数据就会触发printf(“here DMA1_Channel5_IRQHandler”) 接收到6个数据,又触发printf(“here DMA1_Channel5_IRQHandler”),同时这接收到的6个数据,通过重载串口接收中断回调函数来处理。(其实这整个流程就是调用HAL_UART_Receive_DMA函数后还是会回到标准库中找到DMA1_Channel5_IRQHandler相关流通道的中断函数,然后进入HAL_DMA_IRQHandler,这个是hal库中给的统一的dma中断处理函数,然后在里面判断是哪一种中断标志,然后调用相关的串口回调处理函数处理数据),hal库的好处就是我们省去了中间调来调去的过程,用户直接用串口回调函数就好了,对了记得最后如果还要继续调用一次HAL_UART_Receive_DMA继续接收,反正我是没有清除中断标志位的,不知道是不是清除串口中断就可以了,明天测试下发送。有问题的话可以在讨论下,反正我觉得没有标准库好用,可是stmcube好用啊!
上一篇: linux下创建用户和设置文件权限
下一篇: .dll调用