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

基于STM32CUBEME的USART通过DMA接收不定长数据经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-15 21:24
概述
    直接存储器访问(DMA)用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何CPU操作的情况下通过DMA快速传输传输。这样节省的CPU资源可供其它操作使用。
    DMA允许在后台执行数据传输,无需Cortex-MO处理器干预。在此操作过程中,主处理器可以执行其它任务,仅当整个数据块需要处理时,才会中断主处理器。这样即使传输大量数据也不会对系统性能造成太大影响。
    DMA主要用于为不同的外设模块实现集中数据缓冲存储(通常在系统SRAM中)。与分布式解决方案(其中每个外设都需要实现自己的本地数据存储)相比,DMA解决方案在硅片成本和功耗方面的成本较低。
    根据使用的产品型号的不同,有一个或两个DMA模块。
    STM32F0XX DMA控制器总共有5个通道用于DMA1,每个通道都专门管理来自一个或多个外设的存储器访问请求。它具有一个仲裁器,用于处理不同的DMA请求的优先级。
    本篇文章主要介绍如何使用STM32CubeMX实现串口DMA读取,并且打印出去。
6 e! f* ?/ M8 L: m! [$ K6 ^2 J- Y
微信图片_20230415212430.png
9 a" y# q2 V1 W& l7 P0 K, v. Y
硬件准备
    首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:  
4 p, C2 P( i$ W# @) k4 m8 v, ~
   微信图片_20230415212426.jpg

: D( P; A: c& o/ N/ K3 I
选择芯片型号
       使用STM32CUBEMX选择芯片stm32f030r8,如下所示:

9 T( V# b. G+ I+ R, `& Y1 f9 {- Q
微信图片_20230415212423.png
配置时钟源
    HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:
% I& F: o. n+ l* A0 G" B  P
微信图片_20230415212420.png
, z% q" y5 s% @8 _  U+ M/ [; n
配置时钟树
    STM32F0的最高主频到48M,所以配置48即可:
! [. }6 H9 D1 C
微信图片_20230415212418.png
( m8 K1 l) V) f: z6 O; F+ d* M
串口配置
    本次实验使用的串口1进行串口通信,波特率配置为115200。
! M; @6 E* D) ^( t# ]

4 f  R# S9 y3 Y
微信图片_20230415212415.png
! a0 g! R4 A2 h1 K6 ]# m' T
    配置DMA
微信图片_20230415212411.png

+ p2 [0 f- S& g- W4 n
    中断

; }; ]9 H1 |4 V/ `; y! ~6 r
微信图片_20230415212408.png
# |6 s. N7 ~$ m% P
生成工程设置
    注意在生产工程设置中不能出现中文,不然会报错。
+ X3 _4 t8 o  |! P; X
微信图片_20230415212405.png

0 K, r' b( {) B( e2 S+ d
代码生成设置
    最后设置生成独立的初始化文件:
微信图片_20230415212401.png
; Z4 `& G) x$ L" f" L
生成代码
微信图片_20230415212358.png

" N4 [2 Y* j: B# Q# Z4 h! C7 G
4 @6 U! m! r' S3 y+ p) l: N
配置keil
微信图片_20230415212355.png
: J2 C/ E' ^7 |- |3 {! g

8 X4 C$ H$ }( D6 U
微信图片_20230415212352.png

; |' S8 q0 b+ a$ G
    在main.c中,添加头文件,若不添加会出现 identifier "FILE" is undefined报错。8 b7 Z3 G& _9 M  Y
  1. /* USER CODE BEGIN Includes */5 z" f3 \. L* }1 R: \
  2.   p4 T( Y* l3 Z$ \
  3. #include "stdio.h"
    $ |, [6 g& o8 m+ t1 x

  4. ' B* B! `# f0 R) \" O
  5. /* USER CODE END Includes */
复制代码
( R8 I, U8 R: w8 }
    变量定义:
  1. /* USER CODE BEGIN PV */
    3 |" u% c) ~5 Q; R5 s
  2. . c: [; H3 b; s1 W/ _4 b2 y/ H' R5 z. r
  3. #define BUFFERSIZE 255           //可以接收的最大字符个数      
    9 m( U  O) R% }) ?  L9 N
  4. . u% b: R2 a; @; j" s
  5. uint8_t ReceiveBuff[BUFFERSIZE]; //接收缓冲区
    " [( J$ Y  P# Q( q9 w

  6. 5 Y  C  |, `" W: R; M6 R
  7. uint8_t recv_end_flag = 0,Rx_len;//接收完成中断标志,接收到字符长度
    6 i/ g& `# Y  F  k7 D* q5 Z

  8. 2 h# N" y: ?' o1 F8 W
  9. /* USER CODE END PV */
复制代码

7 V4 H% \3 ~: M  F' }
    函数声明和串口重定向:
  1. /* USER CODE BEGIN PFP */( `$ j3 W% E& {6 i; o

  2.   R0 A3 I0 E' a% B$ Y  [- v
  3. void uart1_data(void);                                        //接收函数
    2 j! ^9 I+ A) ^; i) d' Q6 V

  4. : g+ W0 O# X7 l; U7 X
  5. #ifdef __GNUC__                                                                        //串口重定向$ T+ n5 M! q# M0 x7 C

  6. 6 ?$ r: P0 z$ Y6 k
  7. #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    " D$ Z& c' C& C) ]5 h7 _
  8. . ?/ b# i: @2 t% f% m% W: `) D
  9. #else
    * K  w9 r, i: Y2 t' ?* i& a

  10. 5 R8 s' u2 x- M/ b7 C$ [" X
  11. #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)8 G: x, c* T' G! u7 w2 I4 G8 ~
  12. + C4 q7 s6 U/ v& S
  13. #endif , M# |0 `# i- q( s5 I8 L; C
  14. ! G; D1 H$ ~' ?- |
  15. PUTCHAR_PROTOTYPE
    % b: [  W1 T4 D8 z
  16. 0 n) z. V# Q# \# P' Z5 C$ T0 s# n2 D
  17. {* R# z4 B2 |$ p3 h! \

  18. 1 E& p! z2 T" M% ?- _# F% J, S
  19.     HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);. r: I' }) d8 w2 L3 b

  20. - X  d8 Z! q3 p$ g4 p
  21.     return ch;
    & b2 ?7 D& W! n: _' ?' x+ c- Z& k2 x
  22. 0 D& ^% _* b3 ~8 V8 I
  23. }- x) G8 t( e4 j& m/ H* Z
  24. 8 k) y+ @) ]% |, e# E0 t
  25. /* USER CODE END PFP */
复制代码

' `3 s" _, s  u4 C
    开启串口IDLE中断:
  1.   /* USER CODE BEGIN 2 */
    * A- j) ~+ L8 [" s* |! m1 W

  2. 4 d  }; t+ u5 {# e' ^' R1 C
  3.         printf("串口1DMA例程\r\n");
    ' f2 T6 h, U" V! }
  4. # O; u# Y3 t! Y2 t1 y, I- z: c) [
  5.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能串口1 IDLE中断
    % N, L1 K) U7 M. t( g
  6. 5 @2 H& \: O8 |2 e9 l, E
  7.   /* USER CODE END 2 */
复制代码

8 C/ s6 n) s3 K7 s: `6 ^$ w
    主循环:
  1. /* USER CODE BEGIN WHILE */
    & o9 i8 @4 p$ v9 M, X& ^. w

  2. 7 H3 Z# n! h# y" c# ]# f  @
  3.   while (1)% I) E: D$ j* y- E: }8 w

  4. 1 k- T  R+ q& C0 D: [0 t# Q; |
  5.   {9 t# O7 }3 q, X/ x

  6. . ?, o% V, D. U  v$ ?7 F
  7.     /* USER CODE END WHILE */
    2 e9 D# B1 l: o+ ^2 v& z( F
  8. $ H: s' B5 X% c* E; ]
  9.                 uart1_data();//串口数据处理
      [3 V& N9 D3 p3 V" T
  10. 3 M; i0 M6 L: y# D9 D( X
  11.     /* USER CODE BEGIN 3 */$ m( X, u1 D9 M+ Z2 }

  12. 0 R8 p. {$ K6 h  ?
  13.   }
    1 O1 U) [  U2 ~6 ]$ W' N' a
  14. ! P4 }- C- T4 U; T/ b1 f) s: H
  15.   /* USER CODE END 3 */
复制代码
( q8 L4 r5 D7 ~7 i, t
    串口DMA获取:
  1. /* USER CODE BEGIN 4 */
    / y" B4 Y- }' L, `0 A, ^

  2. 9 X1 X+ l7 t" r# D- }
  3. void uart1_data(void)5 b$ i+ P5 ]! c5 {0 U
  4. " c2 H3 N7 {0 ?7 |4 h; G: ]
  5. {
    2 Z# P* X+ s3 E- a5 X9 H% L
  6. ( a+ j/ F4 @' X7 t
  7.         if(recv_end_flag ==1)//接收完成标志3 V: p) ~" W7 a' d: ~

  8.   [; ~  l4 P+ ^1 V
  9.         {+ q/ \8 `0 C  H& T

  10.   M+ g( Z0 s7 b* b' X" Y
  11.                 printf("数据长度=%d\r\n",Rx_len);//打印接收到的数据长度
    3 U$ C- {( z/ M( H3 X8 t
  12. 9 v" Q) W. A4 a6 U1 J5 ^) y8 Z1 p6 M
  13.                 printf("数据内容:");. g$ T3 ?  l, S

  14. 4 D; y7 R! f& G4 n
  15.                 for(int i=0;i<Rx_len;i++)9 z. T2 A7 A6 E* h- E/ m/ f
  16. 1 A5 Y. f8 i( K. o
  17.                 {
    * S  L0 `8 s1 K( {9 t( d3 ]& i

  18. ) q6 j- @% o7 S2 s7 v
  19.                         printf("%c",ReceiveBuff[i]);//向串口打印接收到的数据3 x/ ]5 x$ }1 e1 J8 x! H0 Q
  20. / G5 k4 k% s! f6 r5 a
  21.             }7 Q7 s1 t1 ~* G' p

  22. $ b( ?! a+ {! v% z' x/ B
  23.     printf("\r\n");          * S$ _' `& x$ a0 m2 h" d! I
  24. + _# `- V+ y& t) A2 Q0 `) E: F
  25.     for(int i = 0; i < Rx_len ; i++) //清空接收缓存区
    * r4 i1 y/ W6 h9 w, y
  26. 1 F3 i8 R( i4 k* l* f- _
  27.     ReceiveBuff[i]=0;//置02 {9 Y# |/ V: {0 g+ y

  28. 2 u4 g# ]& ?  V
  29.     Rx_len=0;//接收数据长度清零
    1 I) D. ~( j/ h4 y3 w% J& B

  30. $ _$ C. B. @( b6 K/ I$ ~
  31.     recv_end_flag=0;//接收标志位清零
    ( S/ f* Y' `! v2 O" F8 X0 L# O' v
  32. % X4 q- S$ o  @5 e2 x
  33.     }2 A" _$ n6 c; C* T6 P) T  Z; i- M
  34. : W/ k5 }% V4 E3 I: A7 P
  35.     //开启下一次接收& l9 R! W; z* P4 g4 r6 ?( H# o
  36. , {3 r  g5 B, K+ D# @; v2 @$ j
  37.     HAL_UART_Receive_DMA(&huart1,(uint8_t*)ReceiveBuff,BUFFERSIZE);
    8 H5 w; j. I+ L" [3 a& l% n) a
  38. # a! `$ F4 n3 F& D4 @* Q& u
  39. }
    , {5 @8 h- t: H2 o: k. ^2 L

  40. 5 O/ y7 A6 a" Z, z, u# f+ E
  41. /* USER CODE END 4 */8 k5 U7 s9 j* m
  42. & }: o- T6 ~+ f# x4 D! `
复制代码

( @# j* ]& e  P; _8 y5 t
    #include "stm32f0xx_it.c"文件中断外部变量引用:
  1. /* USER CODE BEGIN 0 */8 J, ~, L3 _: B  G
  2. 1 P# S5 g) l/ w! c
  3. #define BUFFERSIZE 255        //可接收的最大数据量* [* l/ m# s5 ~9 a6 M' F8 X) {1 }
  4. ) l' q2 J6 k* u, D
  5. extern uint8_t recv_end_flag,Rx_len,bootfirst;
    & w9 b1 \2 i8 z) q# }9 c9 f

  6. 9 a* [0 Q( f0 k3 o
  7. /* USER CODE END 0 */
复制代码

& W' P$ ?8 A# {
    串口1中断函数:
  1. /**6 J' N8 g* G* Z- D/ J

  2.   ?. t; U1 V5 F
  3.   * @brief This function handles USART1 global interrupt.* u) Z, L) K! m' O1 f- j
  4. 4 }8 C& I+ i3 b+ L* e5 q1 N: p1 x
  5.   */
    ; l8 N2 E& j7 m
  6. 7 M. Q$ w% F3 c9 V, S
  7. void USART1_IRQHandler(void): w" @% V1 v- C' M" `

  8. 9 _: X1 C1 d, a
  9. {: ]$ S9 [/ {5 s+ B
  10. 9 q  Y& a$ b7 W5 H/ J
  11.   /* USER CODE BEGIN USART1_IRQn 0 */
    9 I- D# |8 F; r5 P- Y

  12. " H; [5 X! I- `# r& V, b

  13. 4 b' C* n5 |- O, h
  14. * c( W/ ?+ ?" N- j' y" ~
  15.   /* USER CODE END USART1_IRQn 0 */
    : p8 |' l( W1 N- l8 i

  16.   s8 S, p- n' ]: l/ b8 G$ `
  17.   HAL_UART_IRQHandler(&huart1);# t" G2 p; u3 @! A
  18. / b: `  X9 V0 _) I
  19.   /* USER CODE BEGIN USART1_IRQn 1 */
    6 b. G+ I) ^+ f) ?' \

  20. ! ]) R; j- U. B) R$ N' \0 g$ a2 e
  21.         uint32_t temp;/ W$ a3 ~) r8 l5 ?1 O0 X3 h1 Y
  22. # I! @, ?( p0 F0 {3 g+ K" |0 X
  23.         if(USART1 == huart1.Instance)//判断是否为串口1中断7 g+ |- {: A$ N0 c2 F" D, r

  24. , [1 U, Z9 g2 J9 t/ R
  25.         {      
    / z7 U9 }, U$ d
  26. , P7 o5 X- n' f- ~$ f/ V
  27.                 if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))//如果为串口1" _0 K& ?- I2 c2 A. g1 W! Z
  28. + X) K5 y, I0 p2 ?0 w) e7 T
  29.                 {
    9 r/ f% b! w* e( D" Q  \
  30. $ \: J) I$ a4 Y. M
  31.                         __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除中断标志
    5 P3 s9 U' p  s3 C% m8 ]8 X

  32. ( b) ?" I: Y5 Z+ A8 m7 O( y+ I
  33.       HAL_UART_DMAStop(&huart1);//停止DMA接收
    7 V$ E# a6 M3 f! a7 X* i7 U! K. Y
  34. 3 m, E' B1 I3 b; l4 O3 |( l* [; @
  35.       temp  = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//获取DMA当前还有多少未填充
    - |7 U% Q+ S% F+ K! ]
  36. + I2 o0 `$ g9 i8 y1 |; k7 q' p' t
  37.       Rx_len =  BUFFERSIZE - temp; //计算串口接收到的数据个数. V2 c7 W$ F3 x/ l: L. S9 f& O, _' i

  38. 7 ^& o& \4 L% w
  39.       recv_end_flag = 1;
    7 B& x+ U( {  L9 A. c
  40. $ m0 T( w$ f3 X; {0 i
  41.      }
    5 o, O$ J5 k6 k/ B) _1 n
  42. 5 ^6 G: m: q7 q* y; o" _
  43.         }       
    . H! V% `! f4 ~' X  U  H- B$ s
  44. 3 F+ ~; ^8 S) F2 K7 {3 ~5 F: D1 k
  45.   /* USER CODE END USART1_IRQn 1 */% p+ C' I6 \+ W7 k/ R' @

  46. 1 K& r" m8 Y6 y: K( H  D
  47. }
复制代码
$ P( W  e  O- |  N) j9 s5 P
演示效果
微信图片_20230415212349.png

. d  a0 E: a4 T6 R/ G
转载自:记帖
如有侵权请联系删除( q+ o: y) n6 O; g- ]2 j: T7 ?- m2 A

; K  u0 C2 ]( F/ Y; }+ N* K7 m1 U( U1 `6 _8 L
赞 收藏 评论0 发布时间:2023-4-15 21:24

举报

0个回答

所属标签

相似技术帖

官网相关资源

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