【背景】有一个自复位按钮和灯,按下按钮后灯亮,松开则灭,但是按钮连续按下超3S后,灯一直亮。此时再按一下,灯灭。【思路】看似需求非常简单,其实涉及定时器、上升沿触发、辅助状态知识。问AI,确实可以给出一堆代码,但代码复杂且测试结果偏离预期,于是决定采用经典状态机思路实现。灯的状态实际只有两种 那就是亮和灭;那么就看两种状态之间怎么实现切换?第一层思维是状态为灯灭时,如果按下按钮,状态变为灯亮,此时如果松开按钮,状态变为灯灭,这样已经实现了最简单的点动效果。模拟行车控制完全可以。
第二层思维是考虑延时,灯亮时,如果此时发现前面按的时间超过了3S,即使此时按钮松开,仍然保持灯亮状态。那怎么让灯再灭哪?不能一直亮下去吧?且看第三层。第三层思维是即使“前一次按的时间不足3S”成为实际记录,但借助一个辅助Bool量,让这个条件变为FALSE。那这个辅助Bool量怎么实现哪?可以在“前一次按的时间3S”时,如果察觉按钮上升沿,则清算一下,即否定“前一次按的时间3S”,从而仍然履行上面的状态机模式。
// 计时器控制 - 按钮按下时开始计时Timer(IN := Button, PT := T#3S);Rtrig01(CLK:=BUTTON,Q=>);//按钮上升沿检测IF Timer.Q THEN TimerTriggered:=1;//一旦按压时间足够,变量赋TRUE;END_IF
IF TimerTriggered=1 AND Rtrig01.Q THEN//即使前面按的时间超过3S,但是此时按钮上升沿可以让其失效 TimerTriggered:=0; END_IF
CASE curState OF
0://灯灭状态
Light:=0;//灯灭IF Button AND NOT TimerTriggered THEN curState:=1;//切换到灯亮状态END_IF
1://灯亮状态
Light:=1;//灯亮IF NOT Button AND NOT TimerTriggered THEN curState:=0;//切换到灯灭状态END_IF
//第二种情况,按下3秒常亮,再按下熄灭;
ton1(IN:=bButton,PT:=T#3S);
R_trig1(CLK:=bButton);
IF ton1.Q THEN
blighton2:=TRUE;
END_IF
IF R_trig1.Q AND blighton2 =1 THEN
blighton2:=FALSE;
END_IF;