老化测试框架举例

背景

使用liteos相关api实现,一个定时器实现1s亮红灯,0.1s亮白灯,5s轮训亮红白灯,上面使用一个定时器,用完可以删除重新建,第二个定时器实现一个信号量的互斥,有三个阶段测试,第一阶段实现1s亮红灯,老化测试lcd屏幕,第二阶段实现0.1s亮白灯,老化测试网口收发包,第三阶段实现5s轮训亮红白灯,老化测试flash读写,三个阶段每一个分别亮10min,没有跑完10min不能打断。

设计方案

主任务创建信号量(初始值1)和定时器2(周期1ms,但暂不启动)。

循环三个阶段:

  1. 请求信号量(Pend)------若当前阶段尚未完成,阻塞等待。

  2. 获得信号量后,重置计时器2的累计值(g_elapsed_ms = 0)。

  3. 根据阶段编号:

  • 设置相应的灯光状态机初始状态。

  • 启动对应的老化测试任务/函数(例如启动 LCD 连续读写)。

  1. 启动定时器1(首次调用其回调函数,内部会创建定时器)。

  2. 启动定时器2,开始 10 分钟倒计时。

  3. 主任务继续等待信号量(阶段运行期间,主任务被 Pend 阻塞,不会切换到下一阶段)。

  4. 定时器2 累计到 10 分钟 → 停止定时器1,关闭 LED,释放信号量(Post)。

  5. 主任务获得信号量,进入下一阶段。

三个阶段全部完成后,清理定时器2。

代码实现

复制代码
#include "los_tick.h"
#include "los_task.h"
#include "los_timer.h"
#include "los_sem.h"
#include "los_typedef.h"
#include <stdio.h>

/*========================== 硬件抽象接口(根据实际硬件替换) ==========================*/
#define LED_RED   0
#define LED_WHITE 1
#define LED_ON(color)      do { printf("LED %s ON\n", (color)==LED_RED ? "RED" : "WHITE"); } while(0)
#define LED_OFF()          printf("LED OFF\n")
#define LCD_Aging_Test()   printf("LCD Aging Test Running...\n")
#define Net_Aging_Test()   printf("Net Aging Test Running...\n")
#define Flash_Aging_Test() printf("Flash Aging Test Running...\n")

/*========================== 全局变量 ==========================*/
UINT32 g_timer1_id = 0xFFFFFFFF;   // 灯光定时器 ID
UINT32 g_timer2_id = 0xFFFFFFFF;   // 计时定时器 ID
UINT32 g_sem_id = 0;               // 信号量 ID
UINT32 g_task_id = 0;              // 老化测试任务 ID

/* 灯光状态机(包含轮询红白交替) */
typedef enum {
    LIGHT_RED_1S = 0,       // 亮红灯,持续1s
    LIGHT_WHITE_01S,        // 亮白灯,持续0.1s
    LIGHT_POLL_RED,         // 轮询亮红灯,持续5s
    LIGHT_POLL_WHITE        // 轮询亮白灯,持续5s
} Light_State;
Light_State g_light_state = LIGHT_RED_1S;

/* 测试阶段 */
typedef enum {
    STAGE1_LCD = 0,
    STAGE2_NET,
    STAGE3_FLASH
} Stage_State;

volatile UINT32 g_elapsed_ms = 0;        // 当前阶段已运行毫秒数
#define TEN_MINUTE_MS (10 * 60 * 1000)   // 600000ms

/*========================== 定时器1 回调(灯光控制,自删除重建) ==========================*/
VOID Timer1_Callback(UINT32 arg)
{
    UINT32 next_interval_ms = 0;

    // 1. 执行当前灯光状态,并决定下一状态
    switch (g_light_state) {
        case LIGHT_RED_1S:
            LED_ON(LED_RED);
            g_light_state = LIGHT_WHITE_01S;
            next_interval_ms = 100;      // 下次触发间隔 100ms
            break;

        case LIGHT_WHITE_01S:
            LED_ON(LED_WHITE);
            g_light_state = LIGHT_POLL_RED;
            next_interval_ms = 5000;     // 进入轮询阶段,间隔 5s
            break;

        case LIGHT_POLL_RED:
            LED_ON(LED_RED);
            g_light_state = LIGHT_POLL_WHITE;
            next_interval_ms = 5000;     // 继续轮询,切换为白灯
            break;

        case LIGHT_POLL_WHITE:
            LED_ON(LED_WHITE);
            g_light_state = LIGHT_RED_1S; // 轮询结束,回到红灯1s模式
            next_interval_ms = 1000;
            break;

        default:
            break;
    }

    // 2. 删除当前定时器
    if (g_timer1_id != 0xFFFFFFFF) {
        (VOID)LOS_TimerDelete(g_timer1_id);
        g_timer1_id = 0xFFFFFFFF;
    }

    // 3. 重建定时器,设定新的间隔
    UINT32 ret = LOS_TimerCreate(&g_timer1_id, LOS_HW_MODE_SINGLE,
                                 Timer1_Callback, NULL, next_interval_ms);
    if (ret == LOS_OK) {
        (VOID)LOS_TimerStart(g_timer1_id);
    } else {
        printf("Timer1 recreate failed, ret=%u\n", ret);
    }
}

/*========================== 定时器2 回调(计时 & 阶段结束释放信号量) ==========================*/
VOID Timer2_Callback(UINT32 arg)
{
    g_elapsed_ms++;
    if (g_elapsed_ms >= TEN_MINUTE_MS) {
        g_elapsed_ms = 0;

        // 停止计时器(本次阶段结束,下一阶段重新启动)
        if (g_timer2_id != 0xFFFFFFFF) {
            (VOID)LOS_TimerStop(g_timer2_id);
        }

        // 停止并删除灯光定时器,关闭LED
        if (g_timer1_id != 0xFFFFFFFF) {
            (VOID)LOS_TimerStop(g_timer1_id);
            (VOID)LOS_TimerDelete(g_timer1_id);
            g_timer1_id = 0xFFFFFFFF;
        }
        LED_OFF();

        // 释放信号量,允许进入下一阶段
        (VOID)LOS_SemPost(g_sem_id);
    }
}

/*========================== 老化测试主任务 ==========================*/
VOID Aging_Test_Task(UINT32 arg)
{
    UINT32 ret;
    Stage_State stage;

    // 创建定时器2(周期1ms,但先不启动)
    ret = LOS_TimerCreate(&g_timer2_id, LOS_HW_MODE_PERIODIC,
                          Timer2_Callback, NULL, 1);
    if (ret != LOS_OK) {
        printf("Timer2 create failed\n");
        return;
    }

    // 三个阶段依次执行
    for (stage = STAGE1_LCD; stage <= STAGE3_FLASH; stage++) {
        // 获取信号量(阻塞直到阶段完成)
        ret = LOS_SemPend(g_sem_id, LOS_WAIT_FOREVER);
        if (ret != LOS_OK) {
            printf("Semaphore pend error\n");
            break;
        }

        // 重置计时器累计值
        g_elapsed_ms = 0;

        // 根据阶段设置灯光初始状态并启动老化测试
        switch (stage) {
            case STAGE1_LCD:
                g_light_state = LIGHT_RED_1S;
                LCD_Aging_Test();
                break;
            case STAGE2_NET:
                g_light_state = LIGHT_WHITE_01S;
                Net_Aging_Test();
                break;
            case STAGE3_FLASH:
                g_light_state = LIGHT_POLL_RED;   // 从轮询红灯开始
                Flash_Aging_Test();
                break;
        }

        // 启动灯光定时器(首次调用回调,内部会创建定时器)
        Timer1_Callback(0);

        // 启动计时定时器,开始10分钟倒计时
        ret = LOS_TimerStart(g_timer2_id);
        if (ret != LOS_OK) {
            printf("Timer2 start failed\n");
            break;
        }

        // 主任务在此阻塞,等待定时器2释放信号量
        // 10分钟后,信号量被释放,任务继续,进入下一阶段
    }

    // 三个阶段全部完成,清理定时器2
    if (g_timer2_id != 0xFFFFFFFF) {
        (VOID)LOS_TimerStop(g_timer2_id);
        (VOID)LOS_TimerDelete(g_timer2_id);
        g_timer2_id = 0xFFFFFFFF;
    }

    printf("All aging tests completed.\n");
}

/*========================== 系统初始化 ==========================*/
VOID App_Init(VOID)
{
    UINT32 ret;

    // 1. 创建信号量,初始值1(空闲状态)
    ret = LOS_SemCreate(1, &g_sem_id);
    if (ret != LOS_OK) {
        printf("Semaphore create failed\n");
        return;
    }

    // 2. 创建老化测试任务
    TSK_INIT_PARAM_S task_param = {0};
    task_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Aging_Test_Task;
    task_param.uwStackSize  = 0x2000;     // 8KB 栈空间
    task_param.pcName       = "AgingTestTask";
    task_param.usTaskPrio   = 5;          // 优先级适中
    ret = LOS_TaskCreate(&g_task_id, &task_param);
    if (ret != LOS_OK) {
        printf("Task create failed\n");
        return;
    }

    printf("Aging test system initialized.\n");
}

代码分析

1,互斥与不可打断性

  • 初始信号量值 = 1,主任务第一个阶段可直接获取。

  • 获取后信号量变为 0,任何其他任务调用 LOS_SemPend 将被阻塞(LOS_WAIT_FOREVER)。

  • 只有定时器2 在累计满 10 分钟后执行 LOS_SemPost,信号量恢复为 1,主任务才能继续下一阶段。

  • 定时器2 在释放信号量后立即停止,防止重复释放,确保阶段切换的严格顺序。

2. 定时器1 的自删除与重建

  • 使用单次触发模式(LOS_HW_MODE_SINGLE),每次回调触发后立即删除自身。

  • 根据当前状态计算下一次的间隔(1000/100/5000 ms),重新创建并启动,实现了"用完即删、按需重建"的设计。

  • 轮询状态拆分为红白两个子状态,交替间隔均为 5s,实现了真正的红白交替闪烁。

3. 阶段与灯光状态分离

  • 三个阶段分别对应不同的灯光初始状态,老化测试函数与灯光控制独立,便于扩展和替换硬件接口。