You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32CubeIDE中toggleButton1无法退出while循环问题求助

问题分析与解决:STM32H750B-DK中toggleButton1无法退出循环的问题

核心问题

你的代码存在两个致命问题:

  • 阻塞式延迟占用CPU:HAL_Delay()是阻塞函数,进入while循环后,CPU会被持续占用在GPIO切换和延迟等待上,导致UI框架(比如TouchGFX)的事件处理线程无法运行,按钮的点击事件得不到响应,toggleButton1.getState()的返回值自然不会更新。
  • 状态检查时机不合理:即使UI能更新状态,你只在四次延迟(总计4秒)后才检查一次按钮状态,用户点击后最多要等4秒才可能触发退出逻辑,体验极差,甚至因为阻塞根本无法更新状态。

解决方案

方案1:非阻塞式逻辑(推荐)

放弃阻塞延迟,用系统滴答定时器记录时间戳,实现非阻塞的GPIO切换,让UI线程能正常处理事件。

// 在Screen1View类中添加成员变量
uint32_t lastToggleTime = 0;
bool isRelayRunning = false;
uint8_t relayStep = 0;

void Screen1View::relay_1()
{
    if(toggleButton1.getState()){
        isRelayRunning = true;
        lastToggleTime = HAL_GetTick();
        relayStep = 0;
    } else {
        isRelayRunning = false;
        // 退出时重置GPIO状态
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_RESET);
    }
}

// 在Screen1View的tick函数中添加逻辑(TouchGFX会定时调用此函数)
void Screen1View::tick()
{
    if(isRelayRunning){
        uint32_t currentTime = HAL_GetTick();
        // 每1秒执行一步GPIO操作
        if(currentTime - lastToggleTime >= 1000){
            lastToggleTime = currentTime;
            switch(relayStep){
                case 0:
                    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_SET);
                    break;
                case 1:
                    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
                    break;
                case 2:
                    HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_SET);
                    break;
                case 3:
                    HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_RESET);
                    break;
            }
            relayStep = (relayStep + 1) % 4;
            
            // 实时检查按钮状态,触发退出
            if(!toggleButton1.getState()){
                isRelayRunning = false;
                HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_RESET);
            }
        }
    }
}

方案2:阻塞循环中主动处理UI事件(临时调试用)

如果一定要保留阻塞逻辑,可在每次延迟后主动调用UI框架的事件处理函数,让按钮状态及时更新:

void Screen1View::relay_1()
{
    if(toggleButton1.getState()){
        while(1){
            HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_SET);
            HAL_Delay(1000);
            // 主动触发TouchGFX事件处理
            touchgfx::HAL::getInstance()->task();
            
            HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
            HAL_Delay(1000);
            touchgfx::HAL::getInstance()->task();
            
            HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_SET);
            HAL_Delay(1000);
            touchgfx::HAL::getInstance()->task();
            
            HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_2, GPIO_PIN_RESET);
            HAL_Delay(1000);
            touchgfx::HAL::getInstance()->task();
            
            if(toggleButton1.getState() == 0){
                break;
            }
        }
    } else {
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);
    }
}

注意:此方法会导致UI响应卡顿,仅适合临时验证问题,长期使用优先选择方案1。

内容的提问来源于stack exchange,提问作者Amadej

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 06:35:49