定时器的作用
定时器(Timer)最基本的功能就是定时,定时功能与外设结合,可
- 定时发送 USART 数据
- 定时采集 AD数据。
将定时器与 GPIO结合起来使用,可以实现非常丰富的功能:
- 可以产生输出波形(如频率、占空比可变方波,频率和数量可控的脉冲,PWM、互补PWM波形)
- 可以测量输入信号的频率、宽度,脉冲计数等
用定时器产生PWM 控制电机状态是工业控制普遍方法
STM32定时器资源
STM32中一共有11个定时器:
- 1个系统嘀嗒定时器
- 2个高级控制定时器
- 4个普通定时器
- 2个基本定时器
- 2个看门狗定时器
STM32中的定时器可以分为两大类:SysTick和常规定时器
(1)内核中的SysTick
SysTick是简易的周期定时器,存在于控制器内核,其使用涉及的寄存器少,相同内核的器件间移植不需要修改程序
(2)常规定时器,共8个,分为三类:
高级定时器2个:TIM1、TIM8
通用定时器4个:TIM2,TIM3, TIM4,TIM5,
基本定时器2个:TIM6、TIM7
TIM1、TIM8的时钟由APB2的输出产生,其他6个定时器的时钟由APB1的输出产生。
不同定时器的应用
TIM1,TIM8是能够产生三对PWM互补输出的高级定时器:
- 电动机的控制。
TIM2~TIM5是通用定时器:
- 输入捕获
- 输出比较
- PWM(边缘或中间对齐模式)
- 单脉冲模式输出
- 脉冲计数
TIM6和TIM7是基本定时器:
- DAC触发信号
CubeMX定时器的初始化配置
时钟树配置
其他参数设置留档
定时器设置
中断时间计算:
选择时钟源为内部时钟,另一个选项是外部触发输入(仅适用于TIM2,3,4)
上图所示,预分频器数值为31999,计数器为3,当时钟树APB1 timer clocks配置为32MHz时,每(32,000*4)/32,000,000=4/1000s=4ms触发定时器TIM2中断一次。
在设置完成后,注意让中断使能。
代码编写
按钮读取
定时器初始化
main.c
int main(void)
{
MX_TIM2_Init();//初始化定时器(见下面程序stm32f1xx_it.c)
MX_TIM3_Init();
HAL_TIM_IRQHandler(&htim2);//启动定时器
HAL_TIM_IRQHandler(&htim3);
}
stm32f1xx_it.c
TIM_HandleTypeDef htim2;
/*
定时器外设结构体--句柄
typedef struct {
TIM_TypeDef *Instance; //寄存器基地址
TIM_Base_InitTypeDef Init; // 基本定时器相关参数设置
HAL_TIM_ActiveChannel Channel; // 使用通道
DMA_HandleTypeDef *hdma[7]; // DMA 相关
HAL_LockTypeDef Lock; // 锁定处理
__IO HAL_TIM_StateTypeDef State; // 定时器运行相关状态
} TIM_HandleTypeDef;
*/
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/*定时器外设结构体--参数初始化*/
htim2.Instance = TIM2;//寄存器基地址
htim2.Init.Prescaler = 31999; //定时器预分频设置,它设定 TIMx_PSC 寄存器的值
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;//定时器计数方式,对于基本定时器只能向上计数,
htim2.Init.Period = 3;//定时器周期,它设定 TIMx_ARR 寄存器的值
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;// 时钟分频
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;//自动重装载
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
时间间隔定时回调函数
/*
通过定时器TIM2完成按键读取定时器TIM3完成对小灯的闪烁
*/
uint8_t key1_count = 0;//按键计数
uint8_t key1_state = 0;//按键状态
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
/*
通过定时器外设结构体中的寄存器基地址判断当前中断是否是所需定时器所触发。
每隔4ms对按键进行扫描,如果为按下状态,则标志位+1,否则标志位清零,
当标志位达到一定的数值的时候(本程序为5),则视为按键按下,改变按钮状态
全局变量。
*/
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == RESET)
{
key1_count++;
}
else
{
key1_count = 0;
}
if(key1_count >= 5)
{
key1_state = 1;
}
else
{
key1_state = 0;
}
}
if(htim->Instance == TIM3)
{
/*使用定时器TIM3完成每500ms对A0引脚小灯进行一次状态翻转*/
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
}
}
主函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_TIM3_Init();
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
while (1)
{
if(key1_state == 1)//判断按钮状态变量,如果按钮按下,则点亮C1引脚小灯
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);
}
}
}
通过定时器中断,能够使小灯1s闪烁一次的同时,还可以随时判断按钮的状态,并同时做出相应的反应,这在之前使用HAL_Delay()
函数的时候可是做不到的。