定时器中断实验
2016-10-18 17:08
295 查看
知识回顾
通用定时器原理通用定时器分为四个部分:
1,选择时钟 2,时基电路 3,输入捕获 4,输出比较
本节定时器中断主要涉及到定时器框图上边两个部分,即选择时钟和时基电路
定时器时钟选择
选择默认的内部时钟,配置时基电路(配置预分频系数,重装载值)计数器时钟来源
1,内部时钟(CK_INT),默认 2,外部时钟模式1:外部输入脚(TIx) 3,外部时钟模式2:外部触发输入(ETR)
时钟选择配置寄存器TIMx_SMCR
TIMx_SMCR-SMS[2:0]:,默认000 关闭从模式,预分频器由内部时钟驱动
内部时钟选择:
AHB时钟经过APB1预分频 如果APB1预分频为1,定时器时钟由APB1*1输出 如果APB1预分频不为1,定时器时钟由APB1*2输出 除非APB1分频系数为1,否则通用定时器时钟等于APB1的2倍
根据系统时钟知识: APB1时钟为AHB时钟(由AHB时钟分频系数为1得到)时,CK_INT = APB1时钟 APB1时钟为AHB时钟不为1分频得到时,CK_INT = APB1时钟 * 2 因为选中的是内部时钟(CK_INT),CK_PCS = CK_INT CK_PSC % N(N为CK_PSC寄存器值+1得到),得到CK_CNT-定时器最终时钟 SYSCLK=72M AHB时钟=72M APB1时钟=36M 所以APB1的预分频系数=AHB/APB1=2 所以,通用定时器时钟CK_INT=2*36M=72M
定时器中断时序
向上计数为例,时钟分频因子为1(加一之后等于1)APB1时钟=CK_INT CNT_EN高电平-定时器使能 定时器时钟CK_CNT(CK_INT % N 得到) 计数器向上计数,到36(到重装载值,产生中断),重新计数 计数器溢出,跳变 更新事件产生,跳变 更新中断标志置1(需软件清零)
寄存器和库函数配置
1,计数器当前值寄存器CNT
16位寄存器,记录计数器当前值
对应框图部分:
2,预分频寄存器TIMx_PSC
3,自动重装载寄存器TIMx_ARR
16位寄存器,设置自动重装载值
4,控制寄存器1 TIMx_CR1
位4-计数方向配置位DIR: 0:向上计数 1:向下计数 位0-使能配置CEN: 0:禁止计数器 1:开启计数器
5,DMA中断使能寄存器
位0-更新中断使能UIE: 0:禁止更新中断 1:允许更新中断
定时器中断相关库函数
1,定时器参数初始化
// stm32f10x_tim.c中TIM_TimeBaseInit定时器初始化函数定义: void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); // TIM_TimeBaseInitTypeDef: typedef struct { uint16_t TIM_Prescaler; // 预分频系数 uint16_t TIM_CounterMode; // 计数模式 uint16_t TIM_Period; // 自动装载值 uint16_t TIM_ClockDivision; // 输入捕获使用 uint8_t TIM_RepetitionCounter; // 高级定时器使用 } TIM_TimeBaseInitTypeDef; // IS_TIM_COUNTER_MODE #define IS_TIM_COUNTER_MODE(MODE) (((MODE) == TIM_CounterMode_Up) || \ ((MODE) == TIM_CounterMode_Down) || \ ((MODE) == TIM_CounterMode_CenterAligned1) || \ ((MODE) == TIM_CounterMode_CenterAligned2) || \ ((MODE) == TIM_CounterMode_CenterAligned3)) // IS_TIM_CKD_DIV #define IS_TIM_CKD_DIV(DIV) (((DIV) == TIM_CKD_DIV1) || \ ((DIV) == TIM_CKD_DIV2) || \ ((DIV) == TIM_CKD_DIV4))
初始化配置对应框图:
2,定时器使能函数TIM_Cmd
作用 : 操作控制寄存器1 TIMx_CR1的位0,使能定时器// stm32f10x_tim.c中TIM_Cmd定时器初始化函数定义: void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
3,定时器中断使能函数
作用 : 操作DMA中断使能寄存器TIMx_DIER使能相应的定时器中断// stm32f10x_tim.c中TIM_Cmd定时器初始化函数定义: void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
4,状态标志位的获取和清除
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);
定时器中断实验的步骤
1,使能定时器时钟 RCC_APB1PeriphClockCmd(); 2,初始化定时器,配置ARR(自动重装载寄存器),PSC(预分频系数) TIM_TimeBaseInit 3,开启定时器中断,配置NVIC中断优先级 TIM_ITConfig() NVIC_Init();(主函数要设置中断优先级分组) 4,使能定时器 TIM_Cmd() 5,编写中断服务函数: TIMx_IRHandler();
实验内容
配置定时器中断,实现每500ms中断一次,中断服务函数控制LED1反转主函数控制LED0每间隔300ms闪烁
实现500ms一次中断: 定时器从计数开始到触发中断所需事件由两个参数控制: ARR:自动重装载值 PSC:定时器时钟 定时器时钟: APB1时钟经过倍频得到(当AHB1分频为1倍,其他为2倍) 定时器一个周期(计数器+1需要的时间)时间 = (PSC+1) / Tclk 一共需要多少个周期:ARR+1 溢出时间 Tout = (ARR + 1) (PSC + 1) / Tclk 当前实验使用系统初始化函数来初始化APB1,预分频系数为2,CK_INT=72M 考虑将PSC+1 = 7200 这样(PSC + 1) / Tclk = 7200/72000000 = 0.1s 便于计算, 所以PSC=7199 500ms中断间隔的实现 500 = ( ARR + 1 ) (PSC + 1) / 72000000 500 = ( ARR + 1 ) * 0.1 ARR=4999 所以设置ARR = 4999 , PSC=7199 实现定时器每500ms进入一次中断
项目初始化
新建文件 HARDWARE/TIMER/timer.c HARDWARE/TIMER/timer.h
添加文件到项目目录,并将timer.h路径添加到配置path中
加入定时器相关库函数文件stm32f10x_tim.c
timer.c中include timer.h 然后编译
timer.h
#ifndef __TIMER_H #define __TIMER_H #include "sys.h" // arr 自动重装载值 psc 定时器时钟 void TIM3_Int_Init(u16 arr,u16 psc); #endif
timer.c
#include "timer.h" #include "led.h" void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; // 1, 使能定时器3时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 2,定时器初始化配置 TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 与此实验关系不大,随意设置一个 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 定时器中断使能 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //更新中断使能 //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; //使能 NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM3, ENABLE); //使能定时器 } //中断服务函数 void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //更新中断发生 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //置位更新状态-清除标志位 LED1=!LED1; // 反转LED1 } }
主函数main.c
#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "timer.h" int main(void) { delay_init(); //延时函数初始化 LED_Init(); //LED初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组配置为2 TIM3_Int_Init(4999,7199);// 初始化TIM3定时器 while(1) { LED0=!LED0; delay_ms(200); //每200msLED0反转 } }
实验结果
实验实现每间隔500msLED1闪烁,每200msLED0闪烁
相关文章推荐
- 定时器中断实验
- S02_CH08_ ZYNQ 定时器中断实验
- Zigbee之旅(四):几个重要的CC2430基础实验——定时器中断
- 中断和定时器实验--c语言实现中断嵌套
- STM32串口采样与仪表步进电机控制程序(主程序与串口程序,需用正点原子定时器中断实验程序模板)
- mini2440 定时器中断实验
- stm32定时器中断实验
- STM32实验1:定时器中断同时产生两路不同频率的信号
- 4、定时器中断实验
- 一起学mini2440裸机开发(十一)--mini2440定时器0中断实验
- 【实验六】定时器中断实验
- 实验3 RTC定时器的应用及中断机制
- 实验二:外部中断与定时器/计数器中断实验
- STM32定时器中断实验-TIM3
- Zigbee之旅(四):几个重要的CC2430基础实验——定时器中断(转)
- STM32F107的通用定时器中断实验总结
- 【黑金ZYNQ7000系列原创视频教程】04.熟悉ZYNQ内部中断——内部定时器中断实验
- STM32 普通定时器(TIM3)中断 实现流水灯实验
- STM32单片机学习(5) 定时器中断实验
- 定时器中断实验