虽然只有2个定时器,但是好在是32bit的,日常使用刚好够,1个定时器当做StopWatch定时器,1us精度,用于时间测量,1个定时器给OS作为滴答时钟使用。
直接上代码:
cpp
/*************************************************************************************************************
* 文件名: t113_timer.c
* 功能: t113定时器支持
* 作者: cp1300@139.com
* 邮箱: cp1300@139.com
* 创建时间: 2023-09-30
* 最后修改时间:2023-09-30
* 详细: 支持timer0 timer1 2个32bit定时器
*************************************************************************************************************/
#include "t113_system.h"
#include "t113_map.h"
#include "typedef.h"
#include "t113_timer.h"
#include "t113_const.h"
/*
writel(0x2EE0, TMR_0_INTV); //Set the interval value
writel(0x94, TMR_0_CTRL); //Select Single mode, 24 MHz clock source, 2 pre-scale
writel(readl(TMR_0_CTRL)|(1<<1), TMR_0_CTRL); //Set the Reload bit
while((readl(TMR_0_CTRL)>>1)&1); //Waiting the Reload bit turns to 0
writel(readl(TMR_0_CTRL)|(1<<0), TMR_0_CTRL); //Enable Timer0
*/
static void (*sg_pTimer0_Callback)(void) = NULL; //定时器0中断回调,外部初始化
static void (*sg_pTimer1_Callback)(void) = NULL; //定时器0中断回调,外部初始化
void TIMER0_IRQHandler(void); //中断处理函数
void TIMER1_IRQHandler(void); //中断处理函数
/*************************************************************************************************************************
* 函数 : void T113_TimerSet(TIMER_CH ch, bool isPeriodicMode,TIMER_PRES_TYPE Pers, u32 Cycle, bool isEnableInt, void (*pCallback)())
* 功能 : 定时器设置
* 参数 : ch:定时器通道选择;isPeriodicMode:是否为周期模式(否则为单次模式);Pers:分频设置;Cycle:计数周期;
isEnableInt:是否使能中断;pCallback:中断回调
* 返回 : 无
* 依赖 : 底层宏定义
* 作者 : cp1300@139.com
* 时间 : 2023-09-30
* 最后修改时间 : 2023-09-30
* 说明 : 会关闭定时器,不会启动定时器
*************************************************************************************************************************/
void T113_TimerSet(TIMER_CH ch, bool isPeriodicMode, TIMER_PRES_TYPE Pers, u32 Cycle, bool isEnableInt, void (*pCallback)())
{
switch (ch)
{
case TIMER_CH0:
{
r_TMR_IRQ_EN &= ~BIT0; //关闭定时器0 中断
r_TMR0_CTRL = 0; //关闭定时器0
if (FALSE == isPeriodicMode) r_TMR0_CTRL |= BIT7; //单次模式
r_TMR0_CTRL |= (Pers & 0x07) << 4; //设置分频
if (Pers & 0x0100) r_TMR0_CTRL |= 1 << 2; //使用24MHz时钟
r_TMR0_INTV_VALUE = Cycle; //设置初值
r_TMR0_CUR_VALUE = Cycle; //计数器值
r_TMR0_CTRL |= BIT1; //使能自动重载,会自动清除
if (TRUE == isEnableInt) //使能中断了
{
r_TMR_IRQ_STA |= BIT0; //清除中断0状态
r_TMR_IRQ_EN |= BIT0; //使能中断
sg_pTimer0_Callback = pCallback; //设置中断回调
GIC_SetIrqPriority(GIC_IRQ_TIMER0, 1); //GIC设置一个中断的优先级
GIC_SetIrqEdgeTriggered(GIC_IRQ_TIMER0, TRUE); //GIC设置一个中断为边沿触发
GIC_RegisterIRQHandler(GIC_IRQ_TIMER0, TIMER0_IRQHandler); //注册中断服务程序
GIC_IrqEnable(GIC_IRQ_TIMER0, TRUE); //GIC中断使能-中断使能
}
else
{
sg_pTimer0_Callback = NULL;
GIC_IrqEnable(GIC_IRQ_TIMER0, FALSE); //GIC中断使能-中断关闭
}
}break;
case TIMER_CH1:
{
r_TMR_IRQ_EN &= ~BIT1; //关闭定时器1中断
r_TMR1_CTRL = 0; //关闭定时器1
if (FALSE == isPeriodicMode) r_TMR1_CTRL |= BIT7; //单次模式
r_TMR1_CTRL |= (Pers & 0x07) << 4; //设置分频
if (Pers & 0x0100) r_TMR1_CTRL |= 1 << 2; //使用24MHz时钟
r_TMR1_INTV_VALUE = Cycle; //设置初值
r_TMR1_CUR_VALUE = Cycle; //计数器值
r_TMR1_CTRL |= BIT1; //使能自动重载,会自动清除
if (TRUE == isEnableInt) //使能中断了
{
r_TMR_IRQ_STA |= BIT1; //清除中断1状态
r_TMR_IRQ_EN |= BIT1; //使能中断
sg_pTimer1_Callback = pCallback; //设置中断回调
GIC_SetIrqPriority(GIC_IRQ_TIMER1, 3); //GIC设置一个中断的优先级
GIC_SetIrqEdgeTriggered(GIC_IRQ_TIMER1, TRUE); //GIC设置一个中断为边沿触发
GIC_RegisterIRQHandler(GIC_IRQ_TIMER1, TIMER1_IRQHandler); //注册中断服务程序
GIC_IrqEnable(GIC_IRQ_TIMER1, TRUE); //GIC中断使能-中断使能
}
else
{
sg_pTimer1_Callback = NULL;
GIC_IrqEnable(GIC_IRQ_TIMER1, FALSE); //GIC中断使能-中断关闭
}
}break;
default: return;
}
}
/*************************************************************************************************************************
* 函数 : void T113_TimerEnable(TIMER_CH ch, bool isEnable)
* 功能 : 使能定时器(开启或关闭定时器)
* 参数 : ch:定时器通道选择;isEnable:TRUE:开启定时器;FALSE:关闭定时器
* 返回 : 无
* 依赖 : 底层宏定义
* 作者 : cp1300@139.com
* 时间 : 2023-09-30
* 最后修改时间 : 2023-09-30
* 说明 : 需要提前初始化定时器
*************************************************************************************************************************/
void T113_TimerEnable(TIMER_CH ch, bool isEnable)
{
switch (ch)
{
case TIMER_CH0:
{
if (TRUE == isEnable)
{
r_TMR0_CTRL |= BIT0; //使能定时器
}
else
{
r_TMR0_CTRL &= ~BIT0; //关闭定时器
}
}break;
case TIMER_CH1:
{
if (TRUE == isEnable)
{
r_TMR1_CTRL |= BIT0; //使能定时器
}
else
{
r_TMR1_CTRL &= ~BIT0; //关闭定时器
}
}break;
default:return;
}
}
/*************************************************************************************************************************
* 函数 : u32 T113_GetTimerCount(TIMER_CH ch)
* 功能 : 获取计数器当前值
* 参数 : ch:定时器通道选择
* 返回 : 无
* 依赖 : 底层宏定义
* 作者 : cp1300@139.com
* 时间 : 2023-10-02
* 最后修改时间 : 2023-10-02
* 说明 : 自减计数器
*************************************************************************************************************************/
u32 T113_GetTimerCount(TIMER_CH ch)
{
switch (ch)
{
case TIMER_CH0: return r_TMR0_CUR_VALUE;
case TIMER_CH1: return r_TMR1_CUR_VALUE;
default:return 0;
}
}
/*************************************************************************************************************************
* 函数 : void T113_ClearTimerInt(TIMER_CH ch)
* 功能 : 清除定时器中断
* 参数 : ch:定时器通道选择
* 返回 : 无
* 依赖 : 底层宏定义
* 作者 : cp1300@139.com
* 时间 : 2024-07-19
* 最后修改时间 : 2024-07-19
* 说明 :
*************************************************************************************************************************/
void T113_ClearTimerInt(TIMER_CH ch)
{
switch (ch)
{
case TIMER_CH0: r_TMR_IRQ_STA |= BIT0; break; //清除中断0状态
case TIMER_CH1: r_TMR_IRQ_STA |= BIT1; break; //清除中断1状态
default:break;
}
}
//中断处理函数 timer0
void TIMER0_IRQHandler(void)
{
r_TMR_IRQ_STA |= BIT0; //清除中断0状态
if (sg_pTimer0_Callback != NULL) sg_pTimer0_Callback();
}
//中断处理函数 timer1
void TIMER1_IRQHandler(void)
{
r_TMR_IRQ_STA |= BIT1; //清除中断1状态
if (sg_pTimer1_Callback != NULL) sg_pTimer1_Callback();
}
cpp
/*************************************************************************************************************
* 文件名: t113_timer.h
* 功能: t113定时器支持
* 作者: cp1300@139.com
* 邮箱: cp1300@139.com
* 创建时间: 2023-09-30
* 最后修改时间:2023-09-30
* 详细: 支持timer0 timer1 2个32bit定时器
*************************************************************************************************************/
#ifndef _T113_TIMER_H_
#define _T113_TIMER_H_
#include "typedef.h"
#include "t113_map.h"
#include "t113_const.h"
//普通定时器通道选择
typedef enum
{
TIMER_CH0 = 0,
TIMER_CH1 = 1,
}TIMER_CH;
//分频选择
typedef enum
{
TIMER_PRES_LOSC_1_1 = 0x0100, //LOSC 1分频
TIMER_PRES_LOSC_1_2 = 0x0101, //LOSC 2分频
TIMER_PRES_LOSC_1_4 = 0x0102, //LOSC 4分频
TIMER_PRES_LOSC_1_8 = 0x0103, //LOSC 8分频
TIMER_PRES_LOSC_1_16 = 0x0104, //LOSC 16分频
TIMER_PRES_LOSC_1_32 = 0x0105, //LOSC 32分频
TIMER_PRES_LOSC_1_64 = 0x0106, //LOSC 64分频
TIMER_PRES_LOSC_1_128 = 0x0107, //LOSC 128分频
TIMER_PRES_24M_1_1 = 0x0100, //24MHz 1分频
TIMER_PRES_24M_1_2 = 0x0101, //24MHz 2分频
TIMER_PRES_24M_1_4 = 0x0102, //24MHz 4分频
TIMER_PRES_24M_1_8 = 0x0103, //24MHz 8分频
TIMER_PRES_24M_1_16 = 0x0104, //24MHz 16分频
TIMER_PRES_24M_1_32 = 0x0105, //24MHz 32分频
TIMER_PRES_24M_1_64 = 0x0106, //24MHz 64分频
TIMER_PRES_24M_1_128 = 0x0107, //24MHz 128分频
}TIMER_PRES_TYPE;
void T113_TimerSet(TIMER_CH ch, bool isPeriodicMode, TIMER_PRES_TYPE Pers, u32 Cycle, bool isEnableInt, void (*pCallback)());//定时器设置
void T113_TimerEnable(TIMER_CH ch, bool isEnable); //使能定时器(开启或关闭定时器)
u32 T113_GetTimerCount(TIMER_CH ch); //获取计数器当前值
void T113_ClearTimerInt(TIMER_CH ch); //清除定时器中断
#endif //_T113_TIMER_H_
注意:定时器需要使用中断,中断需要依赖GIC。
测试代码:
cpp
//中断回调0-闪烁LED
static void time0_callback(void)
{
GPIOD->DATA ^= BIT16;
}
//中断回调1-打印数据
static void time1_callback(void)
{
static u32 count = 0;
uart_printf("tim1:%u\r\n", count++);
}
//定时器测试
void timer_test(void)
{
//timer0 500毫秒中断
T113_TimerSet(TIMER_CH0, TRUE, TIMER_PRES_24M_1_1, 24 * 1000000 * 0.5, TRUE, time0_callback);//定时器设置
T113_TimerEnable(TIMER_CH0, TRUE); //使能定时器(开启或关闭定时器)
//timer1 1中断
T113_TimerSet(TIMER_CH1, TRUE, TIMER_PRES_24M_1_1, 24 * 1000000 * 1, TRUE, time1_callback); //定时器设置
T113_TimerEnable(TIMER_CH1, TRUE); //使能定时器(开启或关闭定时器)
}
例子:
给FreeOS作为滴答时钟
cpp
//RTOS滴答时钟中断初始化
void vConfigureTickInterrupt( void )
{
T113_TimerSet(FREE_RTOS_TIME_CH, TRUE, TIMER_PRES_24M_1_8, RTOS_TIME_CYCLE, TRUE, FreeRTOS_Tick_Handler);
T113_TimerEnable(FREE_RTOS_TIME_CH, TRUE); //启动定时器
}
/*-----------------------------------------------------------*/
void vClearTickInterrupt( void )
{
T113_ClearTimerInt(FREE_RTOS_TIME_CH);//清除定时器中断
}
void vApplicationIRQHandler(uint32_t ulICCIAR)
{
if (ulICCIAR == GIC_IRQ_TIMER0) //如果是定时器0中断,则直接调用 FreeRTOS_Tick_Handler() ,因为定时器0是滴答时钟中断
{
g_OS_RunTime ++; //操作系统运行时间-单位ms
FreeRTOS_Tick_Handler(); //由于直接调用了 FreeRTOS_Tick_Handler 导致定时器的中断没有被清除,所以必须实现 vClearTickInterrupt()
}
else
{
SystemIrqHandler(ulICCIAR);
}
}