查看: 78|回复: 0

【青风带你学stm32f051系列教程】第7课 通用定时器timer

[复制链接]

主题

好友

1114

积分

版主

该用户从未签到

发表于 2012-12-28 23:23:23 |显示全部楼层
第7课 通用定时器timer
Stm32f051系列通用定时器由一个16 位或32 位的自动装载计数器组成,它由一个可编程的预分频器驱动。它适合多种用途,包含测量输入信号的脉冲宽度( 输入捕获),或者产生输出波形( 输出比较和PWM)。学习stm32f051的核心就是认识可编程的预分频器驱动的设置。
本节介绍输出波形:输出比较,通过TM3的比较寄存器CCR3和CCR4产生2路中段,通过定时器产生不同的中断时间。其结构如下图所示:

当我们设置系统时钟位48MHZ,TIM3的计数时钟位为6 MHz时,那么预定标器可以按下面算式进行计算:
Prescaler = (TIM3CLK / TIM3 counter clock) - 1
Prescaler = (PCLK1 /6 MHz) - 1
那么比较寄存器CC3 和CC4的更新率可以如下计算:
CC3 update rate = TIM3 counter clock / CCR3_Val = 439.4 Hz
CC4 update rate = TIM3 counter clock / CCR4_Val = 878.9 Hz
因此中断的产生反转频率为:
CC3 update rate/2和CC4 update rate/2
按照这个设计方案准备设计方案:
硬件准备:
只需要连接2个LED灯,就可以实现TIM捕获定时了:


软件准备:
Time定时器可以进行精确定时,并且通过TIME进行中断触发,在精确控制方面具有很好的优势。本实验采用了TIM3作为定时器,控制2路LED灯翻转。下面将从软硬件入手,分析如何通过STM32F0的定时器进行定时触发中断,从而控制LED灯的亮灭。
在lib库函数调用了stm32f0xx.tim.c函数库,我们在驱动函数time.c中编写定时器输出的相关参量设置。而中断执行函数则在stm32f0xx_it.c函数中进行编写;
配置TIM3的定时中断我们可以分成两个部分完成:
第一步:首先是配置TIM的中断嵌套,代码如下所示:
[c] void TIM_INT_Config(void){   NVIC_InitTypeDef NVIC_InitStructure;  /* TIM3 时钟使能 */  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  /*  TIM3 中断嵌套设计*/  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPriority = 0;  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);}[/c]
上面函数中,设置中断通道为TIM3中断,频道优先级设为0,并且使能频道。这样就配置好了TIM3中断嵌套。当然中断要执行的操作要在stm32f0xx_it.c进行编写,这个等下我们再讲,我们先把TIM3的参数配置进行讨论:
首先来看看TIM定时器的基础配置参数,这个参数的配置要求在文件stm32f0xx_tim.c中进行了描述,通过如下的结构体单元进行了归纳:
[c]typedef struct{uint16_t TIM_Prescaler; /*!指定用来划分TIM时钟预分频值*/uint16_t TIM_CounterMode; /*!指定的计数器模式*/uint32_t TIM_Period; /*设置时钟周期 */uint16_t TIM_ClockDivision; /*设定时钟分频 */uint8_t TIM_RepetitionCounter; /*指定重复计数器值 */} TIM_TimeBaseInitTypeDef;
[/c]
上面的结构体参数就是设置TIME的基础参数,下面我们就来确定这几个参数的设置:
[c] /* Time 定时器基础设置 */          TIM_TimeBaseStructure.TIM_Period = 65535;          TIM_TimeBaseStructure.TIM_Prescaler = 0;          TIM_TimeBaseStructure.TIM_ClockDivision = 0;          TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;          TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);[/c]
TIM_Prescaler设置预分频为0,也就是不预分频。那么系统时钟我们设置为48MHZ,那么TIM定时器也跑在了48MHZ。而TIM_ClockDivision我们设为0,也就是不进行时钟分频。TIM _CounterMode设置为向上计数。TIM计数时钟为6MHZ,那么翻转率按照下面公式继续计算
CC3 翻转率= TIM3 counter clock / CCR3_Val
CC4 翻转率= TIM3 counter clock / CCR4_Val
配置完基础配置后,CC3和CC4的翻转要通过输入捕获实现定时器的翻转,而定时器输入比较模式通过下面的结构体进行配置:
[c] typedef struct        {          uint16_t TIM_OCMode;        /*!指定的TIM模式 */          uint16_t TIM_OutputState;   /*指定的TIM输出比较状态 */          uint16_t TIM_OutputNState;  /*指定TIM互补的输出比较状态. */          uint32_t TIM_Pulse;         /*指定的脉冲值被装入到捕获比较寄存器*/          uint16_t TIM_OCPolarity;    /*指定的脉冲值被装入到捕捉比较寄存器 */          uint16_t TIM_OCNPolarity;   /*指定的互补输出极性 */          uint16_t TIM_OCIdleState;   /*指定在空闲状态下的TIM输出比较引脚的状态 */          uint16_t TIM_OCNIdleState;  /*指定在空闲状态下的互补TIM输出比较引脚的状态. */        } TIM_OCInitTypeDef;
[/c]
对上面的产生配置如下代码:
[c]         /* 输出比较时序模式配置设置 */          TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;          TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          /* 输出比较时序模式配置: 频道3*/          TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;          TIM_OCInitStructure.TIM_Pulse = CCR3_Val;          TIM_OC3Init(TIM3, &TIM_OCInitStructure);          TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable);          /* 输出比较时序模式配置: 频道4 */          TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;          TIM_OCInitStructure.TIM_Pulse = CCR4_Val;          TIM_OC4Init(TIM3, &TIM_OCInitStructure);          TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable);          /* TIM 中断使能 */          TIM_ITConfig(TIM3, TIM_IT_CC3 | TIM_IT_CC4, ENABLE);          /* TIM3 使能 */          TIM_Cmd(TIM3, ENABLE);
[/c]
那么中断我们则执行LED是翻转工作:
[c]        void TIM3_IRQHandler(void)        {          if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)          {            TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
            /* LED3 toggling with frequency = 219.7 Hz */            LED1_Toggle();            capture = TIM_GetCapture3(TIM3);            TIM_SetCompare3(TIM3, capture + CCR3_Val);          }          else          {            TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
            /* LED4 toggling with frequency = 439.4 Hz */            LED2_Toggle();            capture = TIM_GetCapture4(TIM3);            TIM_SetCompare4(TIM3, capture + CCR4_Val);          }        }
[/c]
主函数的编写就较为简单了,直接调用子函数输出:
[c]          int main(void)        {                LED_Init();                LED1_Open();                LED2_Open();                TIM_INT_Config();                TIM_OUT_Config();                  /*无限循环 */          while (1)          {          }        }
[/c]
实验现象:
两个led灯按照不同速率进行翻转。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /4 下一条

手机版|电路城

GMT+8, 2019-7-20 01:33 , Processed in 0.161907 second(s), 14 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz!

返回顶部