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);
    
    }
 }