使用普通定时器2来产生中断,计数方式:增计数!
一、编程配置部分
1、首先进行中断配置,定时器中断肯定要配置的,代码如下:
void TIM2_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
这部分就不详述了
2、定时器的配置才是重点
/*TIM_Period--1000 TIM_Prescaler--71 -->中断周期为1ms*/还是一样,找到这个结构体
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period=1000; /* 自动重装载寄存器周期的值(计数值) */
/* 累计 TIM_Period个频率后产生一个更新或者中断 */
TIM_TimeBaseStructure.TIM_Prescaler= (72 - 1);/* 时钟预分频数 72M/72 */
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; /* 采样分频 */
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; /* 向上计数模式 */
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);/* 清除溢出中断标志 */
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2, ENABLE);/* 开启时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE);/*先关闭等待使用*/
}
TIM_TimeBaseInitTypeDef{
uint16_t TIM_ClockDivision
uint16_t TIM_CounterMode
uint16_t TIM_Period
uint16_t TIM_Prescaler
uint8_t TIM_RepetitionCounter
}
1、TIM_ClockDivision用来设置时钟分频的,它的取值可以是
#define | TIM_CKD_DIV1 ((uint16_t)0x0000) |
#define | TIM_CKD_DIV2 ((uint16_t)0x0100) |
#define | TIM_CKD_DIV4 ((uint16_t)0x0200) |
#define | TIM_CounterMode_CenterAligned1 ((uint16_t)0x0020) |
#define | TIM_CounterMode_CenterAligned2 ((uint16_t)0x0040) |
#define | TIM_CounterMode_CenterAligned3 ((uint16_t)0x0060) |
#define | TIM_CounterMode_Down ((uint16_t)0x0010) |
#define | TIM_CounterMode_Up ((uint16_t)0x0000) |
Specifies the period value to be loaded into the active Auto-Reload Register at the next update event. This parameter must be a number between 0x0000 and 0xFFFF.
就是一个重装值而已!4、TIM_Prescaler明显是一个时钟与分频系数
Specifies the prescaler value used to divide the TIM clock. This parameter can be a number between 0x0000 and 0xFFFF
设置范围比较广,这里有一个计算公式
Specifies the repetition counter value. Each time the RCR downcounter reaches zero, an update event is generated and counting restarts from the RCR value (N)
这是在PWM里面用到的,这里可以不作设置
6、配置中断,清除中断标志位
TIM_ClearFlag(TIM2, TIM_FLAG_Update);/* 清除溢出中断标志 */
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
至此整个TIM2就配置完毕!不难得出,最后出来的结果就是:
/*TIM_Period--1000 TIM_Prescaler--71 -->中断周期为1ms*/
7、还漏了一个初始化函数,就是将TIMx设置为默认值!
void TIM_DeInit(TIM_TypeDef* TIMx)
{
/* Check the parameters */
assert_param(IS_TIM_ALL_PERIPH(TIMx));
switch (*(uint32_t*)&TIMx)
{
case TIM1_BASE:
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE);
break;
case TIM2_BASE:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE);
break;
case TIM3_BASE:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE);
break;
case TIM4_BASE:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);
break;
case TIM5_BASE:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, DISABLE);
break;
case TIM6_BASE:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, DISABLE);
break;
case TIM7_BASE:
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);
break;
case TIM8_BASE:
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, DISABLE);
break;
default:
break;
}
}
可以看到这里设置了各种定时器的默认值,我们只需要传入一个参数就能自动的找到相应的分支进行初始化,非常明朗!
二、毫无疑问,我们既然产生了中断,那么我们的中断函数怎么实现呢?在哪里实现呢?接着看我们在 it.c 文件中实现的中断函数!
void TIM2_IRQHandler(void)看看中断里面做了什么,没关系找手册,可以看到这个
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
{
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
time++;
}
}
TIM_IT_Update: TIM update Interrupt source这就是那个函数的传入参数了,各种中断方式,Checks whether the TIM interrupt has occurred or not.用于检测是否产生对应的中断,因为我们在设置中断的时候就是设置的TIM_IT_Update中断方式,也就是更新事件,重载初值吧,至少我是这样理解的。
TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
TIM_IT_COM: TIM Commutation Interrupt source
TIM_IT_Trigger: TIM Trigger Interrupt source
TIM_IT_Break: TIM Break Interrupt source
中断里面还清除了中断标志位,方便下一次进入中断嘛,然后还有就是对全局变量time自加1,方便主函数里面的检测!
好的,最后贴上主函数的代码,问题应该不大了。
/*******由于没有做外设测试的程序是:按键PA0仅一个LED灯******/
/*******由于没有做外设测试的程序是:串口采用的是PA9->(T<->T),PA9->(R<->R)*****/
#include "stm32f10x.h"
#include "LED.h"
#include "SysTick.h"
#include "Delay.h"
#include "Usart.h"
#include "stdio.h"
#include "Timer3.h"
volatile u32 time; // ms 计时变量
int main(void)
{
//初初始化GPIO
LED_GPIO_Config();
//初始化系统定时器
SysTick_Init();
USART1_Config();
/* TIM2 定时配置 */
TIM2_NVIC_Configuration();
TIM2_Configuration();
printf("\r\n ("__DATE__ " - " __TIME__ ") \r\n");
START_TIME;
while(1)
{
if ( time == 1000 ) /* 1s 时间到 */
{
time = 0;
/* LED1 取反 */
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0))));
}
}
}