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

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

[复制链接]
STMCU小助手 发布时间:2022-4-30 22:43
概述. h/ m0 ], H: K% A3 m
本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接收的数据打印出去。
! M4 @/ Q1 B7 @$ I$ l* Z" m! @
1 c3 w3 j/ j0 t( d& [9 N  M硬件准备, C9 ]' d/ n9 C* Z
首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:- Z1 [7 U5 g' o  m$ W" ]: F' f
$ Y, A1 d% P/ p6 c; J/ o
IS(PD7W85C(SQFJZNK9ANN7.png
8 L7 G: [- c2 R: D1 t( Q% z2 c
& H" Z  P% C# k! }! t; _. K# c& p选择芯片型号
5 s+ j2 ?& P6 Q3 m使用STM32CUBEMX选择芯片stm32f030r8,如下所示:
# s% O( Y( z- _- F/ i3 W$ Y" C2 Z) n
]_SALSJZ8P(PKLRY7982FV0.png ' ~% o" j' j9 O' V7 ^' k

0 Z' p6 z" K+ h7 e0 }2 L# l配置时钟源/ U- `8 d$ e4 B# }7 h
HSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:9 Z. {* Z/ _+ n

: L+ S/ l: C7 @' P, f BQAXB@O$$I[6PQ{OUXEJ2.png 5 U$ i) P9 i9 V! u
2 ^  f2 m4 F# \5 S0 f% Q" s0 `6 b
配置时钟树
: Y/ L: ^2 [2 g6 k+ F' Y+ I+ a4 ISTM32F0的最高主频到48M,所以配置48即可:
  H* Y  c& q1 k$ A9 L0 z3 m, L& P1 f" ~
PVW3)EJK1N`O}GQ_H}Z0S{Q.png " [4 u! u. k! l
, P$ G; K6 N& Y  X8 B& M1 }
串口配置

! f5 q- H* n9 P0 D$ j" B" C' c本次实验使用的串口1进行串口通信,波特率配置为115200。
  M0 ~) k, w( W: J% F2 Q4 {" V: f# c6 y% `$ L  R9 v. L
MV}74_WL51128TP4MVHTQZM.png ; Z& O# K" \5 }8 T
. d& X) T# m+ k( ]& K
中断

1 U2 Q2 ]$ O3 F# \( @
% l' v8 [; X3 x2 n# T* i* F8 } S~6PIGIOL@XGTMBDKV1V5NE.png * L4 l4 g7 ~$ W
& }+ E1 w, ~( P& z5 p
GPIO配置- w) q0 [! a4 V3 M4 R
板子上led为PA5端口,故设置PA5闪烁来验证是否正确。8 s3 a1 G$ X5 \' I
4 s4 v. g5 {! ~3 @1 F6 W
R4UAW2PNKVPMFGFW`2]8]D4.png ( x: d/ h7 b+ Y" V. w3 `  K4 {

3 l4 r. g+ X) \7 d$ Y- F8 _& S定时器配置
+ r8 V: L9 M; r( e1 {' k' H本次实验使用的是TIM3来进行计数。
2 e) |% H- m" @$ p. k. _+ n: p2 e$ x: }8 B+ E8 ?0 K7 a
20201114005250315.png
& S6 i. }# Q6 M* f+ r8 \# @+ S9 t' B
PWM频率计算如下所示
9 W; [  {! O; L6 I( [" K: n
/ P) u* W( y) G  D$ R 20200604121517190.png 1 D7 w( y7 O7 g; F5 W3 K2 x/ H0 T; ?

& l: Y& l+ s# O' P在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。% O7 d- g5 A$ m! R5 L) M
, u- ~# v: }; ?0 c
生成工程设置

: m- p8 ]$ ^2 B注意在生成工程设置中不能出现中文,不然会报错。; A& V* R) R- U) @
9 A3 B& q( @. H. w. x
20201114010119218.png
' ~, v) t: u$ I) C) Z, f: D' {  D$ T7 X+ u: F
代码生成设置
6 V7 z# e0 s: v, q! e2 }
最后设置生成独立的初始化文件:+ P8 ^. \7 H* R4 T6 @6 |
) v* [2 v4 I8 H
20200604142313327.png 8 ^5 J) I" |% M# R

6 R# w& ~) m+ K6 G# C1 x9 t6 J5 p. R生成代码

3 ^6 |8 j0 {4 }1 B* p' I
# q% Q( M. q. }6 L( H: [  t7 W4 z 20200604142359253.png ; L! N* S5 M- J5 R, e' x$ P
  F( l; t( M0 {4 x5 i% x
配置keil6 v: o0 Q# ?' ]  ^
1 i$ C' X. m$ k3 w) X% v' s7 J( t1 f
20201114010535287.png
3 ?6 T) _1 l* J+ K: J
2 H0 S+ p4 }9 \1 a$ v( n3 L3 B& r代码
. l( _) F& @; `6 D* U+ E
在main.c中,先加入头文件。
  1. /* USER CODE BEGIN Includes */5 Q# _. E# x0 v! s0 C0 Z
  2. #include "stdio.h"//printf头文件
    5 Y: T3 f. ]* {4 ?+ }# G7 f* i' k; A
  3. #include "string.h"//memset头文件/ E: c; K4 _1 {: V
  4. /* USER CODE END Includes */. j: U+ T! H" E" A# x8 z5 z
复制代码
4 X2 x* k3 ?! U% _7 g% e
定义变量存储。
/ W2 P% c5 ^4 X9 d/ o
# \! \: d* S4 o% H6 R5 D1 F
  1. /* USER CODE BEGIN PV */
    8 x+ X! [5 s0 ~7 o2 N! ^7 g
  2. uint8_t RxBuff[1];      //进入中断接收数据的数组% A6 {: d& Y) O) ?) r8 {( Z/ _1 P8 p
  3. uint8_t DataBuff[5000]; //保存接收到的数据的数组, e! p0 x: Z8 v: P; Y
  4. int RxLine=0;           //接收到的数据长度
    0 W' Z* I" A: c8 k  m6 s8 j
  5. int Rx_flag=0;                                        //接受到数据标志/ j- h6 t5 h! ]! Q" Y- _
  6. /* USER CODE END PV */
    ; a( l1 n% k: s% r8 D  ~  G6 h( K
复制代码

) F9 \) M* c; N+ D$ o定义printf的重定向函数fputc。
! F. U9 E8 t$ n7 D! k5 t  B/ x" g. U# r& F0 `4 t* y
  1. /* USER CODE BEGIN 0 */( K- h! w! F& H4 I6 N9 u. e
  2. void printf_usart(void);//输出内容
    ) N- M2 C0 S4 C
  3. int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印3 h4 M* L6 [6 \% ^% ]9 U
  4. {
    3 o6 O' g; q6 P- K# W: q
  5.     return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);# P  d9 f7 ?* ?7 P( `  m
  6. }
    & b' b% Q8 q$ {
  7. /* USER CODE END 0 */
复制代码
6 ~" V3 O* Y- @' T
打开串口和定时器。
4 s- T/ w3 g: K. W
5 Z7 _5 I& F' v, _  H
  1.   /* USER CODE BEGIN 2 */
    * p2 p  d" T' k5 E4 D
  2.         HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收. L- u4 j( L0 {  L1 z% z
  3.         HAL_TIM_Base_Start_IT(&htim3);//开启定时器2 c; I' b% ^+ q$ R: q6 U4 k
  4.   /* USER CODE END 2 */
复制代码
6 Q3 s! e- @' y& A$ ?2 K
串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。
& ^0 {2 M+ t8 e6 W; ~
5 L5 ?- l9 ^- v# p8 N  X) K
  1. /* USER CODE BEGIN 4 */3 v5 B& X6 N4 a
  2. void printf_usart(void)
    5 x, ^3 w+ O3 y
  3. {* F) G3 F+ P0 A
  4.         printf("数据长度=%d\r\n",RxLine);
    7 p; C, k3 v/ Y8 C5 V
  5.         for(int i=0;i<RxLine;i++)7 X3 Q4 [8 B! Q. X, U: \% G9 r; V( e
  6.                 printf("数据:[%d] = 0x%x\r\n",i,DataBuff<i>);                           
    + F0 I6 }$ y6 F/ t
  7.         memset(DataBuff,0,sizeof(DataBuff));  //清空缓存数组
    , q4 Y0 a+ e1 `1 J; l1 B0 e4 G
  8.         //memset()作用:可以方便的清空一个结构类型的变量或数组。; O0 N5 i: _+ [+ @
  9.         //例句:memset(aTxbuffer,0,sizeof(aTxbuffer))  用memset清空aTxbuffer。
    - x5 g+ f/ [( z9 ~
  10.         RxLine=0;  //清空接收长度/ b/ ]1 l# H' e" f
  11. }" S4 H  N$ Z/ f9 Y. [' {2 K

  12. 2 e) {3 ]  p, i, r
  13. 3 M3 A# x. q3 V$ @& N" i1 Q# Z, n
  14. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    % ^& m4 c+ e  m, R* k0 H
  15. {' v  d  @* N# U5 m
  16.     if (htim->Instance == htim3.Instance)' q2 N& U9 c7 m% l0 u" i) a- U
  17.     {) y- e3 |; j4 g( s/ c, j& _# D8 x
  18.                         HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
    ) G1 x; H2 g& |
  19.         /* Toggle LED */
    ' L* Z) T6 T1 I$ e
  20.                         if(Rx_flag==1)
    ( ^/ X9 Z6 k  `' X* v  n2 N6 ]
  21.                         {7 ^, K0 G5 b: X+ b9 H1 N
  22.                                 printf_usart();# Z& y  U) @. s! H" y- c. }( }
  23.                                 Rx_flag=0;
    $ E) _  T& O0 r' l  _( }
  24.                         }* B2 j& U; s% a# J1 [
  25.                 }        
    7 o0 {9 R/ v! [. L9 O
  26. }
    , I2 d6 K* W/ d: V" k& j- _% O2 q6 X" [9 G
  27. : p# \2 |, P4 \  j
  28. & O. @+ [4 Z+ u! j/ r0 q) z5 t

  29. ) h/ {, N/ C' \9 N% V. q
  30. // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数6 q$ F% W- r) X, L8 _$ n# Q$ W
  31. void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)1 I  L# z! l4 F3 z3 Z
  32. {
    + a  f9 e6 D" s8 U( r4 Y4 s0 a. V
  33.     RxLine++;                      //每接收到一个数据,进入回调数据长度加1" H, O: M  a) y, P
  34.     DataBuff[RxLine-1]=RxBuff[0];  //把每次接收到的数据保存到缓存数组1 R( D% d  c$ [1 [, ~
  35.                 Rx_flag=1;
    . p4 ?( S0 L9 l
  36.     if(RxBuff[0]==0xff)            //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff
    0 `+ w, Z. k8 D% S* Q4 J* k3 H9 w
  37.     {+ V6 \, c5 h3 c8 N, O1 @7 L  z7 c$ E
  38.                         printf_usart();
    3 `2 c6 Y7 c+ m
  39.     }   
    ) K0 l8 F- c5 _! D
  40.     RxBuff[0]=0;
    4 C$ }8 G0 m" v' P& F& ~% e
  41.     HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收0 m( n0 ?' m4 G/ J: t: f& O
  42.                 __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计
    ; V1 n8 b# x, ]+ n6 k* D
  43. }
    % G' \7 L2 g+ W; X% V, y7 ]
  44. /* USER CODE END 4 */
    & n; q, T' {$ H2 S/ o1 {
  45. </i>
复制代码

8 x, q: d7 |9 p# D2 d6 E演示效果$ `2 T; J" s6 P) b' b
可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。
: H' z" d7 n7 r# S8 W/ `2 j$ d3 b8 ]2 [( T
20201114014530711.png
赞 收藏 评论0 发布时间:2022-4-30 22:43

举报

0个回答

所属标签

相似技术帖

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