夜深人静学32系列14——基本定时器
定时器简介
关于定时器的基本内容,这里不做介绍,不明白的可以观看 “ 蓝桥杯单片机学习6——定时器/计数器&定时器实现秒表功能 ”,这里我们主要来介绍一下STM32的定时器。
根据功能的不同,STM32讲定时器分为常规定时器、专业定时器和内核定时器。
前面我们学习了专用定时器中的独立看门狗和窗口看门狗,现在我们主要学习常规定时器。
根据定时器功能的复杂程度,将常规定时器分类为基本定时器、通用定时器和高级定时器。高级的定时器拥有低级定时器的所有功能。
我们使用的NANO板上一共有八个定时器,分别为:
定时器 | 分类 |
---|---|
TIM1 | 高级定时器 |
TIM2 ~ 5 | 通用定时器 |
TIM9 ~ 11 | 通用定时器 |
TIM2 ~ 5 和 TIM9 ~ 11之间存在一定的差异,所以我们将其分开来
遗憾的的是,我们所用的NANO板子上没有纯粹的基本定时器,只有通用定时器和高级定时器。
基本定时器(我们的NANO板上没有)
基本定时器 TIM6 和 TIM7 包含一个 16 位自动重载计数器,该计数器由可编程预分频器驱动。
此类定时器不仅可用作通用定时器以生成时基,还可以专门用于驱动数模转换器 (DAC)。实 际上,此类定时器内部连接到 DAC 并能够通过其触发输出驱动 DAC。(与51单片机的定时器相似)
这些定时器彼此完全独立,不共享任何资源。
功能框图
基本定时器主要由三个部分组成:
- 第一个部分是时钟源根据定时器挂载在的总线而决定。
- 第二部分为控制器,可以控制定时器的复位、使能(中断使能、定时器使能)、计数、触发等控制位。
- 第三部分是定时器的计数单元,由预分频器、自动重装载寄存器和计数器玩部分完成。当计数器的值等于自动重装载寄存器影子寄存器的值时溢出,可选择触发中断、时间等一系列动作。
其计数原理如下:
总线时钟通过一个预分频器分频后作为计数器的时钟信号,计数器每经过一个脉冲加一/减一,当计数器的值等于自动重装载寄存器影子寄存器的值时,=溢出,产生中断/事件。
通过认为的配置预分频器和自动重装载寄存器的值,可以实现对给定时间的定时。
【注意】:
我们前面讲的自动重装载寄存器和预分频器实际上都有两个相同的寄存器,我们在进行操作的是一个寄存器,而实际起作用的是另一个寄存器,叫做影子寄存器。在每次溢出时,系统会自动将寄存器的值加载到影子寄存器之中,或者操作后直接加载到影子寄存器,这个由定时器的控制寄存器(TIMX_CR1)的ARPE位决定。
计数模式
STM32的定时器具有以上三种计数模式,在不同的触发条件会产生溢出。其中,递增计数模式最为常用。
其中,ARR为自动重装载值,PSC为预分频寄存器的值。
定时器寄存器
控制寄存器1
中断使能寄存器
状态寄存器
计数器和预分频器
自动重装载寄存器
定时器溢出时间的计算
举个栗子:
我们使用NANO板子的定时器10/定时器11,APB2总线频率为100MHz,每1s溢出一次,则可设置ARR = 10000-1,PSC = 10000-1
中断配置步骤
相关HAL库函数介绍
基本定时器实战(这个可以有)
任务要求
- 通过定时器11,以中断的方式控制LED0的闪烁,每1s改变一次LED状态
- 开启独立看门狗,设置喂狗时间为1.25s以内,通过定时器10对独立看门狗每1s喂狗
- 通过串口打印是否喂狗,
- 系统LED1亮起,表示系统正常运行。
- 每串口打印一次,改变LED1的状态。
CubeMX配置
TIM11(TIM10相同)
代码实现
mian.c
uint8_t IWDG_Flag; //喂狗标志位
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM11_Init();
MX_IWDG_Init();
MX_TIM10_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim10); //开启定时10中断
HAL_TIM_Base_Start_IT(&htim11); //开启定时器11中断
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(IWDG_Flag) //喂狗完成后,串口打印,翻转LED2状态
{
printf("USART1:喂狗成功\r\n");
HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
IWDG_Flag = 0; //清除喂狗标志
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
tim.c
其他部分逻辑,前面已经介绍过了,这里不做展示。