定时器电路图
第一步:RCC开启时钟,基本上每个代码都是第一步
第二步:选择时基单元的时钟源(内部时钟)
第三步:配置时基单元,包括预分频器、自动重装器、计数模式等,通过结构体配置
第四步:配置中断输出控制,允许更新中断输出到NVIC
第五步:配置NVIC,在NVIC中打开定时器中断的通道,并分配一个优先级
第六步:运行控制,整个模块配置完成后,还需要使能一下计数器,当定时器使能后,计数器就会开始计数了,当计数器更新时,触发中断,
最后再写一个中断函数,这样这个中断函数每隔一段时间就能自动执行一次了。
定时器库函数
- void TIM_DeInit(TIM_TypeDef* TIMx); // 恢复缺省配置
- void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); // 时基单元初始化 TIMx 选择哪个定时器 对应2
- void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); //时基单元结构体初始化 对应2
- void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);// 使能计时器,运行控制时开启 TIMx 选择哪个定时器 ;NewState:ENABLE 对应6
- void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); //使能中断输出控制 TIMx 选择哪个定时器;TIM_IT:选择配置哪个中断输出;NewState:ENABLE 对应4
- 以下五个时钟源选择对应图中标志1
- void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
- void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
- void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter);
- void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
- void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter);
- void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode); // 预分频设置 Prescaler 0代表1分频,1代表2分频即加1,TIM_PSCReloadMode 代表立即执行还是下个周期执行
- void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode); // 选择计数模式是上升还是下降
- void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState); // 自动预装功能 有无预装器
- void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter); // 手动给一个计数值
- void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload); // 给自动重装器写入一个值
- uint16_t TIM_GetCounter(TIM_TypeDef* TIMx); // 查看当前计数器记到哪里了
- uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);// 获取预分频器的值
// 获取标志位,清除标志位,前两个是CPU运行时获取,后两个为中断获取
- 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);
Time.c
#include "stm32f10x.h" // Device header
extern uint16_t Num; // 告诉编译器已经定义过Num,自己去找 是main.c 中Num的引入
void Timer_Init(void)
{
// 初始化定时器
// 1.开启时钟 TIM2 为 APB1 外设
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
// 2.TIM2的时基单元由内部时钟来驱动了 ,不写也可以,默认上电使用内部时钟
TIM_InternalClockConfig(TIM2);
// 3.配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 配置进入时分频器
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 配置向上计数
TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1; // ARR 的周期(都在65535以内)
TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1; // 预分频的值 PSC
// CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1)
// 1Hz = 72M / 10000 / 7200
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 重复计数的值,此时用不着,设0
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
// 避免刚初始化完就进中断的问题 void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
// 4.配置使能中断 TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // TIM_IT_Update: TIM update Interrupt source
// 5.NVIC配置
// 5.1 优先级分组 NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 5.2 NVIC初始化 void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn; // 中断通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 中断通道使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; // 设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 设置响应优先级
NVIC_Init(&NVIC_InitStruct);
// 6 启动定时器 TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
TIM_Cmd(TIM2, ENABLE);
}
// TIM2中断函数 在Start -》 startup_stm32f10x_md_vl.s中 107 行
void TIM2_IRQHandler(void)
{
// 检查标志位 ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT) 更新中断位
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
Num++;
// 清除标志位 防止不断进中断,使系统崩溃 void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
Timer.h
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
uint16_t Num; // 定义全局变量在中断中加1
int main(void)
{
OLED_Init();
Timer_Init();
OLED_ShowString(1,3,"Num:"); // 字符串用双引号括起来
while(1)
{
OLED_ShowNum(1,7,Num,5);
OLED_ShowNum(2,5,TIM_GetCounter(TIM2),5); // 获取计数器数值
// 由于设置的是 9999 故数值在0 - 9999 之间累加
}
}