YB_5465 2025-10-30 10:40 采纳率: 0%
浏览 18

如何使用LVGL显示UI界面,实现一个定时器循环发送消息,并且消息框实时更新发送的内容?

使用LVGL显示UI界面,实现一个定时器循环发送消息,并且消息框实时更新发送的内容。但是显示出现的问题就是,由于发送的消息比较多比较大,就会导致更新消息框的文本内容时,造成LVGL线程的阻塞。我想知道该怎么去解决这个阻塞的问题。

void UpdateMessageDisplayFromLVGL(char *new_text, uint16_t text_len, uint8_t show_flag,uint8_t direct)
{
    // 始终更新全局消息数组(作为唯一数据源)
    if (g_usSerialTextLen + text_len >= MESSAGE_TEXT_DATA_LEN) {
        // 计算需要移除的字符数
        uint16_t overflow_chars = (g_usSerialTextLen + text_len) - MESSAGE_TEXT_DATA_LEN + 1;
        
        // 移除前面的字符腾出空间
        memmove(g_ucMessageTextArray, 
                g_ucMessageTextArray + overflow_chars, 
                g_usSerialTextLen - overflow_chars);
        
        g_usSerialTextLen -= overflow_chars;
        g_ucMessageTextArray[g_usSerialTextLen] = '\0';
    }
    
    // 追加新文本
    // strncat(g_ucMessageTextArray, new_text, MESSAGE_TEXT_DATA_LEN - g_usSerialTextLen - 1);
    strncat(g_ucMessageTextArray, new_text, MESSAGE_TEXT_DATA_LEN - g_usSerialTextLen);
    g_usSerialTextLen = strlen(g_ucMessageTextArray);
    
    // 根据显示模式更新UI
    if (show_flag) {
        // 立即显示模式:用全局数组内容更新LVGL标签
        lv_label_set_text(serial_Message_Text, g_ucMessageTextArray);
        (direct) ? lv_label_set_text_fmt(serial_RecvCount_table, "R:%d", g_Struct_serial_net_state.serialNet_R_CONUT) : lv_label_set_text_fmt(serial_SendCount_table, "S:%d", g_Struct_serial_net_state.serialNet_S_CONUT);
        lv_obj_scroll_to_y(serial_Message_Frame, LV_COORD_MAX, LV_ANIM_ON);

    }    
}
void SendMessageText_Display(uint8_t *buf_fifo,GENERAL_SET_STATE *General_State_FIFO,uint8_t Show_Flag)
{
    uint16_t text_len   = 0;
    uint16_t buf_len    = strlen((char*)buf_fifo);
    char Time[11];
    char *buf_ptr = g_cTextBuf_2;
    
    if ((buf_len == 0) || (g_Struct_serial_net_state.is_connected == false))  return;           //空则或者串口没打开则返回
                                            //字符串发送
        memcpy(g_cTextBuf_2,buf_fifo,buf_len);          //可优化
        text_len = buf_len;
        //判断是否需要回车换行(16进制发送不可加回车换行符,只能不是才可添加-参考至SSCOM上位机)
        if (General_State_FIFO->is_NewLine){
            g_cTextBuf_2[text_len]   = 0x0D;            //回车符 \r (0x0D)
            g_cTextBuf_2[text_len+1] = 0x0A;            //换行符 \n (0x0A)
            text_len += 2;                              //因为添加换行符所以字节长度加2
        }  
    //保存显示发送的数据长度
    g_Struct_serial_net_state.serialNet_S_CONUT += text_len;
   USART_DMA_SendData((uint8_t*)g_cTextBuf_2,text_len);
    /*-------------------------------------------------*/
    //判断是否显示发送
    if (General_State_FIFO->is_DisplaySend){   
        //回车判断函数
        text_len = Check_Line_Overflow(g_cTextBuf_1,text_len,g_cTextBuf_2);
        UpdateMessageDisplayFromLVGL(g_cTextBuf_1, text_len, Show_Flag,0);
    }      
    memset(g_cTextBuf_1, 0, text_len);
    memset(g_cTextBuf_2, 0, text_len);
    
}
static void LoopSend_timer_cb(lv_timer_t *timer)
{
    uint8_t i = 0,number = 0,is_Hex_fifo = 0;
 if(g_Struct_General_State.is_TimedSend){
        SendMessageText_Display(g_Struct_serial_net_state.serialSendTextArray,&g_Struct_General_State,g_ucExtendShow_Flag);

    }   
}
  • 写回答

4条回答 默认 最新

  • 阿里嘎多学长 2025-10-30 10:53
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    解决方案

    你遇到的问题是由于LVGL线程被阻塞导致的UI更新延迟。一个解决方案是使用STM32的DMA(直接内存访问)功能来异步更新消息框的文本内容。

    核心代码

    // 定义一个DMA传输描述符
    DMA_HandleTypeDef hdma_dma;
    
    // 定义一个消息框的文本内容缓冲区
    char msg_buf[256];
    
    // 定义一个定时器回调函数
    void TIM1_IRQHandler(void) {
        // 发送消息
        sprintf(msg_buf, "消息%d", i++);
        
        // 配置DMA传输描述符
        hdma_dma.Init.Request = DMA_REQUEST;
        hdma_dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_dma.Init.M0Mode = DMA_M0;
        hdma_dma.Init.PINC = DMA_PINC_DISABLE;
        hdma_dma.Init.MDIo = DMA_MDIo_DISABLE;
        hdma_dma.Init.TransferMode = DMA_TRNSFC_MODE;
        hdma_dma.Init.DataSize = DMA_DATASIZE_8BIT;
        hdma_dma.Init.MaxDataSize = 256;
        hdma_dma.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_dma.Init.MemInc = DMA_MINC_ENABLE;
        hdma_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_dma.Init.NBLAlignment = DMA_NBLALIGN_8BITS;
        hdma_dma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        hdma_dma.Init.Priority = DMA_PRIORITY_HIGH;
        hdma_dma.Init.FIFOToggle = DMA_FIFOTOGGLE_DISABLE;
        hdma_dma.Init.MemBurst = DMA_MBURST_SINGLE;
        hdma_dma.Init.PeriphBurst = DMA_PBURST_SINGLE;
        
        // 启动DMA传输
        HAL_DMA_Start(&hdma_dma);
        
        // 更新消息框的文本内容
        lv_obj_set_text(lv_scr_act(), msg_buf, LV_ALIGN_CENTER);
    }
    
    // 定时器初始化
    void TIM1_Init(void) {
        // 配置定时器
        TIM_TimeBaseInitTypeDef sConfig;
        sConfig.TIM_Prescaler = 0;
        sConfig.TIM_CounterMode = TIM_CounterMode_Up;
        sConfig.TIM_Period = 1000; // 1秒
        sConfig.TIM_ClockDivision = TIM_CKD_DIV1;
        HAL_TIM_Base_Init(&htim1, &sConfig);
        
        // 配置定时器中断
        HAL_NVIC_SetPriority(TIM1_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(TIM1_IRQn);
        
        // 启动定时器
        HAL_TIM_Base_Start(&htim1);
    }
    

    注意

    • 这个解决方案假设你已经配置了STM32的DMA功能和定时器。
    • 你需要根据你的具体需求调整DMA传输描述符和定时器配置。
    • 这个解决方案仅提供了核心代码,具体实现可能需要根据你的项目结构和需求进行调整。
    评论

报告相同问题?

问题事件

  • 创建了问题 10月30日