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

STM32 普通定时器

[复制链接]
大碗刚 发布时间:2017-12-26 14:25
本帖最后由 大碗刚 于 2017-12-27 09:01 编辑 ' }& _  \7 m7 D# f& @% X

/ \- _. o+ H9 w2 \' u* u6 Q" D! t0 t! {转载于whsh304的博客3 u! E# C% q8 g3 P& x& X
STM32 普通定时器         (2011-03-22 09:37:59)[url=]转载▼[/url]
) y  k" T' I1 z9 m, ~0 o$ ?

' `4 }! H, E- Y6 d, G& [5 _
标签: 杂谈分类: STM32学习笔记
$ j, a8 W" y8 c' {# K
STM32 系列的 CPU,有多达 8 个定时器,其中 TIM1 和 TIM8 是能够产生三对 PWM 互补输出的高级定时器,常用于三相电机的驱动,它们的时钟由 APB2的输出产生。其它 6 个为普通定时器,时钟由 APB1 的输出产生。如图1.
当 APB1 的预分频系数为 1 时,这个倍频器不起作用,定时器的时钟频率等于 APB1 的频率;当 APB1
1 _  G- Q9 P- ~# u, p的预分频系数为其它数值(即预分频系数为 2、4、8 或 16)时,这个倍频器起作用,定时器的时钟频率等于 APB1 的频率两倍。
当 AHB=72MHz 时,APB1 的预分频系数必须大于 2,因为APB1 的最大频率只能为 36MHz。如果 APB1 的预分频系数=2,则因为这个倍频器,TIM2~7 仍然能够得到 72MHz 的时钟频率。
一、通用定时器
定时器编程,就是中断的编程。因为使用定时器必定要使用到中断(pwm没用到中断)。
步骤一   系统配置 SystemInit();,包括时钟 RCC 的配置,倍频到 72MHZ。
0 k. x- x8 [' |9 P步骤二   GPIO 的配置,使用函数为 GPIO_Config();         输出LED对应的引脚以及输出模式
步骤三   嵌套中断控制器的配置
. u% ~" U- z. L- R' D关键点是NVIC_InitStructure.NVIC_IRQChannel = TIMx_IRQChannel;      //通道
其它的配置都差不多。
步骤四   定时器的初始化配置,使用 Timer_Config();。OK,关键部分出来了。(来自芯达)
# ?% ]1 o: W$ ]3 H" J" }我们来看下实现过程:
4 ?* q; N7 W& G, F+ {. R" f& fvoid Timer_Config(void)
8 o: N4 L* G" `) J{
* ]1 ~+ [3 i0 S. RRCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);! b% I( Q& ^+ \( u5 N; z  O
TIM_DeInit(TIM2);
- g0 p9 R' `1 |& H2 ~' cTIM_TimeBaseStructure.TIM_Period=2000;    //自动重装载寄存器的值+ z) g: y9 b( d! Q& b$ u3 V- t
TIM_TimeBaseStructure.TIM_Prescaler= (36000 - 1);         //时钟预分频数# k9 q0 l+ G8 f1 P
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;     //采样分频
* Z7 G6 u! \, C' V0 y7 g  {TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
9 E  j& H0 A7 f3 |. ATIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
" ~9 s5 `# c% Q9 P7 t6 w' O  mTIM_ClearFlag(TIM2, TIM_FLAG_Update);+ {% Q) M. o3 H3 y7 R" l- o
//清除溢出中断标志) i2 k4 ^3 r3 W- Y
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);3 n5 a3 v( {" ?3 g, z
TIM_Cmd(TIM2, ENABLE);& j/ R' s* y; k% y
/开启时钟
0 h$ \. Q- }! q8 V+ O}+ h' [3 f" \- }* {7 @3 @1 V: B
我们每个语句都来解释一下。首先我们想使用定时器,就必须使能定时器的时钟,这就是函 CC_APB1PeriphClockCmd();  ,  通  过  它  开  启CC_APB1Periph_TIM2。TIM_DeInit( TIM2);  该函数主要用于复位 TIM2 定时器,使之进入初始状态。之后我们对自动重装载寄存器赋值,TIM_Period 的大小实际上表示的是需要经过 TIM_Period 次计数后才会发生一次更新或中断。接下来需要设置时钟预分频数IM_Prescaler,这里有一个公式,我们举例来说明:例如时钟频率=72MHZ/(时钟预分频+1)。说明当前设置的这个 TIM_Prescaler,直接决定定时器的时钟频率。通俗点说,就是一秒钟能计数多少次。比如算出来的时钟频率是 2000,也就是一秒钟会计数 2000 次,而此时如果 TIM_Period 设置为 4000,即 4000 次计数后就会中断一次。由于时钟频率是一秒钟计数 2000 次,因此只要 2 秒钟,就会中断一次。
步骤五   编写中断服务程序。同样需要注意的,一进入中断服务程序,第一步要做的,就是清除掉中断标志位。由于我们使用的是向上溢出模式,因此使用的函数应该是:TIM_ClearITPendingBit(TIM2 ,TIM_FLAG_Update);。芯达 STM32开发板实现的中断服务程序如下:
: e; g, D! r+ ~" r$ g) q- Wvoid TIM2_IRQHandler(void)* X5 f3 |( d, `8 z3 l
{
  p  k3 R( L1 w* d9 m4 Lif ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) {
; y' U" r  y' n0 dTIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);9 x/ e$ K$ B- t
switch(state){% S: ~+ s: k% s/ l. v4 A9 Z  i
case 0:& Z( o( W) K! o. Y2 Z- j
; o# Q' @! g4 t# u/ x( |
GPIO_ResetBits(GPIOB , GPIO_Pin_8);* R# ~8 q& I, Y, ~
GPIO_SetBits(GPIOB, GPIO_Pin_9);
3 h/ r2 B  @. aGPIO_SetBits(GPIOE, GPIO_Pin_0);8 I; }) D5 b  l9 Q% }# T9 B
GPIO_SetBits(GPIOE, GPIO_Pin_1);
. f' m) n  z: u. Jbreak;; i3 p) K6 G) n
...
default:
9 c" d/ E! i6 b% d: Tbreak;
}
if(++state >= 4){      //state在中断函数中定义为全局变量
7 l' w  z/ h; ?' u- _1 pstate = 0;
) F- E5 s  c! k1 ~& Y}
}
}
二、输出比较模式
1.   选择计数器时钟(内部,外部,预分频器)
2 F$ M( k1 {2 f- m" \! B2.   将相应的数据写入TIMx_ARR和TIMx_CCRx寄存器中
$ l2 o* ^& A" ?1 N3.   如果要产生一个中断请求和/或一个DMA请求,设置CCxIE位和/或CCxDE位。
) y% S( k# Q' a4.   选择输出模式,例如:必须设置OCxM=’011’、OCxPE=’0’、CCxP=’0’和CCxE=’1’,当计数器CNT与CCRx匹配时翻转OCx的输出管脚,CCRx预装载未用,开启OCx输出且高电平有效。! ]3 W# c& ?0 _" T, M! C
5.   设置TIMx_CR1寄存器的CEN位启动计数器: a$ H; |4 `3 @# G
TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制输出波形,条件是未使用预装载寄存器(OCxPE=’0’,否则TIMx_CCRx影子寄存器只能在发生下一次更新事件时被更新)。下图给出了一个例子。入图2.
file:///C:\Users\lenovo\AppData\Roaming\Tencent\Users\974670111\QQ\WinTemp\RichOle\JR_$B}_I4UT8XL]KINAK%$1.png9 N3 Q- R( Z/ |) {! ?. a
程序:(库里有提供)
int main(void)
- _$ |( l1 _5 [  `; f# t{# e! Q" |) K/ b8 }! M: e" y8 F
  X' P: p1 Y* J8 K7 E$ K5 {
  RCC_Configuration();

( j- T9 H, r6 N; O7 H  NVIC_Configuration();

+ m( [) ~# r8 [# f  GPIO_Configuration();

" P( ^- g" y% @% V" B- Y0 ~
3 n7 R5 Q+ R8 m3 U: D
  TIM_TimeBaseStructure.TIM_Period = 65535;! [5 ~; b6 c, F" F( o
  TIM_TimeBaseStructure.TIM_Prescaler =0;      //时钟频率
. {  d8 Z2 |6 T  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;
8 y# q; N, |$ B# |( |  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/ f; u5 p* ?; M( L
  TIM_PrescalerConfig(TIM3, 4, TIM_PSCReloadMode_Immediate);  // TIM 预分频值即时装入

3 G& P! E1 e( Y( y% f1 Q' `  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;  //TIM_OCMode 选择定时器模式:TIM 输出比较时间模式# R& {# @4 n4 g2 u- k* q6 `9 f. x
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
& `' W4 r7 q) g' |  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;     //设置了待装入捕获比较寄存器的脉冲值. C- i/ k$ h- q- P& _! A4 G/ X
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // TIM 输出比较极性高
  TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据 TIM_OCInitStruct 中指定的参数初始化外设 TIMx
  TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);   //失能 TIMx 在 CCR3 上的预装载寄存器
( c$ M9 O3 y0 e3 X4 {; q) q
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
( R' Z; n9 M( @  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
  TIM_OC4Init(TIM3, &TIM_OCInitStructure);   //根据 TIM_OC4InitStruct 中指定的参数初始化外设 TIM3
  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable); //失能 TIMx 在 CCR4 上的预装载寄存器

, s8 c4 ~$ N& @9 u6 q; ^( H. Y  TIM_ITConfig(TIM3, TIM_IT_CC3 | TIM_IT_CC4 , ENABLE);
& P8 p3 \$ c7 x$ I; _- A- K8 M* x
  TIM_Cmd(TIM3, ENABLE);
  while (1);1 A4 G2 T" t% w% v0 l
}
中断it.c中
void TIM3_IRQHandler(void)2 L1 n( ^8 m# p! B, K% F9 i
{* t) N9 f, G2 @5 B
  if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)1 m, k* n- U7 R. Y8 J- Z
  {
# `1 z  B  c; X% f4 P& s+ c9 ?    TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
    ( g6 |8 C8 F5 y+ g% W* |
    GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0)));//设置或者清除指定的数据端口位:取反5 k+ j6 V! z- T1 [3 X
    capture = TIM_GetCapture3(TIM3);   //获得 TIM3 输入捕获 3 的值
* n" s/ r7 x. K6 o( w/ y    TIM_SetCompare3(TIM3, capture + CCR3_Val); //设置 TIM3 捕获比较 3 寄存器值) R9 L: D/ Z* A% C* Y# q
  }( h# S3 I7 G4 F  b
  else if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET); w* ^- I4 n- W. ~$ U
  {6 a1 @8 M7 l) D6 k2 P4 r- G1 J
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
   / T' @" V+ b$ D: @6 `$ P% ^
    GPIO_WriteBit(GPIOB, GPIO_Pin_1, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1)));% K: a5 X* t- c7 |2 ?5 Q
    capture = TIM_GetCapture4(TIM3);
; ~- P: Q9 _' X" @% b    TIM_SetCompare4(TIM3, capture + CCR4_Val);. ~3 r2 ~% m- H8 C8 Q
  }  u% ~* B8 o6 A( d
}
三、PWM输出
脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。
0 |2 U% Y" r+ h8 `# ]在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位使能自动重装载的预装载寄存器。
OCx的极性可以通过软件在TIMx_CCER寄存器中的CCxP位设置,它可以设置为高电平有效活或低电平有效。TIMx_CCER寄存器中的CCxE位控制OCx输出使能。
在PWM模式(模式1或模式2)下,TIMx_CNT和TIM1_CCRx始终在进行比较,(依据计数器的计数方向)以确定是否符合TIM1_CCRx≤TIM1_CNT或者TIM1_CNT≤TIM1_CCRx。如图3.
程序:
int main(void)
0 m  O* n( _  a8 a4 U  h{
0 d) r5 l" M( @* ^" p# e7 Z! d 3 ?: V, z3 o5 [2 Q- u4 ?3 P
  RCC_Configuration();

* V# q+ `! Y/ R" E' W& P. w3 n. S# ^  GPIO_Configuration();

4 [, T" u2 L% A( M( ]2 P0 i
& N; V! G( F2 z. |" h/ v
  TIM_TimeBaseStructure.TIM_Period = 999;  //在下一个更新事件装入活动的自动重装载寄存器周期的值5 e% ^8 W! `" b
  TIM_TimeBaseStructure.TIM_Prescaler = 0; //  设置了用来作为 TIMx 时钟频率除数的预分频值8 x- ?9 R/ m+ E$ }1 K5 p
  TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置了时钟分割
5 ?& }* F8 l( X( z8 f  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; " S1 Z0 B, a# k% S- m1 y
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

: t7 H* z# v: J& Q, |3 W* k* N  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  //TIM_OCMode
+ a  t! r3 Q) f1 L! W  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
) m3 ]9 j5 _0 }+ y  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;      //设置了待装入捕获比较寄存器的脉冲值
8 d; Y9 N3 m- @- C2 M  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM_OCPolarity :TIM 输出比较极性高! D8 C9 h; P. b. Z: [
  TIM_OC3Init(TIM3, &TIM_OCInitStructure);
  TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能或者失能 TIM3 在 CCR3 上的预装载寄存器

2 b. A: G9 _* x  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   X& i$ R! H0 J# k2 N' G/ e
  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
  TIM_OC4Init(TIM3, &TIM_OCInitStructure);
  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
3 ]4 A3 ~; }6 M- f( }) E* A: ?
  TIM_Cmd(TIM3, ENABLE);
  while (1)6 f4 {! o  d8 d% E; b) r4 U4 a
  {}
/ U6 r8 `5 B/ }9 _$ N}
6 g2 Y* a( `3 o' G& l" e  }0 R( M它不需要中断程序。输出的是占空比为50%和25%的方波信号。

0 E: y% ?' n! L* a9 e2 R3 P. z  W! p. y+ Z3 \0 `3 |! s
1.png
2.png
3.png

评分

参与人数 1 ST金币 -5 收起 理由
zero99 -5 图挂了,也太不认真了

查看全部评分

赞 收藏 评论0 发布时间:2017-12-26 14:25

举报

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