个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道(我就是用有道划的) C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。4 W+ n9 h- F! `3 ~, O 进入正题:UART以DMA方式接收和发送的函数调用顺序: 循环模式接收:HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)==》DMA1_Channelx_IRQHandler(void)==》HAL_DMA_IRQHandler(&hdma_usartx_rx)==》UART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)==》HAL_UART_RxCpltCallback(huart) 当然这当中还会调用传输 Half 中断,这里就不讨论了。 ( k: _8 O; d$ J1 Y% T3 w 正常模式发送:HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)==》DMA1_Channelx_IRQHandler(void)==》HAL_DMA_IRQHandler(&hdma_usartx_tx)==》UART_DMATransmitCplt(DMA_HandleTypeDef *hdma)==》USART3_IRQHandler(void)==》HAL_UART_IRQHandler(&huart3)==》UART_EndTransmit_IT(huart)==》HAL_UART_RxCpltCallback(huart)1 `9 C$ D/ o& j 0 X4 Z: s1 P* J, o: r; U1 [ 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:7 l2 U m. A5 k. R' X1 ^4 H HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) UART以DMA方式接收指定长度数据到指定缓冲区 { uint32_t *tmp;. w/ o& {! K2 o /* Check that a Rx process is not already ongoing *// P3 e& k1 w3 D if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。- d6 C2 I5 R" Z x c { if((pData == NULL) || (Size == 0U))8 c5 P. g F" E! q' A3 W5 q { return HAL_ERROR; }& ^5 ~! J8 O+ ] /* Process Locked */ __HAL_LOCK(huart); # b. @- l: `, ]9 \; y2 W4 | huart->pRxBuffPtr = pData; huart->RxXferSize = Size; huart->ErrorCode = HAL_UART_ERROR_NONE;8 K1 `" R$ c+ T3 @+ O& D huart->RxState = HAL_UART_STATE_BUSY_RX;6 C* a7 k* S& b" c# G /* Set the UART DMA transfer complete callback */6 p/ w9 c2 e" d4 l% |0 b3 a( n7 _1 p huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用, @. [1 O8 C* K UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数5 t8 l4 s; P6 u; r0 s& D. \ /* Set the UART DMA Half transfer complete callback */ huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;9 S" f" B% s$ A 7 `/ _) j- X7 P /* Set the DMA error callback */ huart->hdmarx->XferErrorCallback = UART_DMAError; - ^2 W# E+ r3 N3 u" q; D /* Set the DMA abort callback */6 \( m# z- o" B4 {* M# `/ P$ p huart->hdmarx->XferAbortCallback = NULL;' L5 ~7 {( I- I; K7 J$ q 7 u. S: s5 Z x9 P /* Enable the DMA channel */ tmp = (uint32_t*)&pData;% Y! m) |) P" f. n" l U# ] HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改# T! S; Z2 T2 N+ l V0 x+ }) ~ /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */) W$ t, O m! u+ F) C5 x2 W. \ __HAL_UART_CLEAR_OREFLAG(huart); ) G" }5 S9 s- |$ t2 l /* Process Unlocked */ __HAL_UNLOCK(huart);' v, O- M# I3 I8 ]4 r /* Enable the UART Parity Error Interrupt */ SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);/ E3 A4 q# n$ f6 T2 i /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ SET_BIT(huart->Instance->CR3, USART_CR3_EIE); /* Enable the DMA transfer for the receiver request by setting the DMAR bit in the UART CR3 register */ SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);$ p9 j: l. V6 z/ c8 r& Q $ _9 r3 a. N. ]. z# F7 X0 @9 V9 ~' N return HAL_OK;; q7 \+ q0 Y( n } else4 z. R- S, D6 ~1 a1 ^, J; O$ S { return HAL_BUSY; }) H6 `: ` T% c5 @0 u1 _ }7 f, @- C& b# n6 L 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。* t3 R( W* Z# g9 ` 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。1 f; d ?( K; {) l 以上两点大家可以自己改改测试。 , B u+ l4 t$ N0 c8 v0 H: { 二、Keil例程编写 , h" V) l% C- C% L9 A- _ 三、测试 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。 最后,奉上测试工程: |
- f+ W! {! ^: @' z) C w( _; x
' X; c, J6 @8 F: s( M
"no source": Error: #5: cannot open source input file "C:/Users/Administrator/STM32Cube/Repository/STM32Cube_FW_F1_V1.6.0/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c": No such file or directory
https://www.stmcu.org.cn/module/forum/thread-614550-1-1.html