Skip to content

12.freertos任务

约 1299 字大约 4 分钟

2025-08-20

/* ======================== 系统配置 ======================== */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "timers.h"
#include "event_groups.h"
#include "lvgl.h"

/* 任务优先级定义 */
#define LVGL_TASK_PRIORITY          (tskIDLE_PRIORITY + 4)  // 最高优先级
#define LIGHT_SENSOR_PRIORITY       (tskIDLE_PRIORITY + 3)
#define KEY_SCAN_PRIORITY           (tskIDLE_PRIORITY + 2)
#define SYSTEM_MONITOR_PRIORITY     (tskIDLE_PRIORITY + 1)

/* 任务堆栈大小 */
#define LVGL_TASK_STACK_SIZE        512
#define LIGHT_SENSOR_STACK_SIZE     256
#define KEY_SCAN_STACK_SIZE         256
#define SYSTEM_MONITOR_STACK_SIZE   256

/* ======================== 数据结构定义 ======================== */
typedef struct {
    float light_value;
    uint32_t timestamp;
    uint8_t sensor_status;  // 传感器状态
} light_data_t;

typedef enum {
    KEY_NONE = 0,
    KEY_UP,
    KEY_DOWN,
    KEY_LEFT,
    KEY_RIGHT,
    KEY_SELECT,
    KEY_LONG_PRESS
} key_event_t;

typedef struct {
    key_event_t key;
    uint32_t timestamp;
} key_message_t;

typedef struct {
    uint32_t cpu_usage;
    uint32_t free_heap;
    uint32_t min_free_heap;
    float temperature;      // 可选:CPU温度
} system_info_t;

/* ======================== 全局变量和句柄 ======================== */
/* 队列句柄 */
QueueHandle_t light_data_queue;
QueueHandle_t key_event_queue;
QueueHandle_t system_info_queue;

/* 互斥锁 */
SemaphoreHandle_t display_mutex;
SemaphoreHandle_t i2c_mutex;        // I2C总线互斥锁
SemaphoreHandle_t spi_mutex;        // SPI总线互斥锁

/* 事件组 */
EventGroupHandle_t system_events;
#define SYSTEM_INIT_COMPLETE_BIT    (1 << 0)
#define SENSOR_ERROR_BIT           (1 << 1)
#define LOW_POWER_BIT              (1 << 2)
#define SCREEN_UPDATE_BIT          (1 << 3)

/* 软件定时器 */
TimerHandle_t heartbeat_timer;
TimerHandle_t screen_saver_timer;

/* LVGL对象句柄 */
lv_obj_t *main_screen;
lv_obj_t *light_label;
lv_obj_t *time_label;
lv_obj_t *system_info_label;
lv_obj_t *menu_container;

/* ======================== 任务实现 ======================== */

/* 1. 光照传感器任务 */
void light_sensor_task(void *pvParameters)
{
    light_data_t light_data;
    TickType_t last_wake_time;
    uint32_t error_count = 0;
    
    // 初始化传感器
    if(light_sensor_init() != 0) {
        // 设置传感器错误标志
        xEventGroupSetBits(system_events, SENSOR_ERROR_BIT);
        vTaskDelete(NULL);  // 删除任务
    }
    
    last_wake_time = xTaskGetTickCount();
    
    while(1)
    {
        // 获取I2C总线访问权限
        if(xSemaphoreTake(i2c_mutex, pdMS_TO_TICKS(50)) == pdTRUE)
        {
            // 读取光照强度
            if(read_light_sensor(&light_data.light_value) == 0)
            {
                light_data.timestamp = xTaskGetTickCount();
                light_data.sensor_status = 1;  // 正常
                error_count = 0;
                
                // 发送数据到队列
                if(xQueueSend(light_data_queue, &light_data, 0) != pdTRUE)
                {
                    // 队列满,清空队列重新发送
                    xQueueReset(light_data_queue);
                    xQueueSend(light_data_queue, &light_data, 0);
                }
                
                // 触发屏幕更新事件
                xEventGroupSetBits(system_events, SCREEN_UPDATE_BIT);
            }
            else
            {
                error_count++;
                if(error_count > 5)
                {
                    // 连续错误,设置错误标志
                    xEventGroupSetBits(system_events, SENSOR_ERROR_BIT);
                }
            }
            
            xSemaphoreGive(i2c_mutex);
        }
        
        // 定时采样,100ms间隔
        vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(100));
    }
}

/* 2. 按键扫描任务 */
void key_scan_task(void *pvParameters)
{
    key_message_t key_msg;
    static uint8_t key_state[5] = {0};          // 按键状态
    static uint32_t key_press_time[5] = {0};    // 按键按下时间
    static uint32_t last_key_time = 0;          // 防抖动
    uint8_t key_raw, key_pressed;
    int i;
    
    while(1)
    {
        // 读取原始按键状态
        key_raw = read_keys_gpio();
        
        // 防抖动处理
        if((xTaskGetTickCount() - last_key_time) < pdMS_TO_TICKS(20))
        {
            vTaskDelay(pdMS_TO_TICKS(10));
            continue;
        }
        
        // 扫描每个按键
        for(i = 0; i < 5; i++)
        {
            key_pressed = (key_raw >> i) & 0x01;
            
            if(key_pressed && !key_state[i])
            {
                // 按键刚被按下
                key_state[i] = 1;
                key_press_time[i] = xTaskGetTickCount();
                
                // 发送按键事件
                key_msg.key = (key_event_t)(i + 1);
                key_msg.timestamp = key_press_time[i];
                xQueueSend(key_event_queue, &key_msg, 0);
                
                last_key_time = xTaskGetTickCount();
                
                // 重置屏保定时器
                xTimerReset(screen_saver_timer, 0);
            }
            else if(!key_pressed && key_state[i])
            {
                // 按键释放,检查是否长按
                uint32_t press_duration = xTaskGetTickCount() - key_press_time[i];
                if(press_duration > pdMS_TO_TICKS(1000))  // 长按1秒
                {
                    key_msg.key = KEY_LONG_PRESS;
                    key_msg.timestamp = xTaskGetTickCount();
                    xQueueSend(key_event_queue, &key_msg, 0);
                }
                
                key_state[i] = 0;
                last_key_time = xTaskGetTickCount();
            }
        }
        
        vTaskDelay(pdMS_TO_TICKS(20));  // 20ms扫描周期
    }
}

/* 3. LVGL显示任务 */
void lvgl_task(void *pvParameters)
{
    light_data_t light_data;
    key_message_t key_msg;
    system_info_t sys_info;
    char display_buffer[64];
    static uint8_t current_page = 0;  // 当前显示页面
    static float last_light_value = -1.0f;
    EventBits_t events;
    
    // 等待系统初始化完成
    xEventGroupWaitBits(system_events, SYSTEM_INIT_COMPLETE_BIT, 
                       pdFALSE, pdTRUE, portMAX_DELAY);
    
    // 创建UI界面
    create_main_ui();
    
    while(1)
    {
        // 等待屏幕更新事件或超时
        events = xEventGroupWaitBits(system_events, 
                                   SCREEN_UPDATE_BIT | SENSOR_ERROR_BIT,
                                   pdTRUE, pdFALSE, pdMS_TO_TICKS(20));
        
        // 获取显示互斥锁
        if(xSemaphoreTake(display_mutex, pdMS_TO_TICKS(10)) == pdTRUE)
        {
            // 处理光照数据更新
            if(xQueueReceive(light_data_queue, &light_data, 0) == pdTRUE)
            {
                if(fabs(light_data.light_value - last_light_value) > 0.5f)
                {
                    snprintf(display_buffer, sizeof(display_buffer), 
                            "Light: %.1f lux", light_data.light_value);
                    lv_label_set_text(light_label, display_buffer);
                    last_light_value = light_data.light_value;
                }
            }
            
            // 处理按键事件
            if(xQueueReceive(key_event_queue, &key_msg, 0) == pdTRUE)
            {
                handle_key_event(&key_msg, &current_page);
            }
            
            // 处理系统信息更新
            if(xQueueReceive(system_info_queue, &sys_info, 0) == pdTRUE)
            {
                update_system_info_display(&sys_info);
            }
            
            // 处理传感器错误
            if(events & SENSOR_ERROR_BIT)
            {
                lv_label_set_text(light_label, "Sensor Error!");
            }
            
            // LVGL任务处理
            lv_task_handler();
            
            xSemaphoreGive(display_mutex);
        }
        
        vTaskDelay(pdMS_TO_TICKS(20));  // 50fps刷新率
    }
}

/* 4. 系统监控任务 */
void system_monitor_task(void *pvParameters)
{
    system_info_t sys_info;
    TaskStatus_t *task_status_array;
    UBaseType_t task_count;
    uint32_t total_runtime, task_runtime;
    
    while(1)
    {
        // 获取系统信息
        sys_info.free_heap = xPortGetFreeHeapSize();
        sys_info.min_free_heap = xPortGetMinimumEverFreeHeapSize();
        
        // 计算CPU使用率
        task_count = uxTaskGetNumberOfTasks();
        task_status_array = pvPortMalloc(task_count * sizeof(TaskStatus_t));
        
        if(task_status_array != NULL)
        {
            task_count = uxTaskGetSystemState(task_status_array, task_count, &total_runtime);
            
            // 简化的CPU使用率计算
            sys_info.cpu_usage = 100 - (xTaskGetIdleTaskCount() * 100 / total_runtime);
            
            vPortFree(task_status_array);
        }
        
        // 检查内存不足情况
        if(sys_info.free_heap < 1024)  // 小于1KB
        {
            xEventGroupSetBits(system_events, LOW_POWER_BIT);
        }
        
        // 发送系统信息
        xQueueSend(system_info_queue, &sys_info, 0);
        
        vTaskDelay(pdMS_TO_TICKS(1000));  // 1秒更新一次
    }
}

/* ======================== 辅助函数 ======================== */

/* UI创建函数 */
void create_main_ui(void)
{
    // 创建主屏幕
    main_screen = lv_obj_create(NULL);
    lv_scr_load(main_screen);
    
    // 创建光照显示标签
    light_label = lv_label_create(main_screen);
    lv_label_set_text(light_label, "Light: -- lux");
    lv_obj_align(light_label, LV_ALIGN_TOP_MID, 0, 20);
    
    // 创建时间显示标签
    time_label = lv_label_create(main_screen);
    lv_label_set_text(time_label, "00:00:00");
    lv_obj_align(time_label, LV_ALIGN_TOP_RIGHT, -10, 5);
    
    // 创建系统信息标签
    system_info_label = lv_label_create(main_screen);
    lv_label_set_text(system_info_label, "CPU: --%");
    lv_obj_align(system_info_label, LV_ALIGN_BOTTOM_LEFT, 10, -5);
}

/* 按键事件处理 */
void handle_key_event(key_message_t *key_msg, uint8_t *current_page)
{
    switch(key_msg->key)
    {
        case KEY_UP:
            // 处理向上按键
            break;
            
        case KEY_DOWN:
            // 处理向下按键
            break;
            
        case KEY_LEFT:
            if(*current_page > 0) (*current_page)--;
            update_display_page(*current_page);
            break;
            
        case KEY_RIGHT:
            (*current_page)++;
            update_display_page(*current_page);
            break;
            
        case KEY_SELECT:
            // 处理选择按键
            break;
            
        case KEY_LONG_PRESS:
            // 进入设置菜单
            enter_settings_menu();
            break;
            
        default:
            break;
    }
}

/* 软件定时器回调函数 */
void heartbeat_timer_callback(TimerHandle_t xTimer)
{
    // 心跳LED闪烁
    toggle_heartbeat_led();
}

void screen_saver_timer_callback(TimerHandle_t xTimer)
{
    // 进入屏保模式
    enter_screen_saver_mode();
}

/* ======================== 系统初始化 ======================== */
void system_init(void)
{
    // 创建队列
    light_data_queue = xQueueCreate(5, sizeof(light_data_t));
    key_event_queue = xQueueCreate(10, sizeof(key_message_t));
    system_info_queue = xQueueCreate(3, sizeof(system_info_t));
    
    // 创建互斥锁
    display_mutex = xSemaphoreCreateMutex();
    i2c_mutex = xSemaphoreCreateMutex();
    spi_mutex = xSemaphoreCreateMutex();
    
    // 创建事件组
    system_events = xEventGroupCreate();
    
    // 创建软件定时器
    heartbeat_timer = xTimerCreate("Heartbeat", pdMS_TO_TICKS(1000), 
                                  pdTRUE, NULL, heartbeat_timer_callback);
    screen_saver_timer = xTimerCreate("ScreenSaver", pdMS_TO_TICKS(30000), 
                                     pdFALSE, NULL, screen_saver_timer_callback);
    
    // 启动定时器
    xTimerStart(heartbeat_timer, 0);
    xTimerStart(screen_saver_timer, 0);
}

/* ======================== 主函数 ======================== */
int main(void)
{
    // 硬件初始化
    SystemClock_Config();
    GPIO_Init();
    USART_Init();
    I2C_Init();
    SPI_Init();
    
    // 系统初始化
    system_init();
    
    // 创建任务
    xTaskCreate(light_sensor_task, "LightSensor", LIGHT_SENSOR_STACK_SIZE, 
               NULL, LIGHT_SENSOR_PRIORITY, NULL);
               
    xTaskCreate(key_scan_task, "KeyScan", KEY_SCAN_STACK_SIZE, 
               NULL, KEY_SCAN_PRIORITY, NULL);
               
    xTaskCreate(lvgl_task, "LVGL", LVGL_TASK_STACK_SIZE, 
               NULL, LVGL_TASK_PRIORITY, NULL);
               
    xTaskCreate(system_monitor_task, "SysMon", SYSTEM_MONITOR_STACK_SIZE, 
               NULL, SYSTEM_MONITOR_PRIORITY, NULL);
    
    // 设置系统初始化完成标志
    xEventGroupSetBits(system_events, SYSTEM_INIT_COMPLETE_BIT);
    
    // 启动调度器
    vTaskStartScheduler();
    
    // 正常情况下不会执行到这里
    while(1);
}