文章目录
- 1 PIT 周期中断定时器
- 2 PIT定时器的使用
- 3 PIT定时器配置
- 3.1 PIT 时钟使能。
- 3.1.1 CLOCK_EnableClock
- 3.2 初始化 PIT 定时器
- 3.2.1 PIT_Init
- 3.3 设置 通道 0 的 加载值
- 3.3.1 PIT_SetTimerPeriod
- 3.4 使能 通道 0 的中断
- 3.4.1 PIT_EnableInterrupts
- 3.5 开启 PIT 定时器
- 3.5.1 PIT_StartTimer
- 3.6开启 PIT 中断并设置优先级
- 3.7编写中断服务函数
- 3.7.1 PIT_GetStatusFlags
- 3.7.2 PIT_ClearStatusFlags
- 3.8 代码
1 PIT 周期中断定时器
PIT 定时器实际上是一个定时器阵列,RT1052 内部的 PIT 定时器共有 4 个通道,可用于产生中断和触发 DMA。
PIT 定时器内部有 4 个计数器(Timer0~Timer3),也就是 4 个通道
- 这些定时器可以产生中断,或者产生触发条件
- 其时钟来自外设总线时钟,即 PERCLK_CLK_ROOT,频率为 75M。
PIT功能
1)32 位计数器(CNT),仅支持递减计数方式。
2)支持四个通道。
3)可以级联,实现超长定时(最长可组成 128 位定时器)。
4)支持中断/触发功能。
2 PIT定时器的使用
以 PIT 定时器通道 0 为例
- 一旦开启 PIT 时钟(MCR[MDIS]=0)
- 并使能通道 0 的计数(TCTRLx[TEN]=1,x=0~3,下同)
- 则通道 0 的 CNT 计数器会从 LDVAL0 加载值开始,做递减计数
- 当 CNT 等于 0 的时候,就产生超时事件,触发中断
- 然后 CNT 的又会重新加载 LDVAL0 的值,进行下一次递减计数周期,依次循环。
3 PIT定时器配置
3.1 PIT 时钟使能。
使用函数 CLOCK_EnableClock 使能 PIT 时钟。此函数会被 PIT 定时器初始化函数 PIT_Init 调用,所以不需要我们显示的调用。
3.1.1 CLOCK_EnableClock
CLOCK_EnableClock(kCLOCK_Pit)
3.2 初始化 PIT 定时器
使用函数 PIT_Init 初始化 PIT 定时器
3.2.1 PIT_Init
void PIT_Init(PIT_Type *base, const pit_config_t *config)
- 第一个参数指定使用哪个 PIT,因为 RT1052 只有一个 PIT 定时器,所以这个参数只能为PIT。
- 第二个参数是指向结构体 pit_config_t 的指针
typedef struct _pit_config
{bool enableRunInDebug; //debug 的时候 PIT 是否可以使用
} pit_config_t;
PIT_Init 的一般使用方法如下:
PIT_GetDefaultConfig(&pit_config); //初始化为默认配置
pit_config.enableRunInDebug=true; //调试模式下 PIT 继续运行
PIT_Init(PIT,&pit_config); //初始化 PIT 定时器
3.3 设置 通道 0 的 加载值
使用函数 PIT_SetTimerPeriod 设置通道 0 的加载值,也就是寄存器 LADVAL0 的值。
3.3.1 PIT_SetTimerPeriod
static inline void PIT_SetTimerPeriod(PIT_Type *base, pit_chnl_t channel, uint32_t count)
- 此函数第一个参数固定为 PIT
- 第二个参数指定设置哪个通道的:
typedef enum _pit_chnl
{kPIT_Chnl_0 = 0U, //PIT 通道 0kPIT_Chnl_1, //PIT 通道 1kPIT_Chnl_2, //PIT 通道 2kPIT_Chnl_3, //PIT 通道 3
} pit_chnl_t;
- 第三个参数就是要设置的加载值
3.4 使能 通道 0 的中断
使能通道 0 的中断以后,每当设置好的加载值倒计数到 0 就会产生相应的中断。
使用函数 PIT_EnableInterrupts 使能通道 0中断
3.4.1 PIT_EnableInterrupts
static inline void PIT_EnableInterrupts(PIT_Type *base, pit_chnl_t channel, int32_t mask)
- 第一个参数固定为 PIT
- 第二个参数是要设置的通道,这里为通道 0,即 kPIT_Chnl_0。
- 第三个参数是要使能的中断类型
typedef enum _pit_interrupt_enable
{kPIT_TimerInterruptEnable = PIT_TCTRL_TIE_MASK,
} pit_interrupt_enable_t;
只 有 一 个 中 断 类 型 kPIT_TimerInterruptEnable。
3.5 开启 PIT 定时器
配置好 PIT 定时器以后需要开启定时器,开启 PIT 定时器的函数为 PIT_StartTimer
3.5.1 PIT_StartTimer
此函数原型如下;
static inline void PIT_StartTimer(PIT_Type *base, pit_chnl_t channel)
- 第一个参数固定为PIT
- 第二个产生是要开启哪个通道,这里是通道0,即kPIT_Chnl_0。设置 TCTRL 的 TEN 位为 1。
3.6开启 PIT 中断并设置优先级
在定时器配置完了之后,因为要产生中断,必不可少的要设置 NVIC 相关寄存器
使用如下函数开启 PIT 中断并设置相应的优先级。
RT1052_NVIC_SetPriority(PIT_IRQn,6,0); //抢占优先级 6,子优先级 0
EnableIRQ(PIT_IRQn); //使能 PIT 中断
3.7编写中断服务函数
在中断产生后使用函数 PIT_GetStatusFlags 来获取中断状态,此函数就是获取 TFLG0 的 TIF 位状态,通过 TIF 位状态判断是否是通道 0 的中断。
- 调用函数 PIT_ClearStatusFlags 来清除相应的中断标志位,就是往 TIF 位写 1。
3.7.1 PIT_GetStatusFlags
中断状态获取函数 PIT_GetStatusFlags 原型如下:
static inline uint32_t PIT_GetStatusFlags(PIT_Type *base, pit_chnl_t channel)
- 第一个参数是要获取的定时器,这里为 PIT
- 第二参数就要获取的通道,这里为 kPIT_Chnl_0
此函数其实就是读取寄存器 TFLG 的值,通过这个返回值就可以知道中断是否发生。
3.7.2 PIT_ClearStatusFlags
中断状态(标志位)清除函数 PIT_ClearStatusFlags 原型如下:
static inline void PIT_ClearStatusFlags(PIT_Type *base, pit_chnl_t channel, uint32_t mask)
- 第一个参数为 PIT
- 第二参数为要清除的通道,本例程选择 kPIT_Chnl_0
- 第三个参数是要清除的中断标志位,这里只有 kPIT_TimerFlag 可选择。
3.8 代码
pit_config_t pit_config;//初始化PIT通道0,PIT时钟源为perclk_clk_root=75MHz.
//ldval: CH0初始值,0~0xFFFFFFFF
//递减计数,当ldval==0时,产生中断.
//定时时间=ldval/PERCLK_CLK_ROOT
void PIT_CH0_Int_Init(u32 ldval)
{PIT_GetDefaultConfig(&pit_config); //初始化为默认配置pit_config.enableRunInDebug=true; //调试模式下PIT继续运行PIT_Init(PIT,&pit_config); //初始化PIT定时器PIT_SetTimerPeriod(PIT,kPIT_Chnl_0,ldval);//设置倒计时初始值PIT_EnableInterrupts(PIT,kPIT_Chnl_0,kPIT_TimerInterruptEnable);//使能中断RT1052_NVIC_SetPriority(PIT_IRQn,6,0); //抢占优先级6,子优先级0EnableIRQ(PIT_IRQn); //使能PIT中断PIT_StartTimer(PIT,kPIT_Chnl_0); //打开PIT
}//PIT中断服务函数
void PIT_IRQHandler(void)
{//PIT CH0中断if((PIT_GetStatusFlags(PIT,kPIT_Chnl_0)&kPIT_TimerFlag)==kPIT_TimerFlag){LED1_Toggle; //LED灯翻转PIT_ClearStatusFlags(PIT,kPIT_Chnl_0,kPIT_TimerFlag);//清楚中断标志位}__DSB(); //数据同步屏蔽指令
}