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

STM32基于CubeMX的高速串口收发程序(DMA模式)  

[复制链接]
radio2radio 发布时间:2019-3-8 22:08
本帖最后由 radio2radio 于 2019-3-11 14:32 编辑 $ g( ~' I3 u6 @7 @* d8 E- \& [" c
- l1 \+ v5 i; l
周末有时间,测试了一下STM32F103的DMA串口收发程序,基于CubeMX的,结果却是令人大失所望。
; S( @. @/ R! ^" n# U) O5 W) t& H2 Z  w8 i
我在去年,测试了一下【中断模式】的,结果是速度超快。
  c  `8 w$ n3 \) b# V- `' w速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。
% \$ Y! @3 h: c  Z0 A: ^/ D详情请见:  STM32基于CubeMX的高速串口收发程序(中断模式). ^& {9 c4 V& N9 ~9 V4 j

  X* _; y) v9 B+ T2 q那时就有网友,问我为什么不用DMA模式,我也认为DMA的好处多多,只是没有时间验证一下。3 F  h0 k9 t: M- R
现在,我得到的结果是,DMA模式用在UART这种低速外设上面,可能性能并不好,不如中断模式的。; P5 n6 f& @6 P" l7 j" ~1 }% Z
请网友们给看一看,希望我的代码有问题。- c6 P) [' o; c' o6 k5 B
先说我的测试结果吧:, Q, b. I% _4 H2 V0 ?- S
STM32F103C8T6 Bluepill板,MCU时钟72MHz,用CubeMX配置出DMA模式的两个串口收发。) p! ^. f, Y( K9 P+ u
添加少量代码,就做成了两个串口互相收发。 与上面说的中断模式的用法一样。
7 r% i7 ~" B# J- s7 {结果是,115200波特率,以10ms间隔发送接收40个字符,单方向正常,双方向同时收发就丢失数据。
, x/ V1 f# A7 @7 }( T9 L, V8 V如果时间间隔放到200ms,双方向同时收发,也能正常了。5 m/ V5 q& E/ V: n1 o. a3 U6 f4 _
+ G4 J$ _" H+ b
下面,看看我用的代码:
1 h& \' J8 H  N9 n$ J! vCubeMX的配置过程,就不累叙了,附件里面有配置文件。6 p  F) O  Q6 v& b( w& A+ I

5 Z$ v; Y! G$ Z3 |3 T
  1. //main.c 添加的代码:5 M. Y/ |, z7 t/ @1 |9 ?- b: ?. i
  2. 0 T6 t) J% x; [0 _8 I
  3. //变量:
    6 T5 U2 Q0 ~0 N
  4. #define DMA_RX_BUFFER_SIZE            128
    ; ?! w: L4 i' ^6 {+ x
  5. uint8_t UART1_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};
    1 @+ n/ |4 C2 X
  6. uint8_t UART2_Rx_Buffer[DMA_RX_BUFFER_SIZE] = {0};( X4 v: O9 ]$ h  Y  Y+ \

  7. : V2 R) D. {7 o! G+ G% o
  8. uint8_t recv_end_flag1 = 0;* K$ o; _& o) W" l. e9 z, [& U  g; b7 v( p
  9. uint8_t rx_len1 = 0;) |/ V. i* w% J& H8 n$ N
  10. uint8_t recv_end_flag2 = 0;
    ) ^' [& ]0 g* y( Z; d0 V
  11. uint8_t rx_len2 = 0;9 R9 n, I' W2 I/ r

  12. 4 b& r$ v0 J  T5 `. n8 W* f. y
  13. 。。。% A9 q% t7 g0 J# X" q0 X4 x* F

  14. * F* x! A  _; m. }4 a
  15. //初始化
    9 Y! d/ U8 f1 ~" g* p( z7 z
  16.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);% h2 O  A- v# m5 ^
  17.   __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
    9 y7 B, z( v  `6 W( G
  18.   0 r" m$ s9 B/ Z7 X  V
  19.   HAL_UART_Receive_DMA(&huart1, UART1_Rx_Buffer, DMA_RX_BUFFER_SIZE);
    . O8 `- l5 u9 p& x) x. v
  20.   HAL_UART_Receive_DMA(&huart2, UART2_Rx_Buffer, DMA_RX_BUFFER_SIZE);& V7 V/ e( V( ^
  21. $ N1 A- Y! h9 d$ v, Y2 S
  22.   。。。2 S2 O! g+ Q* d2 c
  23.   4 Q" m% m1 u% x' e, |. e4 v8 f1 g
  24. //main()
    % j! S* C9 L& W( H0 z1 d
  25.     if(recv_end_flag1 ==1){     //UART1 Rx, UART2 Tx- C% T; ^9 g7 t  v
  26. * J& D3 u+ G" e7 `
  27.       HAL_UART_Transmit_DMA(&huart2,UART1_Rx_Buffer,rx_len1);, G3 A+ P; p6 A9 H0 ~  P

  28. / {9 d# g" D! y& v
  29.       rx_len1=0;+ L! Y* ~# f/ j5 S3 N; ~

  30. ' Q' D- m% {0 y1 [% q6 D
  31.       recv_end_flag1=0;/ f; }+ I/ J* c! U! g! j
  32. 8 p1 }( h: S8 l
  33.       HAL_UART_Receive_DMA(&huart1,UART1_Rx_Buffer,DMA_RX_BUFFER_SIZE);
    + m' d9 p# Y5 V* L! h0 h, O
  34.     }
    ( o$ o" M2 w9 k; u, e- c. K
  35.     6 l+ `* V- \& K$ O8 H/ `1 R
  36.     if(recv_end_flag2 ==1){    //UART2 Rx, UART1 Tx" u% D' K) [  \: O1 u

  37. $ y  A0 a; ^( h7 L0 [: Z
  38.       HAL_UART_Transmit_DMA(&huart1,UART2_Rx_Buffer,rx_len2);9 @% o) ?5 A  m; v, R9 a3 e

  39. 1 n; y' v* J% ]" ]* a) R4 @6 ]
  40.       rx_len2=0;0 D8 g8 C0 \8 P" k8 S1 f

  41. & {1 X' \& g& p7 [. i: H
  42.       recv_end_flag2=0;; R) ]9 N) Y. @  I  K. t
  43. 7 J# n4 Y) V7 d( a5 F
  44.       HAL_UART_Receive_DMA(&huart2,UART2_Rx_Buffer,DMA_RX_BUFFER_SIZE);) V% M- f! l, g9 T. ?
  45.     }  L! X2 S% y+ {. y% f" W% S
  46.    
    2 i$ \% b+ a& e
  47.     & U( S: N# |# n9 o: l8 O
  48.     6 t7 B+ m, r! g9 l
  49.    
    0 q5 \3 f" ]3 Z6 e7 W
  50.     + I( b6 X. `: D4 K: G0 c( b+ l; e
  51. //stm32f1xx_it.c 中断服务程序里面修改的代码:% [2 H0 T" {. Y
  52. 7 Q3 F3 x0 N* {: x
  53. extern uint8_t recv_end_flag1;6 f* n& z# U! x  H/ F
  54. extern uint8_t rx_len1;
    , o6 s. e  m% c
  55. extern uint8_t recv_end_flag2;' R  S8 k+ c& ^) h( x
  56. extern uint8_t rx_len2;
    $ t- _1 \( `' m& w5 a+ s" r
  57. : c; R; n* L" U9 r) _3 B: {: W
  58. #define BUFFER_SIZE 128' P0 ]7 j6 [( J% V$ B

  59. 0 T  t1 o6 f: Y% ?' U, X& x4 b
  60. void USART1_IRQHandler(void)
    ! Z$ K) T0 f6 E& c) J6 m
  61. {6 L: R6 Q% I, c; E% S! m3 @
  62.   /* USER CODE BEGIN USART1_IRQn 0 */
    - k: j# r! o, n9 @5 i- u0 @( E
  63.     uint32_t tmp_flag = 0;
    - W6 _0 q/ u2 y7 C% D; w
  64.     uint32_t temp;6 S( U8 y9 G. `$ z2 m' l) `

  65. 8 q4 w# z" }# `5 e
  66.   /* USER CODE END USART1_IRQn 0 */    " e" d% j2 Q. o9 L3 m: G
  67.   HAL_UART_IRQHandler(&huart1);
    / T. Z  l9 ~2 J/ N4 b: }4 o
  68.   /* USER CODE BEGIN USART1_IRQn 1 */, m' N6 ]3 U4 b' u% p) h
  69. 0 ]1 N' m1 Q2 h( T* k; E
  70.   tmp_flag =  __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
    4 g% U8 Y  j$ {9 _) I
  71. 4 j, j. }# U( \7 o' v
  72.   if((tmp_flag != RESET)){
    # b- T5 ~" _- F4 g" Z. Q/ N
  73. : c0 p4 ?; s1 O1 ?  j+ r: v- W
  74.     __HAL_UART_CLEAR_IDLEFLAG(&huart1);
    9 ~* c- {# A* j2 g6 P# w

  75. 4 f6 T% Q4 H6 S1 b& x; k1 V/ C+ V2 ~
  76.     HAL_UART_DMAStop(&huart1);7 M8 q. A& |  t, f

  77. 5 Y& h% }6 K: |2 o% T0 b
  78.     temp  = hdma_usart1_rx.Instance->CNDTR;; W$ g  P8 B, L" k
  79. 6 g; a' c6 e( b1 n4 }9 e, F5 Y' u
  80.     rx_len1 =  BUFFER_SIZE - temp;$ p; }1 @4 n# h

  81. , _/ ]6 G, Z' m  w9 ?
  82.     recv_end_flag1 = 1;
    3 G4 A6 j9 b, T
  83.   }
    / i4 e. u' S. T0 r+ z5 _, R
  84.   /* USER CODE END USART1_IRQn 1 */: E; E, S8 ^3 r$ I
  85. }
    , |: W/ P( ?/ J
  86. $ P0 y) J. f% g" I5 W' Q9 x) q% M8 Z

  87. & l) \$ E9 k4 P7 k) e
  88. /**0 ]: G$ I, N" q4 r4 q- L
  89. * @brief This function handles USART2 global interrupt.' n. T. _. H2 W% b5 w
  90. */
    , E$ A4 E) k, v  K7 W, t; T5 k
  91. void USART2_IRQHandler(void)
    1 R" [, r+ H. t2 `, C  x) Q  v5 R
  92. {% w0 @3 V1 x& i2 M# z# D
  93.   /* USER CODE BEGIN USART1_IRQn 0 */
    2 [+ k/ q) Q" F8 B* ]0 R# V
  94.     uint32_t tmp_flag = 0;
    ; E9 X0 W7 H1 E! D( u* T9 C5 N9 y7 f
  95.     uint32_t temp;6 t) ^- z& l+ L

  96. 0 A) i; R+ \3 Y( c8 Y
  97.   /* USER CODE END USART1_IRQn 0 */    , {) V( ~9 ]/ Y
  98.   HAL_UART_IRQHandler(&huart2);/ l& q( Z; G% g
  99.   /* USER CODE BEGIN USART1_IRQn 1 */2 L: o8 ~  C& _
  100.   R- R. o2 V9 \  B
  101.   tmp_flag =  __HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE);
    / g, O/ F* D/ L  i& R

  102. / k; w2 J4 w  Y
  103.   if((tmp_flag != RESET)){
    - ^' _0 [, I/ E  D! _. r
  104. 9 J0 }. A/ ?1 I
  105.     __HAL_UART_CLEAR_IDLEFLAG(&huart2);9 j6 N- U/ J+ p0 z# Q- i
  106. 9 b, [6 ]: V* @3 I# W
  107.     HAL_UART_DMAStop(&huart2);" F7 |  @& p! I* F! |6 B  M
  108. 9 a6 s" k& F3 l. A
  109.     temp  = hdma_usart2_rx.Instance->CNDTR;
    8 ~( z/ }' e, x3 l
  110. ( O: }: ^& k8 H3 X+ ]2 n! C
  111.     rx_len2 =  BUFFER_SIZE - temp;
    * I0 Y; ]2 F: y0 i6 ~9 z9 @

  112. ; v" e3 V' g0 j
  113.     recv_end_flag2 = 1;. W/ p# H5 t* i9 y
  114.   }' H; A" @9 Y3 l0 s. s( e
  115.   /* USER CODE END USART1_IRQn 1 */
    8 A' G* c4 I: {9 J% U/ b$ S3 n
  116. }
    + n$ d6 k- f; I
复制代码

. O' e  |$ k3 J: k& o$ ~
) ]9 [* g0 h. o  G# K9 a! \) c0 q/ Z! o" n+ |
上面的代码,也是参考了网上网友的帖子。 希望网友指出问题,和给出更好的代码方案。
" D; p8 ^8 T# K: N8 \2 U也还听说串口DMA有三种方法,我这里用的只是其中之一的“空闲中断”法。/ w( I" G& j- m6 W. E
5 M) L# O+ s8 S2 Y: F9 r4 Y
附完整代码:' ~! s$ v9 e1 R1 v  Q- g

0 e( o7 N# |0 {! A. C: ~6 }9 S! A

STM32F103-USART-DMA.rar

下载

1.66 MB, 下载次数: 356

评分

参与人数 1 ST金币 +1 收起 理由
生命在于折腾! + 1

查看全部评分

1 收藏 8 评论14 发布时间:2019-3-8 22:08

举报

14个回答
radio2radio 回答时间:2019-3-11 14:26:44
今天,有做了一些测试。从使用的角度来看,一楼附件的程序是可以使用的,只要,
: Q7 P2 A3 X( R$ L; q1. 数据包长度不超过DMA缓存的长度。2. 发送的间隔不少于200ms。
0 N3 e' W# f0 e1 G. v0 i' C就可以115200双向同时收发无差错。
  o2 A/ w% \. @+ k
9 u: Q$ S) s' i% r9 _至于单方向收发,1Mbps,2Mbps,都没有问题的,放心使用。
riceglueball 回答时间:2019-3-21 09:50:33
学习了。
wh8 回答时间:2019-3-21 10:47:35
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中断也只在一半完成或全部完成时触发;但无DMA时,每个字节收发时其实CPU都需要入中断操作一次,只不过库函数帮你做了而已。$ b, ^% i4 [* e% r* M
所以个人认为LZ的测试方式其实问题在于,用中断CPU可以收一个马上发一个,虽然两边都CPU占满了但响应肯定快;但DMA是收完全部时再全部返回,那CPU虽然很闲,但响应就肯定慢。这样测试时DMA对CPU占用少的优势就测不出来。
适苦欲死 回答时间:2019-3-21 11:50:19
学习中,之前没有用到DMA,用的好像就是空闲中断
radio2radio 回答时间:2019-3-21 16:36:32
wh8 发表于 2019-3-21 10:47) q5 k/ L" B- k6 z! D
感谢LZ的分享。个人认为DMA的好处还是能释放CPU。一组大量的数据DMA传输,启动后CPU就不用怎么管了,DMA中 ...
1 w5 C' i$ S3 `4 `: G% D
同意,谢谢。
/ a5 d. y6 i" N8 e/ t; X. h
& i' _* d( p% h& x$ c+ w/ p总之,串口通讯,本身是没有纠错重发功能,速度又很慢的外设。: d% D6 K! S2 E# w' \& l! K
影响丢数据的因素,也就是那么几种,照顾到了就没有问题。
Kevin_G 回答时间:2019-3-25 12:52:36
收藏
eugenia2019 回答时间:2019-5-7 19:06:08
学习了
polarbear7 回答时间:2019-11-7 17:18:25
你这个怎么测试的啊,一点串口一点反应都没有的?
适苦欲死 回答时间:2019-12-23 17:19:02
学习了                                   
happyavr128 回答时间:2020-2-6 15:10:14
学习了
owenouyihui 回答时间:2020-5-9 12:32:41
有测试作为数据支持,不错
生命在于折腾! 回答时间:2020-7-21 18:04:16
谢谢 分享
' E9 H9 V9 p8 A
daxinxin12 回答时间:2020-7-23 13:59:38
学习一下DMA的操作
jesseqiao 回答时间:2021-1-19 17:11:51
谢谢了,好用

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版