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

【经验分享】stm32l0xx基于CubeMX使用UART+DMA实现数据接收

[复制链接]
STMCU小助手 发布时间:2021-11-17 23:02
前言, Q: l; T& p- ~3 _* X
最近用了NUCLEO的板子做一些东西,用到了串口通讯,结合一些资料再加上自己整合基本实现了发送和接收任意长度数据段(第一次写博客有点小紧张哈哈)。
; n; ?5 c. S- w. ]: w6 E4 Y" g0 d7 `+ N( x
CubeMx软件的配置过程6 k5 Z( Z. c6 i
首先,建立新的工程,选择芯片类型,这里我用的是stm32l073rz。
' g) f0 C, \  u
20190410100032597.png

& H  T  A  n) |2 O  c: K1 ?
4 t' z+ a9 _) U$ }- _) p( ~, `下面选择sys部分,勾选Debug Serial Wire (这个好像是下载调试 st-link,也不是很清楚)。
7 i3 U/ N& g7 Y5 ~5 B6 h4 C- J1 ^  q7 ~  o4 [5 i
2019041010014633.png
: r  |, x& ]0 N! \+ w

! |& Y6 z# ^$ R  Q8 d4 N2 V选择USART2,选择模式Asynchronous(异步通信)模式。
- f; H% }' \) d4 h' f) N# h7 X/ W2 X0 R
20190410113952285.png

8 d0 x/ V, m. h+ j4 p; C3 E
/ R+ U2 U& R: F选择下面DMA模式 ,添加rx tx,并设置tx为循环模式。
8 z# G3 ^$ p' n8 q" n& H. `5 C& H# I  t
2019041011471796.png

, h" l' \( b7 X0 j: d1 Y
, m9 h1 L' I0 a+ X% d勾选USART2全局中断。
3 }" B+ |" F3 i0 q* z8 W! P% N0 v7 I
20190410114907232.png
8 C" X9 `1 h; H5 f# @8 z

4 a7 O3 a' K! u保存工程,选择相应的选项,生成代码即可。6 b$ m/ [1 U' `/ e" x$ C
& F! U) K+ D& X/ T  e8 n  i
20190410115305458.png
6 I  _% K4 U" J- s- y7 X) u

% g6 ~9 N7 N/ A5 e6 R1 O2 v5 c0 Z代码部分
. r4 d; z. V  }0 z6 n0 j: VC语言的重定向fputc函数
# j$ c- a! n0 Y" J# W  L
  1. int fputc(int ch,FILE *f). t; b7 Z8 i* S- P# }. `
  2. {
    / |8 |, U0 K' z3 b
  3. HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);* v2 a; ?: F" W! l
  4. return ch;3 ^# T. W' h3 ^0 O( _) o$ ?
  5. }
复制代码

$ J$ W2 K* u0 k% Y, H, g& B- Nch为要写入的参数,fp指向FILE结构的指针;这样重新定向后就可以使用printf直接输出。: Z; r4 y4 r9 K& O) ~1 S
5 t" g# ?2 i: u, |5 n) A1 U
变量定义
& J* D" L- J; N% Q1 m" V
  1. #define RX_LEN 1024 //定义总的数据长度$ }2 Y& C8 K% \8 ?
  2. volatile uint8_t  RX_flag=0;        //IDLE 接收标志
    ) w6 t4 V$ ^" K1 d( P
  3. volatile uint8_t RX_Size=0;          //接收的数据段长度
    ' X5 `; q6 F8 u9 q. @- N: V- s
  4. uint8_t  RX_pData[RX_LEN]; //DMA 接收的数组
复制代码
" \# ?0 r& v* m
volatile 关键字提醒编译器定义的变量是易变的,编译后的程序每次需要存储或读取该变量时,会直接从变量地址读取数据。在中断或多线程中使用volatile关键字可以避免不同优化等级时程序出错,提高程序的鲁棒性。; z: R+ t& ?" _: g

$ b( n3 ~& I% ~; `# D4 r2 V中断函数
) P# s0 o5 w! x
  1. void UsartReceive_IDLE(UART_HandleTypeDef *huart)  
    ! l2 p- Z1 u7 p+ `* V* g
  2. {  4 L0 O$ |$ _" D3 i' n
  3. uint32_t temp;  
    ) s) W2 z/ O/ d& R
  4. uint32_t tmp_flag=0;% r6 n, O, O: h! Z& `3 j! F" B% C
  5. tmp_flag =__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE); // USART_IT_IDLE中断,是串口收到一帧数据(也可以叫做一包数据)后,发生的中断。
    . P; }' X: u8 J: \% z1 L
  6.         if((tmp_flag != RESET))//tmp_flag不等于0
    7 L: G  G+ n/ E! e! ~! Z
  7. {   
    ( L3 c" r; `- A0 d- Z" n8 a1 \
  8. __HAL_UART_CLEAR_IDLEFLAG(huart);  //tmp_flag=0;
    5 `" ?* i( p# j* m
  9. HAL_UART_DMAStop(huart);  * s  v' \; i1 B8 Y: b6 o8 M
  10.   temp = hdma_usart2_rx.Instance->CNDTR;  //cndtr为未传输的数据
    # C2 s+ \( x. @* H1 [, j
  11. RX_Size =  RX_LEN - temp;   //总数减去未传输的,得到发送的数据长度
    / T+ I9 u/ G& a* L, p* c  S# W
  12. RX_flag=1;  . `) f5 F8 N/ {- D9 n
  13. }  
    : U; M% Z/ C2 V. z/ d
  14. }
复制代码

; m; S2 \. x. ^, @2 ~4 O5 F& f" L% Z- i5 J, O6 _: t, K
在中断请求函数加入自定义的中断函数。
# p5 W' j) [9 \: r- a6 `) ?- N$ p& d8 k$ o" `
  1. void USART2_IRQHandler(void)//串口中断请求! e' I7 d; E9 _9 g2 @' B
  2. {
    # l; @! k/ L6 M- b
  3.   /* USER CODE BEGIN USART2_IRQn 0 */  x- t9 `* n8 T8 a# F, G! Y
  4.   UsartReceive_IDLE(&huart2);+ ^& i4 a/ W. |9 S9 R. @+ Q
  5.   /* USER CODE END USART2_IRQn 0 */
    9 ]; x  s* \) O" q6 e: e0 s3 b+ B
  6.   HAL_UART_IRQHandler(&huart2);4 P, h6 N+ |; j- v* u$ l& y9 _  k

  7. & x" E: B3 G0 ]' `7 X, x
  8. } / b5 u+ v0 X+ O5 ]; `* W
  9. static void MX_USART2_UART_Init(void)//在这个中间加入使能函数   切记切记
    + N/ y0 a4 ], z" P
  10. {/ m' T5 ~0 ?% f8 P
  11.   /* USER CODE BEGIN USART2_Init 2 */
    ; a" ]4 U, ~1 y! ]+ Z
  12.     __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);//使能idle中断% W) R2 m/ J: d

  13. 6 \7 ~/ d  {4 G" Y7 N$ X9 u5 J+ Y0 E
  14.   /* USER CODE END USART2_Init 2 */
    $ S, S- J3 h3 W0 T6 j
  15. 5 n( R: f2 A4 D" j
  16. }
复制代码

( m3 e! s5 j8 V: f# C发送主函数* F7 Z0 H* T6 @
  1. void uart_pc_com (UART_HandleTypeDef *huart)' p0 m, C) s; Y. @3 c) c, M9 h5 ]$ S) T
  2.    {8 C6 t' U+ x& y  `9 v1 N5 X! O
  3.    if(RX_flag ==1)
    , |& c, @$ |' G1 J
  4.            {
    , C% `& s- b/ u3 L
  5.                    printf("rx_len=%d\r\n",RX_Size);//\r是回车符,\n是换行符' ?" K9 d9 c4 n
  6.                    HAL_UART_Transmit(&huart ,RX_pData, RX_Size,200);: T. x" q+ Z3 Y6 T+ r, g
  7.                    for(uint8_t i=0;i<RX_Size;i++)  Y! ^: n: c6 |: d
  8.                            {
    4 s/ O4 q' ?$ b7 J& a
  9.                                    RX_pData<i>=0;//清除缓存
    / W  H$ k, Z& M1 E
  10.                       </i>     }) N) Q9 J/ g! C$ A( B* t9 q( [% G
  11.                    RX_Size=0;
    - G$ L; V( |- V% b9 f6 F
  12.                    RX_flag=0;//清除结束标志位
    / m5 J7 @9 N5 X( q! q" I8 c+ Z
  13.             }1 q1 a3 d2 s7 g
  14.            HAL_UART_Receive_DMA(huart,RX_pData,RX_LEN );//打开dma数据存入rx——RX_pData
    ( ]. e! }  S+ @
  15.             //加在 MX_USART2_UART_Init中  pc串口助手只能接受到一次数据  只有处于main函数while循环才能一直接受发送
    / \+ n$ Z3 m% ?: m6 E! ]
  16. }
复制代码

' C5 D' L. N& }* D$ a/ o! C9 C; u2 e在main函数的while循环里面加入此函数,并注明使用的uart。9 i+ D0 _/ m* ?8 J8 P

2 o. M( K. \, P$ _对于程序的理解
% _8 i' H" D$ `1 L3 v  d首先uart接受数据,触发idle中断,进入中断请求函数,获取接受到的数据以及数据长度,并将标志位置1,进入主函数输出到串口助手4 e/ o3 J' T& s6 h3 P2 w% [3 y
8 v4 V7 v$ Y& a; v$ M% y
串口助手效果
. _8 w0 D& w- {, t0 g% B8 G9 y
% t6 u  ?  g" ^# @! h基本可以实现本次的目的,首次写,表达不够清楚,望理解。
, i1 y2 |( A( y* a5 Y
. X& C/ c8 {3 R' x4 ^7 w
, M4 ?7 a/ P& o/ l6 |3 c* u1 d: W. d+ J% L
2019041012323246.png
收藏 评论0 发布时间:2021-11-17 23:02

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版