
个人感觉,做嵌入式,底层就是datasheet,顶层就是数理逻辑。% f2 C8 j8 V# `' w6 l# N 不管什么芯片,当我们遇到问题时,通过查阅datasheet或上官网基本上都能找到解决方法。然而,这些基本都是英文。所以,英文好对做研发是有很大益处的。不过好在有翻译工具,如:有道( ![]() C语言虽然没有class,但有struct。我们可以多用struct。ST库和ucos中就包含许多struct。 程序结构多用状态机或switch。个人感觉,状态机看起来很有条理,很清晰,后期修改维护也方便。 鄙人浅见,请大家不吝赐教。 进入正题: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)7 w! Z0 A7 h! E. M" {# | 当然这当中还会调用传输 Half 中断,这里就不讨论了。 ' C u8 F( [8 x2 R. e- h% u; D 正常模式发送: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)- j8 `5 S4 M( S+ O 4 C L( \5 Z% _4 g2 Y 这里只分析 HAL_UART_Receive_DMA 的源码,其它的大家自己分析:. F$ _( M# a0 h) ]$ p% Y3 P HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) UART以DMA方式接收指定长度数据到指定缓冲区 {! J6 h' i8 k: P6 {1 \- F# d# e uint32_t *tmp; /* Check that a Rx process is not already ongoing */+ W/ X; d4 l1 G' t" a if(huart->RxState == HAL_UART_STATE_READY) 检查huart->RxState是否处于 接收空闲 状态。当这一状态标志非READY时,会跳过DMA接收参数设置,直接返回HAL_BUSY。其它的UART接收函数也会检查这个状态,所以,哪个先调用就执行哪个。 {8 d- n, O; \+ D4 D8 t. Y7 O if((pData == NULL) || (Size == 0U)) {5 I4 R5 e/ T4 t! _+ s2 s return HAL_ERROR; \' A( h9 B. f6 F }0 s5 m. O: _0 u1 ^/ p6 V1 } 8 x B8 Z' R; d% \ h& O6 O/ q /* Process Locked */# v, F3 [7 `0 |8 u- R# p- l __HAL_LOCK(huart); s) A. `# X# z2 ^/ R; k4 S huart->pRxBuffPtr = pData; f4 K- j; s& s) ^. m huart->RxXferSize = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX; 3 x# v. F; o# Z. E /* 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接收完成中断的回调函数 /* Set the UART DMA Half transfer complete callback */' s# ^/ |2 \+ B3 h huart->hdmarx->XferHalfCpltCallback = UART_DMARxHalfCplt; & }9 Y( Y, T' O, r0 A /* Set the DMA error callback */ huart->hdmarx->XferErrorCallback = UART_DMAError;# j/ p! r* R) y/ A' }# e /* Set the DMA abort callback */ huart->hdmarx->XferAbortCallback = NULL;) [; R w+ B/ ~% c9 V7 M /* Enable the DMA channel */4 [2 p9 A, B! B' ~, h1 i tmp = (uint32_t*)&pData;3 Z3 a8 j* e9 M6 H( Z) a4 _, a' S HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t*)tmp, Size);以中断方式打开DMA传输。所以CubeMx中DMA中断默认是打开的切不可更改. S8 n3 ]9 L8 ~, X3 W* ? $ p; m; }2 M+ e /* Clear the Overrun flag just before enabling the DMA Rx request: can be mandatory for the second transfer */4 o6 N( h6 v& Y V' e+ O4 R0 F. q __HAL_UART_CLEAR_OREFLAG(huart); ' w& ~; b9 F7 t4 O9 u6 J7 I: {; M) U /* Process Unlocked */. O) {7 B# D! U3 l; V! r __HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */ 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);5 [# Q4 ^" F# w m7 G7 | 6 x! G# z! F( R+ q+ l9 H /* 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);, j4 Q6 I8 X4 w return HAL_OK;+ _2 {( k- w+ G6 b: H; N } else {" G O r6 e: h6 Y/ j2 N return HAL_BUSY; }& F. o" `6 x* v+ v2 ^ } 下面上我做的测试:一、Cube配置 1、DMA接收要用 循环模式,只需调用一次接收函数即可,重复调用也只有第一次调用有效。若是 正常模式,需要在每次接收完成后重复调用。 2、DMA发送要用 正常模式,需在每次发送时重复调用。还要打开UART中断,否则即使重复调用DMA发送函数也只有第一次发送有效,其余不会执行(UART发送状态一直处于 BUSY)。若是 循环模式,则会连续不断地发送,不会停止。 以上两点大家可以自己改改测试。 ![]() ![]() ![]() 8 E2 g: ?/ }3 ?( o% N' q5 l+ w 二、Keil例程编写& A' \2 c W8 O0 G" ?4 X ![]() ![]() ![]() . u' G% g9 U) H3 n* a% a& A 三、测试 可以看到,发送数 = 接收数。大家可以做更大数据的短间隔长时间测试,看看会不会出错。9 z( z' T! C1 @6 h9 Q ![]() 0 m9 Y" `7 c* c1 M2 | 最后,奉上测试工程: ![]() |
h- s; `( r, |9 s* c5 z. s
. t+ p2 c1 v- j9 W4 [
"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