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

STM32 点灯丨V2.0.0

[复制链接]
STMCU小助手 发布时间:2021-1-14 16:15
STM32 点灯丨V2.0.0
接着昨天完成的功能,今天来让咱们的程序进化,怎么用LED灯来提示故障码?
闪烁,咱们已经做了,比较简单。那么提示故障码又该如何做呢?
这个也不算难,就是在闪烁的基础上,加上了次数。
我这里,把LED的功能写成了一个函数,方便以后使用。
写程序,我一般都是直接在原来的工程上修改的。这次我是在正点原子的定时器例程上修改的,因为上面有些东西可以直接用。
我们还是用昨天的硬件,就是挂载在PB5的LED,初始化还是和昨天一样,还加了定时器的初始化。
  1. void TIM3_Int_Init(u16 arr,u16 psc)
    ! S. U. j+ n7 H3 A. [3 w5 u
  2. {
    ; o) a) ]) _& ~! N3 v) N
  3.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
      G7 e+ O. x+ B1 u& O- Q
  4.   NVIC_InitTypeDef NVIC_InitStructure;3 U' V8 S7 [! L& i/ _
  5. 0 Y! A0 q5 K% O0 b, c
  6.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    $ l( B; ?0 p% a' A% q/ I" T/ F6 T
  7.   $ ~8 \: F# S! j+ E" S) }+ Z
  8.   //定时器TIM3初始化. \+ U4 }3 ^+ g' h( M
  9.   TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值  
    / p, r+ Y1 }+ q7 t+ s) l: i
  10.   TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    " C0 b) J, V1 v" w$ b
  11.   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    " T% w; A7 W1 l0 y3 H
  12.   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式3 `( R" Y" h4 `7 H0 ~/ x# q
  13.   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位. Z, `, ~1 A$ w  {( W% c
  14. 1 o& y1 k. ~6 L9 P9 w5 b; ~
  15.   TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断8 |7 }8 y5 ?* E, a( r
  16. + ~  r: S. C7 c+ G, F0 E5 m! h
  17.   //中断优先级NVIC设置3 g9 u( j# \# C; s8 F' D, x
  18.   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断6 e' ?! n0 H. g2 W. D, Q
  19.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级) u+ c! x" @1 m/ y2 G$ H
  20.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级$ Z. r5 P- p5 [$ I0 R
  21.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    9 Z( p, ]! y7 C) l1 u
  22.   NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
    1 }7 s3 b$ D8 I' Z) |

  23. : T, Y) M0 a2 `, u7 R

  24. ; z2 A$ g& N5 \) \, w" j
  25.   TIM_Cmd(TIM3, ENABLE);  //使能TIMx           
    9 X1 ^  Y1 q" f. J4 W; n1 b( ^4 P
  26. }0 ^  W; M" ^; [$ M/ r$ F

  27. 4 s4 U7 @0 m. h" P
  28. void TIM3_IRQHandler(void)   //TIM3中断
    - G/ h3 b' R6 A: b& U- Y
  29. {5 ?- f! h' L+ y  f8 e1 @  f6 F& k/ }
  30.   if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否- T) J$ ^3 E4 q$ m
  31.     {
    2 j6 B7 p' w) [6 i, c, r5 B
  32.         SysTimerFlag = 1;7 B) ~2 \9 t* W! L* j
  33.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);  //清除TIMx更新中断标志
    3 h* U# e1 T# C  p! ?
  34.     }$ O  J5 c' k# q9 c$ y. m
  35. }
复制代码
) p$ p( Z# s  G7 [
我还做了一个函数来获取这个时间标志,这个标志的功能,是让我的程序跑在10ms的循环里
  1. u8 GetTimerFlag(void)2 F% G5 i  P7 ^! c& R
  2. {4 w, c) w; O5 g+ Z. l) |8 `
  3.   if(SysTimerFlag)
      r$ S8 S2 I0 b% F" G
  4.   {, G2 {7 ~1 G: u! ~2 p8 r( z
  5.     SysTimerFlag = 0;
    4 t6 o9 I+ t5 U, A. Z$ P6 I
  6.     return 1;
      \4 K# ~! n: C& y8 |# S
  7.   }3 ^; Q! F$ h2 J- `! z$ N8 e7 g
  8.   return 0;0 t' T- O! k5 F+ I' ^
  9. }
复制代码

( h$ r2 b: T2 r4 N8 Y& d! W
每获取一次,就将标志清零。
最后,就是今天的主角了,为了方便,我用了宏定义将LED的引脚定义出来
  1. #define LED PBout(5)    // PB5
复制代码
. q" h' k5 u- a4 F5 ~
这样就比原来省事多了。
然后就是LED的功能了,我这里用结构体将LED的一些参数进行了封装,方便管理,结构体是真的好用,大家可以多用用。
  1. typedef struct/ T% n5 B$ \7 |! E' @8 Y
  2. {8 d* h& M& \! |/ t; P. ^4 Q2 {; I
  3.     u16 Err_num;  //故障代码( L  l2 J) c3 z2 E6 t
  4.     u8  Type;     //LED的类型,0:常亮,1:闪烁,2:故障提示
    & w4 R: g% H+ ?7 z3 z7 L
  5.     u8  Enable;   //使能led2 M2 ?, m' X/ T& v2 F
  6. }LED_t;2 F" ?; J5 @$ S( c; f

  7. & l% k+ y, B) b9 p
  8. LED_t  s_LED;
复制代码
& k" R; i( v1 U+ D: E& a) U0 b- I
因为要让LED闪烁,这就要关心一下它闪烁的频率,我这里为了以后维护方便,也用宏将它定义出来
  1. #define  FLASH_FREQ     30        //闪烁频率,单位10ms
复制代码

1 u8 S* U1 {4 H) K- T. |, c: m
最后,主要功能的实现,我也做成了函数,只要将这个函数放到一个每10ms执行一次的循环里就可以了
  1. //10ms
    3 L# j* r% O6 t8 o  s+ Q. m
  2. void LED_Lib(void)
    8 j) D0 |2 `3 z* g7 x4 @  q" ?
  3. {
    ) B2 t* a3 t9 l
  4.     static u32 s_Cnt;
    ; Q3 k2 c4 D+ I7 l, {- J- g% X
  5.     static bool  Flash;
    / e7 a" y0 D/ c- R7 m  u9 Z
  6.     static u32 ErrCnt;# c" z- Q1 W4 j
  7.    
    . o1 I! [2 A  P7 |2 s
  8.     s_Cnt = (s_Cnt +1)%(FLASH_FREQ * 1000);
    3 Z! b/ Z/ Z; h  h  {( I
  9.     switch(s_LED.Type): u: Y3 l: h9 y9 c
  10.     {
    ; `$ \. S) m$ H8 |
  11.         case 0 :
    3 k$ L/ `0 E4 V6 Y/ ?
  12.             LED = !s_LED.Enable;  //赋值给IO口1 o  x( t% |# v; o
  13.             break;        * ~4 G0 B! X# W9 ]( u5 I) e8 G8 X$ |
  14.         case 1:+ L: b1 X  t) s* q+ u) w
  15.             if(s_Cnt % FLASH_FREQ == 0)  //500ms,闪烁一次
    3 R; \+ _8 ^6 m
  16.             {
    : n7 |. `3 U/ Q9 }; U" J
  17.                 Flash = !Flash;  //0灭,1:亮  o$ K: a$ n8 Q! ?5 z* p7 G" J
  18.                 ) U7 v  L9 v3 N
  19.                 LED = !(s_LED.Enable & Flash) ;  //赋值给IO口
    8 A1 T) S) V* V
  20.             }        
    5 v! f4 S7 z. |4 x& k- h- d& H8 O
  21.             break;$ O9 r' i0 U9 D7 V* P
  22.         case 2:: d$ F- j7 Z2 \# v2 m! s  }
  23.             if(s_Cnt % FLASH_FREQ == 0)  //间隔500ms
    , G2 z& i) L( }7 S' d; t7 v
  24.             {  E8 E$ S" K8 \
  25.                 Flash = !Flash;  //翻转
    ! M0 t! l$ C  [# {
  26.                 if(Flash == 1)
    6 n! p' L+ B* A3 z- @
  27.                     ErrCnt++;2 f! K$ c9 V+ C2 F* Y; s: P
  28.                 if(ErrCnt > s_LED.Err_num)+ n$ |& M( ?' s! {  [0 D* K; _( [6 p! j
  29.                 {
    ; r0 k! o" i( m, r* R0 ]5 C# E
  30.                     ErrCnt++;
    4 n; V  `" [# N. z. q5 m2 v
  31.                     Flash = 0;
    $ P3 z6 ~9 h3 j6 m. c  x
  32.                     if(ErrCnt > s_LED.Err_num + 2)//灭两个周期0 K1 k- \6 R2 H- u
  33.                         ErrCnt = 0;
    - I) P4 p3 h2 u5 _* h
  34.                 }+ z9 o7 |8 v$ x6 c9 B) o: F7 p
  35.                 LED = !(s_LED.Enable & Flash) ;  //赋值给IO口            8 u% T7 Y$ p! N; Q3 X+ ^
  36.             }1 {  `- i3 G, n
  37.             break;
    ) c6 _. l# W! o% e' K  S
  38.         default:4 @$ b1 }8 v2 g' `9 f1 }& I
  39.             break;            
    ) G& v6 B1 n" ^' ?
  40.     }   
    * Z' }, n6 {. H4 C' E
  41. }
复制代码
1 m. S2 `% J2 F
我这里用到了布尔定义,大家要用这个关键词时,要在文件里包含它的头文件进来
  1. #include "stdbool.h"
复制代码
4 r6 E. e7 Y4 o( k1 E
然后就是主函数了,由于我这里只有这个功能,主函数比较简单
  1. int main(void)0 ]' ~) _% D- ^. r: V
  2. {   
    * S) i) j9 o. `# v3 ?% h! t
  3.   delay_init();                                //延时函数初始化    ' d7 r- p0 Y( C
  4.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    1 |+ k6 j" J$ e! D8 V, ?9 ^  D
  5.    LED_Init();                                  //LED端口初始化3 w4 b; q1 t& R& n( j+ c$ T$ i  ^& ~+ |
  6.   TIM3_Int_Init(99,7199);                         //10Khz的计数频率,计数到100为10ms  
    6 `% T9 I/ W% J5 B6 h
  7.      while(1)9 U* K- J; F% w$ |2 T1 l
  8.   {2 ~* s" K% u) T7 i, S
  9.         if(GetTimerFlag())3 ]2 K2 M0 M; o  D$ A
  10.         {
    1 b8 Y; O0 I; W% |1 A+ I
  11.             LED_Lib();
    ! }5 w+ L1 s6 w& t7 a9 ?( _
  12.         }" A9 u, g% B% [$ H" x
  13.   }   
    ' {  b1 X' G. w; G' z1 D( x) f% \; Z
  14. }   
复制代码

# C& B, A+ U5 x: a& r; `
到这里,程序就写完了,我们可以验证了。大家要主要,刷了程序,直接上电是不亮的,因为当前,s_LED的参数全都是0,所以不亮。我们需要进入Debug,然后手动给s_LED的参数赋值。
实际应用的时候,只要在需要将这个结构体放到头文件里,然后包含到需要的文件里,在需要的时候给这几个参数赋值就好,程序只要走到这段函数里,都会是用最新的参数来执行。
下面是测试,拍得不好,请见谅。
5.1.png
文章出处: Yue無缺
0 h; ]9 c7 U5 ]& X; J
赞 收藏 评论0 发布时间:2021-1-14 16:15

举报

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