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

【经验分享】STM32CUBEMX--USART通过定时器中断方式接收不定长数据

[复制链接]
STMCU小助手 发布时间:2022-5-1 14:29
概述# A: [- Q' r& B5 v3 n+ s
本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接收的数据打印出去。
! g/ m* X% l2 E4 ]; t3 j9 g/ W+ v* C0 v* S
硬件准备: J9 C; c3 q( n7 Q' e7 T
首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:
! ?0 z" j' K& y  @& o$ r" L A]$VRX5W)M~6PAZP0YY9C%2.png
5 v0 I, ?  p5 ^$ ]0 _4 j. L0 R+ W9 e5 T! I
选择芯片型号% j; N6 h+ ]6 I/ Q. Q
使用STM32CUBEMX选择芯片stm32f030r8,如下所示:
6 n; `: c0 r1 h: r  }% {% K+ L* f* R- m) N  k, o
JZJ`]PAHV58]2_AJLLDFI39.png # V- l4 \" L3 J) h
3 l' N, i9 r9 }7 t. i! `
配置时钟源
1 W; D1 G' T; _  a: d9 WHSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:
! _; a) A% Q6 ~. j! \: X9 u0 t0 v; I0 X
0D0R29[ZT$]_(99XXF3)W4R.png
; `! v& ~* O1 `$ j. N- T
2 Q; Z+ G5 f4 }$ G配置时钟树
0 Z6 Y. D2 W3 M* [1 lSTM32F0的最高主频到48M,所以配置48即可:
1 J/ ~& D8 n- {/ y
  v0 P' M& r. t& n 1}B0_GTBTGLWWYQO}P9%%OP.png
- k9 s# a. e+ h% U! }. G% F7 `  U8 V. |4 R# H. ^0 r. F: O1 x4 ^
串口配置
, s5 ~! j# L: n4 N$ j本次实验使用的串口1进行串口通信,波特率配置为115200。: a% v5 F3 ?3 C- \9 `* H

+ M* k( r& ~) e) n4 e, M  K2 Y )%S47A1L@V(`X(B2%GBUQHP.png
  }! N7 J  o. ~
% `5 D6 K' M! ]7 {7 W$ ?, |中断

: J  M2 p5 K3 M/ c  H+ J7 a1 h7 N6 s( j, x, ^8 R
M}G078(JKLX%VO[UT}6GNWV.png , F% Y# ^# K2 d0 L: i5 h$ j
6 ~0 c0 S+ R( i. i5 f+ I" _4 }( h
GPIO配置

+ h, Z7 z7 n: c0 ^  g板子上led为PA5端口,故设置PA5闪烁来验证是否正确。
2 G7 d! [' x4 w* _* {8 k% L& o, u" M! T1 o7 f1 v
U@XAR]1ZAWG]B8@M[]O}KDU.png 0 r1 t% M3 X$ Y: N- a
/ H; U3 i% B$ _3 }
定时器配置
- k0 J  j7 b; b本次实验使用的是TIM3来进行计数。
3 @% n! V, r7 U# i
. B% E4 [6 h, Q FM(O{115{)`75WQR{73}65H.png
6 T. v( r& U3 W2 H# g( V9 j% F, }: o) v8 A+ c+ t) O/ s: {4 c' |
PWM频率计算如下所示0 V+ O! u3 u, k. P5 V
# G( c# E2 A1 Z* b. h/ [
{[1MD[]4SJM)C~Q7QI)JWSV.png 7 t$ P7 Y: t' k) b: N

" q/ ]' m0 Z) g0 F) |在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。! U; L) I- ^; \1 m

% n$ N: y/ G* F- Y* f, J生成工程设置

3 U2 J9 L0 H! W% _注意在生成工程设置中不能出现中文,不然会报错。
/ g+ r' Q1 d( K. v
7 i, J7 T# W- ?( B1 P" O  K UM)Q%RTY_WTC3IX4YE%}W.png
* t$ R" h8 K% o& Z& o
, H  F9 G# c9 e代码生成设置
( q" h1 b% j& }( I0 t. R最后设置生成独立的初始化文件:
. C  [" V% c3 b2 G
2 t& Y  \6 O6 Q* y6 _2 d6 n/ ^) U W%WRFW2K}]7G(C0L9B4GNRM.png : H4 P. @* `- j
0 y* x" w0 C( w( B0 m
生成代码( B- Q: X# w: C1 d: a# z
8 E5 s! K# c  s
B$V$XQYV28`6BA{1JUX6.png
& @: ]. K9 z9 e4 B; m/ u& n1 g' Y3 |* _" R" o! [' T% o
配置keil) l7 N  M$ ^: M

5 J. q5 [) O8 q, u# d
)~FT~P37MF8][G)@ABSHZ]N.png ; ~5 c1 N( v0 r
6 V& h7 e6 ]% m  U
代码
( s. @+ ]1 E  I/ S! n* J4 o, K
在main.c中,先加入头文件。
  1. /* USER CODE BEGIN Includes */
      J" k% _$ Z$ l/ y5 D0 s2 K' x9 J& Z
  2. #include "stdio.h"//printf头文件
    8 U) ?* C4 b& _: m/ C2 U  j
  3. #include "string.h"//memset头文件
    $ J7 ~" v+ F# o) o5 B
  4. /* USER CODE END Includes */
复制代码

- [, W& k$ A1 @  ]/ |/ U定义变量存储。
- b8 O" g" g% v  L, Y7 w- T) U1 X
  1. /* USER CODE BEGIN PV */
    9 w' ?6 A4 I( A# Y& p
  2. uint8_t RxBuff[1];      //进入中断接收数据的数组
    " |2 u& [. Y4 `- o# g1 M2 I- u
  3. uint8_t DataBuff[5000]; //保存接收到的数据的数组
    - {) f9 m7 t* p+ B* [! i% |9 ?+ D
  4. int RxLine=0;           //接收到的数据长度
    3 b$ ]) d6 U' O/ \( P
  5. int Rx_flag=0;                                        //接受到数据标志0 [' q7 ?8 [" i& R
  6. /* USER CODE END PV */
复制代码

0 f/ k+ y% t7 z" I2 o4 [$ O定义printf的重定向函数fputc。
. W) e, g0 [! g( k5 t7 B3 Y, ?  O; e7 P; e" }' v$ Z, Z+ S$ T; O
  1. /* USER CODE BEGIN 0 */
    # O9 a! O8 t, y/ S
  2. void printf_usart(void);//输出内容2 ^) I- @" t2 d" X5 `
  3. int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印3 R- w# Q' t8 [* s  S6 a& Y2 x( u
  4. {
    8 \; S% b6 a2 D
  5.     return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);, Z2 A- c- i: M8 I" Q! c
  6. }
    5 v2 V3 V1 m8 }$ q
  7. /* USER CODE END 0 */
复制代码
3 Y. L2 C  n1 }$ X. V
打开串口和定时器。5 D* G( |1 D9 A7 U) A, l4 ]) M

. A) O( u( l! o5 v4 V
  1.   /* USER CODE BEGIN 2 */- ^+ Q! F( C  n/ y
  2.         HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收) V, i* a" F  `
  3.         HAL_TIM_Base_Start_IT(&htim3);//开启定时器
    / o" \; x$ y+ G: Y
  4.   /* USER CODE END 2 */
复制代码
* K. E' W- m0 i5 n
串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。# _! }7 Y8 ~5 \  }9 a

, N0 p! R( H+ q- H
  1. /* USER CODE BEGIN 4 */7 I- I$ `; n  F
  2. void printf_usart(void)
    5 |- `5 o8 P  ~, B0 Y; v0 D
  3. {
    + t5 _, y7 k3 g% C' L. g$ R
  4.         printf("数据长度=%d\r\n",RxLine);
    # p' Z0 g! B* s" f
  5.         for(int i=0;i<RxLine;i++)
    ! i" e" N# W7 [% p# z
  6.                 printf("数据:[%d] = 0x%x\r\n",i,DataBuff<i>);                           
    % [+ f' E+ r. w2 ]3 W% T
  7.         memset(DataBuff,0,sizeof(DataBuff));  //清空缓存数组
    2 _8 |8 m* g" ]' x+ ^3 F
  8.         //memset()作用:可以方便的清空一个结构类型的变量或数组。
    ( B* f- Z. M2 ^, x4 r4 ~: H
  9.         //例句:memset(aTxbuffer,0,sizeof(aTxbuffer))  用memset清空aTxbuffer。
    * d# G& r' s, l5 ^( U
  10.         RxLine=0;  //清空接收长度
    ' o9 [$ ~% d0 D' J$ a3 L
  11. }
    4 ^/ P5 @$ ?) f% J$ x

  12. 7 h0 _  U1 l3 g+ X/ @3 e

  13. ; Z, [! a- |. \  h! r. }4 J
  14. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)  x( ~. z# E: K2 ^6 g
  15. {
    # O) M; [$ d; c! G9 ]' z7 M0 A6 [
  16.     if (htim->Instance == htim3.Instance)' B, S6 F# z  o# U' ]
  17.     {) D! J7 `0 s0 K7 A: X- L
  18.                         HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
    9 v4 A4 O7 A7 x' l) y6 M
  19.         /* Toggle LED */
    7 J$ w& G4 ]1 v, c
  20.                         if(Rx_flag==1)
    % o6 U3 g' _, Q3 \$ i5 X8 s1 |
  21.                         {
    9 t' l) m6 O0 E% z* }$ _9 x
  22.                                 printf_usart();7 X0 s  g# z% S# W& p7 @8 @* T
  23.                                 Rx_flag=0;/ o) M6 g- U4 k- z
  24.                         }
    # M- I* @; L- o0 z4 f, _  Q
  25.                 }        % J- ~3 B8 t8 O( o" c
  26. }& t  S4 s7 `% H' ^

  27. & B4 i8 m$ v# @' p
  28. ' f8 f$ b. H2 l1 F$ o

  29. - T* k/ q$ x) r: R) Y% c" ~
  30. // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数
    , U/ K+ {2 H/ {9 S  p
  31. void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
    + ~% e4 M( r# c/ e1 w  B  K
  32. {
    ) Q/ R  Y, b: U, |  e4 u3 [
  33.     RxLine++;                      //每接收到一个数据,进入回调数据长度加12 R0 S. z. A! r' c# h  G! X8 }
  34.     DataBuff[RxLine-1]=RxBuff[0];  //把每次接收到的数据保存到缓存数组1 B# [) P/ T4 k6 A7 E7 p$ Q* `
  35.                 Rx_flag=1;
    5 Z3 b: i4 y# s( i
  36.     if(RxBuff[0]==0xff)            //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff
    . z* m- W3 m7 u; }
  37.     {( D2 ^! t7 y0 A  F& Z" g
  38.                         printf_usart();. B. |4 N& F3 _/ t% y! w4 `& a
  39.     }   
    % C4 p1 w, h4 Q5 M/ e9 F7 N
  40.     RxBuff[0]=0;7 e) S5 M7 h4 U! e1 S
  41.     HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收
    " X! n8 k2 }* q6 x- f! D& ?( ?- Q
  42.                 __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计
    % {' f% Z& k( n, y8 w1 Y
  43. }
    $ k- _' J0 @% J5 f- ^
  44. /* USER CODE END 4 */</i>
复制代码

' R6 S  ?1 f6 W; e# t( u演示效果0 N1 Q9 E6 f) p  S& z+ F/ y
可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。( g. p! H2 d4 R: F

8 @8 b7 s7 P- ^( g+ P  Y) N+ h" ] E5%O}9Q@9GASU@0DXORMY0M.png 8 i9 c6 K5 h) C

# [" `! G+ }1 @5 T5 `& W- j$ |' L" n9 N. i( g  D
赞 收藏 评论0 发布时间:2022-5-1 14:29

举报

0个回答

所属标签

相似技术帖

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