如何在液体加注的while循环中实现按键暂停/恢复功能?
液体加注循环中暂停/恢复功能失效的解决方案
问题概述
实现了通过while循环控制液体加注至目标重量的Mezclas::echarLiquido函数,尝试添加暂停/恢复功能但未生效,但同个暂停按键在液体耗尽的逻辑中可正常触发恢复操作。
原代码(含语法错误)
void Mezclas::echarLiquido(int16_t pesoPorechar) { // Encender la bomba correspondiente encenderBombaCorrespondiente(); unsigned long tiempoInicioMezcla = millis(); unsigned long tiempoUltimaVariacion = millis(); pesoLiquido = PesoActual(); pesoRelative = 0; EEPROM.get(PESO_RELATIVO_ADDRESS, pesoRelative); // Mostrar el mensaje adecuado en el LCD mostrarLiquido(); delay(50); // Condition to attempt the weight goal while (pesoRelative < pesoPorechar) { // Pause button is pressed if(botonPausa.pulsado()) { delay(20); pausarReanudarMezcla(); } // Resuming the function if (enPausa) { esperarParaReanudar(); } // Condition of the time error pomp if (millis() - tiempoInicioMezcla > tiempoErrorBomba) { lcd.clear(); delay(20); lcd.setCursor(1,0); lcd.print("ERROR BOMBA"); delay(8000); apagarBombas(); return; } mostrarLiquido(); int16_t nuevoPesoActual = PesoActual(); if (nuevoPesoActual != pesoLiquido) { tiempoUltimaVariacion = millis(); // Reiniciar el temporizador si hay cambio en el peso } // if the weight don't increase it mean's the liquid is exhausted if (millis() - tiempoUltimaVariacion > 15000) // Si no hay cambio en el peso por 5 segundos { mostrarAgotado(); apagarBombas(); // wait until the pause button is pressed to continue and resuming while (!botonAgotado.pulsado()) { delay(300); } // Reiniciar la bomba correspondiente encenderBombaCorrespondiente(); // Reiniciar el tiempo de última variación tiempoUltimaVariacion = millis(); } // resuming the section of the liauid measurement nuevoPesoActual = PesoActual(); pesoRelative += nuevoPesoActual - pesoLiquido; pesoLiquido = nuevoPesoActual; EEPROM.put(PESO_RELATIVO_ADDRESS, pesoRelative); updateProgressBar(pesoRelative, pesoPorechar, 1); delay(500); } // The end of the function pesoLiquido = PesoActual(); EEPROM.put(PESO_ACEITE_ACTUAL_ADRESS, pesoLiquido); EEPROM.put(PESO_RELATIVO_ADDRESS, 0); // Apagar la bomba correspondiente apagarBombas(); delay(1000); // 语法错误:C++不允许函数嵌套定义,此处两个函数不能放在echarLiquido内部 void Mezclas::pausarReanudarMezcla() { enPausa = !enPausa; if (enPausa) { Pantallamezcla(8); } else { Pantallamezcla(9); delay(3000); } } void Mezclas::esperarParaReanudar() { while (enPausa) { // Esperar hasta que se reanude la mezcla if (botonPausa.pulsado()) { pausarReanudarMezcla(); } } } } // 多余的闭合括号
问题分析
- 语法错误:C++不允许函数嵌套定义,
pausarReanudarMezcla和esperarParaReanudar被错误地放在了echarLiquido函数内部,导致编译失败,功能根本无法运行。 - 暂停时未停止油泵:进入暂停状态后,油泵仍在运行,导致液体继续加注,违背暂停的预期。
- 阻塞式延迟影响按键响应:主循环中的
delay(500)会阻塞程序,导致暂停按键的检测不及时;esperarParaReanudar中的循环没有添加短延迟,可能导致CPU占用过高,同时按键检测可能受抖动影响。 - 恢复逻辑缺失油泵重启:恢复时没有重新开启油泵,导致暂停后无法继续加注。
修复方案
1. 修正代码结构
将pausarReanudarMezcla和esperarParaReanudar移至echarLiquido函数外部,确保符合C++语法规范。
2. 完善暂停/恢复逻辑
- 暂停时关闭油泵,恢复时重新开启油泵
- 优化按键检测,添加防抖处理,避免阻塞
- 调整延迟逻辑,确保按键响应及时
修复后的完整代码
// 修正:将函数移至echarLiquido外部 void Mezclas::pausarReanudarMezcla() { enPausa = !enPausa; if (enPausa) { Pantallamezcla(8); apagarBombas(); // 暂停时关闭油泵 } else { Pantallamezcla(9); encenderBombaCorrespondiente(); // 恢复时重新开启油泵 delay(3000); // 给用户留够查看恢复提示的时间 } } void Mezclas::esperarParaReanudar() { while (enPausa) { if (botonPausa.pulsado()) { delay(20); // 防抖处理 if (botonPausa.pulsado()) // 再次确认按键按下 { pausarReanudarMezcla(); } } delay(50); // 降低CPU占用,同时保证按键响应 } } void Mezclas::echarLiquido(int16_t pesoPorechar) { encenderBombaCorrespondiente(); unsigned long tiempoInicioMezcla = millis(); unsigned long tiempoUltimaVariacion = millis(); pesoLiquido = PesoActual(); pesoRelative = 0; EEPROM.get(PESO_RELATIVO_ADDRESS, pesoRelative); mostrarLiquido(); delay(50); while (pesoRelative < pesoPorechar) { // 检测暂停按键,添加防抖 if(botonPausa.pulsado()) { delay(20); if(botonPausa.pulsado()) { pausarReanudarMezcla(); } } // 进入暂停等待逻辑 if (enPausa) { esperarParaReanudar(); // 恢复后重置时间计数器,避免误触发超时错误 tiempoInicioMezcla = millis(); tiempoUltimaVariacion = millis(); } // 油泵超时错误检测 if (millis() - tiempoInicioMezcla > tiempoErrorBomba) { lcd.clear(); delay(20); lcd.setCursor(1,0); lcd.print("ERROR BOMBA"); delay(8000); apagarBombas(); return; } mostrarLiquido(); int16_t nuevoPesoActual = PesoActual(); if (nuevoPesoActual != pesoLiquido) { tiempoUltimaVariacion = millis(); } // 液体耗尽处理 if (millis() - tiempoUltimaVariacion > 15000) { mostrarAgotado(); apagarBombas(); while (!botonAgotado.pulsado()) { delay(50); // 优化延迟,降低CPU占用 } encenderBombaCorrespondiente(); tiempoUltimaVariacion = millis(); tiempoInicioMezcla = millis(); // 重置超时计数器 } nuevoPesoActual = PesoActual(); pesoRelative += nuevoPesoActual - pesoLiquido; pesoLiquido = nuevoPesoActual; EEPROM.put(PESO_RELATIVO_ADDRESS, pesoRelative); updateProgressBar(pesoRelative, pesoPorechar, 1); delay(500); } // 加注完成处理 pesoLiquido = PesoActual(); EEPROM.put(PESO_ACEITE_ACTUAL_ADRESS, pesoLiquido); EEPROM.put(PESO_RELATIVO_ADDRESS, 0); apagarBombas(); delay(1000); }
关键修改说明
- 语法修正:将嵌套的函数移至外部,确保代码能正常编译。
- 暂停时停泵:在
pausarReanudarMezcla的暂停分支中调用apagarBombas(),恢复时调用encenderBombaCorrespondiente()。 - 防抖处理:在按键检测时添加短延迟后再次确认,避免误触发。
- 时间重置:恢复后重置
tiempoInicioMezcla和tiempoUltimaVariacion,防止暂停期间的时间累积触发超时错误。 - 优化CPU占用:在等待循环中添加短延迟,避免CPU满负荷运行。
内容的提问来源于stack exchange,提问作者Abdelhak El Alaoui
相关产品推荐
相关产品推荐

