STM32——定时器:基本定时器

定时器归纳总页:

STM32------定时器-CSDN博客

一、定时器概述

1.1 软件定时原理

cpp 复制代码
51单片机计时,主频 12MHz,1us

for(n)
{
    __nop(); /* 空语句 执行时间1us */
}

使用纯软件的方式实现定时(延时)功能

但是不会很精准,原因:

1.函数有压栈操作耗时

2.有流水线,指令执行可能是多个步骤共同执行。

软件延时缺点:

1.延时不精准

2.CPU死等

所以需要外设硬件定时器

1.2 定时器定时原理(硬件)

使用精准的时基,通过硬件的方式,实现定时功能。

核心就是计数器。

原理:

1.3 STM32定时器分类

1.4 STM32定时器特性表(常规定时器 F1系列)

开发指南:

1.5 STM32基本、通用、高级定时器功能整体的区别

二、基本定时器

2.1 基本定时器简介(F1)

F1-H7都是这两个基本定时器

2.2 基本定时器框图

总线挂载:

芯片手册12页,参考手册56页。

2.3 定时器计数模式以及溢出条件

递减模式

中心对齐,模式

2.4 基本定时器中断实验相关寄存器(TIM6/TIM7)

定时器控制寄存器(TIMx_CR1)

例子:

控制LED 1s亮,2s灭,如果计时满了才操作寄存器,有一定的时延误差,如果在计时结束前提前准备好值,减少操作寄存器的时间误差。

缓冲的作用:提前准备,减少误差

定时器 DMA 中断使能寄存器(TIMx_DIER)

定时器状态寄存器(TIMx_CR1)

用于判断是否发生了更新中断,由硬件置1,软件清零。

计数器(TIMx_CNT)

计数器实时数值,可用于设置计数器初始值。在计数器运行过程中,也可进行写操作。

定时器预分频器(TIMx_PSC)

自动重装载寄存器 (TIMx_ARR)

实际作用的是影子寄存器。

2.5 定时器溢出时间计算方法

:定时器溢出时间,秒

:定时器的未分频的时钟源频率

:自动重装载寄存器的值,需要 ARR+1才是溢出时间

:预分频器寄存器的值,真正的分频系数为PSC+1

推导:

数一个数的时间:

溢出计数的时间:

2.6 定时器中断实验配置步骤

步骤 HAL库函数 备注 主要寄存器
1.配置定时器基础工作参数 HAL_TIM_Base_Init() 初始化定时器基础参数 CR1、ARR、PSC
2.定时器基础MSP初始化 HAL_TIM_Base_MspInit() 空函数,用于存放配置 NVIC、CLOCK、GPIO等的代码
3.使能更新中断并启动计数器 HAL_TIM_Base_Start_IT() 使能更新中断,并启动计数器 DIER、CR1
4.设置优先级,使能中断 HAL_NVIC_SetPriority() HAL_NVIC_EnableIRQ()
5.编写中断服务函数 TIMx_IRQHandler()等 此函数会调用定时器公共处理函数: HAL_TIM_IRQHandler() 会在此公共处理函数中,调用各种callback函数,处理各种中断 SR
6.编写定时器更新中断回调函数 HAL_TIM_PeriodElapsedCallback() 空函数,定时器更新终端回调函数,需要重新定义

关键结构体1:TIM_HandleTypeDef

或者直接搜索 TIM6

句柄的初始化结构体:TIM_Base_InitTypeDef

1.由于基本定时器只允许递增计数模式,也没有其他的寄存器来配置其他的计数模式。所以CounterMode成员对于基本定时器来说是无效的,只有在通用、高级定时器才有效。

2.由于基本定时器没有时钟分频因子的寄存器。所以只有在通用、高级定时器才有效。

3.由于F1的基本、通用定时器没有重复计数器的寄存器。所以只有在高级定时器才有效。

总结:

基本定时器用到了:Prescaler、Period、AutoReloadPreload三个结构体成员

2.7 编程实战:基本定时器中断实验

【免费】基本定时器中断实验工程资源-CSDN下载https://download.csdn.net/download/PinnsiR/92282791

更新中断的两种方式:

1.定时器溢出(硬件),伴随着 更新事件 和 更新中断 的产生(例程使用此方式)

2.软件通过寄存器 的 UG 位,产生软件的更新事件。从而产生更新中断

溢出时间计算:

500ms 溢出时间,主频为 72MHz。

为了得到整数,设置PSC值为 7199,算出ARR为4999

例程:

cpp 复制代码
TIM_HandleTypeDef g_timx_handle;  /* 定时器句柄 */

/**
 * @brief       基本定时器TIMX定时中断初始化函数
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
 *              基本定时器的时钟为APB1时钟的2倍, 而APB1为36M, 所以定时器时钟 = 72Mhz
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft=定时器工作频率,单位:Mhz
 *
 * @param       arr: 自动重装值。
 * @param       psc: 时钟预分频数
 * @retval      无
 */
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_Start_IT(&g_timx_handle);    /* 使能定时器x及其更新中断 */
}

/**
 * @brief       定时器底层驱动,开启时钟,设置中断优先级
                此函数会被HAL_TIM_Base_Init()函数调用
 * @param       htim:定时器句柄
 * @retval      无
 */
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); /* 中断号,子优先级3,组2 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITM3中断 */
    }
}

/**
 * @brief       定时器TIMX中断服务函数
 * @param       无
 * @retval      无
 */
void BTIM_TIMX_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handle); /* 定时器中断公共处理函数 */
}

/**
 * @brief       定时器更新中断回调函数
 * @param       htim:定时器句柄
 * @retval      无
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        LED1_TOGGLE(); /* LED1反转 */
    }
}
cpp 复制代码
#define LED0_TOGGLE()   do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0)        /* 翻转LED0 */

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();
        delay_ms(200);
    }
}
相关推荐
Nautiluss2 小时前
一起调试XVF3800麦克风阵列(十六)
人工智能·单片机·音频·语音识别·dsp开发·智能硬件
Hello_Embed2 小时前
串口面向对象封装实例
笔记·stm32·单片机·学习·操作系统
Zeku2 小时前
Linux驱动学习笔记:SPI OLED 驱动源码深度分析
stm32·freertos·linux驱动开发·linux应用开发
三伏5222 小时前
stm32f103系列手册IIC笔记
笔记·stm32·嵌入式硬件
安庆平.Я2 小时前
STM32——MPU(内存保护)
stm32·单片机·嵌入式硬件·mpu
蝎蟹居3 小时前
GBT 4706.1-2024逐句解读系列(28) 第7.8条款:X,Y型连接正确标示接地符号
人工智能·单片机·嵌入式硬件·物联网·安全
Js_cold3 小时前
Xilinx FPGA Flash启动时钟频率
单片机·嵌入式硬件·fpga开发·vivado·xilinx·flash·cclk
番茄灭世神4 小时前
基于VScode搭建GD32开发环境
arm开发·vscode·单片机·cmake·gd32
TEC_INO4 小时前
stm32_12:RFID-RC522项目
stm32·单片机·嵌入式硬件