通用定时器中断实验详解

发布者:oplndctkl出最新更新时间:2022-04-20 来源: eefocus关键字:定时器中断 手机看文章 扫描二维码
随时随地手机看文章

通用定时器中断实验

定时器中断时钟源解析

我们这个实验使用来自APB1总线的时钟(AHB时钟频率是72MHz),我们注意到AHB->APB1分频器->APB1中如果APB1预分频器的分频系数是1那么TIMXCLK的时钟频率为“TIMCLK=APB1=AHB”,如果APB1预分频器的分频系数为N(N不为1),那么TIMXCLK的时钟频率为“TIMCLK=2xAPB1=2xAHB/N”。


但是当我们调用ST公司提供的初始化时钟源库函数时,APB1分频器默认的分频系数是2,因此最终TIMXCLK=2xAPB1=2xAHB/2=AHB。

TIMXCLK时钟频率=CLK_INT时钟频率,然后通过触发控制器传递给CK_PSC进行第二次分频处理,最终CNT计数器接收到的时钟脉冲为“CLK_INT/(CK_PSC+1)”,(分频系数为何为CK_PSC+1我们稍后再论)


教你如何看逻辑信号图

向上计数模式(时钟分频因子=1)

首先,CK_INT为TIMER的初始时钟源,CNT_EN代表着TIMER使能,CK_CNT是计数器接受的脉冲频率(在CK_PSC寄存器中进行分频后的),计数寄存器的重装载值为36,“中断事件更新”与“计时器溢出”还有“更新中断标志置1”同步进行,但是我们看到如果我们不手动清除中断标志,那么系统会一直处于执行中断当中无论中断条件是否满足。


中央对齐计数模式(时钟分频因子=1,ARR=6)

中央对齐计数模式有些不同的是,分别在向上计数溢出与向下计数溢出时均触发中断,而且如果我们不在每次中断后清除中断标志位,那么无论是否满足中断条件中断行为都会一直存在。


相关寄存器简介

事件产生寄存器(TIMx_EGR)


更新事件中断是通用定时器执行的普通中断。


状态寄存器(TIMx_SR)

计数器(TIMx_CNT)

预分频器(TIMx_PSC)


自动重装载寄存器(TIMx_ARR)

该寄存器用于在计数器的计数值溢出后重新加载计数器的溢出值。


控制寄存器 1(TIMx_CR1)

该寄存器用于请求中断和配置计数器模式,一旦中断触发,所有寄存器都会更新。


用库函数配置带有中断的通用定时器

库函数介绍

image.png

TIM_ClearITPendingBit与TIM_ClearFlag函数的区别


TIM_ClearITPendingBit 清除的是一些中断标志位,TIM_ClearFlag清除的是定时器的状态标志,比如定时器捕获状态位定时器触发标志位。


定时器参数的选取

通用定时器参数主要有两个PSC预分频系数与ARR计数器重装载值。溢出时间指的是“从0x00到TOP的时间”。

设计要求

通过定时器中断配置,每500ms中断一次,然后中断服务函数中控制LED实现LED1状态取反(闪烁)。


TIMX程序设计流程

第一步:初始化TIMER3

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能APB1的外设时钟  

 


第二步:初始化定时器3(配置ARR的值与PSC的值)

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;  

TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Down;  

TIM_TimeBaseInitStructure.TIM_Period = 0x1C20;  // 5000

TIM_TimeBaseInitStructure.TIM_Prescaler = 0x1388;  // 7200

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); // 初始化TIMER3  

 


第三步:初始化NVIC嵌入式中断向量

NVIC_InitTypeDef NVIC_InitStructure;  

  

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  

NVIC_Init(&NVIC_InitStructure); // 初始化NVIC嵌入式外部中断  

 


为什么我们先于NVIC初始化配置NVIC中断向量分组呢?


NVIC中断向量分组是用于约束全体中断向量的,如果我们单独把它放到某一个头文件里,就不能表示这个含义,而且如果我们在不同头文件里声明不同的中断向量分组,那么会乱套的。


第四步:配置TIMX的中断

TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 配置TIMER3的具体中断行为  

 


为什么NVIC的TIM中断通道已经开启,我们还配置TIMX的中断干啥?


我们一开始所使能的是TIMX中断通道,TIMX中断的模式很复杂,有多种中断模式,因此我们先使能TIMX的总中断通道,在进一步配置TIMX中断的属性,例如不同的中断条件:向上计数溢出,向下计数溢出……。


第五步:使能TIMX外设

TIM_Cmd(TIM3, ENABLE); // 使能TIMER3外设  

 


第六步:编写相应的中断服务函数

void TIM3_IRQHandler() // 应该在相应的中断文件内编写中断服务函数  

{  

    if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) // 由于定时器有多个中断模式,因此我们一定要检查相应的中断标志位  

    {  

        LED0 = !LED0;  

    }  

    TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 由于定时器有多个中断模式,因此我们一定要清除相应的中断标志位   

}  

 


代码示例

Main.c

#include "led.h"  

#include "timer.h"  

#include "stm32f10x.h"  

#include "delay.h"  

  

int main()  

{  

    delay_init(); // 只有初始化系统systick时钟,我们才能调用delay系列函数  

    LED_InitConfig(); // LED初始化  

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // NVIC中断向量分组应该先于NVIC初始化  

    TIMER_InitConfig(0x1C20, 0x1388); // 初始化TIMER3,其中PR=7200,ARR=5000  

      

    while(1)  

    {  

        LED1 = !LED1;  

        delay_ms(250);  

    }  

}  

 


Led.c

#include "led.h"  

#include "stm32f10x.h"  

  

void LED_InitConfig()  

{  

    GPIO_InitTypeDef GPIO_InitStructure;  

      

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); // 使能LED0,LED1的时钟  

      

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  

    GPIO_Init(GPIOB, &GPIO_InitStructure); // 配置LED0的GPIO输出属性  

      

    GPIO_ResetBits(GPIOB, GPIO_Pin_5); // 初始化PB5为低电平  

      

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  

    GPIO_Init(GPIOE, &GPIO_InitStructure); // 配置LED1的GPIO输出属性  

      

    GPIO_ResetBits(GPIOE, GPIO_Pin_5); // 初始化PE5为低电平  

}  

 


Led.h

#ifndef _LED_H  

#define _LED_H  

  

#include "sys.h"  

  

void LED_InitConfig();  

  

#define LED0 PBout(5)  

#define LED1 PEout(5)  

  

#endif  

 


Timer.h

#ifndef _TIMER_H  

#define _TIMER_H  

  

#include "sys.h"  

  

void TIMER_InitConfig(u16 ARR, u16 PR);  

  

#endif  

 

Timer.c

 

运行结果

链接:https://blog.csdn.net/weixin_45590473/article/details/108048325


关键字:定时器中断 引用地址:通用定时器中断实验详解

上一篇:浅谈中断挂起与中断标志的区别
下一篇:PWM输出实验详细示例

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved