Bootstrap

LiteOS内核开发(七)

本章将介绍LiteOS内核中的软件定时器

1. 基本概念与简介

软件定时器是为了满足在实际设计中硬件定时器数量不足,而开发出的使用软件来模拟定时器功能。基于系统Tick时钟中断,在经过特定的Tick后,会触发用户自定义的回调函数(类似硬件的中断服务函数)。一般来说,软件定时器回调函数的上下文是任务,且回调函数也要快进快出,且回调函数中不能有任何阻塞任务运行的情况,容易造成执行混乱。

LiteOS下软件定时器有以下功能:创建软件定时器,启动软件定时器,停止软件定时器,删除软件定时器,获取软件定时器剩余Tick数,可配置支持的软件定时器个数。

2.  运作机制

运作机制上,软件定时器是系统资源,在初始化时已经分配了一块内存,在使用上需要用到队列和任务资源,软件定时器的触发遵循队列规则,先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先触发的准则,同时软件定时器以Tick为基本计时单位,当创建并启动一个软件定时器时,Huawei LiteOS会根据当前系统Tick时间及设置的定时时长确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。

当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,检查是否有定时器超时,若有则将超时的定时器记录下来。Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用已经记录下来的定时器的回调函数。

例如软件定时器队列中一开始只有一个周期为200Tick的软件定时器A,那么A定时器在200Tick后就会调用一次回调函数,但是,现在插入一个周期为100Tick的软件定时器B,那么100个Tick之后,软件定时器B的回调函数就要调用一次,而原来在200个Tick后调用回调函数的软件定时器A就会变成在软件定时器B调用之后的100个Tick进行唤醒,然后调用对应的回调函数,软件定时器C也是同理,如下图所示

                               

在支持模式上,软件定时器支持三种定时器模式分别为

单次触发定时器:这类定时器在启动后只会触发一次定时器事件,然后定时器自动删除。

周期触发定时器:这类定时器会周期性的触发定时器事件,直到用户手动停止定时器,否则将永远持续执行下去。

单次触发定时器:但这类定时器超时触发后不会自动删除,需要调用定时器删除接口删除定时器。

同时,软件定时器任务的有限级始终为0(最高),不能修改。

3. 实例分析

3.1 前提条件

在menuconfig中完成配置,在Kernel -> Enable Software Timer下,将LOSCFG_BASE_CORE_SWTMR(软件定时器裁剪开关)使能,将LOSCFG_BASE_CORE_SWTMR_IN_ISR(在中断中直接执行回调函数)关闭,将LOSCFG_BASE_CORE_SWTMR_LIMIT(最大支持的软件定时器数)和LOSCFG_BASE_CORE_TSK_SWTMR_STACK_SIZE(软件定时器任务栈大小)分别置为1024和24576。

3.2 具体步骤

 在完成上述准备工作后,就可以在LiteOS Stdio下新建工程开始写程序了,主程序部分代码如下所示

UINT32 g_timerCount1 = 0;
UINT32 g_timerCount2 = 0;

VOID Timer1_CallBack(UINT32 arg)//定时器1回调函数
{
    UINT64 lastTick;

    g_timerCount1++;
    lastTick=(UINT32)LOS_TickCountGet();//获取当前的Tick计数
    dprintf("g_timerCount1=%d\n", g_timerCount1);
    dprintf("tick_last1=%d\n", lastTick);
}

VOID Timer2_CallBack(UINT32 arg)
{
    UINT64 lastTick;

    lastTick=(UINT32)LOS_TickCountGet();
    g_timerCount2++;
    dprintf("g_timerCount2=%d\n", g_timerCount2);
    dprintf("tick_last2=%d\n", lastTick);
}

VOID Timer_example(VOID)
{
    UINT16 id1;     // Timer1 id
    UINT16 id2;     // Timer2 id
    UINT32 tick;

    LOS_SwtmrCreate(1000, LOS_SWTMR_MODE_ONCE, Timer1_CallBack, &id1, 1);//创建一个周期为1000Tick,单次触发模式,以Timer1_CallBack为回调函数,id1为名称,回调函数被调用时传入参数为1的定时器
    LOS_SwtmrCreate(100, LOS_SWTMR_MODE_PERIOD, Timer2_CallBack, &id2, 1);// 创建一个周期为1000Tick,多次触发模式,以Timer1_CallBack为回调函数,id1为名称,回调函数被调用时传入参数为1的定时器
    dprintf("create Timer1 success\n");

    LOS_SwtmrStart(id1);//开启定时器1
    dprintf("start Timer1 sucess\n");
    LOS_TaskDelay(200);//延时200Tick
    LOS_SwtmrTimeGet(id1, &tick);//获取id1定时器中剩余tick数传入tick变量
    dprintf("tick =%d\n", tick);
    LOS_SwtmrStop(id1);//停止定时器1
    dprintf("stop Timer1 sucess\n");

    LOS_SwtmrStart(id1);
    LOS_TaskDelay(1000);
    LOS_SwtmrDelete(id1);//删除定时器1
    dprintf("delete Timer1 sucess\n");

    LOS_SwtmrStart(id2);//开启定时器2
    dprintf("start Timer2\n");
    LOS_TaskDelay(1000);
    LOS_SwtmrStop(id2);
    LOS_SwtmrDelete(id2); 
}

其输出结果为

Create Timer1 success
start Timer1 sucess
tick =800
Stop Timer1 sucess
g_timerCount1=1201
tick_last1=1201
delete Timer1 success
Start Timer2
g_timerCount2=1
tick_last2=1301
g_timerCount2=2
tick_last2=1401
g_timerCount2=3
tick_last2=1501
g_timerCount2=4
tick_last2=1601
g_timerCount2=5
tick_last2=1701
g_timerCount2=6
tick_last2=1801
g_timerCount2=7
tick_last2=1901
g_timerCount2=8
tick_last2=2001
g_timerCount2=9
tick_last2=2101
g_timerCount2=10
tick_last2=2201

这个程序主要完成的步骤为,建立两个定时器1和2,分别赋予1000和100两种不同的定时周期和不同的回调函数,单次和周期两种不同定时模式。在主函数中依次创建定时器,手动开启定时器,延时一定的时间,查看输出情况,最后手动停止并删除定时器。

;