一、要求分析
利用状态机程序思想,使用MSP-EXP430F5529 Launchpad板卡实现以下模拟饮水机的功能。
饮水机是我们生活中常见的家用设备。假设一个简易的饮水机有两个按键:童锁按键[PUSH1]和热水按键[PUSH2]。
按键功能说明: 1.童锁按键: ① 平时“童锁按键”处于锁定状态[RED_LED初始化条件],长按“童锁按键”3秒后进入解锁状态[长按PUSH1事件]; ② 如果“童锁按键”处于解锁状态,3秒内没有按下“热水按键”,“童锁按键”回到锁定状态[闲置PUSH2事件]。 2.热水按键: ①“童锁按键”处于锁定状态时,按下“热水按键”不起作用(不放水)
[无用限制条件]; ② “童锁按键”处于解锁状态时,单击“热水按键”(按键释放有效)进入放水状态,开 始放水[松开PUSH2事件]; ③ 处于放水状态时,双击“热水按键”(按键释放有效),停止放热水,“童锁按键” 回到锁定状态[松开PUSH2事件]; ③ 处于放水状态时,按“童锁按键”不起作用[放水时童锁一定解锁,按童锁键是为了解锁,本身成立]。 ④在解锁状态时,长按“热水按键”超过3秒不放,不会自动回到“锁定状态”,按“童锁按键”也不起作用。[这里的长按具有迷惑性,根据前面其他描述,恢复锁定状态的条件是通过PUSH2未按下时作出闲置响应,但是按下了PUSH2后,PUSH2处于按击状态,不用考虑恢复锁定的问题] 。请设计程序,模拟饮水机的工作。PUSH1为“童锁按键”,PUSH2为“热水按键”;锁定状态红 色LED亮,解锁状态红色LED灭;放水状态绿色LED亮。
二、完整代码 (仅供参考!!!)
#include "Timer.h"
int ChildLockState=0; //童锁状态,0锁定,1解锁
int ChildLockButtonState=0; //童锁按键(PUSH1)状态,0闲置,1短按,2长按
int WaterState=0; // 放水状态,0不放水,1放水
int WaterButtonState=0; //热水按键(PUSH2)状态,0闲置,1单击/双击[通过两次松开间隔判断](不区分短按/长按)
int LastClButton=1;
int CurClButton=1;
int LastWButton=1;
int CurWButton=1;
int ClCnt=0; //童锁按键长按计时器
int WCnt_Empty=0; //热水按键闲置计数器
int DoubleFlag=0;
int DoubleCnt=0;
void setup() {
pinMode(PUSH1,INPUT_PULLUP);
pinMode(PUSH2,INPUT_PULLUP);
pinMode(RED_LED,OUTPUT);
pinMode(GREEN_LED,OUTPUT);
digitalWrite(RED_LED,HIGH); //初始童锁锁定,红色LED亮
digitalWrite(GREEN_LED,LOW); //初始处于未放水状态,绿色LED灭
SetTimer(irsTimer,20); //设置定时中断计时器,中断周期为20ms
Serial.begin(9600);
}
void loop() {
}
void irsTimer()
{
if(DoubleFlag) DoubleCnt++;
int ClButton=0; //童锁按键瞬时状态,0无改变,1按下,2松开
int WButton=0; //热水按键瞬时状态,0无改变,1按下,2松开
//按键消抖,检测按键变化(1、童锁;2、热水按键)
//1、检测童锁按键变化
CurClButton=digitalRead(PUSH1);
if(CurClButton!=LastClButton)
{
if(CurClButton==LOW) ClButton=1;
else ClButton=2;
}
//2.检测热水按键变化
CurWButton=digitalRead(PUSH2);
if(CurWButton!=LastWButton)
{
if(CurWButton==LOW) WButton=1;
else WButton=2;
}
//检测按键状态
//检测童锁按键状态
switch(ChildLockButtonState)
{
case 0:
if(ClButton==1)
{
ChildLockButtonState=1; //若按下按键,切换为短按状态
ClCnt=0;
}
break;
case 1:
if(ClButton==2)
{
ChildLockButtonState=0; //若松开按键,切换为闲置状态
ClCnt=0;
}
else if(ClButton==0) //如果按键状态未改变,则开始计数
{
ClCnt++;
if(ClCnt>=150) //3s/20ms=150
{
ChildLockButtonState=2; //达到计数门限,切换为长按状态
ClCnt=0;
}
}
break;
case 2:
//长按童锁时,解锁童锁(不放水状态时)
if(ClButton==0){
ChildLockState=1;
ChildUnlocked();
WCnt_Empty=0;
}
if(ClButton==2) {
ChildLockButtonState=0;
}
break;
}
switch(WaterButtonState)
{
case 0:
if(WButton==0)
{
if(WaterState==0&&ChildLockState==1)
{
Serial.println(WCnt_Empty);
WCnt_Empty++;
if (WCnt_Empty>=150)
{
WCnt_Empty=0;
ChildLockState=0; //3s未按热水按键,锁定童锁
ChildLocked();
}
}
}
if(WButton==1)
WaterButtonState=1; //若按下按键,切换为短按状态
break;
case 1:
if(WButton==2) //完整短按一次热水按键,若童锁已解锁则放水
{
//区分单击和双击
if(!DoubleFlag||DoubleCnt>15) //单击事件处理
{
if(!DoubleFlag) DoubleFlag=1;
if(ChildLockState==1&&WaterState==0)
{
WaterState=1;
InWater();
}
DoubleCnt=0;//计时器归零
}
else{ //双击事件处理
if(ChildLockState==1&&WaterState==1)
{
ChildLockState=0;
ChildLocked();
WaterState=0;
NoWater();
}
DoubleCnt=0;
}
WaterButtonState=0;
WCnt_Empty=0;
}
break;
case 2:
}
LastClButton=CurClButton;
LastWButton=CurWButton;
}
void NoWater()
{
digitalWrite(GREEN_LED,LOW);
}
void InWater()
{
digitalWrite(GREEN_LED,HIGH);
}
void ChildLocked()
{
digitalWrite(RED_LED,HIGH);
}
void ChildUnlocked()
{
digitalWrite(RED_LED,LOW);
}