stm32入门-----TIM定时器(定时与中断——下)

 目录

前言

一、C语言编程步骤

1.开启定时器时钟

 2.配置时基单元

 3.配置NVIC

4.开启定时器和开启定时器中断

三、项目实操 

1.内部定时器中断计数

2.外部定时器中断计数


前言

        本期接着上一期的内容继续学习stm32的定时器中断(上一期链接:stm32入门-----TIM定时器(定时与中断——上)-CSDN博客)本期主要分为两个项目实操,分别是内部定时器中断实现一秒计一个数,另外一个就是对射红外线传感器外部定时中断实现计数。(视频:[6-2] 定时器定时中断&定时器外部时钟_哔哩哔哩_bilibili

一、C语言编程步骤

上图展示的就是定时器中断的过程,实际上我们编程只需要把这些箭头指向的通路打开即可。这里我选择通用定时器内部定时中断作为示例。

1.开启定时器时钟

类型

编号

总线

功能

高级定时器

TIM1TIM8

APB2

拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能

通用定时器

TIM2TIM3TIM4TIM5

APB1

拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能

基本定时器

TIM6TIM7

APB1

拥有定时中断、主模式触发DAC的功能

 根据上表我们可以看到通用定时器的时钟总线为APB1,所以要去打开APB1的时钟,然后去启用编号为TIM2的定时器(其他三个也是没问题的,都是通用定时器),代码示例如下:

//1.开启定时器时钟,TIM2总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    TIM_InternalClockConfig(TIM2);  //给TIM2选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的

 2.配置时基单元

这个是定时器的核心部分,配置定时器的时基单元就基本上设置好了定时的时间以及计数方式,代码示例如下:

//2.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
					       = CK_PSC / (PSC + 1) / (ARR + 1) 
       根据公式下面去配置重装值和分频器值要进行减一操作,因为在定时器计算的时候会自动加上1的,要抵        
       消掉*/
    TIM_timebasestruct.TIM_Period=10000-1;  //计数器的重装值,目标值
    TIM_timebasestruct.TIM_Prescaler=7200-1; //预分频器的值
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
	TIM_TimeBaseInit(TIM2,&TIM_timebasestruct);

    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit初始化时基单元的时候更新了相关配置此时,就会自动取进入到中断,这里设置清除中断就行了

 最后对于为什么要去清除掉这个定时中断的指示位,看下图就可以知道,因为在初始化后定时器会自动执行一次中断,这时候我们就要对这个中断指示位进行清除。

 3.配置NVIC

 //3.配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组
	
    NVIC_InitTypeDef NVIC_initstruct;
    NVIC_initstruct.NVIC_IRQChannel=TIM2_IRQn;  //中断通道为定时器TIM2
    NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;  //对通道进行使能
    NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级
    NVIC_initstruct.NVIC_IRQChannelSubPriority=1;   //响应优先级
    NVIC_Init(&NVIC_initstruct);

4.开启定时器和开启定时器中断

    //5.开启定时器、开启定时器中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启定时器中断,设置为TIM_IT_Update 更新进入中断
    TIM_Cmd(TIM2,ENABLE);//开启定时器

以上就是C语言去初始化定时器的过程了,这是内部定时器中断的操作示例,要改为其他中断的话,我们只需要把中断的方式修改即可。整体代码如下:

#include "stm32f10x.h"                  // Device header

void Timer_init(){
    //1.开启定时器时钟,TIM2总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    TIM_InternalClockConfig(TIM2);  //给TIM2选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的
	
    //2.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
					       = CK_PSC / (PSC + 1) / (ARR + 1) */
    TIM_timebasestruct.TIM_Period=10000-1;  //计数器的重装值,目标值
    TIM_timebasestruct.TIM_Prescaler=7200-1; //预分配器的值
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
	TIM_TimeBaseInit(TIM2,&TIM_timebasestruct);

    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit初始化时基单元的时候更新了相关配置此时,就会自动取进入到中断,这里设置清除中断就行了


    //3.配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组
	
    NVIC_InitTypeDef NVIC_initstruct;
    NVIC_initstruct.NVIC_IRQChannel=TIM2_IRQn;  //中断通道为定时器TIM2
    NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;  //对通道进行使能
    NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级
    NVIC_initstruct.NVIC_IRQChannelSubPriority=1;   //响应优先级
    NVIC_Init(&NVIC_initstruct);

    //5.开启定时器、开启定时器中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启定时器中断,设置为TIM_IT_Update 更新进入中断
    TIM_Cmd(TIM2,ENABLE);//开启定时器
}


三、项目实操 

OLED显示屏的驱动代码可在这里获取。

链接:https://pan.baidu.com/s/1yq5HwFcvqHVBlBTqzlQYxg?pwd=8985 
提取码:8985

1.内部定时器中断计数

先看效果:

stm32外部定时器中断

硬件电路连接图:

很简单哈,只需要连这个oled屏幕就行了。

定时器是stm32自身有的,这里就是属于系统部分的资源,所以文件要去添加到system这边,项目工程文件如下:

 

C语言代码:

Timer.c文件:

#include "stm32f10x.h"                  // Device header

//extern uint16_t num;//跨文件变量

void Timer_init(){
    //1.开启定时器时钟,TIM2总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    TIM_InternalClockConfig(TIM2);  //给TIM2选择时钟 为内部时钟,定时器默认是使用内部的时钟,不写这一行也行的
	
    //2.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
					       = CK_PSC / (PSC + 1) / (ARR + 1) */
    TIM_timebasestruct.TIM_Period=10000-1;  //计数器的重装值,目标值
    TIM_timebasestruct.TIM_Prescaler=7200-1; //预分配器的值
    TIM_timebasestruct.TIM_RepetitionCounter=0;//重复计数功能,这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
	TIM_TimeBaseInit(TIM2,&TIM_timebasestruct);

    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit初始化时基单元的时候更新了相关配置此时,就会自动取进入到中断,这里设置清除中断就行了


    //3.配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分组
	
    NVIC_InitTypeDef NVIC_initstruct;
    NVIC_initstruct.NVIC_IRQChannel=TIM2_IRQn;  //中断通道为定时器TIM2
    NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;  //对通道进行使能
    NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级
    NVIC_initstruct.NVIC_IRQChannelSubPriority=1;   //响应优先级
    NVIC_Init(&NVIC_initstruct);

    //5.开启定时器、开启定时器中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启定时器中断,设置为TIM_IT_Update 更新进入中断
    TIM_Cmd(TIM2,ENABLE);//开启定时器
}


Timer.h文件

#ifndef __TIMER_H
#define __TIMER_H
void Timer_init();
#endif // !__TIMER_H

主函数main.c文件代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t num;
int main(void)
{	
	
	OLED_Init();
	Timer_init();
	OLED_ShowString(1,1,"count:");
	while(1){
		
		OLED_ShowNum(1,7,num,3);
		OLED_ShowNum(2,7,TIM_GetCounter(TIM2),5);
	}
}

//定时器2中断
void TIM2_IRQHandler(){
    if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
        num++;
        TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
    }
}

2.外部定时器中断计数

先看效果:

stm32外部定时器中断

硬件电路连接图:

工程文件同上:

Timer.c代码:

#include "stm32f10x.h"                  // Device header

//extern uint16_t num;//跨文件变量

void Timer_init(){
    //1.开启定时器,TIM2总线是为APB1的
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    //配置GPIOA
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitTypeDef GPIO_initstruct;
    GPIO_initstruct.GPIO_Mode=GPIO_Mode_IPU;
    GPIO_initstruct.GPIO_Pin=GPIO_Pin_0;
    GPIO_initstruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_initstruct);

    // 选择外部时间输入信号
	TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0F);


    //2.配置时基单元
    TIM_TimeBaseInitTypeDef TIM_timebasestruct;
    //下面两个是运行控制操作值
    TIM_timebasestruct.TIM_ClockDivision=TIM_CKD_DIV1;//对输入信号进行初步分频,内部时钟72Mhz信号,这里就没有分频
    TIM_timebasestruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式选择向上计数
    //以下三个是时基单元里面的实际参数值
    /* 计数器溢出频率:CK_CNT_OV = CK_CNT / (ARR + 1)
					       = CK_PSC / (PSC + 1) / (ARR + 1) */
    TIM_timebasestruct.TIM_Period=10-1;  //计数器的重装值,目标值
    TIM_timebasestruct.TIM_Prescaler=1-1; //预分频器的值
    TIM_timebasestruct.TIM_RepetitionCounter=0;//这个是高级计数器才有的,当前选择的是通用计数器,设置0即可
	TIM_TimeBaseInit(TIM2,&TIM_timebasestruct);

    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//因为TIM_TimeBaseInit初始化时基单元的时候更新了相关配置此时,就会自动取进入到中断,这里设置清除中断就行了

    //3.计数完成后使能中断,开启中断到NVIC的通路
    

    //4.配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_initstruct;
    NVIC_initstruct.NVIC_IRQChannel=TIM2_IRQn;
    NVIC_initstruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_initstruct.NVIC_IRQChannelPreemptionPriority=2;
    NVIC_initstruct.NVIC_IRQChannelSubPriority=1;
    NVIC_Init(&NVIC_initstruct);

     //5.开启定时器、开启定时器中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启定时器中断,设置为TIM_IT_Update 更新进入中断
    TIM_Cmd(TIM2,ENABLE);//开启定时器

}

//返回定时器时钟输入的值
uint16_t Timer_Getcounter(){
    return TIM_GetCounter(TIM2);
}

Timer.h代码:

#ifndef __TIMER_H
#define __TIMER_H
void Timer_init();
uint16_t Timer_Getcounter();
#endif // !__TIMER_H

主函数main.c代码:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t num;
int main(void)
{	
	
	OLED_Init();
	Timer_init();
	OLED_ShowString(1,1,"count:");
	OLED_ShowString(2,1,"CNT:");
	while(1){
		
		OLED_ShowNum(1,7,num,3);
		OLED_ShowNum(2,7,Timer_Getcounter(),5);
	}
}

//定时器2中断
void TIM2_IRQHandler(){
    if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
        num++;
        TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
    }
}

以上就是本期的全部内容了,我们下次见!

每日壁纸:

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Fitz&

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

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

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

打赏作者

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

抵扣说明:

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

余额充值