STM32 Timer (2) 定时器中断代码框架
x1/x2 /N(预分频)
APB1时钟------->F(CK_PSC)--------------->CK_CNT
如果APB1的分频系数为1, CK_INT的倍频系数就是x1
如果APB1的分频系数不为1, CK_INT的倍频系数就是x2
|
|
|||||
SYSCLK | 72 | 168 | 216 | |||
AHB | 72 | 168 | 216 | |||
APB1 (AHB/4) | 18 | 42 | 54 | |||
CK_INT(x1/x2) | 36 | 84 | 108 | |||
PSC预分频 |
举例:实现 0.5s 的led闪烁 当前使用F7 所以 CK_INT = 108MHz PSC预分频:Prescaler 自动重装载寄存器: Period time = (Period)(Prescaler)/CK_INT 0.5 = (Period)(Prescaler)/108000000 预分频 Prescaler 方便计算 设置为 108000(整除), 自动重装载 Period 设置为 500 计算: 500*108000/108000000 = 0.5 但是,因为受到16位寄存器的约束, 108000 超过的65535(2的16次方) 所以稍微调整: 5000 * 10800 同样满足要求。 所以配置: Prescaler = 10800 Period = 5000 根据定时需求调整 time = (Period)(Prescaler)/CK_INT
从 int main() { }开始了解定时器的实现
// 1.使能定时器时钟 __HAL_RCC_TIM3_CLK_ENABLE(); //2. 初始话定时器,配置Prescaler,Period HAL_TIM_Base_Init(); // 3. 开启定时器/中断 HAL_TIM_Base_Start(); HAL_TIM_Base_Start_IT(); // 4. 设置中断优先级 HAL_NVIC_SetPriority(); HAL_NVIC_EnableIRQ(); // 5. 编写中断服务函数 TIMx_IRQHandler(); //中断服务函数 HAL_TIM_IRQHandler(); //中断处理入口函数 HAL_TIM_PeriodElapsedCallback();//定时器更新中断回调函数
//正式开始 // 1. 自定义一个TIM初始化函数 void TIM3_Init() { //... } int main() { TIM3_Init(); }
//Tim3_Init()做些什么事? void TIM3_Init() { //1. 定时器初始化函数 HAL_TIM_Base_Init(); //需要一个参数 } //函数原型: HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim) //所以设置TIM句柄 TIM_HandleTypeDef htim3; //设置了句柄,就要对其中的参数进行初始化 htim3.Instance = TIM3; htim3.Init.Prescaler = 10800-1; //预分频系数 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //计数模式 htim3.Init.Period = 5000-1; //自动装载值
//结果: TIM_HandleTypeDef htim3; void TIM3_Init() { htim3.Instance = TIM3; htim3.Init.Prescaler = 10800-1; //预分频系数 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //计数模式 htim3.Init.Period = 5000-1; //自动装载值 HAL_TIM_Base_Init(htim3); }
//2. 然后嘞就要使能时钟定时器 //在HAL_TIM_Base_Init(htim3) 函数中有: HAL_TIM_Base_MspInit(htim); //这个函数Msp 表示回调函数, 一般在文件stm32f4xx_hal_msp.c文件中,如果没有,自己实现也是一样 // 这个函数主要实现 时钟的开启, GPIO的配置, 中断优先级的配置 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) { if(htim_base->Instance==TIM3) { __HAL_RCC_TIM3_CLK_ENABLE(); } } //因为HAL_TIM_Base_Init 这个函数不仅仅针对与TIM3, 所以在Msp函数中, 要进行if判断 htim_base->Instance==TIM3 //在这个函数中, 进行 TIM时钟的开启 __HAL_RCC_TIM3_CLK_ENABLE();
// 3.开启Tim3且中断 void TIM3_Init() { htim3.Instance = TIM3; htim3.Init.Prescaler = 10800-1; //预分频系数 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //计数模式 htim3.Init.Period = 5000-1; //自动装载值 HAL_TIM_Base_Init(htim3); //new HAL_TIM_Base_Start_IT(&htim3); //开启定时器中断 }
//4 .开启了中断后,就要设置中断优先级 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) { if(htim_base->Instance==TIM3) { __HAL_RCC_TIM3_CLK_ENABLE(); //中断优先级 HAL_NVIC_EnableIRQ(TIM3_IRQn); HAL_NVIC_SetPriority(TIM3_IRQn,1,3); } }
// 5. 编写中断服务函数 //在start.s文件中,有中断触发函数列表,查找之。 void TIM3_IRQHandler(void) { //待编写 } //写什么呢,TIM的api中,有中断触发函数 HAL_TIM_IRQHandler(&htim3); ---> void TIM3_IRQHandler(void) { HAL_TIM_IRQHandler(&htim3); } //继续跟踪 HAL_TIM_IRQHandler(&htim3);
/* TIM Update event */ if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET) { __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) htim->PeriodElapsedCallback(htim); #else HAL_TIM_PeriodElapsedCallback(htim); #endif /* USE_HAL_TIM_REGISTER_CALLBACKS */ } } //有各种各样的中断,这里实现更新中断, 调用了 HAL_TIM_PeriodElapsedCallback(htim); //所以重写回调函数HAL_TIM_PeriodElapsedCallback(htim);
//time更新回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { //LED 反转 }
#include <rtthread.h> #include <rtdevice.h> #include <board.h> #define LED0 GET_PIN(B,0) #define LED1 GET_PIN(B,1) static rt_uint8_t flag = 0; TIM_HandleTypeDef htim3; void TIM3_Init() { htim3.Instance = TIM3; htim3.Init.Prescaler = 10800-1; //预分频系数 htim3.Init.CounterMode = TIM_COUNTERMODE_UP; //计数模式 htim3.Init.Period = 5000-1; //自动装载值 HAL_TIM_Base_Init(&htim3); HAL_TIM_Base_Start_IT(&htim3); //开启tim3中断 //因为开启了中断,所以要设置中断优先级 //本来要自己实现中断函数HAL_TIM_Base_MspInit 的,但是在 //stm32f7xx_hal_msp.c文件中已经写了,所以去这个文件编写中断优先级 } //中断配置后,实现中断服务函数 //中断服务函数 void TIM3_IRQHandler(void) { HAL_TIM_IRQHandler(&htim3); } //time更新回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(flag == 0) { rt_pin_write(LED0,PIN_LOW); flag = 1; return; } if(flag == 1) { rt_pin_write(LED0,PIN_HIGH); flag = 0; return; } } void LED_Init(void) { rt_pin_mode(LED0,PIN_MODE_OUTPUT); } int main(void) { LED_Init(); TIM3_Init(); return 0; }
htm32f7xx_hal_msp.c
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) { if(htim_base->Instance==TIM3) { __HAL_RCC_TIM3_CLK_ENABLE(); //中断优先级 HAL_NVIC_EnableIRQ(TIM3_IRQn); HAL_NVIC_SetPriority(TIM3_IRQn,1,3); } }