1、基本定时器简介
- 时钟源
时钟挂载在APB1总线下,中间有一个倍频器,sys_stm32_clock_init时钟已经设置APB1总线时钟频率为36M,预分频器分频系数为2,所以挂载在APB1总线的定时器时钟频率为72Mhz,图中对应的时钟信号为CK_INT。 - 控制器
能够控制定时器复位、使能、计数,还能触发DAC转换。 - 时基单元
时基单元包括:计数器寄存器、预分频寄存器、自动重载寄存器。预分频寄存器的输入来源于CK_PSC,也就是CK_INT,输出为CK_CNT,CK_CNT是通过预分频器分频后的信号。预分频寄存器和自动重载寄存器都有影子寄存器,影子寄存器就是当写入新的值的时候,这个值不会直接写进影子寄存器,会在寄存器中缓冲,在下一个更新事件出现的时候,才会写入,区别在于自动重载寄存器是否有缓冲作用还受到ARPE位控制。 - 更新事件
一由软件产生,将TIMx_EGR寄存器的位UG置1,产生更新事件后,硬件会自动将UG位清零。
二由硬件产生,当计数器的值等于自动重装载寄存器影子寄存器的值时。
2、寄存器
- 控制寄存器(TIMx_CR1)
- DMA/中断使能寄存器(TIMx_DIER) 位0控制使能或者禁止更新中断
- 状态寄存器(TIMx_SR) 位0是中断更新的标志位,需要软件清零
- 计数器寄存器(TIMx_CNT) [15:0]计数器的实时计数值
- 预分频寄存器(TIMx_PSC) [15:0]预分频数值
- 自动重载寄存器(TIMx_ARR) [15:0]自动重载数值
3、硬件
(1)功能
LED0用来指示程序运行,每200ms翻转一次。我们在更新中断中,将LED1的状态取反。 LED1用于指示定时器发生更新事件的频率,500ms取反一次
(2)资源
LED0-PB5
LED1-PE5
定时器
4、程序设计
定时器中断配置步骤
1)定时器时钟使能
__HAL_RCC_TIMx_CLK_ENABLE()
2) 初始化定时器参数,设置自动重装值,分频系数,计数方式
使用HAL_TIM_Base_Init(),传入TIM_HandleTypeDef类型结构体
3)使能定时器更新中断,开启定时器计数,配置定时器中断优先级
通过HAL_TIM_Base_Start_IT函数使能定时器更新中断和开启定时器计数
在HAL_TIM_Base_Init()函数中的HAL_TIM_Base_MspInit()函数中通过HAL_NVIC_EnableIRQ函数使能定时器中断,通过HAL_NVIC_SetPriority函数设置中断优先级
4)编写终端服务函数
编写BTIM_TIMX_INT_IRQHandler函数,调用公共接口HAL_TIM_IRQHandler,再编写回调函数,实现LED1翻转功能。
TIM_HandleTypeDef g_timx_handle; /* 定时器句柄 */
//初始化基本定时器
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
g_timx_handle.Instance = BTIM_TIMX_INT; /* 通用定时器X */
g_timx_handle.Init.Prescaler = psc; /* 设置预分频系数 */
g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
g_timx_handle.Init.Period = arr; /* 自动装载值 */
HAL_TIM_Base_Init(&g_timx_handle); /*这个函数里会调用HAL_TIM_Base_MspInit*/
HAL_TIM_Base_Start_IT(&g_timx_handle); /* 使能定时器x及其更新中断 */
}
//初始化定时器底层驱动
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == BTIM_TIMX_INT)
{
BTIM_TIMX_INT_CLK_ENABLE(); /* 使能TIM时钟 */
HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 1, 3); /* 抢占1,子优先级3,组2 */
HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn); /* 开启ITM3中断 */
}
}
//定时器中断服务函数
void BTIM_TIMX_INT_IRQHandler(void)
{
HAL_TIM_IRQHandler(&g_timx_handle); /* 定时器中断公共处理函数 */
}
//这个函数将会被定时器中断公共处理函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == BTIM_TIMX_INT)
{
LED1_TOGGLE(); /* LED1反转 */
}
}
完成驱动文件后,main函数如下
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
btim_timx_int_init(5000 - 1, 7200 - 1); /* 10Khz的计数频率,计数5K次为500ms */
while (1)
{
LED0_TOGGLE(); /*LED灯翻转*/
delay_ms(200);
}
}