// Tim Hirzel // Machine state - this file is the espresso machine state // it manages overarching "glue" issues such as connecting temperature readings, PID control, and heat power settings /* from www.ardino.cc: PROGMEM string demo Information summarized from: http://www.nongnu.org/avr-libc/user-manual/pgmspace.html */ // These are addresses into EEPROM memory. The values to be stores are floats which // need 4 bytes each. Thus 0,4,8,12,... #include "EEPROM.h" #include "floatToString.h" boolean espressoState, waterState; boolean shotTimerRunning; unsigned long shotTimeBegin; unsigned long currentTime, lastTime; unsigned long lastPIDTime; // most recent PID update time in ms int elapsedShotSeconds; unsigned long sleepCounter; boolean sleeping = false; boolean temphigh = false; boolean woke = false; float currentTemp; // current actual temperature //byte wakeHour = 25; //byte wakeMinute = 0; // RelayControl // Tim Hirzel Dec 2007 // For the 3 set function 0 = off, 1= on, and -1 = auto toggle void setupRelay(byte pin) { pinMode(pin , OUTPUT); digitalWrite(pin, LOW); } void setRelay(byte pin, boolean on) { digitalWrite(pin, on); } void setupMachineState() { lastPIDTime = millis() + PID_UPDATE_INTERVAL; lastTime = 0; //targetTemp = readFloat(ESPRESSO_TEMP_ADDRESS); // from EEPROM. load the saved value setUseHighTemp(false); setupRelay(SOLENOID_RELAY_PIN); setupRelay(PUMP_RELAY_PIN); setupRelay(GROUND_EFFECT_RELAY_PIN); } //void setWakeTimeHours(float hours) { // writeFloat(hours, WAKE_TIME_ADDRESS); //} char * getWakeString(char *buff) { int hours = (int)readFloat(WAKE_TIME_ADDRESS); int minutes = (int)((readFloat(WAKE_TIME_ADDRESS) - hours) * 60); if (hours < 24 and hours > -1) { floatToString(buff, (float)hours, 0, 2, true, false); if (minutes == 0) { buff[4] = '0'; } else { floatToString(&buff[3], (float)minutes, 0, 2, true, false); } if (minutes< 10) buff[3] = '0'; buff[2] = ':'; buff[5] = '\0'; return buff; } return "never"; } unsigned long getSleepTime() { return sleepCounter; } boolean isSleeping() { return sleeping; } void resetSleep() { sleepCounter = 0; } void updateMachineState() { if (!sleeping) { updateTempSensor(); updateHeater(); currentTime = millis(); // check for one second, or millis() overflow if (shotTimerRunning and (currentTime >= shotTimeBegin)){ elapsedShotSeconds += 1; shotTimeBegin += 1000; } // overflow case //if (currentTime < shotTimeBegin) { // shotTimeBegin = currentTime; // elapsedShotSeconds += 1; //} // every second, update the power using the PID algorithm // This checks for rollover with millis() if ((currentTime >= lastPIDTime) or (currentTime < lastTime)) { sleepCounter += 1; lastPIDTime = currentTime + PID_UPDATE_INTERVAL; if (temphigh) setHeatPowerPercentage(updatePID(readFloat(STEAM_TEMP_ADDRESS), getFreshTemp())); else setHeatPowerPercentage(updatePID(readFloat(ESPRESSO_TEMP_ADDRESS), getFreshTemp())); } if (sleepCounter / 60 > readFloat(SLEEP_MINUTES_ADDRESS)) { machineWakeOrSleep(false); } } else { int hours = (int)readFloat(WAKE_TIME_ADDRESS); if (!woke and hours == readHour() and (int)((readFloat(WAKE_TIME_ADDRESS) - hours) * 60) == readMinute()) { machineWakeOrSleep(true); woke = true; } else { woke = false; } } lastTime = currentTime; } void setShotTimer(boolean on) { if (on) { //shotTimer = True; shotTimeBegin = millis(); elapsedShotSeconds = 0; //started_at = time_count; shotTimerRunning = true; } else { shotTimerRunning = false; } } int getShotTime() { return elapsedShotSeconds; } void machineWakeOrSleep(boolean wakeup) { if (wakeup) { sleeping = false; resetSleep(); lcdBacklightOn(); setRelay(GROUND_EFFECT_RELAY_PIN, true); } else { sleeping = true; lcdBacklightOff(); setRelay(GROUND_EFFECT_RELAY_PIN, false); setHeatPowerPercentage(0.0); updateHeater(); // make sure that the heater gets turned off. } } void espresso(int on) { //toggle if (on == -1) { espressoState = !espressoState; on = espressoState; } else { espressoState = on; } setShotTimer(on); setRelay(SOLENOID_RELAY_PIN, on); setRelay(PUMP_RELAY_PIN, on); resetSleep(); } //void setWand(short on); void water(int on) { // make sure not to shut off the pump while espresso brewing, leaving solenoid if (!espressoState) { if (on == -1){ waterState = !waterState; on = waterState; } else waterState = on; setRelay(PUMP_RELAY_PIN, on); } resetSleep(); } void setUseHighTemp(int on) { if (on == -1) { temphigh = !temphigh; } else temphigh = (boolean) on; resetSleep(); } //void setCurVar(float delta) { // float f; //if (pmode == IGAIN_ADR) { // delta *= 0.01; //} //f = loadfloat(pmode); //f += delta; //savefloat(f,pmode); // resetSleep(); //} //void selectCurVar(int delta) { //pmode += delta; //if (pmode == VAR_NUM+1) pmode = 1; //if (pmode == 0) pmode = VAR_NUM; // resetSleep(); //} //char * getCurrentVariableName() { // return currentVariableName; //} /************************************************************************ * TIMER FUNCTIONS ************************************************************************/ /* #int_rtcc clock_isr() { if(--time_count==0) { ++seconds_on; time_count = INTS_PER_SECOND; } if (runtimer == 1 && time_count == started_at) ++shottime; } */