PIT 定时器寄存器配置
本文整理自
17. PIT—周期中断定时器 — [野火]i.MX RT库开发实战指南——基于i.MXRT1052 文档
用作个人学习和分享
一、PIT 定时器寄存器详解
PIT 定时器的功能实现依赖于一系列专用寄存器,不同寄存器负责控制时钟使能、计数模式、中断状态等关键环节。下表先对核心寄存器进行汇总,再逐一解析各寄存器的位段功能。
1.1 核心寄存器汇总
寄存器名称 | 寄存器描述 |
---|---|
MCR | PIT 控制寄存器(全局使能、调试模式控制) |
LTMR64H | 64 位计数模式下的高 32 位数据寄存器(仅定时器 0/1 组合时使用) |
LTMR64L | 64 位计数模式下的低 32 位数据寄存器(仅定时器 0/1 组合时使用) |
LDVALx | 定时器 x(x=0~3)自动重装载值寄存器(设定计数周期) |
CVALx | 定时器 x(x=0~3)当前计数值寄存器(读取实时计数) |
TCTRLx | 定时器 x(x=0~3)控制寄存器(使能定时器、中断、连接模式) |
TFLGx | 定时器 x(x=0~3)状态标志寄存器(中断标志位) |
1.2 关键寄存器位段解析
1.2.1 PIT 控制寄存器(MCR)
MCR 寄存器用于全局控制 PIT 定时器的使能状态和调试模式行为,仅 2 个有效位,其余位保留。
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
2~31 | 保留 | - | 0 | 无功能,读写无效 |
1 | MDIS | R/W | 1 | PIT 全局使能控制:0 = 启用 PIT 定时器(时钟正常供给)1 = 禁用 PIT 定时器(时钟关闭,计数停止) |
0 | FRZ | R/W | 0 | 调试模式控制:0 = 调试模式(如断点)时定时器继续运行1 = 调试模式时定时器停止运行(避免调试时时序混乱) |
1.2.2 64 位计数数据寄存器(LTMR64H/LTMR64L)
当定时器 0 和定时器 1 组合为 64 位计数器时,这两个寄存器用于读取当前 64 位计数值,仅支持读操作。
寄存器 | 位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|---|
LTMR64H | 23~0 | LTMR64H | R | 0 | 存储 64 位计数器的高 32 位(对应定时器 1 的当前值) |
LTMR64L | 23~0 | LTMR64L | R | 0 | 存储 64 位计数器的低 32 位(对应定时器 0 的当前值) |
1.2.3 自动重装载值寄存器(LDVALx)
LDVALx 用于设定定时器 x 的计数周期,当定时器计数到 0 时,会自动重新加载该寄存器的值,实现周期性计数。
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
23~0 | TSV | R/W | 0 | 自动重装载值设定:1. 计数到 0 时,触发溢出标志(TFLGx [TIF]),若使能中断则生成中断;2. 写入新值后不会立即生效,需等待当前计数周期结束;3. 若需新值立即生效,需先停止定时器(TCTRLx [TEN]=0),写入后重新使能。 |
1.2.4 当前计数值寄存器(CVALx)
CVALx 用于读取定时器 x 的实时计数值,仅支持读操作,调试模式下值会冻结。
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
31~0 | TVL | R | 0 | 定时器当前计数值:1. 定时器使能(TEN=1)时,值随计数递减;2. 调试模式(FRZ=1)时,值保持不变。 |
1.2.5 定时器控制寄存器(TCTRLx)
TCTRLx 是定时器 x 的核心控制寄存器,负责使能定时器、中断和 64 位连接模式。
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
31~3 | 保留 | - | 0 | 无功能,读写无效 |
2 | CHN | R/W | 0 | 连接模式控制(仅定时器 1/2/3 支持,定时器 0 不支持):0 = 不启用连接模式(独立 32 位定时器)1 = 启用连接模式(定时器 1 与 0 组合为 64 位定时器) |
1 | TIE | R/W | 0 | 中断使能控制:0 = 禁用计数结束中断1 = 使能计数结束中断⚠️ 注意:若 TFLGx [TIF] 已为 1,开启 TIE 后会立即触发中断,需先清除 TIF 位。 |
0 | TEN | R/W | 0 | 定时器使能控制:0 = 禁用定时器(计数停止)1 = 启用定时器(开始递减计数) |
1.2.6 状态标志寄存器(TFLGx)
TFLGx 仅包含 1 个有效位,用于指示定时器计数是否完成,需通过写 1 清除(W1C 类型)。
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
23~1 | 保留 | - | 0 | 无功能,读写无效 |
0 | TIF | W1C | 0 | 计数结束标志:1. 定时器计数到 0 时自动置 1,若使能中断则触发中断;2. 清除方式:向该位写 1(写 0 无效);⚠️ 注意:开启中断前必须清除 TIF,否则会立即触发中断。 |
二、PIT 定时器常用配置流程
RT1052 PIT 定时器的配置逻辑简洁,核心分为 “独立 32 位模式” 和 “64 位连接模式”,以下分别介绍两种模式的配置步骤及定时时间计算方法。
2.1 独立 32 位模式配置(无连接、可选中断)
独立模式下,单个定时器(如定时器 0)作为 32 位计数器使用,适用于中等精度的定时需求(最大定时时间 = 2³² / 时钟频率)。
配置步骤:
- 全局使能 PIT:配置 MCR 寄存器,设置 MDIS=0(启用 PIT 时钟),FRZ 按调试需求设为 0 或 1(如调试时需暂停则设为 1)。
- 设定计数周期:向 LDVALx 寄存器写入自动重装载值
time
(time
为计数次数,需根据定时需求计算)。 - 中断配置(可选):
- 清除中断标志:向 TFLGx [TIF] 写 1,避免开启中断后立即触发。
- 使能中断:设置 TCTRLx [TIE] = 1。
- 启动定时器:设置 TCTRLx [TEN] = 1,定时器开始从 LDVALx 的值递减计数。
2.2 64 位连接模式配置(定时器 0+1,可选中断)
当需要更长的定时时间(超过 32 位计数器上限)时,可将定时器 0 和 1 组合为 64 位计数器(定时器 1 为高 32 位,定时器 0 为低 32 位)。
配置步骤(以定时器 2 为例,含中断):
- 全局使能 PIT:同独立模式步骤 1,配置 MCR 寄存器。
- 配置低 32 位定时器(定时器 0):
- 向 LDVAL0 写入重装载值
time1
。 - 清除 TFLG0 [TIF],设置 TCTRL0 [TIE] = 1(使能中断)。
- 向 LDVAL0 写入重装载值
- 配置高 32 位定时器(定时器 1):
- 向 LDVAL1 写入重装载值
time2
。 - 设置 TCTRL1 [CHN] = 1(启用连接模式,与定时器 0 组合为 64 位)。
- 向 LDVAL1 写入重装载值
- 启动定时器:先设置 TCTRL0 [TEN] = 1,再设置 TCTRL1 [TEN] = 1(需按顺序启动)。
2.3 定时时间计算
定时时间的核心是 “计数次数” 与 “时钟频率” 的比值,公式如下:
1. 独立 32 位模式:
plaintext
定时时间(秒) = time / fpit_clock
time
:LDVALx 寄存器的重装载值(整数)。fpit_clock
:PIT 定时器的时钟频率(单位:Hz,如 24MHz)。
2. 64 位连接模式:
plaintext
定时时间(秒) = (time1 * time2) / fpit_clock
time1
:定时器 0(低 32 位)的重装载值。time2
:定时器 1(高 32 位)的重装载值。
2.4 SDK 库的优势
RT1052 的 SDK 库已将寄存器操作封装为标准化函数(如 PIT_Init()
、PIT_SetTimerPeriod()
),并通过宏定义(如 kPIT_Chnl_0
)和枚举类型简化配置。开发者无需直接操作寄存器,可大幅提升代码可读性和稳定性,本文后续实验将基于 SDK 库实现。
三、PIT 定时器实战实验:1 秒 LED 闪烁
本节通过 “PIT 定时器产生 1 秒时基,控制 RGB LED 闪烁” 的实验,将理论知识落地为实际代码,帮助理解 PIT 的完整应用流程。
3.1 硬件设计
PIT 是芯片内部外设,无需额外硬件电路,仅需通过 GPIO 控制 RGB LED 的亮灭(如 RT1052 开发板上的 RGB LED 对应引脚为 GPIO1_IO04、GPIO1_IO05、GPIO1_IO06)。
3.2 软件设计
实验代码分为 “驱动文件(bsp_pit.c/h)” 和 “主函数”,核心是 PIT 初始化、中断服务函数和 LED 控制逻辑。以下仅展示关键代码,完整工程需参考配套头文件(如 fsl_pit.h
、fsl_gpio.h
)。
3.2.1 编程要点
- 配置 PIT 时钟源和分频系数。
- 初始化 PIT 定时器(设定调试模式、重装载值)。
- 配置中断(清除标志、使能中断、设置优先级)。
- 编写中断服务函数,实现 LED 状态翻转。
3.2.2 关键代码解析
1. 宏定义(bsp_pit.h)
通过宏定义统一管理时钟频率、中断、通道和定时时间,便于后续修改。
/* PIT 时钟频率(OSC 时钟为 24MHz) */
#define PIT_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_OscClk)/* 中断相关宏定义 */
#define PIT_IRQ_ID PIT_IRQn // 中断 ID
#define PIT_LED_HANDLER PIT_IRQHandler // 中断服务函数名/* 定时器通道(使用通道 0) */
#define PIT_CHANNEL_X kPIT_Chnl_0/* 定时时间(1 秒 = 1000000 微秒) */
#define TIME_0 1000000U
2. PIT 初始化函数(bsp_pit.c)
初始化函数分为 “时钟配置”“PIT 初始化”“重装载值设定”“中断配置” 四部分,逻辑清晰且符合 SDK 规范。
#include "bsp_pit.h"
#include "fsl_pit.h"
#include "fsl_clock.h"
#include "fsl_nvic.h"void PIT_TIMER_Init(void)
{pit_config_t pitConfig; // PIT 初始化结构体/************************** 1. 配置 PIT 时钟 **************************/CLOCK_SetMux(kCLOCK_PerclkMux, 1U); // 选择 OSC 时钟(24MHz)作为 PIT 时钟源CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U); // 时钟分频系数为 1(无分频,频率=24MHz)/************************** 2. 初始化 PIT **************************/PIT_GetDefaultConfig(&pitConfig); // 获取默认配置(debug 模式禁用)pitConfig.enableRunInDebug = true; // 调试模式下 PIT 继续运行(可选)PIT_Init(PIT, &pitConfig); // 初始化 PIT 外设/************************** 3. 设定重装载值 **************************/// 将 1 秒(1000000us)转换为计数次数:count = (1000000us * 24000000Hz) / 1000000PIT_SetTimerPeriod(PIT, PIT_CHANNEL_X, USEC_TO_COUNT(TIME_0, PIT_SOURCE_CLOCK));/************************** 4. 配置中断 **************************/PIT_ClearStatusFlags(PIT, PIT_CHANNEL_X, kPIT_TimerFlag); // 清除中断标志PIT_EnableInterrupts(PIT, PIT_CHANNEL_X, kPIT_TimerInterruptEnable); // 使能中断NVIC_SetPriority(PIT_IRQ_ID, 6); // 设置中断优先级(抢占优先级 6,子优先级 0)EnableIRQ(PIT_IRQ_ID); // 使能 NVIC 中断
}
3. 中断服务函数(bsp_pit.c)
中断服务函数的核心是 “清除中断标志” 和 “翻转 LED 状态”,需注意必须先清除标志,再处理业务逻辑。
#include "bsp_led.h" // 假设已实现 LED 控制函数unsigned int g_irqCount = 0; // 中断计数变量void PIT_LED_HANDLER(void)
{// 1. 清除中断标志(必须先执行,避免重复触发)PIT_ClearStatusFlags(PIT, PIT_CHANNEL_X, kPIT_TimerFlag);// 2. 每 2 次中断翻转一次 LED(实现 1 秒亮、1 秒灭)g_irqCount++;if (g_irqCount % 2 == 1){RGB_RED_LED_ON; // 红灯亮(需在 bsp_led.h 中实现 GPIO 置位)}else{RGB_RED_LED_OFF; // 红灯灭(需在 bsp_led.h 中实现 GPIO 复位)}
}
4. 主函数(main.c)
主函数负责系统初始化(MPU、时钟、GPIO)、PIT 初始化和启动定时器,之后进入死循环等待中断触发。
#include "board.h"
#include "bsp_pit.h"
#include "bsp_led.h"int main(void)
{/************************** 1. 系统初始化 **************************/BOARD_ConfigMPU(); // 初始化内存保护单元BOARD_InitPins(); // 初始化开发板引脚BOARD_BootClockRUN(); // 初始化系统时钟(如 600MHz)BOARD_InitDebugConsole(); // 初始化调试串口(用于打印信息)NVIC_SetPriorityGrouping(4); // 设置中断优先级分组(4 位抢占优先级,0 位子优先级)/************************** 2. 打印调试信息 **************************/