我正在开发一个 Arduino 项目来管理继电器开关的时序,该项目由 4 个继电器、3 个按钮和一个 7 段显示器组成。虽然我已经完成了设置,但我正在努力设计一个系统,用户可以使用三个按钮和 7 段显示器来调整继电器的开/关持续时间。下面是我的代码:
#define CLK 2
#define DIO 3
TM1637Display display(CLK, DIO);
int relayPins[] = {4, 5, 6, 7};
int onTimes[] = {2000, 4000, 5000, 3000};
int offTimes[] = {1000, 2000, 1000, 3000};
void setup() {
for (int i = 0; i < 4; i++) {
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], LOW);
}
display.setBrightness(0x0f);
}
void loop() {
for (int i = 0; i < 4; i++) {
digitalWrite(relayPins[i], HIGH);
for (int j = onTimes[i] / 1000; j > 0; j--) {
display.showNumberDec(j, false, 2, 0);
delay(1000);
}
digitalWrite(relayPins[i], LOW);
for (int j = offTimes[i] / 1000; j > 0; j--) {
display.showNumberDec(j, false, 2, 0);
delay(1000);
}
}
}
我需要帮助实现一种机制,用户可以使用按钮和显示屏调整每个继电器的开/关持续时间。我该如何修改这段代码来实现这一目标?
在尝试修改用户可调时序的变量时,我最初尝试集成其他函数来读取按钮的状态并相应地更新 onTimes[] 和 offTimes[] 数组。然而,我在将按钮输入与每个继电器的时间间隔正确同步方面遇到了困难。具体来说,我努力根据用户输入有效地更新定时变量,同时确保平稳的继电器操作和显示更新。我期望成功实现一个系统,用户可以使用按钮交互式地调整计时持续时间,并观察 7 段显示屏上反映的变化
为了使 Arduino“大循环”框架有效工作,您应该将设计分解为单独的非阻塞状态机。当然,如果您希望能够同时处理中继切换和用户交互,您应该避免阻塞
delay()
调用。
事实上,您现有的实现无论如何都会被破坏,因为它按顺序执行每个继电器的开-关-切换,因此每个继电器的关闭时间将是其他三个继电器的开+关时间的总和。
如果您按如下方式更改
loop()
功能:
void loop()
{
relay_statemachine() ;
ui_statemachine() ;
}
然后,同时运行所有四个继电器开关周期并且不阻塞(即总是立即返回,以便
relay_statemachine()
可以运行)的 ui_statemachine()
实现可能如下所示:
void relay_statemachine()
{
static struct
{
int state ; // current relay state
int timestamp ; // time of last relay state change
} relay[] = { 0 } ;
// Current time
unsigned long now = millis() ;
// For each realy
for( int r = 0; r < 4; r++ )
{
// If relay is off...
if( relay[r].state == LOW )
{
// ... if it is time to switch ...
if( now - relay[r].timestamp > offTimes[r] )
{
// ... change state and timestamp it
relay[r].state = HIGH ;
relay[r].timestamp = now ;
}
}
else // ... else relay is on...
{
// ... if it is time to switch ...
if( now - relay[r].timestamp > onTimes[r] )
{
// ... change state and timestamp it
relay[r].state = LOW ;
relay[r].timestamp = now ;
}
}
// Assert current relay state.
digitalWrite (relayPins[r], relay[r].state ) ;
}
}
然后,您可以类似地将
ui_statemachine()
实现为状态机(没有延迟或阻塞),其中触发器是按钮事件(不要忘记需要去抖)。您尚未定义 UI 将如何工作,但我建议: