你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L4使用DMA发送串口数据

[复制链接]
STMCU小助手 发布时间:2022-8-27 15:00
一、CubeMX的配置
% ^* d  n) j3 D& i依次点击Configuration->DMA即可进入DMA口详细配置界面。
+ S2 \* D: D! g 20200104190918651.png
/ S4 S- s; W; _9 U3 F0 D( j$ i% `) b; H
点击【Add】添加DMA传输请求,然后选择USART1_TX请求;( _8 A# Z1 m' e, _/ U; h' b1 Y

7 D. \8 J$ y6 C; a  }7 y4 x 20200104191228913.png " G/ R8 h, x  f) ?. \: S

3 Z) o6 ^$ |: s" a9 f其他设置如下即可3 K5 g9 m) A; ]% h4 Z
- [0 o0 Z# C* r8 d! ]& u
20200104191837475.png
& g# U- V0 B$ Z0 l% [
% i8 q# J1 H2 w) D  L! X" ]然后依旧是工程设置里,将HAL改成HAL/ A9 k$ C( p$ s+ x- z1 B9 A
* T+ \- ^! l+ |% ~
20200104192127235.png - E( }  H8 ~- p# V

5 x/ g6 B% }. m! t$ g. {1 Q, e' I4 z然后便可以生成代码  G( W, r9 P) ?5 ?  G5 B! ?

: C* K0 x! Q. c: d- _8 Y 20200104192752796.png
! {1 f7 S" G% e5 D8 M( D! n
5 e6 _) l8 Y; C二、用户代码修改2 O, \) Q2 J. k! w
代码生成后打开工程,我们可以看到,在static void MX_USART1_UART_Init(void)函数中多了这些和USART_TX的DMA相关配置代码% s& K1 g4 ?. x3 @9 r# ^2 L5 Z+ x

5 o9 Y- s- }, m% j" d; Z8 D 20200104204929943.png - x: I1 z; }7 X' Q0 f7 }) I5 Q
+ h4 Y+ M, n0 Y4 j. o' }  p
然后我们将其复制,在usart.c文件中添加static void USART1_DMA_Init(void)函数并粘贴,另外将static void MX_DMA_Init(void) 函数中的DMA时钟使能代码复制到USART1_DMA_Init()函数头部;
: E' p7 G+ b: G7 Y' B6 n+ t$ |0 x9 I- A# k
20200104205147660.png
% B. G0 G  q: i" P, y- f
: T4 l' H  w% o- W另外添加外设和内存地址设置函数到USART1_DMA_Init()函数中,得到
/ n& _9 f. a8 {. S4 U7 _+ R2 o6 }  W* ]- U- S8 A+ T
  1. //USART1_TX DMA Init
    $ @% u8 b2 ~' h+ l- Q; C' ^
  2. static void USART1_DMA_Init(void)6 U* N+ r8 R* V! T2 z
  3. {
    + l- O0 g) `, @5 W" P% c
  4.         //使能DMA1时钟9 r$ p3 l6 Z8 }, F
  5.         LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);) N9 q- Z2 ~% [' B' W- m0 C! U- L
  6.         //DMA1通道4选择为USART1_TX请求5 A. Z* \8 n6 Z7 X/ W
  7.         LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_2);
    6 @  q5 M* Y' j# i5 Y, L
  8.         //数据传输方向为存储器到外设
    # C/ @( L* z9 [. X! [& k6 \
  9.         LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
    ( ]3 A( \7 z0 [
  10.         //通道优先级
    7 i, }; n6 ^. r0 I& W, f
  11.         LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_LOW);* U8 {& }  g* a% ?! t9 j
  12.         //不执行循环操作
    ( C" h0 t! e. E% I/ W
  13.         LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);' ]7 u; A& W0 q  _2 |) r: ^
  14.         //不执行外设地址增量操作
    ; O3 e5 v" H% z! r" V, `
  15.         LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);  O) R) g* h' X) _
  16.         //执行存储器地址增量操作) r  I. G: [; W" L5 O
  17.         LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);2 ?7 R9 ]  G7 Q3 @
  18.         //外设数据宽度$ k% ?0 v% I+ u" S
  19.         LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_BYTE);2 T% u9 w. X1 H% Z4 B
  20.         //存储器数据宽度
    + b$ z) ]9 R$ N9 p! M. y
  21.         LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE);
    5 _% ~3 Q) ~$ W2 ]& O" F
  22.         //DMA内存基地址: N# u& l) U) e+ P) g
  23.         LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4,(u32)USART1_TX_BUF);
      f1 p/ R8 n% k) T  @* c
  24.         //DMA外设基地址
    1 i) U: r1 l' K
  25.         LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4,(u32)&USART1->TDR);. m' h/ U5 n/ \9 Z$ m* [
  26. }
复制代码
$ \- q6 z( z- ?7 o. n1 @$ z0 R$ v
然后将其添加到uart_init()函数中,并添加串口1的DMA发送使能函数,如下图; q6 G0 D& a5 J9 B- M

2 n5 v! b, u3 Q# o4 N7 @ 20200104205905455.png ! q: L! j: O% E/ j% |0 H

: F" F% ^; ~3 u9 D可见,我们需要声明USART1_DMA_EN,我们在usart.c头部添加一下代码:0 `. D7 x9 j! T, j1 N, u

0 q- p& V' Y- c% C, m9 ? 20200104210135397.png * a; i2 C& N9 y5 x

" \* y9 i/ k9 t8 U2 k4 U- L! M然后重写一个串口1打印函数:8 p8 Z5 m$ Q9 q
5 N# j& ~7 g) Q
  1. //串口1,printf 函数  j- o5 {  B. ^9 w% B9 F  N
  2. //确保一次发送数据不超过USART1_TX_LEN字节9 @: `" h  A: g+ H+ v6 j
  3. void u1_printf(char* fmt,...)  ' g6 e0 B- k7 K; U7 [# v
  4. {  
    ' s9 N; _$ C7 T2 p! p. X
  5.         static u8 first = 1;
    : s1 a4 X5 ^* C3 u4 [' m
  6.         u16 i;
    0 I9 b/ X# R& G0 Q( s2 z
  7.         va_list ap;
    . {+ q0 |. ]2 ^" W( D/ @& P$ m4 k
  8.         va_start(ap,fmt);
    % B+ ?  J7 N6 O3 s: `) N0 {3 {8 [
  9.         
    3 O2 i3 m: A; u$ `! m; r6 k
  10.         if(first == 0)
    7 T3 c3 Q- T9 L: m2 Q
  11.                 while(LL_DMA_IsActiveFlag_TC4(DMA1) == RESET);        //等待通道4传输完成- q1 T+ ?& s1 U& O
  12.         else4 m' C/ O/ z# ~6 H
  13.                 first = 0;
    ' }+ i% v2 G4 ^' J3 I1 s
  14.         
    # z( u/ p! ^% V+ H: ^* p
  15.         vsprintf((char*)USART1_TX_BUF,fmt,ap);
    1 z2 K, s2 s* v" W
  16.         va_end(ap);
    6 i4 e/ T" A$ T( b, Q. E
  17.         USART1_TX_BUF[USART1_TX_LEN-1] = '\0';
    ' ~: o& S3 o; @4 E" P) ]) X0 [" I  J
  18.         i=strlen((const char*)USART1_TX_BUF);                //此次发送数据的长度
    ' x( O, m. k5 I; N% ~

  19. - i& T4 E. J4 O" z  \
  20.         LL_DMA_ClearFlag_TC4(DMA1);        //清除通道4传输完成标志
    . {0 @, r9 Q3 B& w# k: A
  21.         LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_4 );  //关闭USART1 TX DMA1 所指示的通道      
      n9 Y9 [, `, ~6 L) E8 j& ?
  22.          LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_4,i);        //DMA通道的DMA缓存的大小
    9 h) Y" [. a. |8 S% c5 |
  23.          LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);  //使能USART1 TX DMA1 所指示的通道
    % O# K/ ^4 C) n- y" [4 z
  24. }
复制代码
) U1 G0 \) N& w2 O. `4 A
然后将主函数中的printf()换成u1_printf()5 p! V! m0 o7 C4 j- S+ ?# I
2 O1 S8 n9 N8 m
20200104210603837.png
2 I  k+ |+ }% }
$ R6 |# k$ m7 n7 @1 w$ n1 B编译下载到小熊派开发板,通过串口调试助手可以看到
) q9 D" O: r& E* Y4 L) ]
" \8 n7 a9 d6 g  p! P/ Y 20200104211654519.png
) ?/ O' l( N+ B6 b. L9 @( M2 g8 I' y5 J% X! w. N( X! S
三、代码的优化修改

# c8 w8 w' v5 u4 a8 ^在stm32l4xx_ll_dma.c文件中我发现了LL_DMA_DeInit()和LL_DMA_Init()两个函数,和标识外设库的及其相似,所以我想着使用这两个函数重写USART1_DMA_Init()函数,重写后如下
$ {9 O; M# ?3 r7 P: P$ t2 t, G8 B' T* Q# v( w% l1 b/ \" B
  1. //USART1_TX DMA Init5 G* \  R5 m- D. \) b, g
  2. static void USART1_DMA_Init(void)& L4 q. }' x& `9 ]0 U% M* S* t* M
  3. {; T; x1 ~. E6 i5 g- q
  4.         LL_DMA_InitTypeDef DMA_InitStructure;9 [5 J5 G. [( t0 c
  5.                                                 6 a+ N4 e/ z! d) e
  6.         LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);        //使能DMA1时钟
    # O& K. Y. E' n3 B% S# }8 P
  7.         LL_DMA_DeInit(DMA1,LL_DMA_CHANNEL_4);//将DMA1的通道4寄存器重设为缺省值
    ; `; o$ F, G4 q8 z9 H+ N& g* e
  8.         
    3 R. b- h6 g$ p) B" z& r3 \: X
  9.         DMA_InitStructure.PeriphRequest=LL_DMA_REQUEST_2;        //选择为USART1_TX请求6 H) Y2 }8 p; I$ d4 E
  10.         DMA_InitStructure.Priority=LL_DMA_PRIORITY_LOW;                //通道优先级/ r: a5 B% ~1 Z5 C2 S. ~8 J
  11.         DMA_InitStructure.Direction=LL_DMA_DIRECTION_MEMORY_TO_PERIPH;//数据传输方向为存储器到外设
    / q" r; e9 }  S
  12.         DMA_InitStructure.MemoryOrM2MDstAddress=(u32)USART1_TX_BUF;                //DMA内存基地址
    ( i" P; G$ D7 T4 s* D' h
  13.         DMA_InitStructure.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_BYTE;//存储器数据宽度
    4 s& h3 b$ ^/ C* g/ _
  14.         DMA_InitStructure.MemoryOrM2MDstIncMode=LL_DMA_MEMORY_INCREMENT;//执行存储器地址增量操作7 U- b& F* v0 }+ ^4 `+ Q
  15.         DMA_InitStructure.Mode=LL_DMA_MODE_NORMAL;        //正常模式,不执行循环操作
    % K8 N) h  G7 Q) d! ]7 K5 k2 l
  16.         DMA_InitStructure.NbData=USART1_TX_LEN;                //数据传输量
    % R0 U  p+ j; M6 A! j2 w
  17.         DMA_InitStructure.PeriphOrM2MSrcAddress=(u32)&USART1->TDR;                        //DMA外设基地址
    7 Z+ Y8 Y: x1 V/ ?- ^8 w# g" V1 Q
  18.         DMA_InitStructure.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_BYTE;        //外设数据宽度
    8 G$ h% q* Y* i$ e# e/ F6 O
  19.         DMA_InitStructure.PeriphOrM2MSrcIncMode=LL_DMA_PERIPH_NOINCREMENT;        //不执行外设地址增量操作
    ; [  ^, G6 \( p5 f- u- e. b& Y7 R
  20.         LL_DMA_Init(DMA1, LL_DMA_CHANNEL_4,&DMA_InitStructure);
    # z) ?+ I* k' w: W: j1 U
  21. }
复制代码

/ g" q2 ?4 L3 O* O' e, k是不是有一种莫名的熟悉感。# X- k9 y7 [( P& |. h
同样,串口助手验证成功9 Y& e- G0 L! H; G

* n' ~* v3 a+ o6 R. a- R 20200104215241547.png 5 f. b3 Z4 }6 n  D( ~+ E. S( F( M

: U. ~: y- W# x0 k  c7 N四、源码下载: Y. h; w+ [& J" W- Z* O; V; w
————————————————, n9 V6 A8 {. @
转载:Willliam_william
, o7 w9 F8 G" ?' W' R& B+ k$ P6 |1 t  v

2 q$ d* M5 v$ L6 e
赞 收藏 评论0 发布时间:2022-8-27 15:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版