中断接收方式,最大的缺点就是中断过于频繁,为了解决这个问题那就把DMA搬过来,它不就是专门搬用数据的嘛,不用多可惜。
6 p* e0 H" T% O% v6 g+ p+ G: p7 I/ `; m7 A
首先我们需要大致了解,DMA和外设传送数据,例如串口,我们希望,当一帧数据接收完毕了,有个东西告诉主程序,串口接收到了一帧n个字节的数据存在某个地方,接收过程中你丫别打搅我。
# u) E- ~0 a( ?/ v* U9 w. q5 W" \; X C+ x7 T% t! d6 ^
DMA就能胜任这个工作,他可以以中断的形式告诉你这些信息。相比中断接收方式,是不是省了很多中断,主程序被打断的次数也就少了。
9 j: p3 i( j2 `6 \& {. O
. _, ]& c+ p' R! O( `8 B W' ?( m还是按照上一篇形式大概看一下,HAL库中DMA是怎么和串口配合的。1 f9 O$ a9 S4 L7 u: r
" D3 N- w' F2 X6 G0 y6 s- /**! _) Y: h, K% N" _3 P# ?* |
- * @brief Receive an amount of data in DMA mode.
. o$ b/ b% N6 A2 q+ E$ | - * @note When the UART parity is enabled (PCE = 1), the received data contain5 x5 d; d# x' [% Q9 R3 ?
- * the parity bit (MSB position).! }3 R8 e5 |% b/ W
- * @param huart UART handle.6 c! R2 w# W5 q9 ]" P F; L4 O* ]
- * @param pData Pointer to data buffer.3 D% v- [2 m/ Z0 ~4 Q9 D9 y
- * @param Size Amount of data to be received.
9 H) S, X* c7 S8 a3 K - * @retval HAL status
4 [6 Y6 g" ^. E/ Q# W - */
8 `3 ~3 d% ?. g6 U! q5 R0 t - HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
/ W8 m% Y. c+ d+ J - {( f- p% `9 u* r# w' Q' f
- /* 其他关系不大的代码省略 有兴趣可以自己看 下同 */
/ S0 h, l( q# K* _# \5 v8 ~ - //1.检查参数 判断串口接收状态为就绪 把缓存区参数传递到串口句柄 修改某些状态
2 p1 ?+ l p1 R - //2.判断和串口句柄关联的DMA句柄地址不为空 然后给DMA句柄注册一些回调函数
+ ?7 k/ l0 G8 F2 g5 z8 |; Z/ X - /* Enable the DMA channel */
: B1 A2 Y ? \+ ~! x: k - if (HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size) != HAL_OK). W, w1 W9 g# q! @8 _4 r
- {7 \7 @ H% W7 r0 @1 p; _9 T) A, F+ T9 H. N
- ......
) t- I0 @. F R. ^8 J5 r8 V# T7 a; z - }
+ Z- Y1 C4 l) b" k - }
复制代码 + A* T7 n, g! j2 H
HAL_UART_Receive_DMA这个函数里最主要的就是调用了HAL_DMA_Start_IT这个函数,你看他连参数都没怎么变,就把句柄换了,其他三个原封不动的传递过去了。所以函数内其他内容几乎不用考虑了。直接往下看这个函数。; R. F. [* ]( O4 K
! ~/ x# W9 u* m
- /**# v. e* e# R! }/ ]( P; V+ ~
- * @brief Start the DMA Transfer with interrupt enabled.# q+ ^; O, W8 S, j- x
- * @param hdma: pointer to a DMA_HandleTypeDef structure that contains
/ h3 M' D# E a1 O3 Y( t# R - * the configuration information for the specified DMA Stream./ I, g% S; B& y% U
- * @param SrcAddress: The source memory Buffer address4 U# ]/ W( p/ Z& H+ U
- * @param DstAddress: The destination memory Buffer address P9 j0 _3 G' _7 j" b1 w) n
- * @param DataLength: The length of data to be transferred from source to destination- d5 ?+ D" f F" q8 X' h% f
- * @retval HAL status
9 P6 W6 l- A) `* A - */
. q! D8 b; x; ^; x I! t/ j( H2 J - HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)' x7 k. Y6 p* X$ `. Y+ D
- {
4 S# |* H8 x9 y* i9 L9 n* f - //1.检查参数 给句柄上锁 判断状态 只有在就绪状态下才允许配置$ L. E: G% X. y5 Y: S3 N
- //2.判断就绪状态
* P8 U. I0 ]1 P2 x/ ? - {
# p4 G! e% P+ u) {) k' e' { e - ......
& e6 j1 W/ s; j9 D - /* Configure the source, destination address and the data length */
4 A1 o9 j* Y+ h - DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
- m) U. n) m2 V5 x5 f - ......) V. S# r' }9 [
- //这里会开启一堆中断 完事要用 暂时可以不关心
% l- O1 H. X/ U" c Z - }5 r' \( r) h% O; D( T& e8 R5 ~
- }
复制代码 , K& u9 ~" L C9 I& t6 }& {7 j
上面这个函数也差不多还是那个意思,都懒的看了,主要是调用了DMA_SetConfig这个函数,追踪过去,它才是真正配置寄存器的函数,HAL库就是这么繁琐。$ @/ i) O) U8 x3 N* o6 D
1 F& \& p+ X- _/ n2 b# g) `. k
- /**2 t" y. g* M) B
- * @brief Sets the DMA Transfer parameter.3 V# y2 i4 z5 Y( p) ~% J
- * @param hdma: pointer to a DMA_HandleTypeDef structure that contains+ D6 i f& F; e/ Q
- * the configuration information for the specified DMA Stream.* z- ?7 P& M2 u" Q6 x7 P
- * @param SrcAddress: The source memory Buffer address6 Z; z4 R2 E+ {" c1 S
- * @param DstAddress: The destination memory Buffer address3 n9 T! V- X9 V) m4 D
- * @param DataLength: The length of data to be transferred from source to destination5 Y/ v' u ^8 Y$ k8 O
- * @retval None
: T. j0 }2 l+ ~/ N/ h1 ~ - */
" d8 @: a# [8 x - static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
4 k- o* ?: l5 ^6 k1 F1 U, `& ] - {
# I1 m3 G( h2 o* E F) C& N0 w - /* calculate DMA base and stream number */
4 T* z8 j9 T0 T/ g) r/ Q# ^4 ` - //获取DMA控制器对应流的基地址( m2 P: }" U$ h' e+ }4 [
- DMA_Base_Registers *regs_dma = (DMA_Base_Registers *)hdma->StreamBaseAddress;6 R4 [& ?$ s6 r$ R! n2 t' q
- BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;
; M& K. f0 b! k( w% G6 a& Y; q - 2 d7 c5 t7 s3 ~" G) h# _9 j
- /* Clear the DMAMUX synchro overrun flag */! |: D7 X, z6 s9 T. ?3 D- H
- hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask; M" [5 r. _1 J% B; z
- + f" v) A Y3 M
- if(hdma->DMAmuxRequestGen != 0U); q# W/ I/ b3 \" Q
- {# }/ l' |; }: z9 q/ r" D
- /* Clear the DMAMUX request generator overrun flag */0 F! v: r3 |0 C+ A$ e% E5 J+ y
- hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;: I* g4 q* H5 V! X; P0 P: |* {
- }
0 Q) p7 _) | b9 W @; }4 p" U
! w! n" U* r4 h- if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */+ @. C4 G' S$ B& V- I1 M* d
- {+ I) M* Y+ Y* \7 S: K
- /* Clear all interrupt flags at correct offset within the register */
- X- d# l4 l: `! ?% S - regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);' `' J6 l3 t! Z
; t; D! v1 t" h+ Q! n- /* Clear DBM bit */2 n) M$ Z) K2 v' `
- ((DMA_Stream_TypeDef *)hdma->Instance)->CR &= (uint32_t)(~DMA_SxCR_DBM);
1 Q7 I7 R/ u9 r$ E6 U% k
& ^. X. g1 f3 i, \' U+ o$ C3 C4 h- /* Configure DMA Stream data length */
; R5 v" {2 q( h/ E6 a - //这里设置搬用的目标数据长度" ^1 i+ f- \7 K/ }7 \0 ]7 b9 w& K
- ((DMA_Stream_TypeDef *)hdma->Instance)->NDTR = DataLength;
5 h6 k, R$ i+ j* j: w2 x- Y, d. M - 5 a7 j* X" x1 U
- /* Peripheral to Memory */
! J! N& u) D- A e( [ - //整个这个if判断是在设置DMA搬运数据的目标地址和源地址: w- x' I5 i3 E. @
- if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
- K: ^0 q5 O: `4 x1 c- _$ O - {6 M& w- e6 }& w" h
- /* Configure DMA Stream destination address */* [# c, w' C; p5 Z) a; [/ N1 h6 G( d
- ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = DstAddress;# Z9 o5 Y' D5 H1 [9 s" ]
- v/ W9 ^" ?; K6 T/ c+ L n- /* Configure DMA Stream source address */( }3 |- `: C I
- ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = SrcAddress;
' ]* h$ k1 t# A) s" `* R - }) x/ }+ {. l1 `# _/ H& m6 S
- /* Memory to Peripheral */# _9 Q. z3 u% O2 `0 x+ J N/ i
- else: n7 d3 \, f9 @2 C: n
- {- ]* Y9 `: Y7 [" H) @! {1 c8 x
- /* Configure DMA Stream source address */
* \! y7 W6 ~. u: C3 ~/ }& G - ((DMA_Stream_TypeDef *)hdma->Instance)->PAR = SrcAddress;# d7 _- O8 S/ H' a( k
- , k. _5 Z* _ F4 ^
- /* Configure DMA Stream destination address */6 R; @+ E( Z) s' n9 O. X
- ((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = DstAddress;
& O3 v: F3 a0 o8 t, | J; @* U6 J - }1 b" A5 P9 g2 v# J' t/ U3 P
- }+ \& \) ^2 F. e8 }+ T# |: m) |
- else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U) /* BDMA instance(s) */" U- J0 q; M' u) J
- {1 K3 ?8 n, _0 X- |: ~
- /* Clear all flags */
5 n) t4 [7 T$ O2 ? - regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);
Q" _/ o2 S2 H( T - 6 f' n# X# _+ j, h
- /* Configure DMA Channel data length */
7 _- {$ n% I9 r+ x9 n0 g - ((BDMA_Channel_TypeDef *)hdma->Instance)->CNDTR = DataLength;
2 g" Y9 t. j# \. S/ Y+ L) p
! }0 h e: s& ~9 F" }- /* Peripheral to Memory */
; s0 M" e$ F) a - if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)" z/ u! r* a7 A# F% h
- {
2 {& _3 y, |- L - /* Configure DMA Channel destination address */
& L9 J6 W4 V3 i! K( @% Y+ l - ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = DstAddress;
$ e: e, ]8 j1 a# Y/ d" Q
* [! S+ C- f+ s, ^$ \9 S3 u- /* Configure DMA Channel source address */
9 c2 i8 Q3 G: @: @- | - ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = SrcAddress;6 p' K& H3 D c1 i; f' v# E
- }7 n' r: t* e4 p% _
- /* Memory to Peripheral */
# y+ L6 a# S6 J/ Z! _ J - else' Q6 \& U* l4 e: x" R
- {: t3 V" P1 V, |+ A! ] Y$ h
- /* Configure DMA Channel source address */% G- H5 r# l" Q% U
- ((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = SrcAddress;
1 \4 {9 P- O& G6 G
( d+ }" X2 d! o( a& u6 j1 ]" U: X7 p d- /* Configure DMA Channel destination address */
+ o6 a3 Z8 L7 q# g0 ^/ d - ((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = DstAddress;
9 `/ a2 |# ~3 g$ n/ d - }+ e# _& ^4 a0 p
- }
5 C" b" c' O( B3 X' @ - else9 @; T; V/ C E+ k
- {; |4 k4 m' k! N* t
- /* Nothing To Do */
- w0 ~ \/ D* O4 U - } # M8 y" Y5 W4 v* F$ E K
- }
复制代码
# T! @9 Y" G+ h7 G各位同志你们自己看吧这个函数最主要的目的就是配置DMA寄存器。以上就是串口DMA接收函数中最重要的部分。好像没什么意义一样,因为我要用到其中的一点点东西,所以必须要分析源码。
, i' j2 E7 O* X8 L: M. r6 F
" s4 D' c, v. r+ E; `+ h我们只是说了调用接收函数,参数里边指定了接收缓存,也指定了大小,似乎和我们的目标不符合,假设我们的DMA和串口之间的配置已经配置好了,那现在能做到的就是把数据收集到这个缓冲区里,可是并不能告诉主程序接收到了数据,和接收了多少,想要知道这个,有两种方法,一种是CPU定时去问DMA接收了多少数据,然后自己定义一个记录变化的变量,配合,另一种是中断方式,我们通过查询得知,DMA只有接收完成和接收半完成两个中断。; `+ r) W, I2 V3 |# a0 G
2 D4 X" [" i1 D/ c _. V
最最主要的串口的空闲中断不要忘了呀,这个可以告诉你,一帧数据接收完了,你可以根据这个中断去搞,接收了多少,在什么地方。1 v- h- m( y" J, |; @7 P, `+ ~
/ e) k8 L0 K9 R5 B0 ?因为这个编辑器不知道咋回事,贴代码总是挂,上边那个函数就贴了我很长时间,很生气,所以我就无耻的把源码整到这里了,整个工程哦(暂时还没有上传)。9 z1 x. y' h% Z
. |+ s6 P8 s5 G3 e再试试贴代码吧,方便你我他,要积分的都无耻。改天7 h5 X, P! ]; T+ r: y) a2 z1 ?
' K8 o; P! I8 R# }, M+ Vuart.c文件就这么多代码,8 u9 M# ]4 Z0 |! j% |
. J! ?8 q( }1 `1 x/ t3 o8 s! Q- #include "Uart.h"( `, w* Q2 @+ U
- #include "stm32h7xx_hal.h"
9 T( Q- X. s9 ?. O9 o
3 c) @. k: [" j: g- Z- #define RxBufSize 1024
5 C0 d+ f+ u' ]$ ~ - ; d9 _. U2 G. T- E% P
- UART_HandleTypeDef hUart1 = {0};+ b4 v2 P' S3 }: y6 `
- DMA_HandleTypeDef hDmaUart1Tx = {0};
) W- M4 Y1 N# a$ i- D5 l3 l: i - DMA_HandleTypeDef hDmaUart1Rx = {0};0 b V/ r+ ]$ v5 A% w: t
/ o5 H S* m6 i- //数组后边的那个限定跟你的内存分配有关 如果你的主RAM在512K的那个片内存就可以不加 这是AC6编译器用法
2 D d( b# \2 d0 [2 c - uint8_t RxBuf[2][RxBufSize] __attribute__((section (".RAM_D1")));- e8 C9 E" ]2 K
- void (*Uart1RxCompleteCallback)(uint8_t *pData,uint16_t *Count);" Q0 E& N) y" o! v# r) n
- 8 ^9 s% A* W* M! J5 o/ @
- void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count))
4 z; R- N4 p0 r$ k: M8 h - {
) P* ]8 U' A0 ^" B - hUart1.Instance = USART1;
' D$ P2 @) T- X% ]# A9 i - hUart1.Init.BaudRate = BaudRate;
3 \ z3 }2 S, t3 e, z4 D- r - hUart1.Init.ClockPrescaler = UART_PRESCALER_DIV2;
3 o& [5 Q$ w; P3 k6 d. Z - hUart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;3 N" Q* H3 _+ A5 K3 y, i
- hUart1.Init.Mode = UART_MODE_TX_RX;
! w! f/ k9 C7 I3 q; \ - hUart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;$ E7 d+ N O$ U0 D8 I3 B
- hUart1.Init.OverSampling = UART_OVERSAMPLING_8;
& ?+ |( f8 h: x, m8 V - hUart1.Init.Parity = UART_PARITY_NONE;
% B: l/ B( `- H% f& y - hUart1.Init.StopBits = UART_STOPBITS_1;
1 W& C; R1 h! D% |3 H0 m - hUart1.Init.WordLength = UART_WORDLENGTH_8B;
& K* v; x" i4 R8 g2 }+ Q - hUart1.FifoMode = UART_FIFOMODE_DISABLE;
/ t6 Y$ {9 i; {5 I
6 k) \, n! ]" ~0 x, x2 F- HAL_UART_Init(&hUart1);
/ M$ u1 [- \& D+ I' g \
. i2 ]9 |- P5 ]# R( ?" C- __HAL_RCC_DMA1_CLK_ENABLE();& K( I: Z, H5 ]1 H9 i$ n- r
) G. m# F; I( Y! M0 }- s- hDmaUart1Tx.Instance = DMA1_Stream0;- `6 r7 j- Y2 z$ ^1 f! r
- hDmaUart1Tx.Init.Request = DMA_REQUEST_USART1_TX;
) d, U% b. k' L/ M- H" w6 t5 g - hDmaUart1Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;7 C/ B/ l+ E$ R1 c6 J) O
- hDmaUart1Tx.Init.PeriphInc = DMA_PINC_DISABLE;7 u8 T1 k; p5 h6 v9 E
- hDmaUart1Tx.Init.MemInc = DMA_MINC_ENABLE;7 a2 U5 `/ ^" I$ ?4 X* f
- hDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
5 ]+ d4 v6 f9 n* ]8 q - hDmaUart1Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;3 Z! }3 Z( x1 h9 f x
- hDmaUart1Tx.Init.Mode = DMA_NORMAL;, Q% i1 {& K5 F
- hDmaUart1Tx.Init.Priority = DMA_PRIORITY_MEDIUM;+ Q) e/ W1 U* _) T; o
- * C/ H# n' \8 j3 Q/ z3 g
- HAL_DMA_Init(&hDmaUart1Tx);: M& B) `! C# Y* W1 }) I
- __HAL_LINKDMA(&hUart1,hdmatx,hDmaUart1Tx);
1 C% P6 k4 [4 ~/ e R - $ O Z: f! K3 P* ?
- hDmaUart1Rx.Instance = DMA1_Stream1;
% q% O1 E2 j% M+ ?! Y4 h - hDmaUart1Rx.Init.Request = DMA_REQUEST_USART1_RX;
6 h8 p6 H( E t s3 C0 O - hDmaUart1Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
( G" k2 s8 _7 C. [ - hDmaUart1Rx.Init.PeriphInc = DMA_PINC_DISABLE;4 u6 b" W+ \1 G" U6 h8 C' A) q- g
- hDmaUart1Rx.Init.MemInc = DMA_MINC_ENABLE;
( }9 l0 u- ^) e/ F - hDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
; {+ c, E$ t( B2 S+ }, G - hDmaUart1Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;: { A7 T5 }, q: n& W6 a% v
- hDmaUart1Rx.Init.Mode = DMA_NORMAL;
' D' S+ C; i1 t, |+ O) _ - hDmaUart1Rx.Init.Priority = DMA_PRIORITY_MEDIUM;# Z' y. H" E9 \* [( C
- / R8 {$ g( k& b. [9 h
- HAL_DMA_Init(&hDmaUart1Rx);0 b1 B/ k# D% d6 e' W
- __HAL_LINKDMA(&hUart1,hdmarx,hDmaUart1Rx);7 N. Q; I7 S: s# m
) y8 h5 k! ~; o8 I" c5 e6 G1 C- HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
1 f& J) X/ ^' M
; O2 B3 m! P% V( J0 K1 }. w4 D- __HAL_UART_ENABLE_IT(&hUart1,UART_IT_IDLE);
9 p! V9 c+ I; @ - HAL_NVIC_EnableIRQ(USART1_IRQn);2 U7 o3 [$ |' z F% l4 j# ]' z
- HAL_NVIC_SetPriority(USART1_IRQn,14,0);2 o4 s* D% v- F* G* {
0 }% K: v, Z* m ~$ h) P- p4 h7 U- HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);//Tx
3 a8 E+ g0 M5 E" p e4 g: {' t: L - HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,14,0);
/ @9 h* H5 z5 w/ I, o& z5 c - 2 p! x$ U& ~- Z& ~ b( E
- HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);//Rx
# P6 o# t" s2 \ - HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,14,0);2 G! C, X- n6 B0 O7 N) N. V# ?+ R) W
- 3 M) q* J: h/ z8 k$ p, ^9 q+ H! N: x
- Uart1RxCompleteCallback = RxCompleteCallback;0 b8 O5 G. M2 [" e# q/ X. Q' H
- }
$ @2 {$ }3 }0 P! J
& \9 n# v& J* w& a( e- void HAL_UART_MspInit(UART_HandleTypeDef *huart)
( h- R' w; i' P8 G- D9 t. _: _ - {
9 h+ A9 ~. z! n0 s - if(huart == &hUart1)//串口1
1 ^3 p) e1 Y+ T" w5 V; S - {
- Z6 |0 T# {2 |, M4 m8 ]" ~0 C" G - GPIO_InitTypeDef GPIO_InitStruct;' C, D) u- Z0 S6 D2 W$ I
. G) W. Q+ f% G- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;: f# M' P# Y2 a0 @0 s
- GPIO_InitStruct.Pull = GPIO_NOPULL;
$ q6 a; r# X7 T2 X1 Y7 m5 J - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
+ D! b5 T$ z/ S4 y - GPIO_InitStruct.Alternate = GPIO_AF7_USART1;) r: O) e7 t& o# V
- GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9;
8 k; r9 O9 H5 d" r1 `& o/ q
/ u- J; ^. W9 a0 X: O9 w+ W- __HAL_RCC_GPIOA_CLK_ENABLE();+ ~9 o) P$ {0 P
- __HAL_RCC_USART1_CLK_ENABLE();
% T- ~. w/ k. e
: o8 ~# N- {& u7 n% [9 w( d# D, b- HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);+ v' `8 }, ^+ T& P$ t: p+ h
- }! V/ ^* k1 a! `1 b$ u
- }
8 {8 h. L8 C) |6 Y9 i7 O2 ?
) \- Z* R' P' h1 _& \- void Uart1TxData(uint8_t *pData,uint16_t Count): Y+ [5 O; w! K8 t/ y$ W
- {
& t9 l, g |% G6 |6 Z1 P - if(Count)
% \- S$ m4 m, L5 H' g. S$ y7 H - HAL_UART_Transmit_DMA(&hUart1,pData,Count);/ p/ G/ h( ~# r6 O
- }
4 p1 b/ \; c( _6 U" y& @ - 2 j, Y7 |. g$ L/ ]6 `0 p2 f, j
- void USART1_IRQHandler(void)
* a" K2 ^% \2 E/ u5 I8 y1 Q - {
9 \0 j, L: P1 O& B - if(__HAL_UART_GET_FLAG(&hUart1,UART_FLAG_IDLE))
1 n% [) u/ u8 g( p1 v7 W* g( v - {
9 c% K/ g. ?3 A3 X2 y; b - static uint16_t count;+ z3 A* F. m: ], V
- __HAL_UART_CLEAR_IDLEFLAG(&hUart1);
2 _# H2 J7 |/ Q6 B$ u) h - if(Uart1RxCompleteCallback)* k" y J1 j; p
- {
- \: K$ F2 X& U. Y6 U+ D - hUart1.RxState = HAL_UART_STATE_READY;5 Y" `( i8 h1 A5 U: O/ z
- hDmaUart1Rx.State = HAL_DMA_STATE_READY;
0 X# L- A: i( B0 V; q6 ?6 l - HAL_UART_RxCpltCallback(&hUart1);0 _0 W: x% {7 \3 ~$ `& W
- }$ A- f; i8 G# w c" n' f
- }! {! o4 ^/ h3 q2 k
- else2 R6 M+ X2 z; i
- HAL_UART_IRQHandler(&hUart1);
" B8 F: o( h1 o - }
. {1 u, Q2 Z$ j) S
8 G- B& A% A, [9 K- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)3 R2 f7 ^; |9 P( p6 q
- {
3 a$ ], ~- i% k9 ^6 R, l - if(huart == &hUart1)4 L. I3 {, s1 ?7 {5 s8 r# o
- {
# V% }/ G4 P1 e5 a- s1 O6 h0 L4 f - static uint16_t count;
) G9 K. ^; ^' W" }2 t! A5 F, G - count = RxBufSize - __HAL_DMA_GET_COUNTER(&hDmaUart1Rx);1 t: Y; _# A) K" z+ \: F
- if(count == 0)return;
8 m5 S+ x) B$ ?* Q+ G - hDmaUart1Rx.Lock = HAL_UNLOCKED;& V* Z* N# i( X+ b/ l0 n8 r" b8 l2 m
- if(huart->pRxBuffPtr < RxBuf[1])
[. S% ]& b) N( D* |$ _ - {
- O6 x1 q" @- R4 j5 {4 r4 ^" y5 t, N - Uart1RxCompleteCallback(RxBuf[0],&count);
5 j5 Y/ {1 Q% c- j' |3 l" v6 A - HAL_UART_Receive_DMA(&hUart1,RxBuf[1],RxBufSize);$ P$ g4 ~+ s! k2 S- r4 \6 ]2 ~/ V7 c
- }' }- q6 n. h9 `8 a x! u) f/ u! R
- else9 J3 O( k: T3 ]3 e% T+ K
- {4 f* R v. q/ m4 V0 d& \8 V
- Uart1RxCompleteCallback(RxBuf[1],&count);5 ?* E/ k0 O. l' p& c5 ?; P
- HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
: w& g/ U2 V* k - }
1 V" L4 \: H3 b/ n8 H! v- z' h - hDmaUart1Rx.Lock = HAL_LOCKED;# D a4 ~/ v Y# h8 h+ X
- }
+ ~# e0 L3 Y' w, h - }8 T2 w/ n/ `+ `3 F6 u, X4 P
- , T7 F1 c4 q3 Z( O0 Y! K
- void DMA1_Stream0_IRQHandler(void)% t+ u9 P( \; S
- {
9 J. q$ S( L) I/ v - HAL_DMA_IRQHandler(&hDmaUart1Tx);
$ i8 L9 n5 K! m - }! W) m) a2 C7 V% W' g5 b0 G
: N5 k( [0 O7 m" c! H/ O- void DMA1_Stream1_IRQHandler(void)' |0 y+ ]( z3 v" H
- {
) r6 U3 O1 @( Z4 y6 }, F+ ] - HAL_DMA_IRQHandler(&hDmaUart1Rx);' t9 A) c* s9 ]1 Y
- }
复制代码
% `" M" Y7 d4 X3 `; r这个是Uart.h文件
+ K+ n$ |0 W$ h+ T3 x
' j- F+ S& `8 b2 ^- #ifndef __Uart_H_4 R7 F4 ]; C0 r- C% e" {
- #define __Uart_H_
0 e# E4 |! T0 E* |! H3 u J( ?
8 r- f7 _0 v5 J- d" w" f- #include "stdint.h"
: ~0 w3 V. C+ k1 I! t" |
: l: i ^- M: ~* |0 B8 X- void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count));# Q; x" m% d8 j
- void Uart1TxData(uint8_t *pData,uint16_t Count);( G2 S9 m/ ~* @4 C
! r. Z+ k9 D+ i. l/ N- #endif /* End __Uart_H_ */
复制代码
3 e/ [; o6 B* D) A" H; I+ D这个是应用文件,实现了把收到的数据在发回去的功能。1 V9 n- K( Z' h3 b- o
9 H4 e- E1 o$ P7 ?- q
- #include "Uart1Task.h"3 A! r8 }+ v% \* M* |- j
- #include "limits.h"//ULONG_MAX
' a7 J0 f2 x$ e& }% ^/ O0 L# c - #include "Uart.h"
9 N/ b" H9 k( }2 x; [: N4 ]* v - #include "string.h"
. u# Z" d9 y! l( G1 w - #include "SystemConfTask.h"
+ q5 T4 Z& a& E" z r
6 N, C+ d- f! i, M8 n, T+ ?- #define Uart1RxCompleteFlag 0x01
3 G5 G: Y7 c7 C - + K9 D' }- d9 ?/ h
- static uint8_t *Uart1RxData;
6 G- @' |" [8 Y1 W, A' V - static uint16_t Uart1RxCount;# \. k1 k; [4 a1 B
- TaskHandle_t Uart1TaskHandle;
" }; [; Y$ `1 o) q6 o - 8 v& A8 d3 X) N3 q, M
- void Uart1RxIRQ(uint8_t *pData,uint16_t *Count);
. S! N: j0 z9 R! f( h5 A' R
9 t- B* {+ T$ O R- TaskHandle_t *GetUart1TaskHandle(void)7 A, R6 D) C5 `) B/ {
- {5 z) X, N9 M: m
- return &Uart1TaskHandle;
: l& h8 ]$ j# P& m) Z - }4 q/ J2 f% e2 v/ R
2 W7 k4 h& G* t- h, E- void Uart1Task(void *pvParameter)
u' l: Q1 R9 Z: J9 Z - {
& C* z: q7 G1 R3 H2 y - Uart1Init(115200,Uart1RxIRQ);
8 i* T! Q( [$ _6 { - while(1)+ ?, X8 E. l" l/ ^9 m; ?1 _
- {
2 \: H4 J8 \: H3 u; M$ X5 N: e - uint32_t NotifyValue = 0;3 \- W" S* P: a8 J
- xTaskNotifyWait(pdFALSE,ULONG_MAX,&NotifyValue,portMAX_DELAY);
$ M6 ?! p* s8 i' k0 R - Uart1TxData(Uart1RxData,Uart1RxCount);5 U+ Z$ ?0 w1 M; y- F. I9 v4 o7 {6 `
- }
$ u$ @" y/ {, O4 B |) t, A* A h0 {$ q5 ^ - }
8 }3 a9 @( g- H# \) [ - * e! I8 D0 L- [2 L
- void Uart1RxIRQ(uint8_t *pData,uint16_t *Count)
1 |+ {: m J. t2 U6 o% F+ E; U% S - {9 |% q" V6 h" f
- Uart1RxData = pData;, O1 T8 L- m; ?' I7 P
- Uart1RxCount = *Count;! [; ^: @/ x7 Q
- BaseType_t pxHigherPriorityTaskWoken;4 P0 R# ]0 S9 l+ ^4 W$ ~" R
- xTaskNotifyFromISR(*GetUart1TaskHandle(),Uart1RxCompleteFlag,eSetBits,&pxHigherPriorityTaskWoken);
! L4 f( P9 Y2 R' m8 J5 @ - portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);: u/ \' b% i* e6 \& G# L. |
- }
复制代码
, V8 B- P9 N4 O. i) u3 I6 o A串口驱动里做了一个双缓冲的,防止大量数据出问题0 x$ k+ R9 V3 z7 _ W* r: N# F
0 Y$ T6 g r- Y$ Z9 o7 M; f* ~
* O0 w6 ? S a3 p: q2 t: N |