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

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

[复制链接]
STMCU小助手 发布时间:2022-5-1 14:29
概述
' T# y6 w; b0 E9 x0 n0 g本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接收的数据打印出去。
4 y( T+ J, r3 f2 K( q, w3 r- C$ y2 X( g" m' w
硬件准备
6 v, ^5 U  o4 N' J首先需要准备一个开发板,这里我准备的是NUCLEO-F030R8的开发板:$ e; N" s. h$ f3 u% \! Z% r
A]$VRX5W)M~6PAZP0YY9C%2.png
$ U! W% s" c& c, G4 z
" M" {, ]- ?4 k1 p) Z$ y% M  x选择芯片型号
* v' e9 v7 N  x9 Q* y2 I- p使用STM32CUBEMX选择芯片stm32f030r8,如下所示:% W/ u8 x, |; n1 i) P

; j6 ^4 P5 ~) q' w JZJ`]PAHV58]2_AJLLDFI39.png
1 r8 a7 `& i' L0 ^
6 |  m$ X4 W5 R! f2 J配置时钟源
' |! e# m0 j+ a) D* @% yHSE与LSE分别为外部高速时钟和低速时钟,在本文中使用内置的时钟源,故都选择Disable选项,如下所示:
" E# P5 l3 w9 t0 r; |
+ A1 J3 z7 \) l 0D0R29[ZT$]_(99XXF3)W4R.png
: p& W! Z5 s0 I) Q  h. n) s, L* K+ H
配置时钟树
$ f$ _9 t" v0 h1 Z- D$ {STM32F0的最高主频到48M,所以配置48即可:5 K% |1 X8 Q* d+ V; a8 Z  s

% E0 C  f$ f4 Z 1}B0_GTBTGLWWYQO}P9%%OP.png
, h+ T% t0 ~0 a/ A3 j  m% J0 ~( G
* J& T' h$ t5 [, N串口配置. {  Q# l9 o* {4 C: c: _0 r/ }$ Y
本次实验使用的串口1进行串口通信,波特率配置为115200。
+ G2 ~1 N! I0 Z. V2 ~9 y" L$ h& x9 T' q7 W4 ~. O5 n! R
)%S47A1L@V(`X(B2%GBUQHP.png
  F7 u' C& s4 u) F  E: N/ A6 Q' P- F9 d" W8 g4 v; B% d
中断

$ I7 B. N* Q! j# \+ ^: R+ F! k# O2 S& e$ [6 @3 r
M}G078(JKLX%VO[UT}6GNWV.png 9 Q2 C# N9 c' s# C3 M
7 U1 ^1 s; `4 q
GPIO配置

7 o' ?5 O' {6 U' t: f板子上led为PA5端口,故设置PA5闪烁来验证是否正确。
' B' n: ~1 E$ r2 p7 N2 j/ P5 T, y. q* Z0 {! t/ \. z+ _: X
U@XAR]1ZAWG]B8@M[]O}KDU.png
' \1 d8 d* w: B! F" u* V. t3 y2 C  D- W7 g
定时器配置
$ g0 g7 K% R3 [, ?6 X0 l, S0 A本次实验使用的是TIM3来进行计数。
' b) i# t4 O% v( V/ w) }. N. }8 y0 F! B: m2 n& ^
FM(O{115{)`75WQR{73}65H.png ) ~3 j7 U3 @9 I7 x! g! C$ Y1 P# ]2 |

# B$ @& i# h8 F$ ^4 c2 N# cPWM频率计算如下所示
, U  t1 x0 D: w: K" R; q0 t3 Z/ l$ L2 I$ V
{[1MD[]4SJM)C~Q7QI)JWSV.png . j; Z$ W5 i* X# W# {% N7 a2 Q
8 x& L. w2 U2 _$ D' D4 V$ C% F. Z8 W
在上面配置TIM3参数,预分频系数设置为480-1, 自动重载值设置为10000-1,那么PWM频率为48,000,000/((480-1+1)*(10000-1+1))=10Hz,即 100ms一个周期。
; D* q' v4 [' A- K0 [$ T
7 M* ~0 h; e8 J- L! ^生成工程设置
" S- J  w$ ^' W! a' Y3 K
注意在生成工程设置中不能出现中文,不然会报错。
, ?" k9 X' Z8 c/ W; H  ^
* a1 R1 N6 D" }! B2 d0 v UM)Q%RTY_WTC3IX4YE%}W.png 2 N; E) T) k2 ]2 Z7 c1 @6 ^

) y" F" [! n$ W8 }* x代码生成设置
% B: \* ^6 B6 W, v最后设置生成独立的初始化文件:
3 G8 L! e( P! l+ \, F7 n: x: @6 U9 _, i9 f# S8 |" T7 q6 z, N. ?6 g6 ~
W%WRFW2K}]7G(C0L9B4GNRM.png
' \" X0 G  ]# c4 y( ]2 N2 \! M4 g: x
生成代码! t) y0 \- V  u* {: L" ~

: l' ~; G" x, A9 M; z
B$V$XQYV28`6BA{1JUX6.png & G1 ^, ^) _, ?$ B8 q. S

4 X# C, I, ?( L3 D* d) p" k配置keil
. X4 w, W, W* n  h3 c$ [" l# Z. P! {: Y7 u" N
)~FT~P37MF8][G)@ABSHZ]N.png , l1 `  l6 Y. h( i; e% G0 y  j9 U' \
; y# E( o+ Z, a5 v8 S7 s# y! m
代码

' T; k( \+ \0 X# `! c在main.c中,先加入头文件。
  1. /* USER CODE BEGIN Includes */
    3 I. p9 H3 c" q, [+ V- c& U& O
  2. #include "stdio.h"//printf头文件' C* ^  E0 X4 |! \! l$ O4 N
  3. #include "string.h"//memset头文件
    9 P. T+ g7 M0 j, n0 K' E4 k
  4. /* USER CODE END Includes */
复制代码

( \; \0 `+ u* o# C" d1 Z/ s定义变量存储。1 p' Z% O* ?- X# G, v+ @
  H" o. r4 t/ |- J6 H- t
  1. /* USER CODE BEGIN PV */
    - X4 r# n1 R0 e# a2 @: @
  2. uint8_t RxBuff[1];      //进入中断接收数据的数组7 q5 _0 ?6 f& B1 p
  3. uint8_t DataBuff[5000]; //保存接收到的数据的数组3 ~. M$ F, W) }1 T
  4. int RxLine=0;           //接收到的数据长度
    6 j+ R1 E3 P0 W0 v7 v$ d
  5. int Rx_flag=0;                                        //接受到数据标志
    - V6 [  n/ P4 t8 m: [* E
  6. /* USER CODE END PV */
复制代码
+ e$ m  z% g5 \" h1 j* _* c
定义printf的重定向函数fputc。
+ M$ |# F: b" D- G: ]
# @- n6 C8 T& a# M; w  v
  1. /* USER CODE BEGIN 0 */
    . Z  [$ i/ R' q+ I. N
  2. void printf_usart(void);//输出内容1 v- R/ [& y0 |8 e4 M9 x
  3. int fputc(int ch, FILE* file)//定义printf的重定向函数fputc,满足串口调试打印, [* N1 P5 X. ?
  4. {
    7 I% E- p9 m* F
  5.     return HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 100);
    ; J6 r& r6 X; h: N1 k$ Y
  6. }
    / w; J) P9 y+ s2 _# H. g8 c$ C
  7. /* USER CODE END 0 */
复制代码

$ S( _1 E  G- l. Z打开串口和定时器。
! D3 o; ?, p8 V4 X' g
1 U+ u3 x5 D  B" n. P5 T' b9 y
  1.   /* USER CODE BEGIN 2 */2 W3 W; A# B. P  v4 R& f
  2.         HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //打开串口中断接收
    * u! T- S+ i$ @4 \! v, `
  3.         HAL_TIM_Base_Start_IT(&htim3);//开启定时器
    5 r% [" G1 G+ d7 D1 M) ~( H2 z
  4.   /* USER CODE END 2 */
复制代码
2 c4 Q4 A% W$ E4 V% \& ?
串口接受代码,当接受到最后数据为FF时候,直接打印,否则等待100ms打印。
4 d, B: b" O- u9 Z$ K* k
1 l2 u& ^# s1 Y" k- r# L
  1. /* USER CODE BEGIN 4 */
    + j9 ?) K* P( R, |: e, w0 l0 I
  2. void printf_usart(void)% V! V* ~6 ]& f+ C$ C* H
  3. {
    6 l& u7 ?9 K3 b: {* U
  4.         printf("数据长度=%d\r\n",RxLine); ) M, z& [) |' m' H. T
  5.         for(int i=0;i<RxLine;i++)
    6 a. C) h  U- }2 W8 y! H( k! J
  6.                 printf("数据:[%d] = 0x%x\r\n",i,DataBuff<i>);                           
    " ~7 J: {9 X/ H8 R
  7.         memset(DataBuff,0,sizeof(DataBuff));  //清空缓存数组
    $ w: H( L% U& Z$ R
  8.         //memset()作用:可以方便的清空一个结构类型的变量或数组。
    ; L2 v) F4 }( o8 O
  9.         //例句:memset(aTxbuffer,0,sizeof(aTxbuffer))  用memset清空aTxbuffer。
    8 Z( P6 }* A2 |
  10.         RxLine=0;  //清空接收长度- u1 j% o5 T8 ^* x" N- @4 r7 a  J
  11. }5 d3 K. j5 L- C/ q8 h
  12. 3 R$ U8 W3 X: ^% r" f, U

  13. 3 U7 D$ K1 U' e7 p4 K# T9 m
  14. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    ) t3 g+ e" C: d' G( Y
  15. {4 Y# E  M4 h. \$ e. ?
  16.     if (htim->Instance == htim3.Instance)0 z  i+ {# D  N7 e% M, v
  17.     {# y' Z. E* W$ I0 n4 f
  18.                         HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
    5 d% j6 Z! q8 o* y6 m0 U5 x
  19.         /* Toggle LED */
    ! Y; P: y7 k8 t& f- ~% q) |
  20.                         if(Rx_flag==1)
    * q& g3 N# N8 N; }: K
  21.                         {7 \. f! s- E! U+ q
  22.                                 printf_usart();' s; a9 G% k5 ]! Z! Q1 S9 h# X
  23.                                 Rx_flag=0;& x. D" z4 H" F' o
  24.                         }
    # ?. `! w( I" n( s
  25.                 }        
    ( t/ U/ F  H9 Q4 v% r
  26. }
    6 v. T5 D4 _* K1 U" f
  27. 0 C$ P, S5 j  A8 q9 }; Z; h: K
  28. - i; w( g7 U( g: ?! y- h  E

  29. / W' G2 i  X- n; C, y9 ?
  30. // 捕获中断回调函数,每次捕获到信号就会进入这个回调函数
    ' R8 {3 R, {  T: Q  {
  31. void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)3 S% N% G/ l! e% U: s+ M3 `' d
  32. {& O8 O+ z. B$ a0 u! g0 \) S# o, g
  33.     RxLine++;                      //每接收到一个数据,进入回调数据长度加16 ^% A8 b  j; Y' \+ x4 s  L. F
  34.     DataBuff[RxLine-1]=RxBuff[0];  //把每次接收到的数据保存到缓存数组, x" G# @5 e+ A/ n7 F
  35.                 Rx_flag=1;
    $ u7 b$ K' Y5 T' Z/ W; c# o
  36.     if(RxBuff[0]==0xff)            //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff
    % |" V+ g* f/ h
  37.     {
    5 A) O; M2 A/ N2 \4 C; n
  38.                         printf_usart();0 D7 n% i$ B  j/ U
  39.     }   1 O3 l1 h: g( Z; a& V' u
  40.     RxBuff[0]=0;
    0 n" q; e5 s6 r0 {* I
  41.     HAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收
    & B5 M" Y6 a- d4 q
  42.                 __HAL_TIM_SET_COUNTER(&htim3, 1); // 计数清零,从头开始计
    9 @  x, B/ X" w* [. `" Y
  43. }
    1 Q; \! |9 y: D( r" W1 z& ~: o# |
  44. /* USER CODE END 4 */</i>
复制代码
' S/ Y8 K9 f  |3 ^( s
演示效果  j5 \. c- @: m3 E. Y5 m
可以看到 发送11 12 13需要等待100ms左右才能发送,如果最后加上ff直接发送。5 o3 }, C0 I, c

* y! I. Q. A9 ]( ~; O$ y E5%O}9Q@9GASU@0DXORMY0M.png 6 s' |: Y. {. e' Z
! I% _  O' V; L8 Q

3 k+ u: i. p  w6 f) d( z
赞 收藏 评论0 发布时间:2022-5-1 14:29

举报

0个回答

所属标签

相似技术帖

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