1、定时原理
1.1 软件定时原理
使用纯软件(CPU死等)的方式实现定时(延时)功能
void delay_us(uint32_t us) {
us *= 72;
while(us--);
}
缺点:①延时不精准;②CPU死等(阻塞)
1.2 定时器定时原理
使用精准的时基,通过硬件的方式,实现定时功能
定时器核心就是计数器
定时器简易框图
1.3 定时器分类
常规定时器的区别
1.4 定时器特性表
2、基本定时器
2.1 简介
2.2 框图
2.3 溢出时间计算公式
:定时器溢出时间
:定时器的时钟源频率,72Mhz
ARR:自动重装载寄存器的值
PSC:预分频寄存器的值
3、定时器中断的配置步骤
3.1 配置定时器基础工作参数
void base_tim_init(uint16_t arr,uint16_t psc); //自己写的初始化函数
3.2 定时器基础MSP初始化
__weak void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim); //配置NVIC、CLOCK等
3.3 使能更新中断并启动计数器
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim);
{
TIM_TypeDef *Instance; /* 寄存器基地址 */
TIM_Base_InitTypeDef Init; /* TIM时基所需参数 */
......#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
......
#endif
} TIM_HandleTypeDef;
typedef struct
{
uint32_t Prescaler; /* 预分频系数(范围:0x0000~0xFFFF) */uint32_t CounterMode; /* 计数模式 */
uint32_t Period; /* 自动重装载值(范围:0x0000~0xFFFF) */
uint32_t ClockDivision; /* 预分频因子,高级定时器会用到 */
uint32_t RepetitionCounter;
uint32_t AutoReloadPreload; /* 自动重装载预装载使能 */
} TIM_Base_InitTypeDef;
CounterMode 如下所示:
#define TIM_COUNTERMODE_UP 0x00000000U
/* 用作向上计数器的计数器 */
#define TIM_COUNTERMODE_DOWN TIM_CR1_DIR/*!< 用作向下计数器的计数器 */
#define TIM_COUNTERMODE_CENTERALIGNED1 TIM_CR1_CMS_0/* 居中对齐模式1 */
#define TIM_COUNTERMODE_CENTERALIGNED2 TIM_CR1_CMS_1/* 居中对齐模式2 */
#define TIM_COUNTERMODE_CENTERALIGNED3 TIM_CR1_CMS/* 居中对齐模式3 */
AutoReloadPreload 如下所示:
#define TIM_AUTORELOAD_PRELOAD_DISABLE 0x00000000U
/* TIMx_ARR寄存器未缓冲 */
#define TIM_AUTORELOAD_PRELOAD_ENABLE TIM_CR1_ARPE/* TIMx_ARR寄存器已缓冲 */
3.4 设置优先级,使能中断
HAL_NVIC_SetPriority();
HAL_NVIC_EnableIRQ();
在32单片机——外部中断_32中断-CSDN博客中有解释
3.5 编写中断服务函数
void TIM6_IRQHandler(void){
HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim); //中断公共处理函数
}
3.6 编写定时器更新中断回调函数
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
例子
使用基本定时器TIM6实现精准定时,使LED1每隔500ms翻转一次,在主函数用LED0的翻转来提示程序正在运行
分析:实现500ms定时 psc:7199;arr:4999
base_time.h
#ifndef _BASE_TIME_H
#define _BASE_TIME_H
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"//定时器初始化
void base_tim_init(uint16_t arr,uint16_t psc);#endif
base_time.c
#include "./BSP/TIMER/base_tim.h"
TIM_HandleTypeDef base_tim_handle; //定时器句柄
void base_tim_init(uint16_t arr,uint16_t psc){
base_tim_handle.Instance=TIM6; //寄存器基地址
base_tim_handle.Init.Prescaler=psc; //预分频系数
base_tim_handle.Init.Period=arr; //自动重装载值
base_tim_handle.Init.CounterMode=TIM_COUNTERMODE_UP; //计数模式
base_tim_handle.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE; //自动重装载预装载使能
//base_tim_handle.Init.ClockDivision= //预分频因子,高级定时器会用到
HAL_TIM_Base_Init(&base_tim_handle);
//开启定时器
HAL_TIM_Base_Start_IT(&base_tim_handle);
}
//定时器Msp回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM6){
//CLOCK
__HAL_RCC_TIM6_CLK_ENABLE();
//设置优先级
HAL_NVIC_SetPriority(TIM6_IRQn,0,0);
HAL_NVIC_EnableIRQ(TIM6_IRQn);
}
}
//中断服务函数
void TIM6_IRQHandler(void){
HAL_TIM_IRQHandler(&base_tim_handle); //中断公共处理函数
}
//定时器更新中断回调函数 定时500msvoid HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM6){
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
}
}
main.c
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/base_tim.h"
int main(void){
uint8_t i=0;
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9); //设置系统时钟
delay_init(72);
led_init();
base_tim_init(4999,7199);
while (1){
i++;
if(i>20){
i=20;
delay_ms(100);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5); //LED0闪烁,指示程序正常运行
}
}
}