采用STM32cube完成ADC的DMA功能 STM32F051C8T6 STM32CubeMX ADC-DMA-UART教程 一直困惑怎么在Cube上实现串口+DMA+空闲中断接收不定长数据。 使用下来发现Cube好的地方就是你按照图形画方式配置后会帮你省掉很多初始化的工作。但是从标准库走过来略有点别扭,可能用用就习惯了。 想把这几天搞的跟大家聊聊,有不对的地方请指正啊。同时感谢网友baifernlover对本菜的指导。 USART1+DMA配置如下图: 串å£1-DMAæ¥æ¶ 生成工程后,在主函数里添加:
中断函数里面:
之前看到帖子说HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)和HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)接收需要指定接收Size长度值,但是这两个函数的Size有所区别。 HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)主要做了两件事: 1. huart->pRxBuffPtr = pData; /*!< Pointer to UART Rx transfer Buffer */ huart->RxXferSize = Size; /*!< UART Rx Transfer size */ 这个赋值好像没什么用 huart->RxXferCount = Size; /*!< UART Rx Transfer Counter */ 2.使能中断 /* Enable the UART Data Register not empty Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); 在中断处理函数中,去判断中断标志位;然后再根据相应的中断标志位去处理: tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE); tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE); /* UART in mode Receiver ---------------------------------------------------*/ if((tmp1 != RESET) && (tmp2 != RESET)) { UART_Receive_IT(huart); } UART_Receive_IT函数里感觉做了两件事: 1.*huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF); //存数据 2.if(--huart->RxXferCount == 0) //之前赋值的 huart->RxXferCount = Size; { __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE); //最后一个数据接收完了就关闭中断 } HAL_UART_RxCpltCallback(huart); //调用接收完成回调函数 整个过程中,来一个数据,huart->RxXferCount做一次减法,直到等于0,去调用回调函数。 HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)中: 1. HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);---> 2.DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);这里的DataLength就是之前的Size吧----> 3. /* Configure DMA Stream data length */ hdma->Instance->NDTR = DataLength; 对NDTR寄存器描述:This register can be written only when the stream is disabled. When the stream is enabled, this register is read-only, indicating the remaining data items to be transmitted. This register decrements after each DMA transfer. 这里的定义的Size赋给了DMA_SxNDTR。使能之后,只能读取,表示还有多少字节需要被“传送”。所以空闲中断里面 temp = hdma_usart1_rx.Instance->NDTR; //读取还没有被传送的个数 rx_len = BUFFER_SIZE - temp; //DMA缓存大小减去没有被传送的个数,就等于已经被传送的个数,也就是接收到的个数。 先这样子理解了。所以感觉如果是DMA接收,即使外部过来的数据个数不等于设定的Size,那么数据也还是被接收到了指定的buffer中。 DMA中断处理函数HAL_DMA_IRQHandler里面会判断DMA传输的状态,完了去调用各自的回调函数。比如传输完成的话会去调用UART_DMAReceiveCplt()--->HAL_UART_RxCpltCallback(huart);最后还是调用了HAL_UART_RxCpltCallback(huart)函数。 最后附上工程文件,欢迎大家多多讨论。 |
STM32_USART_DMA_IDLE.rar
下载6.17 MB, 下载次数: 19826, 下载积分: ST金币 -1
Cube_USART_DMA_IDLE
我觉得大家把这个路走歪了点,
__HAL_DMA_DISABLE_IT(huart1.hdmarx, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE);//关闭DMA 错误 传输一半 全部完成 中断
这里如果将DMA配置成一锤子买卖,肯定会丢东西。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
不如将DMA配置成Circular模式,不要停止DMA,另外开启
DMA缓冲区可以设置为256字节,这样缓冲区读指针可以采用基地址+一个UINT8偏移实现,UINT8自动溢出循环256。
HAL_UART_Receive_DMA(&huart1, RX_DATA, RX_DATA_NUM);
__HAL_DMA_DISABLE_IT(huart1.hdmarx, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE);//关闭DMA 错误 传输一半 全部完成 中断
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能 串口 空闲中断
HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn); //使能中断
void USART1_IRQHandler(void)
{
if((__HAL_DMA_GET_COUNTER(huart1.hdmarx) + RX_DATA[3]) == (RX_DATA_NUM - 6))
{
Flag_RX = 1;
}
__HAL_UART_CLEAR_IT(&huart1, UART_CLEAR_IDLEF);
__HAL_DMA_DISABLE(huart1.hdmarx);
huart1.hdmarx->Instance->CNDTR = RX_DATA_NUM;
__HAL_DMA_ENABLE(huart1.hdmarx); //DMA接收数据 必须在 DMA 禁止 时 重新写入
}
按HAL的回调方式写,是指在HAL_UART_IRQHandler()中添加
tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE);
tmp2 = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_IDLE);
/* UART in mode Receiver ---------------------------------------------------*/
if((tmp1 != RESET) && (tmp2 != RESET))
{
UART_XXX_IT(huart);
}
这个意思吗?
还有我在while(1)里面一直HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);这样子会不会有额外的开销。这里一点我有点不确定,在while一直这样调用会不会有问题。