赞
踩
1.使用系统滴答定时器实现LED灯的翻转(0.5s翻转一次)。
2.实现定时器6的定时功能,让LED2以500ms一次的频率闪烁。
3.配置定时器2,实现一个1s的定时功能(到时间LED4翻转)。
STM32里面有几个定时器:
高级定时器:TIM1,8
通用定时器: TIM2,3,4,5
基本定时器:TIM6,7
系统定时器(滴答定时器):Systick
由于系统定时器在内核中,所以想要配置系统定时器的相关寄存器,需要打开内核手册。
首先要打开时钟源和分频器
由内核手册可知该寄存器的0,1,2位均要置1。
代码如下:
//系统滴答定时器定时 1ms
//时钟源和分频器 72m 7 2000 000
SysTick->CTRL |= 0x1<<2;
//计数器 打开
SysTick->CTRL |= 0x1<<0;
//打开系统定时器中断
SysTick->CTRL |= 0x1<<1;
配置完成后,还需要配置重载值
代码如下:
SysTick->LOAD = 72000-1;//计数器计数从72000-1计数到0产生中断
或者直接使用内核写好的函数
SysTick_Config(72000); //1ms中断进入一次
SysTick_Config(72000)代表:72000*(1/72MHz)=1/1000=1(ms)。即定时为1ms。
最后的NVIC可配可不配。
配置完系统定时器后,我们就可以实现一个类似事件轴的东西,比单纯使用delay函数更准确。
代码如下:
delay.c 里加入void SysTick_Handler(void)函数
void SysTick_Handler(void) //1ms调用一次
{
systicktime++;
led1_count++;
led2_count++;
}
在main函数中外部声明一下 led1_count和led2_count。
这样我们就得到了一个1ms计数一次的时间轴,当我们需要时只需要在主函数中判断计数即可。
if(led1_count>=500){//过去500ms
led1_count=0;
/***LED1闪烁任务***/
Led_Toggle(1);
}
if(led2_count>=700){//过去500ms
led2_count=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、写一个中断服务函数。
首先创建一个tim.c和tim.h文件
在.c中创建void TIM6_Config(uint16_t psc,uint16_t reload)函数
然后打开手册找到TIM6定时器
由图中可以看到,只要配置好分频器,计数器自动重装载寄存器即可。
首先还是老规矩,先打开时钟源,顺着手册看TIM6的时钟源是在APB1还是APB2上。
从手册中得知该时钟源是在APB1总线上,所以将其RCC_APB1第四位置1即可。
RCC->APB1ENR |= 0x01<<4;
由于该分频器是自动+1,所以传参时应-1。
//分频器
TIM6->PSC = psc-1;
由于该寄存器是从0开始重载,所以需要初始值-1
//装载值
TIM6->ARR = reload-1;
直接找到手册里的TIM6控制寄存器
可知将TIM6 和TIM7 控制寄存器1的第0位置1即可使该计数器使能。
//计数器使能
TIM6->CR1 |= 0x01<<0;
由手册可知,将TIM6 和TIM7 DMA/中断使能寄存器(TIMx_DIER)的第0位置1即可打开。
最后配置一下NVIC即可
//打开定时器中断
TIM6->DIER |= 0x01<<0;
NVIC_SetPriority(TIM6_IRQn,5);//设置优先级0~15
NVIC_EnableIRQ(TIM6_IRQn);//使能中断通道
先在.s文件中找到TIM6对应的中断函数复制,然后看TIM6的SR是如何判断的。
由图可知,当TIM6->SR的第0位为1时产生中断。
void TIM6_IRQHandler()
{
//判断中断标志位
if((TIM6->SR&(0x01<<0))!=0){
//清理中断标志位
TIM6->SR &= ~(0x01<<0);
printf("定时器中断\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");
}
}
跟TIM6配置一样
照着流程走即可
需求实现代码如下:
main.c
#include "stm32f10x.h" #include "usart.h" #include "stdio.h" #include "led.h" #include "delay.h" #include "tim.h" int main() { NVIC_SetPriorityGrouping(5);//两位抢占两位次级 TIM2_Config(7200,10000); Usart1_Config(); Led_Init(); while(1) { } } void TIM2_IRQHandler() { //判断中断标志位 if((TIM2->SR&(0x01<<0))!=0){ //翻转LED2 Led_Toggle(2); //清理中断标志位 TIM2->SR &= ~(0x01<<0); printf("定时器中断\r\n"); } }
tim.c
#include "stm32f10x.h" /* 配置定时器的基本功能 参数1psc:分频系数 参数2reload:装载值 */ void TIM6_Config(uint16_t psc,uint16_t reload) { //时钟源APB1*2=72MHz,时钟源使能 RCC->APB1ENR |= 0x01<<4; //分频器 TIM6->PSC = psc-1; //装载值 TIM6->ARR = reload-1; //计数器使能 TIM6->CR1 |= 0x01<<0; //打开定时器中断 TIM6->DIER |= 0x01<<0; NVIC_SetPriority(TIM6_IRQn,5);//设置优先级0~15 NVIC_EnableIRQ(TIM6_IRQn);//使能中断通道 } 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);//使能中断通道 }
tim.h
#ifndef _TIM_H_
#define _TIM_H_
#include "stm32f10x.h"
void TIM6_Config(uint16_t psc,uint16_t reload);
void TIM2_Config(uint16_t psc,uint16_t reload);
#endif
1.了解了STM32中定时器的种类及作用。
2.学会了配置及使用系统定时器,基本定时器和通用计时器。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。