定时器中断实验

知识回顾

通用定时器原理

通用定时器分为四个部分:

 1,选择时钟
 2,时基电路
 3,输入捕获
 4,输出比较

本节定时器中断主要涉及到定时器框图上边两个部分,即选择时钟和时基电路
重点框图


定时器时钟选择

选择默认的内部时钟,配置时基电路(配置预分频系数,重装载值)
预分频系数,重装载值


计数器时钟来源

 1,内部时钟(CK_INT),默认
 2,外部时钟模式1:外部输入脚(TIx)
 3,外部时钟模式2:外部触发输入(ETR)

时钟选择配置寄存器TIMx_SMCR

时钟选择配置寄存器

TIMx_SMCR-SMS[2:0]:,默认000 关闭从模式,预分频器由内部时钟驱动


内部时钟选择:

内部时钟选择

 AHB时钟经过APB1预分频
 如果APB1预分频为1,定时器时钟由APB1*1输出
 如果APB1预分频不为1,定时器时钟由APB1*2输出

 除非APB1分频系数为1,否则通用定时器时钟等于APB1的2倍

内部时钟选择

根据系统时钟知识:
    APB1时钟为AHB时钟(由AHB时钟分频系数为1得到)时,CK_INT = APB1时钟
    APB1时钟为AHB时钟不为1分频得到时,CK_INT = APB1时钟 * 2

    因为选中的是内部时钟(CK_INT),CK_PCS = CK_INT
    CK_PSC % N(N为CK_PSC寄存器值+1得到),得到CK_CNT-定时器最终时钟

    SYSCLK=72M
    AHB时钟=72M
    APB1时钟=36M
    所以APB1的预分频系数=AHB/APB1=2
    所以,通用定时器时钟CK_INT=2*36M=72M

定时器中断时序

向上计数为例,时钟分频因子为1(加一之后等于1)

定时器中断时序

APB1时钟=CK_INT
CNT_EN高电平-定时器使能
定时器时钟CK_CNT(CK_INT % N 得到)
计数器向上计数,到36(到重装载值,产生中断),重新计数
计数器溢出,跳变
更新事件产生,跳变
更新中断标志置1(需软件清零)

寄存器和库函数配置

1,计数器当前值寄存器CNT

计数器当前值寄存器CNT

16位寄存器,记录计数器当前值

对应框图部分:

CNT对应框图部分


2,预分频寄存器TIMx_PSC

预分频寄存器TIMx_PSC


3,自动重装载寄存器TIMx_ARR

自动重装载寄存器TIMx_ARR

16位寄存器,设置自动重装载值


4,控制寄存器1 TIMx_CR1

控制寄存器1 TIMx_CR1

位4-计数方向配置位DIR:
     0:向上计数
     1:向下计数
位0-使能配置CEN:
     0:禁止计数器
     1:开启计数器

5,DMA中断使能寄存器

DMA中断使能寄存器

位0-更新中断使能UIE:
     0:禁止更新中断
     1:允许更新中断

定时器中断相关库函数

1,定时器参数初始化

// stm32f10x_tim.c中TIM_TimeBaseInit定时器初始化函数定义:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

// TIM_TimeBaseInitTypeDef:
typedef struct
{
  uint16_t TIM_Prescaler;              // 预分频系数
  uint16_t TIM_CounterMode;       // 计数模式
  uint16_t TIM_Period;                   // 自动装载值
  uint16_t TIM_ClockDivision;        // 输入捕获使用
  uint8_t TIM_RepetitionCounter;   // 高级定时器使用
} TIM_TimeBaseInitTypeDef;

// IS_TIM_COUNTER_MODE
#define IS_TIM_COUNTER_MODE(MODE) (((MODE) == TIM_CounterMode_Up) ||  \
                                   ((MODE) == TIM_CounterMode_Down) || \
                                   ((MODE) == TIM_CounterMode_CenterAligned1) || \
                                   ((MODE) == TIM_CounterMode_CenterAligned2) || \
                                   ((MODE) == TIM_CounterMode_CenterAligned3))

// IS_TIM_CKD_DIV
#define IS_TIM_CKD_DIV(DIV) (((DIV) == TIM_CKD_DIV1) || \
                             ((DIV) == TIM_CKD_DIV2) || \
                             ((DIV) == TIM_CKD_DIV4))

初始化配置对应框图:

初始化配置对应框图


2,定时器使能函数TIM_Cmd

作用 : 操作控制寄存器1 TIMx_CR1的位0,使能定时器

// stm32f10x_tim.c中TIM_Cmd定时器初始化函数定义:
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);

3,定时器中断使能函数

作用 : 操作DMA中断使能寄存器TIMx_DIER使能相应的定时器中断

// stm32f10x_tim.c中TIM_Cmd定时器初始化函数定义:
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

4,状态标志位的获取和清除

FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

定时器中断实验的步骤

1,使能定时器时钟
    RCC_APB1PeriphClockCmd();
2,初始化定时器,配置ARR(自动重装载寄存器),PSC(预分频系数)
    TIM_TimeBaseInit
3,开启定时器中断,配置NVIC中断优先级
    TIM_ITConfig()
    NVIC_Init();(主函数要设置中断优先级分组)
4,使能定时器
    TIM_Cmd()
5,编写中断服务函数:
    TIMx_IRHandler();

实验内容

配置定时器中断,实现每500ms中断一次,中断服务函数控制LED1反转
主函数控制LED0每间隔300ms闪烁

实现500ms一次中断:

 定时器从计数开始到触发中断所需事件由两个参数控制:
      ARR:自动重装载值
      PSC:定时器时钟
 定时器时钟: APB1时钟经过倍频得到(当AHB1分频为1倍,其他为2倍)

 定时器一个周期(计数器+1需要的时间)时间 = (PSC+1) / Tclk
 一共需要多少个周期:ARR+1
 溢出时间 Tout = (ARR + 1) (PSC + 1) / Tclk

 当前实验使用系统初始化函数来初始化APB1,预分频系数为2,CK_INT=72M
 考虑将PSC+1 = 7200   这样(PSC + 1) / Tclk = 7200/72000000 = 0.1s 便于计算,
 所以PSC=7199

 500ms中断间隔的实现
      500 = ( ARR + 1 ) (PSC + 1) / 72000000
      500 = ( ARR + 1 ) * 0.1
      ARR=4999

 所以设置ARR = 4999 , PSC=7199 实现定时器每500ms进入一次中断

项目初始化

新建文件
    HARDWARE/TIMER/timer.c
    HARDWARE/TIMER/timer.h

添加文件到项目目录,并将timer.h路径添加到配置path中

添加到配置path

加入定时器相关库函数文件stm32f10x_tim.c
timer.c中include timer.h 然后编译


timer.h

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"

// arr  自动重装载值 psc 定时器时钟
void TIM3_Int_Init(u16 arr,u16 psc);

#endif

timer.c

#include "timer.h"
#include "led.h"

void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 1, 使能定时器3时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // 2,定时器初始化配置
    TIM_TimeBaseStructure.TIM_Period = arr;    //自动重装载值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频系数
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 与此实验关系不大,随意设置一个
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    // 定时器中断使能
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //更新中断使能

    //NVIC中断优先级初始化设置 - 需要先在主函数中配置中断优先级分组
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //抢占优先级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM3, ENABLE);  //使能定时器
}

//中断服务函数
void TIM3_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //更新中断发生
        {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //置位更新状态-清除标志位
        LED1=!LED1;     // 反转LED1
        }
}

主函数main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "timer.h"

 int main(void)
 {

    delay_init();             //延时函数初始化
     LED_Init();                 //LED初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组配置为2

    TIM3_Int_Init(4999,7199);// 初始化TIM3定时器
       while(1)
    {
        LED0=!LED0;
        delay_ms(200);           //每200msLED0反转
    }

}

实验结果

实验实现每间隔500msLED1闪烁,每200msLED0闪烁
  • 9
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BraveWangDev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值