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

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

[复制链接]
STMCU小助手 发布时间:2022-1-27 23:18
STM32 定时器(一)——定时器时间的计算
STM32的定时器是灰常NB的,也是灰常让人头晕的(当然是对于白菜来说的)。
STM32中的定时器有很多用法:
(一)系统时钟(SysTick)
设置非常简单,以下是产生1ms中断的设置,和产生10ms延时的函数:
  1. <div align="left">void RCC_Configuration(void)
    / h7 `1 q: j& Q! y. b% S' r  M
  2. {6 J- F4 a, y1 G' w# d( M+ k
  3. RCC_ClocksTypeDef RCC_ClockFreq;7 [$ l2 @: _5 Z
  4. SystemInit();//源自system_stm32f10x.c文件,只需要调用此函数,则可完成RCC的配置.3 Q) [! \9 A( E0 H( h
  5. RCC_GetClocksFreq(&RCC_ClockFreq);</div><div align="left">//SYSTICK分频--1ms的系统时钟中断4 j9 A' O& P0 W2 D% f" P# D! v
  6. if (SysTick_Config(SystemFrequency / 1000))9 c* \% Z3 i+ }3 z- s  u
  7. {   & v1 ]- o/ }: s" ~9 \. w" ]7 A$ b* o
  8.     while (1);   // Capture error1 A2 o  S3 h' K- n4 N) f* e
  9. }
    1 N: h* g. Z3 N7 Q7 t
  10. }</div><div align="left">void SysTick_Handler(void)//在中断处理函数中的程序
      h) @/ Q- J3 C2 A, `
  11. {
    6 B/ q2 x, @6 `, Y! j. g2 J
  12. while(tim)
    1 }: g/ f/ P8 K$ W3 v9 c: Z  I* S
  13. {- e" |3 X, w7 h4 J2 \; C
  14. tim--;
      D8 c6 Z: J# Y9 b6 a
  15. }
    ! Z5 Q* [6 z, E6 k
  16. }</div><div align="left">//调用程序:
    * n& k! x- u, v
  17. Delay_Ms(10);</div>
复制代码
$ {/ O, `4 u  R
当然,前提是要设置好,变量tim要设置成volatile类型的。
(二)第二种涉及到定时器计数时间(TIMx)
  1. /*TIM3时钟配置*/! ~- X8 L+ Q6 Y9 u: g) R% }
  2. TIM_TimeBaseStructure.TIM_Prescaler = 2;       //预分频(时钟分频)72M/(2+1)=24M4 n$ C' c/ @5 x
  3. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数
    . Y1 u% p" }3 X" A2 k9 j) R
  4. TIM_TimeBaseStructure.TIM_Period = 65535;        //装载值18k/144=125hz
    2 Y0 Z: e  a/ k+ U; [; O( n
  5. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;, s! S  X6 ^6 F6 ?- D7 Z
  6. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;! t$ \, B9 H* Z0 t6 Q' E+ c/ x
  7. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
复制代码

- g5 ?% s, f2 F! J5 s
定时时间计算:
; V8 K6 I) L3 y% _( ~
  1. TIM_TimeBaseStructure.TIM_Prescaler = 2;2 K8 ]) s/ T4 y, X  B
  2. //分频2      72M/(2+1)/2=24MHz7 e! T8 h$ a# K8 i( ?4 A
  3. TIM_TimeBaseStructure.TIM_Period = 65535; //计数值65535
    9 c! D" ]/ q' V4 z/ H
  4. ((1+TIM_Prescaler )/72M)*(1+TIM_Period )=((1+2)/72M)*(1+65535)=0.00273秒=366.2Hz */
复制代码
/ u# A. h! u' K/ r- _4 ~
注意两点(来自大虾网,未经检验)
+ B/ G, g  Q" |( r; z& }' h(1)TIMx(1-8),在库设置默认的情况下,都是72M的时钟;9 t2 @% F8 I; }6 e0 G" N6 v
(2)TIM_TimeBaseStructure.TIM_RepetitionCounter=0;/ Z. Q3 k( U9 j$ q
是重复计数,就是重复溢出多少次才给你来一个溢出中断,2 e/ T8 ]& _$ c
它对应的寄存器叫TIM1 RCR.
( G+ c! Y# W) B0 q2 ?* h如果这个值不配置,上电的时候寄存器值可是随机的,本来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-> 左右脉冲输入 */
    ! ^6 P& U3 t2 }  g6 Z* w
  2. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12;
    . l, u/ \) W! b  _; L
  3. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //
    5 ~9 G, }! ]: U# M: m
  4. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    5 Q8 Z1 U0 m& s" T
  5. GPIO_Init(GPIOA, &GPIO_InitStructure);</div>
复制代码
) S9 Q' l4 K0 x/ n
注意:(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的配置.
    $ G3 J1 o" z: q/ n
  2. RCC_GetClocksFreq(&RCC_ClockFreq);</div><div align="left">RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    - b9 P- D- N) ~4 p" ]& D
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    ) k' |% Z& [% @$ \" w- Q8 [/ j- ]2 _, _
  4. RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    3 _) p" `9 b: Z& `+ r- G2 w! a0 ?
  5. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);</div>
复制代码
9 a+ k3 u* j! q" q9 I) u: q$ [% C
第三步,设置定时器模式
  1. <div align="left">void TIM1_Configuration(void) //只用一个外部脉冲端口
    ' W; }, p4 ~. L% s" F# b+ O/ n! y
  2. {  s5 \8 G- g) \1 K4 l# M1 p- e+ w5 A
  3. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;</div><div align="left">
    3 c" s+ b* p9 q, z. ~
  4.    //配置TIMER1作为计数器
    : c3 B2 v2 ~  V& ], |
  5.    TIM_DeInit(TIM1);</div><div align="left">   TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    2 |& H5 `$ i; b+ b; ?9 R* E
  6. TIM_TimeBaseStructure.TIM_Prescaler = 0x00;
    6 [8 e; ^; r$ n  N
  7. TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;8 [, e" U9 ]6 P
  8. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    % Q& c6 K0 P5 V* n! u
  9. TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // Time base configuration! V2 c& r; E) _1 s

  10. 4 s' h: h, Q4 P) L1 S3 q
  11. TIM_ETRClockMode2Config(TIM1, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);</div><div align="left">TIM_SetCounter(TIM1, 0);  @$ C0 I1 r& g7 n
  12. TIM_Cmd(TIM1, ENABLE);
    . E, T, W  r" c6 N, Q1 |" f
  13. }
    1 D2 ~1 P% u  K& k" {
  14. . P+ a& L/ f9 R0 c* G
  15. void TIM2_Configuration(void) //只用一个外部脉冲端口
    6 N! h7 j, W% I( u4 B+ j
  16. {
    ! i, t5 S2 x% b* u4 u
  17. TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;</div><div align="left">
    - y2 h4 m; {* y7 E" A
  18.    //配置TIMER2作为计数器# Y, `2 t( U5 r/ U( G
  19.    TIM_DeInit(TIM2);</div><div align="left">   TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
      N- _+ j: |; \# R& B$ U" Y2 w. G
  20. TIM_TimeBaseStructure.TIM_Prescaler = 0x00;
    8 Z  }2 v: A- p( a+ J3 E
  21. TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
    2 _6 C  i  s9 a1 S- {4 D5 i  s
  22. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;8 P' C1 y9 G8 H
  23. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // Time base configuration
    / n0 c% ~: W* p2 A* N' Z% i
  24. & o( |; }' ~. R% L" G7 f
  25. TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);</div><div align="left">TIM_SetCounter(TIM2, 0);8 d0 j  u" w& b+ r
  26. TIM_Cmd(TIM2, ENABLE);
      P+ n# v* E7 ~! J6 n$ i
  27. }</div>
复制代码
, w- @+ J! B: E. [
第四步,可以在主函数中读取计数器的值,其它的应用,就看具体的情况了。
  1. <div align="left">u16 COUN1=0;6 z' _, d* {: q9 K+ h* {* \
  2. u16 COUN2=0;</div><div align="left">int main(void)8 l, Y0 S3 ]' w2 r7 O& h
  3. {/ Q6 r% I+ \' H2 z5 t; M% {
  4. ChipHalInit();$ m# ^0 a7 O  S* L) s$ o* Z
  5. ChipOutHalInit();</div><div align="left">while(1)
    ! }; l7 c2 a9 z1 y
  6. {
    5 |- T4 X5 I4 g+ @& \* {; n- s2 [
  7.    COUN1=TIM1->CNT;* v* e8 g  `6 J
  8.    COUN2=TIM2->CNT;# \0 y( x: n) R4 l
  9. }</div><div align="left">}</div>
复制代码
' z5 e7 U6 g/ E$ U) E. D

' g8 R$ E% U1 ^% f  a

+ L4 l2 L0 q$ _8 F, v$ t7 H
/ |. P2 j8 A0 V8 d
收藏 评论0 发布时间:2022-1-27 23:18

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版