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