个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。$ L7 `6 c! N" r3 v7 R9 v 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道(我就是用有道划的) C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。$ f6 [2 C0 p. k4 J3 q& N0 ^ 鄙人浅见,请大家不吝赐教。 进入正题:UART以DMA方式接收和发送的函数调用顺序:, [- S$ ]% t. B; z4 s9 k3 `. W 循环模式接收: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 中断,这里就不讨论了。 [! Q) U2 M1 x9 t( Y 正常模式发送: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) 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:5 l2 f2 m+ k- J* r* g7 T8 _ HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)( ?& ], K" Q1 d- ?* j- { UART以DMA方式接收指定长度数据到指定缓冲区1 a8 b) n2 E+ q4 z- u4 [* V5 G {1 A9 a; v+ {% [4 d! l: E" W uint32_t *tmp; /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。 { if((pData == NULL) || (Size == 0U)) {4 U: g& }/ O& x: w4 P3 t* B return HAL_ERROR;& G& a6 o) L- E; u; v: i- i/ j } /* Process Locked */ __HAL_LOCK(huart);" S* l e6 O1 Y' \' j' j 4 I$ |; p4 v$ `! l: ]- i0 l. c huart->pRxBuffPtr = pData;/ E( k+ a$ C1 X0 S6 k7 d huart->RxXferSize = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX;! R$ B- `1 }/ h7 q6 o, y0 }/ h - @" V# `; l1 R5 v- }. t /* Set the UART DMA transfer complete callback */0 W! ~2 Y. M, I/ ]1 d1 s huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用 UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数! p' c$ `7 p5 Z7 J5 L& k( ? /* Set the UART DMA Half transfer complete callback */6 J$ F9 }& t5 D4 M2 P4 P huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt;5 Q0 p! x, t' ]5 i% M( {' U: \( S /* Set the DMA error callback */& Y$ r1 x9 O( U+ b5 c6 H/ S" \ huart->hdmarx->XferErrorCallback = UART_DMAError;! T: `8 `+ `' f# f% K /* Set the DMA abort callback */. H& Y/ ~& X" I* J huart->hdmarx->XferAbortCallback = NULL;" ~5 y" |3 K/ O, J$ R0 m G; M8 e4 n9 u- E$ v- K1 L /* Enable the DMA channel */ tmp = (uint32_t*)&pData;/ ?, v g6 ^& ?8 A9 b HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改 /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */ __HAL_UART_CLEAR_OREFLAG(huart);9 O/ @, G* o7 C8 L8 C$ I8 C5 A /* Process Unlocked */ __HAL_UNLOCK(huart);6 b8 B# \; {; K. g' G 6 J5 v ]: L' N4 x, p /* Enable the UART Parity Error Interrupt */ SET_BIT(huart->Instance->CR1, USART_CR1_PEIE); 5 l- y; j0 x$ y% P! V7 u1 y /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ SET_BIT(huart->Instance->CR3, USART_CR3_EIE); j5 ]! }( i7 L1 z$ Z! N5 X# I /* Enable the DMA transfer for the receiver request by setting the DMAR bit in the UART CR3 register */ I" O% S; [ i# T' G9 \* u SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);( Z [" I* x3 v/ @3 I5 P6 W return HAL_OK;9 N; E ~% h4 f } else {/ a! ?, J( b! \8 Q' [* L1 t- U return HAL_BUSY;9 d) g' K K; w* A. t" W- x } }9 {: T$ T4 [: t. a) B3 P- U' _0 I* G 下面上我做的测试:一、Cube配置. Z, t; @- d& T/ w( }3 C+ K A 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。8 [% l( Z! m* o5 f& l% o 以上两点大家可以自己改改测试。 二、Keil例程编写 2 L l& m# K! @3 d6 z- m; w 三、测试# ~& K( p! @2 h! E4 o! ]& { 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。; a& q; O5 k9 O1 `7 c6 j p 7 M9 \. U; A w$ n) M+ a 最后,奉上测试工程: |
"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