STM32定时器编程

一.实验目的

  1. 了解STM32中定时器的原理。

  2. 掌握在STM32如何实现精确定时。

二.实验要求

  1. 了解STM32中定时器的原理。

  2. 掌握在STM32如何实现精确定时。

  3. 学习STM32通用定时器的编程方式,实现LED每秒闪烁一次。

三.实验软硬件

  1. PC机一台

  2. WINDOWS操作系统

  3. ARM集成开发环境

  4. WSN实验箱

四.实验步骤

1.定时器简介

STM32总共有8个定时器,TIM1和TIM8是16位的高级定时器,TIM2、TIM3、TIM4、TIM5是通用定时器。本实验中使用通用定时器TIM2,来实现精确定时。

通用定时器是一个通过可编程预分频器驱动的16 位自动装载计数器构成。这里为了体现其精确定时,用LED灯进行观察实验现象。如果有条件的实验室,可以配置示波器来观察信号情况。(特别是在做脉冲实验进行波形输出时)。使用定时器预分频器和RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。

2. 定时器时钟配置

如图4.20所示,TIMx的有八个,其中TIM1和TIM8挂在APB2总线上,而TIM2-TIM7则挂在APB1总线上。其中TIM1&TIM8称为高级控制定时器(advanced control timer).他们所在的APB2总线也比APB1总线要好。APB2可以工作在72MHz下,而APB1最大是36MHz。

STM32定时器编程_第1张图片
TIM时钟配置

图4.17 TIM时钟配置

由图4.20可知,当APB1 的预分频系数为1 时,这个倍频器不起作用,定时器的时钟频率等于APB1 的频率;当APB1的预分频系数为其它数值(即预分频系数为2、4、8 或16)时,这个倍频器起作用,定时器的时钟频率等于APB1 的频率两倍。因为APB1最大为36MHz,而AHB预分频输出的频率为72MHz,所以APB1预分频器进行了2分频,所以定时器的时钟频率为2倍的APB1的频率,即72MHz。

3.通用定时器初始化配置

通用定时器初始化配置流程为:

3.1 首先进行配置一个TIM_TimeBaseInitTypeDef 的结构体。

例如:TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

3.2 将定时器TIMx设置为默认值的定时器。例如:TIM_DeInit(TIM2);

3.3根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 。进行如下配置。

a.配置定时器的周期加载值(TIM_Period)。它设置了在下一个更新事件装入活动的自动重装载寄存器周期的值。它的取值必须在0x0000和0xFFFF之间。例如:

TIM_TimeBaseStructure.TIM_Period=1000;

b.设置定时器时钟预分频值(TIM_Prescaler)。设置了用来作为TIMx时钟频率除数的预分频值。它的取值必须在0x0000和0xFFFF之间。例如:

TIM_TimeBaseStructure.TIM_Prescaler= 71;

c.设置时钟分割。实验中设置为如下,即来自APB1的时钟不分频。

TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;

d.选择定时器的计数方式。这里选择向上计数方式。其从0开始计数,当向上计数值增加到配置的周期加载值时,会触发定时器中断。然后计数值自动清零。

TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;

e.初始化定时器。调用定时器API函数为:TIM_TimeBaseInit();

f.实验中采用中断的方式进行精确定时。所以在初始化定时器时要清除以前的中断标志。调用定时器的中断标志位函数为:TIM_ClearFlag(TIMx, TIM_FLAG_Update);

g.使能定时器中断。调用定时器中断API函数为:

TIM_ITConfig(TIMx,TIM_IT_Update,ENABLE);

h.使能定时器TIM_Cmd(TIMx, ENABLE);

4.NVIC初始化配置

4.1.设置中断名称。本例为TIM2_IRQn。

4.2.中断优先级的设置。

4.3. IRQ通道使能。

4.4. 根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器TIM2.

以上为设置流程。根据以上设置,例如调用相关的API函数如下NVIC中断,具体请参考STM32数据手册。

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//开TIM2中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

5.实现LED(绿灯和红灯)以1s、2s、5s的频率闪烁。其中配置GPIO、TIM的时钟;GPIO设置;定时器中断需要配置NVIC;定时器的初始化;以及定时器中断处理。

注:发生中断时间=(TIM_Prescaler+1)* (TIM_Period+1)/FLK(此处FLK为72MHz)

五.实验报告具体要求

实验报告应包括以下几个部分:

1.实验目的。

2.问题描述。

3.实验详细步骤(包含源码)。

4.实验过程中遇到的问题,及解决办法。

5.实验心得。

实验代码

#include "stm32f10x.h"
#include "stm32f10x_rtc.h"
#include "stm32f10x_tim.h"
#include "misc.h"
#include "core_cm3.h"


void RCC_Configuration(void);
void GPIO_Configuration(void);
void TIM_Configuration(void);
void TIM2_IRQHandler(void);
void NVIC_Configuration(void);

#define GreenLight_On()     GPIO_SetBits(GPIOB,GPIO_Pin_8)
#define GreenLight_Off()    GPIO_ResetBits(GPIOB,GPIO_Pin_8)

#define REDLight_On()       GPIO_SetBits(GPIOB,GPIO_Pin_9)
#define REDLight_Off()      GPIO_ResetBits(GPIOB,GPIO_Pin_9)


/* 
 * 函数名:main
 * 描述    :主函数
 * 输入    :无
 * 输出    :无       
 */
int main(void)
{
    RCC_Configuration();
        GPIO_Configuration();
            
        NVIC_Configuration();
        TIM_Configuration();
        
    // 等待中断触发   
    while(1);
}





void RCC_Configuration(void)
{
    ErrorStatus HSEStartUpStatus;
    //编程习惯,用于异常处理

    SystemInit();   //初始化微控制系统
    RCC_DeInit();   //将RCC时钟控制器设为默认状态
    
    
    //使能外部晶振
    RCC_HSEConfig(RCC_HSE_ON);
    
    //等待外部晶振稳定
    /*这一步是必须的,不稳定的时钟无法为
    外设如GPIO、UART、ADC等提供服务*/
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    
    
    //如果外部晶振启动成功,则进行下一步操作
    if(HSEStartUpStatus==SUCCESS)
    {
        //设置HCLK(AHB时钟)=SYSCLK=72
        RCC_HCLKConfig(RCC_SYSCLK_Div1);

        //PCLK1(APB1) = HCLK/2=36MHZ
        RCC_PCLK1Config(RCC_HCLK_Div2);

        //PCLK2(APB2) = HCLK=72MHZ
        RCC_PCLK2Config(RCC_HCLK_Div1);
       
        //FLASH时序控制
        //推荐值:SYSCLK = 0~24MHz   Latency=0
        //        SYSCLK = 24~48MHz  Latency=1
        //        SYSCLK = 48~72MHz  Latency=2
        //开启FLASH预取指令功能
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        
        FLASH_SetLatency(FLASH_Latency_2);

        //PLL设置 SYSCLK/1 * 9 = 8/1*6 = 9MHz
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        
        //启动PLL
        RCC_PLLCmd(ENABLE);
        
        //等待PLL稳定
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){};
        
        //系统时钟SYSCLK来自PLL输出
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        
        //切换时钟后等待系统时钟稳定
        while(RCC_GetSYSCLKSource()!=0x08){};
          
    }      
     
        //启动GPIO
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,ENABLE);
    //启动TIM2
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2,ENABLE);
   
}


void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

}


// TIM 配置
void TIM_Configuration(void)
{
        void TIM_TimeBaseInit(TIM_TypeDef*TIMx,
        TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); //前面指是哪个TIM,后面指TimeBaseInitStruct结构体指针。

         

        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   //定义TIM初始化类型结构体变量
        
        TIM_DeInit(TIM2);

        TIM_TimeBaseStructure.TIM_Period = 9999;   //设置自动重载计数周期值

        TIM_TimeBaseStructure.TIM_Prescaler =7199;   //设置分频系数
        //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频因子

        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置为向上计数方式

        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  
        TIM_ARRPreloadConfig(TIM2, ENABLE);                       //允许自动重装载寄存器(ARR)
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                 //允许TIM2溢出中断
        
        TIM_Cmd(TIM2, ENABLE);                                 //TIM2开启时钟
                
}


// TIM2 中断处理
void TIM2_IRQHandler(void)
{
        int i, j;
        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);  
                //清除TIMx的中断待处理位:TIM 中断源
            REDLight_On();
        for(i = 0; i < 999; i++)
            for(j = 0; j < 999; j++);
        REDLight_Off();
}
//注意这里清除中断源,不然无法正确切换模式ON||OFF
// NVIC 配置
void NVIC_Configuration(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//开TIM2中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}

按照公式计算得到的单位是秒!
https://www.cnblogs.com/sankye/archive/2012/05/05/2484711.html
http://www.51hei.com/stm32/4261.html

你可能感兴趣的:(STM32定时器编程)