
个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。2 j9 }# A" @: e! U. ^ S) b 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道( ![]() C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。 进入正题:UART以DMA方式接收和发送的函数调用顺序:0 z/ K. R+ a8 ]: x2 \+ Q% X3 j 循环模式接收: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). |! @% D# B( k: v2 n0 y2 w 当然这当中还会调用传输 Half 中断,这里就不讨论了。 , m" |( [+ h! k3 p9 n$ ] 正常模式发送: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 的源码,其它的大家自己分析:- w! r" ^: P/ b# ? HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)/ Z' c4 ?" B( _7 w! [ UART以DMA方式接收指定长度数据到指定缓冲区 {3 G+ M9 R. c6 W0 I uint32_t *tmp;& F- C5 O& a# Z1 c& n( m. { # v: a# f( ~1 ` /* Check that a Rx process is not already ongoing */) p: F9 y6 z) b i: G% ] if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。 {7 i+ M, F; I3 X. Z$ ]) e/ k3 s if((pData == NULL) || (Size == 0U)) {% d! W( d: A" i. Z% k return HAL_ERROR;* I! ?* L7 ?4 t: z9 [ } + Y3 }, r0 q/ z- w6 L1 \7 x /* Process Locked */ __HAL_LOCK(huart);. e4 F$ G; { [& i5 J' m5 @( t7 i , o6 r( Z- z7 a3 k9 W: k# H huart->pRxBuffPtr = pData;6 C, _; P! f' E( x3 e" A6 [* C huart->RxXferSize = Size;) D T2 Q: w t5 n# ` Z ] + ]" B6 a# r. |1 L4 ^ huart->ErrorCode = HAL_UART_ERROR_NONE;6 f5 y: I% q# L huart->RxState = HAL_UART_STATE_BUSY_RX; /* Set the UART DMA transfer complete callback */3 ^4 q& N7 `" W* T0 T6 p' ^ huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用 UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数 /* Set the UART DMA Half transfer complete callback */ huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; /* Set the DMA error callback */' R: C/ V2 P6 K" q2 e Q+ v huart->hdmarx->XferErrorCallback = UART_DMAError;8 k5 {0 m2 U* E" J9 S& v /* Set the DMA abort callback */ huart->hdmarx->XferAbortCallback = NULL;9 Z7 m7 Q1 g* C9 x, d: i9 E 2 Y+ z+ j1 h; R% Q3 O. J4 F /* Enable the DMA channel */ tmp = (uint32_t*)&pData;. K+ _# |* w* C' ^. R4 e; A( y5 C HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改1 a: A/ O1 g y8 U) ~# p # U; `6 ~; l5 H /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */: t# c9 U( A8 b7 ]$ |$ t: ? __HAL_UART_CLEAR_OREFLAG(huart); " u) T- {! z3 E& W /* Process Unlocked */. e, V6 l/ }) E9 u5 ?: ~ __HAL_UNLOCK(huart); 9 @8 u- }2 ^, }7 N0 R* u /* Enable the UART Parity Error Interrupt */ SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);8 P% w3 ]$ [7 X /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */6 o8 q# j' V0 C: j7 N) a( J SET_BIT(huart->Instance->CR3, USART_CR3_EIE); ( u) E* @ S9 y" ^; q% b /* Enable the DMA transfer for the receiver request by setting the DMAR bit 1 b7 U, Q. I. F in the UART CR3 register */! U6 Q, s' {8 f, R1 Y SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);' L- m* s w3 C' @9 b8 ]4 N! t! ~/ r return HAL_OK; } else1 _4 r9 ]0 m& V) S1 b$ V) H7 Q" U {7 C* t0 H2 j/ j9 n* | return HAL_BUSY;: C& o$ t" O6 a+ _1 h6 L# y+ X }, b$ @ [/ Q% V( e, ~& L4 U } 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。7 l0 N, E" F, K) L" @8 R 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。 以上两点大家可以自己改改测试。 ![]() ![]() ![]() 5 m: T0 \' k9 ?/ G& x 二、Keil例程编写 ![]() ![]() ![]() 三、测试 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。 ![]() 2 @4 m% s2 R# H8 j+ X9 F2 N- g 最后,奉上测试工程: ![]() |
+ m; [* ]; g( u: {% f% G3 k
"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