个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道(我就是用有道划的) ]4 C2 |1 P( R! X" d) C C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。: L! D C7 L" z6 l" M, {3 B 进入正题:UART以DMA方式接收和发送的函数调用顺序:- c# G8 ^3 g1 A% @. c' C( r 循环模式接收: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): |3 j# X8 \/ b4 z, o* |4 B( O 当然这当中还会调用传输 Half 中断,这里就不讨论了。 2 ?0 ]1 C5 Q3 V3 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) # q3 ~ [8 h) S/ Z; i9 h 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析: HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)$ h j y9 \7 \* i; W1 [3 q UART以DMA方式接收指定长度数据到指定缓冲区 { uint32_t *tmp; C, G" O$ V- l& P. Z- V- B, C B0 [1 H- Q1 ] /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。1 t- o- _) @) S) n Q: G! g4 k( l { if((pData == NULL) || (Size == 0U))% y7 \7 Q, p0 F, U) \0 { { return HAL_ERROR; }6 R8 e5 Q& ]9 \) ? : L% R& ]! T$ M$ x7 R, u /* Process Locked */ __HAL_LOCK(huart); . P \0 c& t; V2 q2 S, E huart->pRxBuffPtr = pData; huart->RxXferSize = Size;" S6 B7 k6 Y/ x. P2 p0 p3 ? huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX;& r( A. r! c9 ~( F /* Set the UART DMA transfer complete callback */( v, G2 h1 I. ^9 p. X huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用/ T4 b0 Q. t7 I UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数 /* Set the UART DMA Half transfer complete callback */ huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; /* Set the DMA error callback */. O" o, U! Z {+ {4 l huart->hdmarx->XferErrorCallback = UART_DMAError;' J* j; o' U" q /* Set the DMA abort callback */ huart->hdmarx->XferAbortCallback = NULL; /* Enable the DMA channel */ tmp = (uint32_t*)&pData;: z& S- N8 L1 {5 C 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 *// c# r; g N% S# V __HAL_UART_CLEAR_OREFLAG(huart); /* Process Unlocked */ __HAL_UNLOCK(huart);# K5 O% H0 x/ v8 B) u$ A8 C /* Enable the UART Parity Error Interrupt */% S0 z0 a- C: _* b SET_BIT(huart->Instance->CR1, USART_CR1_PEIE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */$ g* C" J2 `7 p' U SET_BIT(huart->Instance->CR3, USART_CR3_EIE);0 o2 }" F" p5 Z4 H8 I ( d" S U' T- U0 y4 v% ] /* Enable the DMA transfer for the receiver request by setting the DMAR bit / ?' Q# ]/ Q5 ?7 E/ H" p# ~ in the UART CR3 register */ SET_BIT(huart->Instance->CR3, USART_CR3_DMAR); s! t" D* ^& x0 K; _ return HAL_OK;. Z( v. t' I, c& T5 S }- d7 N( `5 h5 V' m/ n7 V& ? else: ]6 ~$ Z( p+ A { return HAL_BUSY;) b( _7 b% l7 }: |" q1 P }8 c5 n, z) }: u. j. D/ ?& J9 r) Z }: U8 ?- ? Z8 m" Y 下面上我做的测试:一、Cube配置4 [% s1 h( z; w" j# T 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。( D z' x9 U8 m- g0 V# [- | \# s 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。; j8 y9 k7 J a2 P 以上两点大家可以自己改改测试。7 U2 G+ k9 H$ \" i' V/ m' S 7 a! d% k% b" l" c$ b 二、Keil例程编写 三、测试/ J8 W: m' t( S" j: ^( y) i 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。1 K4 s5 c# E$ J2 {5 A4 ? , O$ N8 |7 h p' E 最后,奉上测试工程: |
`$ A1 f9 }2 \! ?
7 ?0 P0 w6 [2 H1 t2 Y# F& H; ~- s; S
"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