目录
- 定时器需求
- 一、系统滴答定时器
- 1.配置流程
- 2.程序配置
- 二、基本定时器
- 1.TIM6定时器配置
- 1.时钟源使能
- 2.分频器
- 3.装载值
- 4.计数器使能
- 5.打开定时器中断并配置
- 6.中断函数编写
- 三、通用定时器
- TIM2
定时器需求
1.使用系统滴答定时器实现LED灯的翻转(0.5s翻转一次)。
2.实现定时器6的定时功能,让LED2以500ms一次的频率闪烁。
3.配置定时器2,实现一个1s的定时功能(到时间LED4翻转)。
一、系统滴答定时器
STM32里面有几个定时器:
高级定时器:TIM1,8
通用定时器: TIM2,3,4,5
基本定时器:TIM6,7
系统定时器:Systick
1.配置流程
由于系统定时器在内核中,所以想要配置系统定时器的相关寄存器,需要打开内核手册。
Bits 31:17保留,必须保持清除。
第16位计数标志:
如果计时器自上次读取以来计数为0,则返回1。
Bits 15:3保留,必须保持清除。
位2 CLKSOURCE:时钟源选择
选择时钟源。
0:AHB/8
1:处理器时钟(AHB)
Bit 1 TICKINT:SysTick异常请求启用
0:倒计时到零不会断言SysTick异常请求
1:倒计时到零以断言SysTick异常请求。
注意:软件可以使用COUNTFLAG来确定SysTick是否曾经计数为零。
位0启用:计数器启用
启用计数器。当ENABLE设置为1时,计数器从以下位置加载RELOAD值
加载寄存器,然后倒计时。当达到0时,它将COUNTFLAG设置为1
根据TICKINT的值,可选地断言SysTick。然后加载RELOAD
再次取值,并开始计数。
0:计数器已禁用
1:计数器已启用
由内核手册可知该寄存器的0,1,2位均要置1。
//系统滴答定时器定时 1ms
//时钟源和分频器 72m 7 2000 000
SysTick->CTRL |= 0x1<<2;
//计数器 打开
SysTick->CTRL |= 0x1<<0;
//打开系统定时器中断
SysTick->CTRL |= 0x1<<1;
之后还要配置重装载值
Bits 31:24保留,必须保持清除。
位23:0重新加载[23:0]:重新加载值
LOAD寄存器指定计数器为时加载到VAL寄存器的起始值
启用,当它达到0时。计算RELOAD值RELOAD值可以是0x0000001-x00FFFFFF范围内的任何值。起始值为0是可能的,但没有效果,因为SysTick异常请求和COUNTFLAG从1到0计数时激活。
RELOAD值根据其用途计算:
l要生成具有N个处理器时钟周期的多触发定时器,请使用RELOAD
N-1的值。例如,如果每100个时钟脉冲需要SysTick中断,则设置
重新加载到99。l要在延迟N个处理器时钟周期后传递单个SysTick中断,请使用值为N的RELOAD。例如,如果在400时钟后需要SysTick中断
脉冲,将RELOAD设置为400。
SysTick->LOAD = 72000-1;//计数器计数从72000-1计数到0产生中断
意思为72000*1/72HZ=1/1000=1ms,即为1ms进入中断一次。
也可以用内核写好的函数进行应用。
SysTick_Config(72000);
2.程序配置
之后在delay.c 里加入void SysTick_Handler(void)函数
uint32_t systicktime = 0;
uint16_t ledcnt[2]={0,1000};//500ms 每个任务执行的时间
uint16_t led2cnt[2]={0,1500};//700ms
uint16_t keycnt[2]={0,10};//10ms检测一次
void SysTick_Handler(void)//1ms调用一次
{
//不需要清中断挂起位
systicktime++;
ledcnt[0]++;
led2cnt[0]++;
keycnt[0]++;
}
if(led1>=500){//过去500ms
led1=0;
/***LED1闪烁任务***/
Led_Toggle(1);
}
if(led2>=700){//过去500ms
led2=0;
/***LED2闪烁任务***/
Led_Toggle(2);
}
二、基本定时器
STM32中定时器分类以及相关作用
高级控制定时器:TIM1、TIM8 定时+输入捕获+输出比较+死区+互补PWM
通用定时器:TIM2、3、4、5 定时+输入捕获+输出比较
基本定时器:TIM6、7 定时
定时器配置的大致流程:
1、时钟源 RCC内部的时钟 APB1 36M APB1*2 = 72M
2、配置时需要打开APB1上TIM2、3、4、5、6、7或APB2上 TIM1、8的时钟(根据需求)
3、配置分频器:根据实际情况计算,不能超过65536 (TIMx_PSC)
4、配置重装载值:根据实际情况计算,不能超过65536(TIM_ARR)
5、打开计数器:
TIM_CR1(位0,位2) TIMx_DIER位0;
6、使能中断通道、配置中断优先级。
7、写一个中断服务函数。
1.TIM6定时器配置
1.时钟源使能
首先进行开时钟,在APB1上找到TIM6的时钟置为1即可。
RCC->APB1ENR |= 0x1<<4;
2.分频器
由于该分频器是自动+1,所以传参时应-1。
分频器
TIM6->PSC = psc-1;
3.装载值
TIM6 和TIM7 控制寄存器1的第0位置1即可使该计数器使能。
//装载值
TIM6->ARR = reload-1;
4.计数器使能
//计数器使能
TIM6->CR1 |= 0x1<<0;
5.打开定时器中断并配置
将TIM6 和TIM7 DMA/中断使能寄存器(TIMx_DIER)的第0位置1即可打开。
//打开定时器中断
TIM6->DIER |= 0x01<<0;
NVIC_SetPriority(TIM6_IRQn,5);//设置优先级0~15
NVIC_EnableIRQ(TIM6_IRQn);//使能中断通道
6.中断函数编写
void TIM6_IRQHandler(void)
{
//判断中断标志位
if((TIM6->SR&(0x1<<0)) != 0){
//清理中断标志位
TIM6->SR &= ~(0x1<<0);
printf("定时器6触发中断\r\n");
}
}
应用:
首先在主函数中调用 TIM6_Config();
由于需求是让LED2以500ms一次的频率闪烁,所以此时函数中应填写
TIM6_Config(7200,5000);
系统时钟是72Mhz,等于72000000hz。除于7200,等于0.1ms计数一次。
5000代表计数5000次定时器报警,也就是说500ms产生中断一次
最后,在产生中断时翻转LED2即可。
中断函数代码为:
void TIM6_IRQHandler()
{
//判断中断标志位
if((TIM6->SR&(0x01<<0))!=0){
//翻转LED2
Led_Toggle(2);
//清理中断标志位
TIM6->SR &= ~(0x01<<0);
printf("定时器中断\r\n");
}
}
库函数写法:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure={0};
TIM_TimeBaseStructure.TIM_Period = reload-1;//装载值
TIM_TimeBaseStructure.TIM_Prescaler = psc-1;//分频器
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数模式选择向上计数
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
//定时器使能
TIM_Cmd(TIM6,ENABLE);
//定时器中断使能
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
NVIC_SetPriority(TIM6_IRQn,5);
NVIC_EnableIRQ(TIM6_IRQn);
}
void TIM6_IRQHandler(void)
{
//判断中断标志位
if((TIM6->SR&(0x1<<0)) != 0){
//清理中断标志位
TIM6->SR &= ~(0x1<<0);
printf("定时器6触发中断\r\n");
}
}
三、通用定时器
TIM2
void TIM2_Config(uint16_t psc,uint16_t reload)
{
//时钟源APB1*2=72MHz,时钟源使能
RCC->APB1ENR |= 0x01<<0;
//分频器
TIM2->PSC = psc-1;
//装载值
TIM2->ARR = reload-1;
//计数器使能
TIM2->CR1 |= 0x01<<0;
//打开定时器中断
TIM2->DIER = 0x01<<0;
NVIC_SetPriority(TIM2_IRQn,3);//设置优先级0~15
NVIC_EnableIRQ(TIM2_IRQn);//使能中断通道
}
void TIM2_IRQHandler()
{
//判断中断标志位
if((TIM2->SR&(0x01<<0))!=0){
//翻转LED2
Led_Toggle(2);
//清理中断标志位
TIM2->SR &= ~(0x01<<0);
printf("定时器中断\r\n");
}
}
主函数中:
TIM2_Config(7200,10000);
表示0.1ms计数一次,一共计数10000次,一共1000ms,即为一秒。