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

【经验分享】STM32 定时器用于外部脉冲计数

[复制链接]
STMCU小助手 发布时间:2022-1-27 23:18
STM32 定时器(一)——定时器时间的计算
STM32的定时器是灰常NB的,也是灰常让人头晕的(当然是对于白菜来说的)。
STM32中的定时器有很多用法:
(一)系统时钟(SysTick)
设置非常简单,以下是产生1ms中断的设置,和产生10ms延时的函数:
  1. <div align="left">void RCC_Configuration(void)
    # L9 C5 w) N3 N
  2. {, F: f' G7 ~! f& |9 n; u# m
  3. RCC_ClocksTypeDef RCC_ClockFreq;
    & f  V3 v$ x7 z. K$ K/ P0 j0 _
  4. SystemInit();//源自system_stm32f10x.c文件,只需要调用此函数,则可完成RCC的配置.
    * ]( O: K* B' q' E5 s2 p( g
  5. RCC_GetClocksFreq(&RCC_ClockFreq);</div><div align="left">//SYSTICK分频--1ms的系统时钟中断
      s! V2 H6 a! E3 @  k8 z
  6. if (SysTick_Config(SystemFrequency / 1000))
    2 L  u3 ?- x  w
  7. {   $ x% ?- m& w% R  t# B
  8.     while (1);   // Capture error3 V0 d4 ~" r8 l
  9. }
    " T* o) Y5 h; |& R% u6 S  S
  10. }</div><div align="left">void SysTick_Handler(void)//在中断处理函数中的程序
    0 |& _5 P' J6 j# H! G$ r; ~  E% _9 j
  11. {$ d# j' ~2 H! t6 T6 h
  12. while(tim). b( Z/ e  h! ~1 d. L
  13. {- Q: I- A$ @! G$ M$ G* `! a
  14. tim--;
    + r! m( ?8 n/ ^2 i5 ^/ P
  15. }% O, F; j  O, H1 E+ t1 m# B0 G* Z
  16. }</div><div align="left">//调用程序:
    / R3 t1 k. ]. A( T4 P+ U# J: s
  17. Delay_Ms(10);</div>
复制代码
) ?" J1 [' x6 n$ @9 T9 _& J
当然,前提是要设置好,变量tim要设置成volatile类型的。
(二)第二种涉及到定时器计数时间(TIMx)
  1. /*TIM3时钟配置*/5 U: w# P$ Y# `( Z9 @% @
  2. TIM_TimeBaseStructure.TIM_Prescaler = 2;       //预分频(时钟分频)72M/(2+1)=24M
    ( Y6 T3 [# o5 O5 T% d# a
  3. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数
    ) O1 Y0 |! `" L7 `( X' O# h8 Y# y
  4. TIM_TimeBaseStructure.TIM_Period = 65535;        //装载值18k/144=125hz
    . }  l! p, f9 P* [9 C2 i
  5. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;2 Z" t4 e  O; B0 B- H
  6. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;0 [0 @9 q, k5 z
  7. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
复制代码

5 R& q, L: e) y- f! `& Y( B5 r* x
定时时间计算:4 p6 Q6 w2 `" |( z" f, l* W/ I
  1. TIM_TimeBaseStructure.TIM_Prescaler = 2;, H/ W( H4 F& d! O5 [6 {, ?
  2. //分频2      72M/(2+1)/2=24MHz9 R  j- t2 L! J  V
  3. TIM_TimeBaseStructure.TIM_Period = 65535; //计数值65535; R) _2 f  r5 b3 q1 }
  4. ((1+TIM_Prescaler )/72M)*(1+TIM_Period )=((1+2)/72M)*(1+65535)=0.00273秒=366.2Hz */
复制代码
) O& b- g$ C) L: y7 g1 z, X7 n9 K/ z
注意两点(来自大虾网,未经检验)1 F8 U" t( M" p0 X6 c9 U$ g2 A
(1)TIMx(1-8),在库设置默认的情况下,都是72M的时钟;" O/ g! r9 k2 X: Q- s2 v4 v2 c1 g; Z$ l
(2)TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
/ c) _7 L9 ?  U是重复计数,就是重复溢出多少次才给你来一个溢出中断,( y' _8 I2 V6 ]3 j) }$ d
它对应的寄存器叫TIM1 RCR.
9 M1 [1 U; Z* N* X( e. B, P/ C如果这个值不配置,上电的时候寄存器值可是随机的,本来1秒中断一次,可能变成N 秒中断一次,让你超级头大!
STM32 定时器用于外部脉冲计数
     因为用stm32f103c8作主控制器,来控制小车,小车的转速由两路光电编码盘输入(左右各一路).因此想到外部时钟触发模式(TIM——ETRClockMode2Config)。
     可以试好好久,发现TIM1不能计数,到网上查了很久,也没有找到相关的文章,开始怀疑TIM1是不是需要特殊设置。经过很久的纠结,终于找到了问题——其实是我自己在GPIO设置的时候,后面的不小心覆盖了前面的了——没想到自己也会犯这么SB的事情。
     现总结程序如下:
第一步,设置GPIO
  1. <div align="left">GPIO_InitTypeDef GPIO_InitStructure;</div><div align="left">/* PA0,PA12-> 左右脉冲输入 */
    : ~, F) i$ c3 o4 B6 H+ ^) w+ [7 c
  2. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12;1 m3 k/ D$ ~  }: z' v4 A9 a/ F
  3. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //2 Y9 ~* [! ~" N& m- A4 e, C
  4. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    0 M- O# {* c) Y* o
  5. GPIO_Init(GPIOA, &GPIO_InitStructure);</div>
复制代码

4 D4 p6 Y6 f4 B7 U! B4 u: r
注意:(1)stm32f103c8只有TIM1_ETR(PA12,Pin33),和TIM2_CH1_ETR(PA0,Pin10)两个可以用。其它更多管脚的芯片,有更多的可以输入(如100管脚的有4个可以输入的);(2)外部时钟输入与中断无关;(3)stm32f103c8的这个两个应用中,不需要重映射。
对于哪些需要重映射,参考数据手册。
第二步:设置RCC
  1. <div align="left">RCC_ClocksTypeDef RCC_ClockFreq;</div><div align="left">SystemInit();//源自system_stm32f10x.c文件,只需要调用此函数,则可完成RCC的配置.
    ' n1 P( h. p. d: v& ]( O
  2. RCC_GetClocksFreq(&RCC_ClockFreq);</div><div align="left">RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);* [  Q4 F2 z9 @6 v' q! w1 V. ]
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);2 X! w# z8 R2 H( T; K5 O1 C
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);( u7 O  q4 k! Y& f. N
  5. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);</div>
复制代码

7 {, Q3 J7 l! Y1 h  e( e2 }
第三步,设置定时器模式
  1. <div align="left">void TIM1_Configuration(void) //只用一个外部脉冲端口
    & H9 u$ {% e3 G. \- I8 |3 G
  2. {0 P6 h. g8 X6 b. U7 G8 \+ ~
  3. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;</div><div align="left">
    7 ]/ E7 z  ~6 t9 r
  4.    //配置TIMER1作为计数器
      B& K) U  k2 d, d, `: d0 C; i5 M
  5.    TIM_DeInit(TIM1);</div><div align="left">   TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    , P6 \' T- K- j
  6. TIM_TimeBaseStructure.TIM_Prescaler = 0x00;* {9 I5 e( f/ O" b$ I1 q
  7. TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
    ' `) r4 ?$ N/ J) e  q$ t
  8. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      p0 Z. f7 d0 l! V
  9. TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // Time base configuration  Y+ e3 v+ _! J( `% G5 P2 M

  10. 2 {" r, ]- C! Y- Z
  11. TIM_ETRClockMode2Config(TIM1, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);</div><div align="left">TIM_SetCounter(TIM1, 0);
    4 N/ {; r* r8 G5 X$ q: \
  12. TIM_Cmd(TIM1, ENABLE);
    0 x+ m2 r: |+ T* |
  13. }
    4 G! f/ d  P: W. P3 E3 u: O
  14. - D( l! j& t' I# A) v% F
  15. void TIM2_Configuration(void) //只用一个外部脉冲端口* q# ^- `9 U' ~% [$ S
  16. {
    " m3 e* s6 ^# F# c5 v6 P
  17. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;</div><div align="left">
    $ q! {+ N$ h2 d3 V2 r8 s3 G9 U
  18.    //配置TIMER2作为计数器: F- |) {! J# ?- Q  |* w- e
  19.    TIM_DeInit(TIM2);</div><div align="left">   TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    . R2 q" T& ~; C; a" ~/ ^/ {' T. |7 V
  20. TIM_TimeBaseStructure.TIM_Prescaler = 0x00;' ^$ e+ S$ R! h& C
  21. TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;0 s- Z: ~' {, K$ K% v% \/ T  N
  22. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;5 V) W$ ?: j0 L" e$ v$ y
  23. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // Time base configuration: {  C! s4 k& v$ Z1 _
  24. / L; h7 h/ w$ ~( p; k, u
  25. TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);</div><div align="left">TIM_SetCounter(TIM2, 0);
    - R5 I- o% M) K- h! e* k
  26. TIM_Cmd(TIM2, ENABLE);8 g" @" x! T  |
  27. }</div>
复制代码

& p- n- W% `& u& r" h$ ^( R* a
第四步,可以在主函数中读取计数器的值,其它的应用,就看具体的情况了。
  1. <div align="left">u16 COUN1=0;
    ' g! U2 T$ F3 v' Y% }6 f1 k
  2. u16 COUN2=0;</div><div align="left">int main(void)+ n3 w' k$ u5 F' R6 z
  3. {; |8 F4 @1 s* p3 ?: y
  4. ChipHalInit();8 R* \  J, e! r" x7 h
  5. ChipOutHalInit();</div><div align="left">while(1)
    4 ^4 ~: T' e) _( x
  6. {
    - H: G, \$ G" Q6 K* J
  7.    COUN1=TIM1->CNT;
    ( _, J  S* l% q# s
  8.    COUN2=TIM2->CNT;
    8 l! y! |# M; m% w6 f
  9. }</div><div align="left">}</div>
复制代码
# p$ M. ^$ Y& ^/ y* J7 j8 l" ~
2 M3 L- _$ W) `' k. i$ X# x% A) S
+ M3 e# }0 n: J
% F' n1 a. J/ C( L4 \0 a
赞 收藏 评论0 发布时间:2022-1-27 23:18

举报

0个回答

所属标签

相似技术帖

官网相关资源

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