文章目录
- 4 TIM
- 4.1 SysTick系统定时器
- 4.2 TIM定时器中断与微秒级延时
- 4.3 TIM使用PWM波
- 4.3.1 PWM介绍
- 4.3.2 无源蜂鸣器实现
- 4.4 TIM ,PWM常用函数
4 TIM
4.1 SysTick系统定时器
Systick系统滴答,(同时他有属于自己的中断,可以利用它来做看门狗):一般是一个24位的向下递减的计数器,一个时钟周期减1,减少到0时,触发中断。大小是从0~2的24次方-1。它的作用是用来做分时调动,维持os系统心跳,确定时间等,甚至有自己的中断SysTick_Hander,因为它的上限是24位的,所以对应的时钟的频率最高是16Mhz,主频如果超过它了,那就无法实现秒级延迟了,但是可以实现毫秒级延迟。Systick的赋值我们一般取HCLK时钟。所有时钟的来源最终都来源于内部RC震荡电路或者外部晶振。SysTick也不例外。
TIM计时器模型:
- 是RCC给该计时器的时钟源,通过时钟树配置。
- PSC预分频器,会将时钟源频率分成n+1份(因为是从0开始的),所以假如需要分成80份,那么要写80-1。
- CK_CNT:这个寄存器中存放着当前计数的值。
- ARR:即自动重装载计数器。
**TIM寄存器:**一般有四种寄存器
-
控制状态寄存器(CTRL):
位段 名称 可读写类型 复位值 描述 16 COUNTFLAG R 0 主要是用来防止多读和误读。如果在上次读取本寄存器后,SysTick已经数到了0,则该位置设置为1,如果读取该位,该位将自动清零。 2 CLKSOURCE R/W 0 时钟源的选择寄存器: 0=外部时钟源 (STCLK) 1=内部时钟源 (FCLK) 1 TICKINT R/W 0 即是否产生异常请求: 1=倒数到0时产生SysTick异常请求 0=数到0时无动作。 0 ENABLE R/W 0 使能位,即SysTick定时器是否使能。 -
装载和重装载寄存器
位段 名称 可读写类型 复位值 描述 23:0 RELOAD R/W 0 当倒数至0时,将被重装载的值 影子寄存器 LOAD R/W - RELOAD被重装载的值就在这里存储 -
当前数字寄存器(VAL):
位段 名称 可读写类型 复位值 描述 23:0 CURRENT R/Wc 0 读取时返回当前倒计时的值,读取没有问题,但当写它则使之清零,同时还会清除在Systick控制及状态寄存器中的COUNTFLAG标志 -
校准数值寄存器(CALIB)
位段 名称 可读写类型 复位值 描述 31 NOREF R - 1=没有外部参考时钟(即不可用) 0=外部参考时钟可用 30 SKEW R - 1=校准值不是准确的10ms 0=校准值准确的10ms 23:0 TENMS R/W 0 0=无法使用校准功能 >0倒计数的格数
4.2 TIM定时器中断与微秒级延时
- 通用定时器:只有定时功能,一般16位(0~65535)。
- 高级定时器:除了定时功能,还有PWM功能。以及DAC为DMA提供时钟的功能。
计数器模式:有如上三种模式,使用定时器时有一些常用的参数如下:
- PSC:分频器。
- ARR:自动装载值,到这个值就触发自动重装载,即恢复到初始值。
- 当前的值存放在CURRENT寄存器中。
微秒级延时实现:
实现原理:例如80Mhz的工作频率,意味着1s中跳动了80M次,我们先使用分频器将定时器的工作频率分为80份,也就是1Mhz,那么对应的1hz就是1us。接下来我们基于这个原理来是实现它。
//如上,将PSC分频率器设置为80-1,由于计时器是16位的,所以滴答范围是0~65535.共65536个滴答,下面我们通过代码来实现。(tim是up模式)
void delay_us(uint16_t us)
{
if (us>60000)
{
return ;
}
uint16_t differ=60000-us;
HAL_TIM_Base_Start(&htim6);
__HAL_TIM_SET_COUNTER(&htim6, differ);
while(differ<60000)
{
differ = __HAL_TIM_GET_COUNTER(&htim6);
}
HAL_TIM_Base_Stop(&htim6);
return ;
}
//之后修改tim.h头文件,添加extern void delay_us(uint16_t us);
4.3 TIM使用PWM波
4.3.1 PWM介绍
定时器除了定时以外,还能够产生PWM波。首先我们先来介绍一下PWM波。即脉冲宽度调制(Pulse-width modulation)。pwm波可以简单理解为可以调试占空比的方波。占空比(即脉宽时间占整个周期的比例),整个周期就是一个脉冲信号的时间,而脉宽时间就是高电平的时间。PWM波可以用来模拟不同的输出电压。其原理就是通过不同的占空比比例实现D/A转化。
-
ARR:自动装载值。
-
CRR:决定了占空比,PWM波从CRR处电平反转。
4.3.2 无源蜂鸣器实现
首先我们先明白有源蜂鸣器和无源蜂鸣器的区别,这个“源”指的是震荡源,所以:
- 有源蜂鸣器内部带震荡源,所以只要一通电(给高电平或低电平)就会叫,即电平触发;
- 而无源蜂鸣器内部不带震荡源,直流信号无法令其鸣叫,必须用 2K~5K 的方波去驱动它;
无源蜂鸣器配置:
- 配置预分频:TIM2 的输入时钟为 APB1 时钟 80MHz,这个速率对定时器来说实在太快,
这时需要对它做个预分频:CK_CNT = TIMxCLK/(PSC+1)=80MHz/(80-1+1)=1MHz; - 配置 PWM 时钟:通过 TIM2 定时器的 ARR(自动重装载寄存)的值可以调整 PWM 的输出。
频率,这里想让蜂鸣器工作在 2.7KHz,则:ARR=1MHz/2700 ~= 370。 - 配置占空比: 这里我们设置占空比为 50%,则 Pulse=370/2=185。
PWM波蜂鸣器实现:找到蜂鸣器对应的引脚的TIM的通道,我这里是TIM1的CHANNEL_4
//buzzer.h文件
#ifndef __BUZZER_H__
#define __BUZZER_H__
#include "tim.h"
extern void beep_start(uint8_t times, uint16_t interval);
#endif
//buzzer.c文件
#include "buzzer.h"
void beep_start(uint8_t times, uint16_t interval)
{
while(times--)
{
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(interval);
if (HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(interval);
}
}
4.4 TIM ,PWM常用函数
//启动计时器tim1
HAL_TIM_Base_Start(&htim1);
//设置/获取COUNTER寄存器中的值
__HAL_TIM_SET_COUNTER(&htim1, differ);
__HAL_TIM_GET_COUNTER(&htim1);
//停止计时器tim1
HAL_TIM_Base_Stop(&htim1);
//启动PWM波型输出(定时器1的通道4),若成功返回HAL_OK
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4)
//关闭PWM波形输出(定时器1的通道4),若成功返回HAL_OK
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4)