当前位置: 首页 > news >正文

STM32F103 basic定时器的介绍和应用

目录

概述

1 定时器的重要参数

1.1 核心概念 

1.2 使用步骤 (以产生固定周期中断为例)

2 使用STM32Cube工具配置参数

2.1 配置定时器参数

2.2  配置项目参数

3 定时器的使用

3.1 实现功能代码

3.2 测试


概述

STM32F103 的基础定时器(TIM6 和 TIM7)是相对简单的定时器,主要用于产生精确的时间基准、触发 DAC 转换或驱动软件定时器。它们没有输入捕获或输出比较通道,结构简单,是理解 STM32 定时器工作原理的良好起点。

1 定时器的重要参数

1.1 核心概念 

  1. 时钟源 (Clock Source): 定时器的核心是一个计数器,它需要一个时钟信号来驱动计数。基础定时器的时钟源固定来自 APB1 总线时钟 (PCLK1)。

  2. 预分频器 (Prescaler - PSC): 用于将输入的时钟频率进行分频,降低计数器的计数速度。CK_CNT = PCLK1 / (PSC + 1)

  3. 自动重装载寄存器 (Auto-Reload Register - ARR): 定义了计数器计数的上限(周期)。计数器从 0 开始计数,达到 ARR 值时,产生更新事件 (Update Event - UE),然后通常复位回 0(或根据配置),重新开始计数。

  4. 计数器 (Counter - CNT): 实际的计数值寄存器,在时钟驱动下递增(或递减)。

  5. 更新事件 (Update Event - UE): 当计数器达到 ARR 值(溢出)时发生。这是定时器最基本的“定时完成”信号。

  6. 更新中断 (Update Interrupt - UI): 如果使能了中断,当更新事件发生时,会触发中断请求。

1.2 使用步骤 (以产生固定周期中断为例)

1) 使能定时器时钟

  • 定时器挂载在 APB1 总线下。

  • 在 RCC 寄存器中使能 TIM6 (或 TIM7) 的时钟。

// 标准外设库 (Standard Peripheral Library - SPL)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);// HAL 库
__HAL_RCC_TIM6_CLK_ENABLE(); // 通常写在 HAL_TIM_Base_Init() 内部

2) 配置时基单元 (Time Base Unit)

  • 这是最核心的配置,设置 PSC 和 ARR 以确定定时器的溢出周期。

  • 计算公式: 定时周期 T = (ARR + 1) * (PSC + 1) / TIMx_CLK

    • TIMx_CLK: 通常是 PCLK1 (APB1 时钟频率)。注意 STM32F103 的 APB1 最大频率为 36MHz。

    • PSC: 预分频器值 (0 到 65535)。

    • ARR: 自动重装载值 (0 到 65535)。

  • 目标: 例如,系统时钟 SYSCLK = 72MHzAPB1 预分频器为 /2,则 PCLK1 = 36MHz (TIMx_CLK = PCLK1 = 36MHz)。要产生一个 1ms (0.001s) 的周期中断:

    • T = 0.001 = (ARR + 1) * (PSC + 1) / 36000000

    • (ARR + 1) * (PSC + 1) = 36000

    • 可以选取 PSC = 35999 (即分频 36000 倍),则 ARR + 1 = 1 -> ARR = 0

    • 也可以选取 PSC = 35 (分频 36 倍),则 ARR + 1 = 1000 -> ARR = 999

    • 通常让 ARR 大一些,PSC 小一些,分辨率更高(计数器步进时间更小)。但两种组合都能达到 1ms 周期。

参考代码如下:

// SPL 配置时基结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 999;        // ARR 值 (0 - 65535)
TIM_TimeBaseStructure.TIM_Prescaler = 35;      // PSC 值 (0 - 65535)
TIM_TimeBaseStructure.TIM_ClockDivision = 0;   // 基础定时器通常忽略或设为0
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 基础定时器只能向上计数
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); // 应用配置// HAL 配置时基结构体
TIM_HandleTypeDef htim6;
htim6.Instance = TIM6;
htim6.Init.Prescaler = 35;         // PSC 值
htim6.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数
htim6.Init.Period = 999;            // ARR 值
htim6.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 通常忽略
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; // ARR是否缓冲 (可选)
if (HAL_TIM_Base_Init(&htim6) != HAL_OK) {// 初始化错误处理
}

3) 使能更新中断 (如果需要中断):

  • 配置定时器中断源(更新事件中断)。

  • 配置 NVIC (嵌套向量中断控制器) 以允许定时器中断请求到达 CPU。

// SPL
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // 使能 TIM6 更新中断// 配置 NVIC (需先定义 NVIC 初始化结构体)
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; // TIM6 全局中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);// HAL
// HAL_TIM_Base_Init() 内部通常会调用 HAL_NVIC_SetPriority() 和 HAL_NVIC_EnableIRQ()
// 但通常需要在主程序中显式调用中断使能函数
HAL_NVIC_SetPriority(TIM6_IRQn, 0, 0); // 设置优先级
HAL_NVIC_EnableIRQ(TIM6_IRQn);         // 使能 TIM6 中断通道

4) 使能定时器

  • 启动计数器开始计数。

// SPL
TIM_Cmd(TIM6, ENABLE); // 启动 TIM6// HAL (使用中断模式启动)
HAL_TIM_Base_Start_IT(&htim6);

5) 编写中断服务程序 (ISR - 如果使用了中断):

  • 在中断服务程序中,必须检查中断标志位,并在处理完成后清除该标志位。

  • 这里是执行定时任务的代码位置(例如,翻转 LED、更新变量、读取传感器等)。

// SPL
void TIM6_IRQHandler(void) { // TIM6 中断服务函数名是固定的if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) { // 检查更新中断标志// 用户代码 - 在这里执行你的定时任务// 例如: GPIO_ToggleBits(GPIOA, GPIO_Pin_0); // 翻转 PA0 引脚状态TIM_ClearITPendingBit(TIM6, TIM_IT_Update); // 清除更新中断标志位!非常重要!}
}// HAL
void TIM6_IRQHandler(void) {HAL_TIM_IRQHandler(&htim6); // HAL 库的通用中断处理函数
}// HAL 回调函数 (在 HAL_TIM_IRQHandler 内部调用)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {if (htim->Instance == TIM6) { // 检查是哪个定时器触发的回调// 用户代码 - 在这里执行你的定时任务// 例如: HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); // 翻转 PA0}
}

6)不使用中断的查询方式:

如果你不需要中断,只想在主循环中查询定时器是否溢出:

// SPL
TIM_Cmd(TIM6, ENABLE); // 启动定时器
while (1) {if (TIM_GetFlagStatus(TIM6, TIM_FLAG_Update) != RESET) { // 查询更新标志// 用户代码 - 执行定时任务TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 清除更新标志}// ... 其他代码 ...
}// HAL
HAL_TIM_Base_Start(&htim6); // 启动定时器 (不使用中断)
while (1) {if (__HAL_TIM_GET_FLAG(&htim6, TIM_FLAG_UPDATE) != RESET) { // 查询标志if (__HAL_TIM_GET_IT_SOURCE(&htim6, TIM_IT_UPDATE) != RESET) { // 检查中断源使能 (可选)// 用户代码__HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE); // 清除标志}}// ... 其他代码 ...
}

2 使用STM32Cube工具配置参数

2.1 配置定时器参数

1) 在Clcok configuration 中配置时钟,具体参数如下:

2) 定时器相关的配置,选择Timer-6,配置参数,产生1ms的定时中断 

3) 配置中断函数,使能中断,并设置中的函数的优先级 

2.2  配置项目参数

在Project Setting卡片上配置开发工具和堆栈参数

完成以上参数配置后,可点击GNERATE CODE生成代码

项目结构如下:

3 定时器的使用

3.1 实现功能代码

1) 启动定时器

源代码如下:

   HAL_TIM_Base_Start_IT(&htim6);

2) 重写回调函数,并在该函数中调用相应的功能

源代码如下:

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* USER CODE BEGIN Callback 0 */static int count = 0;/* USER CODE END Callback 0 */if (htim->Instance == TIM6) {if( count %150 == 0){}count++;}/* USER CODE BEGIN Callback 1 */if (htim->Instance == TIM7) {}/* USER CODE END Callback 1 */
}
/* USER CODE END 4 */

3.2 测试

完成以上代码后,可编译代码并下载到板卡中运行,运行情况如下:

http://www.lryc.cn/news/621076.html

相关文章:

  • Android UI(一)登录注册 - Compose
  • 有哪些开源卫星姿控软件
  • 具身智能Scaling Law缺失:机器人界的“摩尔定律“何时诞生?
  • 用SQL实现对DuckDB rusty_sheet插件批量测试
  • 树莓派 4B 上部署 Minecraft PaperMC 1.20.x 的一键部署脚本
  • Qwen2-VL-2B 轻量化部署实战:数据集构建、LoRA微调、GPTQ量化与vLLM加速
  • Java Stream API:让业务数据处理更优雅
  • HTTP协议深度解析
  • 多种适用于 MCU 固件的 OTA 升级方案
  • STM32学习笔记11-通信协议-串口基本发送与接收
  • Autoppt-AI驱动的演示文稿生成工具
  • pygame的帧处理中,涉及键盘的有`pg.event.get()`与`pg.key.get_pressed()` ,二者有什么区别与联系?
  • ModuleNotFoundError: No module named ‘vllm._C‘
  • 界面设计风格解析 | ABB 3D社交媒体视觉效果设计
  • 3ds MAX文件/贴图名称乱码?6大根源及解决方案
  • tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
  • Java 技术栈中间件优雅停机方案设计与实现全景图
  • FreeSWITCH 对接阿里云流式 TTS:让大模型通话秒级响应
  • Elasticsearch ABAC 配置:基于患者数据的动态访问控制
  • 功能菜:吃对比吃饱更实在的健康菜
  • 企业智脑正在构建企业第二大脑,四大场景引擎驱动数字化转型新范式
  • 资本的自我否定:四重矛盾中的历史辩证法
  • 【科研绘图系列】R语言绘制蝶形条形图蝶形柱状堆积图
  • nginx-集成prometheus监控(k8s)
  • 高并发内存池 性能瓶颈分析与基数树优化(9)
  • anaconda创建pytorch1.10.0和pytorch2.0.0的GPU环境
  • lesson38:MySQL数据库核心操作详解:从基础查询到高级应用
  • app-4 日志上传
  • 第一章 java基础
  • 在IAR Embedded Workbench for Arm中实现NXP S32K3安全调试