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

目录

前言

一、C语言编程步骤

1.开启定时器时钟

2.配置时基单元

3.配置NVIC

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

三、项目实操

1.内部定时器中断计数

2.外部定时器中断计数


前言

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

一、C语言编程步骤

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

1.开启定时器时钟

|--------|---------------------|--------|----------------------------------------------------|
| 类型 | 编号 | 总线 | 功能 |
| 高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
| 通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
| 基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 |

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

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

2.配置时基单元

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

cpp 复制代码
//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

cpp 复制代码
 //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.开启定时器和开启定时器中断

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

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

cpp 复制代码
#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文件:

cpp 复制代码
#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文件

cpp 复制代码
#ifndef __TIMER_H
#define __TIMER_H
void Timer_init();
#endif // !__TIMER_H

主函数main.c文件代码:

cpp 复制代码
#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代码:

cpp 复制代码
#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代码:

cpp 复制代码
#ifndef __TIMER_H
#define __TIMER_H
void Timer_init();
uint16_t Timer_Getcounter();
#endif // !__TIMER_H

主函数main.c代码:

cpp 复制代码
#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);
    }
}

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

每日壁纸:

相关推荐
善 .3 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件
超级码农ProMax3 小时前
STM32——“SPI Flash”
stm32·单片机·嵌入式硬件
Asa3193 小时前
stm32点灯Hal库
stm32·单片机·嵌入式硬件
end_SJ5 小时前
初学stm32 --- 外部中断
stm32·单片机·嵌入式硬件
gantengsheng6 小时前
基于51单片机和OLED12864的小游戏《贪吃蛇》
单片机·嵌入式硬件·游戏·51单片机
嵌入式小强工作室7 小时前
stm32 查找进硬件错误方法
stm32·单片机·嵌入式硬件
委员7 小时前
基于NodeMCU的物联网窗帘控制系统设计
单片机·mcu·物联网·智能家居·iot
wenchm7 小时前
细说STM32F407单片机DMA方式读写SPI FLASH W25Q16BV
stm32·单片机·嵌入式硬件
南城花随雪。7 小时前
单片机:实现自动关机电路(附带源码)
单片机·嵌入式硬件
逝灮8 小时前
【蓝桥杯——物联网设计与开发】拓展模块4 - 脉冲模块
stm32·单片机·嵌入式硬件·mcu·物联网·蓝桥杯·脉冲测量