韦德斯 2024-06-04 16:40 采纳率: 42.9%
浏览 28

lvgl异步调用问题

LVGL好像不是线程安全的,怎么实现串口读取数据,并进行处理,然后显示到UI上,我写的东西似乎会阻塞UI,代码如下:

int main(void)
{
init_serial();
    lv_power();//构建UI函数
    data_handle();//UI数据初始化函数
    alarm_init();//串口3报警
    /*Handle LitlevGL tasks (tickless mode)*/
    while(1) {
        lv_timer_handler();
        usleep(5000);
}

void alarm_init(void)
{
    //初始化报警定时器
    uart3_timer = lv_timer_create(uart3_timer_cb,2*1000,NULL);
    //开始运行报警定时器
    lv_timer_ready(uart3_timer);
    // //创建灯泡定时器
    for(int i=0;i<30;i++)
    {
        danger_led_timer[i] = lv_timer_create(danger_led_timer_cb,500,NULL);
        lv_timer_set_repeat_count(danger_led_timer[i],-1);
        lv_timer_pause(danger_led_timer[i]);    
    }
}

static void uart3_timer_cb(lv_timer_t * t)
{
    char uart3_buffer[1024]={0};
    read_from_serial2(uart3_buffer,sizeof(uart3_buffer));//读取报警串口
    alarm_handle(uart3_buffer);
    
}

//处理主动上传的报警信息
void alarm_handle(char *json_str)
{
    cJSON *root = cJSON_Parse(json_str);  
    if (root == NULL)
    {  
        printf("Error before: [%s]\n", cJSON_GetErrorPtr());  
        return;  
    }  

    // 提取frame和code  
    const char *frame = cJSON_GetObjectItemCaseSensitive(root, "frm")->valuestring;  
    int code = cJSON_GetObjectItemCaseSensitive(root, "cd")->valueint;  
    char *SN = cJSON_GetObjectItemCaseSensitive(root, "SN")->valuestring; 

    if(strcmp(frame,"BJ")==0)
    {
        if(code == 1004)
        {
            int i,j;
            //由SN得到窗口号
            for(int x = 0; x < 5; x++)  
            {  
                for(int y = 0; y < 6; y++)  
                {  
                    const char *label_text = lv_label_get_text(win_ids[x][y]);  
                    const char *id_start = strstr(label_text, "ID:");  
        
                    if (id_start != NULL)  
                    {  
                        // 移动指针到"ID:"之后  
                        id_start += 3; // 跳过"ID:"  
        
                        // 计算SN的长度(不包括结束符)  
                        size_t sn_length = strcspn(id_start, "\n"); // 假设SN不包含换行符  
        
                        // 分配足够的空间来存储去除前缀后的字符串(包括结束符)  
                        char sn[sn_length + 1];  
        
                        // 复制SN并添加结束符  
                        strncpy(sn, id_start, sn_length);  
                        sn[sn_length] = '\0'; // 显式添加结束符  
        
                        if(strcmp(sn,SN)==0)
                        {
                            i=x;
                            j=y;
                        }
                    }  
                    else  
                    {  
                        printf("Prefix 'ID:' not found in the label text for [%d][%d].\n", x, y);  
                    }  
                }  
            }  

            cJSON *pki_array = cJSON_GetObjectItemCaseSensitive(root,"peakage");
            if(!cJSON_IsArray(pki_array))
            {
                printf("Error:peakage is not an array\n");
                cJSON_Delete(root);

            }

            cJSON *pkR_array = cJSON_GetObjectItemCaseSensitive(root,"peakageR");
            if(!cJSON_IsArray(pkR_array))
            {
                printf("Error:pkR is not an array\n");
                cJSON_Delete(root);

            }

            for(int t=0;t<cJSON_GetArraySize(pki_array);t++)
            {
                cJSON *value = cJSON_GetArrayItem(pki_array,t);
                if(value && cJSON_IsNumber(value))
                {
                    double uA_value = value->valuedouble;
                    double A_value = uA_value/10.0;
                    char text[32];
                    snprintf(text,sizeof(text),"%.1f",A_value);
                    if(t==0)
                    {
                        lv_label_set_text(lbl_A_Ix_real[i][j], text);
                    }
                    else if(t==1)
                    {
                        lv_label_set_text(lbl_B_Ix_real[i][j], text);
                    }
                    else if(t==2)
                    {
                        lv_label_set_text(lbl_C_Ix_real[i][j], text);
                    }
                }
            
            }

            for(int t=0;t<cJSON_GetArraySize(pkR_array);t++)
            {
                cJSON *value = cJSON_GetArrayItem(pkR_array,t);
                if(value && cJSON_IsNumber(value))
                {
                    double uA_value = value->valuedouble;
                    double A_value = uA_value/10.0;
                    char text[32];
                    snprintf(text,sizeof(text),"%.1f",A_value);
                    if(t==0)
                    {
                        lv_label_set_text(lbl_A_Ir_real[i][j], text);
                    }
                    else if(t==1)
                    {
                        lv_label_set_text(lbl_B_Ir_real[i][j], text);
                    }
                    else if(t==2)
                    {
                        lv_label_set_text(lbl_C_Ir_real[i][j], text);
                    }
                }
            
            }
            //红窗口
            lv_obj_set_style_bg_color(windows[i][j],lv_color_hex(0xff0000),LV_PART_MAIN);
            //灯闪
            led_sum=6*i+j;
            lv_timer_resume(danger_led_timer[led_sum]);//灯泡定时器

            ///蜂鸣器
            danger_beep_timer = lv_timer_create(danger_beep_timer_cb,500,NULL);
            lv_timer_set_repeat_count(danger_beep_timer,-1);
            lv_timer_ready(danger_beep_timer);

            /*报警提示窗口*/
            static const char * btns[] = {"OK", ""};
            lv_obj_t *msgbox_opendanger = lv_msgbox_create(mainmenu,LV_SYMBOL_WARNING "Warning","Danger! ",btns, false);
            lv_obj_set_size(msgbox_opendanger,150,120);
            lv_obj_align(msgbox_opendanger,LV_ALIGN_CENTER,0,0);
            lv_obj_t *MSG_content = lv_msgbox_get_content(msgbox_opendanger);
            lv_obj_align(MSG_content,LV_ALIGN_CENTER,30,0);
            lv_obj_t *btn = lv_msgbox_get_btns(msgbox_opendanger);                                              /* 获取按钮矩阵部分 */
            lv_obj_set_style_bg_opa(btn, 0, LV_PART_ITEMS);                                          /* 设置按钮背景透明度 */
            lv_obj_set_style_shadow_width(btn, 0, LV_PART_ITEMS);                                    /* 去除按钮阴影 */
            lv_obj_add_event_cb(msgbox_opendanger, danger_event_cb, LV_EVENT_VALUE_CHANGED, NULL); 

        }
    }
    cJSON_Delete(root);
}

main函数里面加上 alarm_init();这个函数就会阻塞UI

  • 写回答

2条回答 默认 最新

  • 阿里嘎多学长 2024-06-04 16:40
    关注

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    针对您的问题,我为您提供以下建议和解决方案:

    解决方案

    1. 使用线程安全的方法更新UI: LVGL 默认不是线程安全的,因此当您在非UI线程中更新UI时,需要确保线程安全。一种常见的做法是使用互斥锁(mutex)来防止多个线程同时访问UI组件。

    2. 异步串口数据读取: 您可以使用一个单独的线程或任务来处理串口数据的读取和处理。这个后台线程可以负责读取数据,处理数据,然后使用信号或回调函数来通知UI线程更新UI。

    3. 使用LVGL的定时器和事件系统: LVGL 提供了定时器(lv_timer)和事件系统,您可以使用这些工具来异步更新UI。例如,您可以在后台线程中设置一个定时器,定时器到期时触发一个事件,该事件会安全地更新UI。

    代码实现示例

    以下是一个简化的示例,展示如何使用互斥锁和LVGL定时器来异步更新UI:

    #include "lvgl.h"
    #include "FreeRTOS.h"
    #include "semphr.h"
    
    // 创建一个互斥锁
    xSemaphoreHandle xMutex = NULL;
    
    // UI更新函数,需要在UI线程中调用
    void update_ui_with_data(const char *data) {
        // 锁住互斥锁
        xSemaphoreTake(xMutex, portMAX_DELAY);
        // 更新UI组件
        // 例如:lv_label_set_text(ui_label, data);
        // 释放互斥锁
        xSemaphoreGive(xMutex);
    }
    
    // 后台线程,负责读取串口数据
    void vSerialReadTask(void *pvParameters) {
        char buffer[1024];
    
        for(;;) {
            // 读取串口数据
            read_from_serial(buffer, sizeof(buffer));
    
            // 使用信号通知UI线程更新UI
            // 注意:这里需要确保信号的使用是线程安全的
            xSemaphoreGiveFromISR(xMutex, pdFALSE);
    
            // 稍作延时,避免过快地读取
            vTaskDelay(pdMS_TO_TICKS(100));
        }
    }
    
    // UI线程中,定时更新UI
    void vUITask(void *pvParameters) {
        for(;;) {
            // 等待信号,准备更新UI
            xSemaphoreTake(xMutex, portMAX_DELAY);
    
            // 更新UI
            update_ui_with_data("New data from serial");
    
            // 完成更新后,继续监听
        }
    }
    
    int main(void) {
        // 初始化LVGL和FreeRTOS
        lv_init();
        // 创建互斥锁
        xMutex = xSemaphoreCreateMutex();
    
        // 创建后台串口读取任务和UI更新任务
        xTaskCreate(vSerialReadTask, "SerialReadTask", 1024, NULL, 2, NULL);
        xTaskCreate(vUITask, "UITask", 1024, NULL, 1, NULL);
    
        // 调度任务
        vTaskStartScheduler();
    
        return 0;
    }
    

    参考资料

    1. LVGL官方文档 - 线程安全[^1^]
    2. FreeRTOS官方文档 - 互斥锁[^2^]
    3. FreeRTOS官方文档 - 信号量[^3^]

    请注意,上述代码仅为示例,您需要根据您的具体需求进行调整。希望这些建议和示例能够帮助您解决问题。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 6月4日

悬赏问题

  • ¥15 Coze智能助手搭建过程中的问题请教
  • ¥15 12864只亮屏 不显示汉字
  • ¥20 三极管1000倍放大电路
  • ¥15 vscode报错如何解决
  • ¥15 前端vue CryptoJS Aes CBC加密后端java解密
  • ¥15 python随机森林对两个excel表格读取,shap报错
  • ¥15 基于STM32心率血氧监测(OLED显示)相关代码运行成功后烧录成功OLED显示屏不显示的原因是什么
  • ¥100 X轴为分离变量(因子变量),如何控制X轴每个分类变量的长度。
  • ¥30 求给定范围的全体素数p的(p-2)/p的连乘积值
  • ¥15 VFP如何使用阿里TTS实现文字转语音?