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

【经验分享】STM32使用HAL库DMA+空闲中断实现串口不定长数据接收

[复制链接]
STMCU小助手 发布时间:2022-4-10 21:55
首先配置串口:$ l/ v6 J  \6 U9 w+ g, B1 `
+ o, G/ w) r% q4 N" ~4 D* z6 O
V~7F]1~1DR$S0$$%C`}0@CU.png
. U7 X2 Z! H/ y' V7 g" a
7 q) \4 t, N7 c9 R! U8 S开启串口中断:( L' F; Z2 l/ D5 `4 l1 k+ ]( d; P5 E

0 s6 M4 k8 X% S( ^& J$ R6 l
ZJH@T_F`WF[`H@6$E6O$QGC.png ' P% Q7 M6 K) \. P+ I
7 \6 u  R- ~7 g4 _
开启DMA接收:9 B+ ?9 s3 V% k0 r' @: s; F$ y

4 W1 Q6 ]9 P6 d4 D0 A" E
MR{5DNR]34L5HW_8R4PZF]E.png % s* z7 r* t$ L$ O8 B, s6 W
' P4 x; a( Y; l- K# M2 y9 |' L) ]: A
配置中断分组:7 q! {( {  z9 S
8 d; Q3 P6 S- n4 A  G
M~]XVNW_]TZWS`765LI7O_W.png 3 A: J  A; c/ ~5 O8 {
, b8 ^3 b1 T) m! i5 q, ^' _+ F6 j0 E
取消自动生成串口1的中断服务程序,我们自己写:# r/ g$ R: `5 r8 Q4 Y1 I4 A

# |0 S. U) N. W2 h
[J@)QLG}$H%(4R04YBH3GLP.png / p7 B* Q2 |; r" |! F0 P- F1 E9 Q! c
# j- x4 r& E7 a; z! U" g1 Q
然后生成代码就可以了。
# T- e& q% h: R8 C8 n- c9 P5 g

4 y+ q) d. r% C+ \进入代码,添加串口1中断服务程序:

1 J5 G) Y$ u  t, v$ R4 o2 ]. y3 T3 E% i, J0 Z
  1. #define UART_RX_LEN 1024           // 一次最大接收的数据量' V& _0 g  q# N/ e" [# Q
  2. uint8_t UART_RX_BUF[UART_RX_LEN];  // DMA数据接收缓存
    2 h4 g$ L0 m3 m8 ^+ ?
  3. __IO uint16_t UART_RX_STA = 0;     // 第15bit表示一帧数据接收完成,第14~0位表示接收到的数据量
      s- o# l: b& o5 S2 z
  4. 4 s' c! J& i" P( g: f6 W& f' ~
  5. void USART1_IRQHandler(void)
    7 H3 x8 a" a# _" b
  6. {
    & o; K7 l, \: j* E3 ]  u
  7.         if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)  // 空闲中断标记被置位) \" Z2 x% Z$ N* u& u. D
  8.         {
    0 _  Q2 j. |* k3 g4 x7 R: q6 y2 h! F
  9.             __HAL_UART_CLEAR_IDLEFLAG(&huart1);  // 清除中断标记/ [; |* T! z% H7 H6 @- N  h9 I* ]
  10.             HAL_UART_DMAStop(&huart1);           // 停止DMA接收- I/ `% j! ^# {+ t# z& U
  11.             UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);  // 总数据量减去未接收到的数据量为已经接收到的数据量
    ) x+ j4 y: S# G) ]8 P: G5 b3 L
  12.             UART_RX_BUF[UART_RX_STA] = 0;  // 添加结束符# x$ y8 c- G& G+ G+ n, }1 V
  13.             UART_RX_STA |= 0X8000;         // 标记接收结束
    ; \7 b2 F1 @: w
  14.             HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN);  // 重新启动DMA接收
    , O' \$ L. K0 w3 S! h  z
  15.         }
    ; z7 i4 u) h5 D' l; c
  16. }0 }+ s( g9 ~8 Z/ X, x
复制代码
- Z, V( K2 c& F
使能空闲中断和DMA接收:
5 I2 C* z* R7 n. S# I+ ]
% \: H7 B2 v) ?7 |2 a) `- H. E
  1.         HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN);  // 启动DMA接收
    # I1 q) G, J# D8 o: `& e
  2.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);              // 使能空闲中断
复制代码

! m. |! C6 Z- f3 e/ m  ^while死循环中加入发回的代码:: m/ x) |1 [  m  W, a5 Q; n

& p: Y/ P( H/ Z" V) `; h$ p
  1. if(UART_RX_STA & 0X8000)8 J( h: j; b+ q! N8 O
  2. {+ [0 @9 u" W7 A
  3.         HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100);    // 将接收到的数据发送回去
    9 h6 Z" _8 Z2 v  x1 a4 z- B
  4.         UART_RX_STA = 0;  // 清除标记' l% H4 W$ u3 h  d$ c) n. V
  5. }
复制代码
2 e% t! H! F7 L; B
完整代码如下:
& ]- _: r, y( [* H5 |  Z( U
2 S9 W( Y  h' g
  1. /* USER CODE BEGIN 0 */
    7 H/ e6 C( e7 \+ R2 k& r
  2. & `  t" b& a$ V! m, e5 Q; O
  3. #define UART_RX_LEN 1024+ T3 _) j7 c4 U/ Q# S: y5 X
  4. uint8_t UART_RX_BUF[UART_RX_LEN];
    6 R6 O) l2 h! S/ L4 B
  5. __IO uint16_t UART_RX_STA = 0;
    " c: a! |9 p, `, ?- R
  6. + l4 L6 _$ o2 u; V
  7. void USART1_IRQHandler(void)! G* d% g5 K# `% ]: @0 P2 O
  8. {
    5 y: |! s& V4 P) t$ W# V
  9.         if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)  // 空闲中断标记被置位
    . C" \# |/ z# B) b! i* v) ^
  10.         {& [2 _& K1 X5 N4 B! o1 L
  11.             __HAL_UART_CLEAR_IDLEFLAG(&huart1);  // 清楚中断标记0 X( S, |& |" q1 w! B
  12.             HAL_UART_DMAStop(&huart1);           // 停止DMA接收( l+ P3 D" y* g; H5 |% f( u3 N+ {+ W
  13.             UART_RX_STA = UART_RX_LEN - __HAL_DMA_GET_COUNTER(huart1.hdmarx);  // 总数据量减去未接收到的数据量为已经接收到的数据量
    # L* ]. P, W4 o0 t; y8 p2 ]
  14.             UART_RX_BUF[UART_RX_STA] = 0;  // 添加结束符% a: v2 Z; J* J
  15.             UART_RX_STA |= 0X8000;         // 标记接收结束+ {/ ?) O, ~( t7 m5 G1 g" r5 B
  16.             HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN);  // 重新启动DMA接收3 Q/ s' p6 p5 I: t$ ~$ X8 Q
  17.         }
      W; i) l1 \5 f+ k' d
  18. }
    * S0 T) V& Q$ k' M! @" M4 y
  19. : Y/ p: `/ Q) [
  20. / n5 b3 C; U3 L9 _- X! Z5 Z
  21. int main(void)% ~  I$ Z% R& G$ T- W
  22. {
    / |" \/ U% `7 I. T* S2 X
  23.         HAL_Init();. S: ?  V: G5 c% G
  24.         SystemClock_Config();1 S) ]( ?0 T. q- X
  25.         MX_GPIO_Init();$ u+ w; L& @3 M1 t: v! i% i8 c
  26.         MX_DMA_Init();
    * ^1 r% {1 x4 J3 A  O* V  M$ \
  27.         MX_USART1_UART_Init();
    8 s5 B- M' f* J7 S' `* O
  28.         HAL_UART_Receive_DMA(&huart1, UART_RX_BUF, UART_RX_LEN);  // 启动DMA接收9 e* |1 s1 v4 t& [" t& ~0 S
  29.         __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);              // 使能空闲中断: N6 D6 x# `! }) O. Y
  30.         while (1)4 j1 r. V2 f: p, {% y" ~# B$ q
  31.         {
    . x! U2 u, c3 N$ V2 Z$ A1 P  U/ [
  32.                 if(UART_RX_STA & 0X8000)
    5 P) L1 G, w+ Z; f# I+ c8 W
  33.                 {
    2 a* d2 K1 e0 T
  34.                         HAL_UART_Transmit(&huart1, UART_RX_BUF, UART_RX_STA & 0X7FFF, 100);    // 将接收到的数据发送回去" q9 J/ \3 P% F. ^3 u$ v
  35.                         UART_RX_STA = 0;
    4 P2 T6 p# k! @- F& p$ |# _
  36.                 }
    . o7 B+ N. V7 I6 n  ^. X( X. o
  37.         }
    ' X6 j; S) a- A1 Y3 A) |
  38. }  g' b0 j( S0 ?& s9 A

  39. - |% F  t) `4 I) }: Y& v& Q4 r
  40. /* USER CODE END 0 */5 n, X0 i8 D3 l, }. u/ a$ ^
复制代码
5 H$ F0 f$ A1 x3 y. E. O: k: U6 ^* f4 F
程序效果:

9 v$ }- D0 [6 q5 Q0 ], Z4 M
3 p& n1 h' B. X6 \, ^1 C 20200903164720325.gif
7 Q2 g: s/ [& P# l+ `, C$ ^, o4 H! U, u" f. h
ends…
% ^8 y3 o) e' \$ ?
" X  J5 h) a6 f* _- R' I9 Y) q! |  W; t0 F
赞 收藏 评论0 发布时间:2022-4-10 21:55

举报

0个回答

所属标签

相似技术帖

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