个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。- V: k6 d% s; s) t 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道(我就是用有道划的)1 u/ f) B2 b' }9 o: D. N C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。8 L0 q# A4 w: g) c( ?# @2 v 进入正题:UART以DMA方式接收和发送的函数调用顺序:: d. p3 L9 j& a; h0 p7 P 循环模式接收: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)1 i% t4 ~" I8 i3 H 当然这当中还会调用传输 Half 中断,这里就不讨论了。 ! ?6 }) a5 t5 w' v 正常模式发送: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) ' H' ~' Y4 s3 F. V) Y 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:! O% D# \* T5 F( `; _) v HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) UART以DMA方式接收指定长度数据到指定缓冲区% s' a: Q* H' I5 |7 z {9 Z0 D; ^/ k2 @' r" {! e uint32_t *tmp;" n, P; R. B9 F5 ^1 J% c 2 \4 k3 S/ D4 D+ X+ T+ m- Y5 g9 c /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。 {6 z7 z7 t& F& v8 N if((pData == NULL) || (Size == 0U)) { return HAL_ERROR;* U$ H2 _: l6 y r }; v m4 h2 S0 m0 Y * _( }3 h0 e& q /* Process Locked */ __HAL_LOCK(huart); & h" J' w. t. ?0 V9 ` huart->pRxBuffPtr = pData; huart->RxXferSize = Size;" B2 C/ C" o- k: E4 u " ~7 f3 ]! ?" _ {1 q* X! P huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX;6 z7 _: [% h. _9 r: ?+ D( q5 o /* Set the UART DMA transfer complete callback */ huart->hdmarx->XferCpltCallback = UART_DMAReceiveCplt; 设置DMA传输完成的回调函数。当DMA以循环方式传输时会调用UART接收完成中断的回调函数;以Normal方式传输时会关闭UART的DMA通道,并使能UART传输完成中断,触发UART传输完成中断,设置huart->RxState为READY,并调用 UART接收完成中断的回调函数。所以,不管DMA按循环或正常模式传输,到最后都会调用UART接收完成中断的回调函数7 X O1 W( P) U: q8 ^) B /* Set the UART DMA Half transfer complete callback */$ v+ b- g3 T: R: p( _: d* K huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; ' D* v/ c0 A5 F3 c8 e /* Set the DMA error callback */ huart->hdmarx->XferErrorCallback = UART_DMAError;/ B9 ?3 ?9 D1 J+ z3 ]' i- o. F3 ` /* Set the DMA abort callback */ huart->hdmarx->XferAbortCallback = NULL;' B |" T! ]7 X, | 7 e' F1 ]& z6 @. b* L /* Enable the DMA channel */5 P# s' j. T0 N& h. } tmp = (uint32_t*)&pData;0 r$ i- l' }6 I! t# t0 q HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改0 q8 ]0 H. c# H2 O /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer *// r- V. S& g3 T7 N+ y& t3 d __HAL_UART_CLEAR_OREFLAG(huart);; O1 l1 [3 U+ l, M* t& G /* Process Unlocked */6 j ?$ C. u! @ __HAL_UNLOCK(huart);; \2 B5 o7 ^: D4 K& A/ q 1 \' _6 l0 @( v2 u /* Enable the UART Parity Error Interrupt */4 t0 ~* s8 l9 Y& x: @) q8 f( @6 P SET_BIT(huart->Instance->CR1, USART_CR1_PEIE); /* 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 - ?/ h2 X# \1 E* A1 y8 z) L) I in the UART CR3 register */; u$ B5 T9 o4 G6 N SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);" G, ~+ U' x! q+ P 7 c6 {- I# W$ T- T, s return HAL_OK;$ V# b C( o- S. o. I }. c8 ^' z( i1 m/ @5 A- w8 W else { return HAL_BUSY; } }9 L% ?" U# s6 ]! I. \4 S 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。4 B# o# }) R. Q' \ C* E 以上两点大家可以自己改改测试。 二、Keil例程编写 3 e2 m& E) o2 ? 三、测试* {. q( A, H c' F) L* V% ` 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。 最后,奉上测试工程: |
+ T8 k8 H. ?7 E o' d& [
" f2 y8 h4 z' G3 ? I1 W9 T0 ?$ v
"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