目录
一、通用定时器是什么?
1.计数模式
2.工作过程编辑
3.内部时钟选择
二、通用定时器HAL库函数流程
三、小实验程序要求
四、代码实现
1.TIM.h
2.TIM.c
3.main.c
通用定时器包含一个 16 位或 32 位自动重载计数器( CNT),该计数器由可编程预分频器( PSC) 驱动。 STM32F429 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。 STM32F429 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
通用定时器可以向上计数,向下计数、向上向下双向计数模式。
①向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
②向下计数模式:计数器从自动加载值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
③中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
红色框作用就是产生CK_PSC时钟,之后经过CK_PSC预分频器,到CNT计数器,可以通过触发控制器里的从模式控制器来使CNT复位、使能、递增/递减等等。
四种来源产生CK_PSC时钟(计数器时钟可以由以下时钟源提供):
1.内部时钟(CK_INT);
2.TIMx_ETR(外部时钟来源);
3.ITR0-ITR4(定时器级联:输出的定时器可以作为输入)(内部触发输入口)经过选择器选择哪一路,一路到触发控制器;
4.通过外部通道引脚TIMx_CH1和TIMx_CH2,经过Tl1FP1和Tl2FP2选择器到达触发控制器。
如果APB1分频系数是1,则CK_INT就是×1倍,就该是多是是多少;如果APB1分频系数是2或者4或者其他的系数,则CK_INT就得×2倍。
对于F407,配置系统时钟为:
SYSCLK = 168M; AHB时钟 = 168M; APB1时钟 = 42M;
APB1分频系数 = AHB / APB1 = 4,所以通用定时器CK_INT = 2 * 42M = 48
1.TIMx时钟使能(x:2~5) 拿TIM3为例
HAL_RCC_TIM3_CLK_ENABLE(); // 使能TIM3时钟
2.初始化定时器参数,设置自动重装值,分频系数,计数方式等
HAL_TIM_Base_Init();
3.使能定时器更新中断,使能定时器
HAL_TIM_Base_Start_IT; // 使能句柄指定的定时器更新中断
HAL_TIM_Base_Start; // 使能句柄指定的定时器
4.TIM3中断优先级设置
HAL_NVIC_SetPriority(TIM3_IRQn, x, x);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
5.编写中断服务函数(也要编写中断回调函数)
void HAL_TIM_IRQHandler(); // 中断服务函数
HAL_TIM_IRQHandler(); // 中断处理入口函数
void HAL_TIM_PeriodElapseCallback(); // 定时器更新中断回调函数
通过定时器中断配置,每500ms中断一次,然后中断服务函数中控制LED1实现LED1状态取反。LED0在主函数利用delay_ms实现1s一次反转。
公式:Tout(溢出时间) = (ARR + 1)(PSC + 1) / Tclk
例如500ms:
ARR + 1 = 5000 PSC + 1 = 9000 Tclk = 90M(STM32F429)
Tout = 500ms
#ifndef __TIM3_H
#define __TIM3_H
#include "sys.h"
void TIM3_Init(void);
#endif
#include "TIM3.h"
#include "led.h"
TIM_HandleTypeDef TIM3_Handler; // TIM句柄
void TIM3_Init(void)
{
TIM3_Handler.Instance = TIM3;
TIM3_Handler.Init.Period = 4999; // 自动装载值,公式中会自动加1
TIM3_Handler.Init.Prescaler = 8999; // 预分频器,公式中会自动加1
TIM3_Handler.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_Base_Init(&TIM3_Handler); // TIM初始化
HAL_TIM_Base_Start_IT(&TIM3_Handler); // 使能定时器3,并且开启更新中断
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) // Init回调函数
{
if (htim->Instance == TIM3) // 定时器中得判断是否为TIM3,也可也用else if来判断其他的定时器
{
__HAL_RCC_TIM3_CLK_ENABLE(); // 时钟使能
HAL_NVIC_EnableIRQ(TIM3_IRQn); // 使能TIM3中断
HAL_NVIC_SetPriority(TIM3_IRQn, 2, 3); // 中断优先级
}
}
void TIM3_IRQHandler(void) // 中断服务函数
{
HAL_TIM_IRQHandler(&TIM3_Handler); // 中断处理入口函数
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) // 中断回调函数
{
if (htim->Instance == TIM3)
{
LED1 = !LED1; // LED1反转
}
}
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "TIM3.h"
int main()
{
HAL_Init();
Stm32_Clock_Init(360, 25, 2, 8);
delay_init(180);
uart_init(115200);
led_Init();
TIM3_Init();
while (1)
{
LED0 = !LED0;
delay_ms(1000);
}
}