3. 代码框架
3.1 分频系数的计算
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
3.2 代码细讲
从 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 反转
}
3.3 全代码
其中LED的初始化基于RT-thread, 若非RTOS自行替换,跟框架无关。
main.c
#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);
}
}