实现内容
利用TIM3的定时器中断来控制DS1的翻转,在主函数用DS0 的翻转来提示程序正在运行。
定时器介绍
定时器可以认为是一个计数器;给定计数器一个初值,每当计数一次,就会走过一个固定的时间,当达到我们给定的初值时,该定时器就完成了自己的使命,产生定时器中断,执行中断函数中的程序命令。
STM32F4_定时器精讲(TIM)
STM32F1 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
STM3F1 的通用 TIMx (TIM2、TIM3、TIM4 和TIM5)定时器功能包括:
- 16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
- 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
5)如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理
寄存器介绍
控制寄存器1(TIMx_CR1)
最低位0是使能位,只有置1时才会开始计时。
第4位是选择计数方式:向上0,向下1。
第5,6位是对齐方式:00(边沿对齐模式),01(中央对齐模式1),10(中央对齐模式2),11(中央对齐模式3)
第8,9位设置时钟分频因子:00(1),01(2),10(4),11(保留)
DMA/中断使能寄存器(TIMx_DIER)
仅关注第0位使能位。置1时允许由于更新事件所产生的中断。
预分频寄存器(TIMx_PSC)
设置对时钟进行分频,然后提供给计数器,作为计数器的时钟。
TIMx_SMCR寄存器
设置定时器的时钟来源。
定时器的时钟来源:
1) 内部时钟(CK_INT)
2) 外部时钟模式 1:外部输入脚(TIx)
3) 外部时钟模式 2:外部触发输入(ETR)
4) 内部触发输入(ITRx):使用A 定时器作为B 定时器的预分频器(A 为B 提供时钟)。
CK_INT时钟是从APB1 倍频的来的,除非 APB1 的时钟分频数设置为 1,否则通用定时器TIMx 的时钟是 APB1 时钟的 2 倍,当 APB1 的时钟不分频的时候,通用定时器 TIMx 的时钟就等于 APB1的时钟。这里还要注意的就是高级定时器的时钟不是来自 APB1,而是来自APB2 的。
TIMx_CNT寄存器
定时器的计数器,该寄存器存储了当前定时器的计数值。
自动重载寄存器(TIMx_ARR)
该寄存器在物理上实际对应着2 个寄存器。一个是程序员可以直接操作的,另外一个是程序员看不到的,这个看不到的寄存器被叫做影子寄存器。事实上真正起作用的是影子寄存器。根据 TIMx_CR1 寄存器中 APRE 位的设置:APRE=0 时,预装载寄存器的内容可以随时传送到影子寄存器,此时 2者是连通的;而APRE=1 时,在每一次更新事件(UEV)时,才把预装在寄存器的内容传送到影子寄存器。
状态寄存器(TIMx_SR)
用来标记当前与定时器相关的各种事件/中断是否发生。
实验
1.TIM3时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
2.初始化定时器参数,设置自动重装值,分频系数,计数方式等。
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
typedef struct
{
uint16_t TIM_Prescaler;//设置分频系数
uint16_t TIM_CounterMode;//设置计数方式
uint16_t TIM_Period;//设置自动重载计数周期值
uint16_t TIM_ClockDivision;//设置时钟分频因子
unt8_t TIM_RepetitionCounter;//高级定时器时使用
}
TimeOut = ((Prescaler + 1) * (Period + 1) ) / TimeClockFren;
3.设置TIM3_DIER 允许更新中断。
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
//第一个参数是选择定时器号,取值为 TIM1~TIM17。
//第二个参数用来指明我们使能的定时器中断的类型,定时器中断的类型有很多种,包括更新中断 TIM_IT_Update,触发中断 TIM_IT_Trigger,以及输入捕获中断等等。
//第三个参数是失能还是使能。
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );
4.TIM3 中断优先级设置。
5.允许TIM3 工作,也就是使能TIM3。
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
TIM_Cmd(TIM3, ENABLE); //使能 TIMx 外设
6.编写中断服务函数。
在中断产生后,通过状态寄存器的值来判断此次产生的中断属于什么类型。然后执行相关的操作,我们这里使用的是更新(溢出)中断,所以在状态寄存器 SR 的最低位。在处理完中断之后应该向TIM3_SR 的最低位写 0,来清除该中断标志。
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)//判断定时器TIMx的中断类型TIM_IT是否发生中断
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)//清除中断标志位
main.c
#include"led.h"
#include"time.h"
#include"delay.h"
int main()
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响
LED_Init();
TIM3_Int_Init(4999,7199);
while(1)
{
LED0=!LED0;
delay_ms(200);
}
}
time.h
#ifndef TIME_H_
#define TIME_H_
#include"stm32f10x_tim.h"
#endif
time.c
#include"time.h"
#include"led.h"
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)//发生更新中断
{
LED1=!LED1;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
}