1

Тема: Варим пиво с Ардуино

Приветствую всех.

Недавно ко мне обратились за помощью в написании скетча для варки пива smile.
Скажем так хочу поделиться им с вами.

Процесс прост, в резервуар подается пар, а Ардуино в свое время контролирует температуру открывая или закрывая клапан подачи холодной воды в контур резервуара.

Для воссоздания вам понадобиться:

  • Arduino UNO - Контроллер

  • Arduino Keypad Shield - Дисплей + кнопки

  • RTC DS1302 - Часы

  • 5В Реле

  • Термометр DS18B20 влагозащищенный + резистор 4.7 кОм

  • Электромагнитный (соленоидный) клапан 12В

Ну и собственно сам скетч

#include <iarduino_RTC.h>
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <CyberLib.h>

// Кнопки.
const byte BUTTON_NONE   = 0; 
const byte BUTTON_RIGHT  = 1;
const byte BUTTON_UP     = 2;
const byte BUTTON_DOWN   = 3;
const byte BUTTON_LEFT   = 4;
const byte BUTTON_SELECT = 5;
static byte currentButtonState, previousButtonState = BUTTON_NONE;

// Дисплей.
LiquidCrystal lcdDisplay(8, 9, 4, 5, 6, 7);
const byte MENU_MAIN = 0;
const byte MENU_DATETIME = 101;  
volatile byte currentMode = MENU_MAIN;
volatile byte dtPos = 255;
volatile bool cBlink = false;
  
// Температура.
OneWire oneWire(12);
DallasTemperature tempSensor(&oneWire);
uint8_t degree[8] = {140, 146, 146, 140, 128, 128, 128, 128};
volatile float currTemp = DEVICE_DISCONNECTED_C;
volatile float workTemp = DEVICE_DISCONNECTED_C;
const float deadzone = 0.5;

// Часы.
iarduino_RTC timeModule(RTC_DS1302, 11, 3, 2);
#define LEAP_YEAR(_year) ((_year % 4) == 0)
static byte monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

// Работа.
struct datetime {
  byte seconds = 0;
  byte minutes = 0;
  byte hours   = 0;
  byte day     = 0;
  byte month   = 0;
  byte year    = 0;
};
volatile datetime currentTime;
volatile datetime editTime;
volatile datetime procTime;
volatile datetime step0Time;
volatile datetime step1Time;
volatile datetime step2Time;
volatile datetime step3Time;
volatile datetime step4Time;
volatile datetime step5Time;
volatile datetime step6Time;
volatile datetime step7Time;
volatile datetime step8Time;
volatile datetime step9Time;
volatile byte editTemp;
volatile byte step0Temp;
volatile byte step1Temp;
volatile byte step2Temp;
volatile byte step3Temp;
volatile byte step4Temp;
volatile byte step5Temp;
volatile byte step6Temp;
volatile byte step7Temp;
volatile byte step8Temp;
volatile byte step9Temp;
volatile byte procStart;

// Получить текущее время и дату.
datetime getDatetime()
{
  datetime dt;
  timeModule.gettime();
  dt.seconds = timeModule.seconds;
  dt.minutes = timeModule.minutes;
  dt.hours   = timeModule.Hours;
  dt.day     = timeModule.day;
  dt.month   = timeModule.month;
  dt.year    = timeModule.year;
  return dt;  
}

void copyDatetime(volatile datetime * d1, volatile datetime * d2)
{
  d1->seconds = d2->seconds;
  d1->minutes = d2->minutes;
  d1->hours   = d2->hours;
  d1->day     = d2->day;
  d1->month   = d2->month;
  d1->year    = d2->year;
}

// Установить время и дату.
void setDatetime(volatile datetime * dt)
{
  timeModule.settime(dt->seconds, dt->minutes, dt->hours);
  timeModule.settime(-1, -1, -1, dt->day, dt->month, dt->year);
}

// Прочитать из EEPROM дату и время.
datetime readDatetime(int Pos, volatile datetime * dt)
{
  dt->seconds = ReadEEPROM_Byte(Pos + 0);
  dt->minutes = ReadEEPROM_Byte(Pos + 1);
  dt->hours   = ReadEEPROM_Byte(Pos + 2);
  dt->day     = ReadEEPROM_Byte(Pos + 3);
  dt->month   = ReadEEPROM_Byte(Pos + 4);
  dt->year    = ReadEEPROM_Byte(Pos + 5);
}

// Прочитать из EEPROM время.
datetime readTime(int Pos, volatile datetime * dt)
{
  dt->seconds = ReadEEPROM_Byte(Pos + 0);
  dt->minutes = ReadEEPROM_Byte(Pos + 1);
  dt->hours   = ReadEEPROM_Byte(Pos + 2);
  dt->day     = 0;
  dt->month   = 0;
  dt->year    = 0;
}

// Записать в EEPROM дату и время.
void writeDatetime(int Pos, volatile datetime * dt)
{
  WriteEEPROM_Byte(Pos + 0, dt->seconds);
  WriteEEPROM_Byte(Pos + 1, dt->minutes);
  WriteEEPROM_Byte(Pos + 2, dt->hours);
  WriteEEPROM_Byte(Pos + 3, dt->day);
  WriteEEPROM_Byte(Pos + 4, dt->month);
  WriteEEPROM_Byte(Pos + 5, dt->year);
}

// Записать в EEPROM время.
void writeTime(int Pos, volatile datetime * dt)
{
  WriteEEPROM_Byte(Pos + 0, dt->seconds);
  WriteEEPROM_Byte(Pos + 1, dt->minutes);
  WriteEEPROM_Byte(Pos + 2, dt->hours);
  WriteEEPROM_Byte(Pos + 3, 0);
  WriteEEPROM_Byte(Pos + 4, 0);
  WriteEEPROM_Byte(Pos + 5, 0);
}
    
// Получение текущей нажатой кнопки.
byte getPressedButton()
{
  int buttonValue = A0_Read;  
  if (buttonValue < 100) return BUTTON_RIGHT;  else
  if (buttonValue < 200) return BUTTON_UP;     else
  if (buttonValue < 400) return BUTTON_DOWN;   else
  if (buttonValue < 600) return BUTTON_LEFT;   else
  if (buttonValue < 800) return BUTTON_SELECT; else
  return BUTTON_NONE;
}

// Обработка мирцающего курсора в редакторах.
void cursorBlink(byte col, byte row)
{
  cBlink = !cBlink;
  lcdDisplay.setCursor(col, row);
  if (cBlink) lcdDisplay.cursor(); else lcdDisplay.noCursor(); 
}

// Преобразование даты и времени в timestamp (количество секунд прошедших с 1 января 1970 года).
unsigned long makeDateTime(byte sec, byte min, byte hour, byte day, byte month, int year)
{
  int i;
  unsigned long seconds = 0;
  if (year < 69) year += 2000;
  seconds = (year - 1970) * (60 * 60 * 24L * 365);
  for (i = 1970; i < year; i++)
    if (LEAP_YEAR(i)) seconds += 60 * 60 * 24L;
  for (i = 0; i< month; i++)
    if (i == 1 && LEAP_YEAR(year)) seconds += 60 * 60 * 24L * 29; else seconds += 60 * 60 * 24L * monthDays[i];
  seconds += (day - 1) * 3600 * 24L;
  seconds += (hour * 3600L) + (min * 60L) + sec;
  return seconds; 
}

// Преобразование времени в количество секунд.
unsigned long makeTime(byte sec, byte min, byte hour)
{
  return (hour * 3600L) + (min * 60L) + sec; 
}

// Обработка нажатия кнопки.
void ButtonEventProc(byte buttonIndex)
{  
  switch(buttonIndex)
  {
    case BUTTON_SELECT:
      if (currentMode) currentMode = 0; else currentMode = 1;
      dtPos = 255;
      break;
    case BUTTON_LEFT:
      dtPos = 255;
      if (currentMode == MENU_DATETIME)
      {
        setDatetime(&editTime);
        currentMode = MENU_MAIN;
      }
      if (currentMode == 104)
      {
        writeTime(100, &editTime);
        WriteEEPROM_Byte(200, editTemp);
        copyDatetime(&step0Time, &editTime);
        step0Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 105)
      {
        writeTime(110, &editTime);
        WriteEEPROM_Byte(210, editTemp);
        copyDatetime(&step1Time, &editTime);
        step1Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 106)
      {
        writeTime(120, &editTime);
        WriteEEPROM_Byte(220, editTemp);
        copyDatetime(&step2Time, &editTime);
        step2Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 107)
      {
        writeTime(130, &editTime);
        WriteEEPROM_Byte(230, editTemp);
        copyDatetime(&step3Time, &editTime);
        step3Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 108)
      {
        writeTime(140, &editTime);
        WriteEEPROM_Byte(240, editTemp);
        copyDatetime(&step4Time, &editTime);
        step4Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 109)
      {
        writeTime(150, &editTime);
        WriteEEPROM_Byte(250, editTemp);
        copyDatetime(&step5Time, &editTime);
        step5Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 110)
      {
        writeTime(160, &editTime);
        WriteEEPROM_Byte(260, editTemp);
        copyDatetime(&step6Time, &editTime);
        step6Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 111)
      {
        writeTime(170, &editTime);
        WriteEEPROM_Byte(270, editTemp);
        copyDatetime(&step7Time, &editTime);
        step7Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 112)
      {
        writeTime(180, &editTime);
        WriteEEPROM_Byte(280, editTemp);
        copyDatetime(&step8Time, &editTime);
        step8Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      if (currentMode == 113)
      {
        writeTime(190, &editTime);
        WriteEEPROM_Byte(290, editTemp);
        copyDatetime(&step9Time, &editTime);
        step9Temp = editTemp;
        currentMode = MENU_MAIN;
      }
      break;
    case BUTTON_RIGHT:
      if (currentMode == 1)
      {
        currentMode = MENU_DATETIME;
        copyDatetime(&editTime, &currentTime);      
      }
      if (currentMode == 2)
      {
        procStart = 1;
        WriteEEPROM_Byte(1, procStart);
        copyDatetime(&procTime, &currentTime); 
        writeDatetime(10, &procTime);
        currentMode = MENU_MAIN;
      }
      if (currentMode == 3)
      {
        procStart = 0;
        WriteEEPROM_Byte(1, procStart);
        currentMode = MENU_MAIN;
      }
      if (currentMode == 4)
      {
        copyDatetime(&editTime, &step0Time);
        editTemp = step0Temp;
        currentMode = 104;
      }
      if (currentMode == 5)
      {
        copyDatetime(&editTime, &step1Time);
        editTemp = step1Temp;
        currentMode = 105;
      }
      if (currentMode == 6)
      {
        copyDatetime(&editTime, &step2Time);
        editTemp = step2Temp;
        currentMode = 106;
      }
      if (currentMode == 7)
      {
        copyDatetime(&editTime, &step3Time);
        editTemp = step3Temp;
        currentMode = 107;
      }
      if (currentMode == 8)
      {
        copyDatetime(&editTime, &step4Time);
        editTemp = step4Temp;
        currentMode = 108;
      }
      if (currentMode == 9)
      {
        copyDatetime(&editTime, &step5Time);
        editTemp = step5Temp;
        currentMode = 109;
      }
      if (currentMode == 10)
      {
        copyDatetime(&editTime, &step6Time);
        editTemp = step6Temp;
        currentMode = 110;
      }
      if (currentMode == 11)
      {
        copyDatetime(&editTime, &step7Time);
        editTemp = step7Temp;
        currentMode = 111;
      }
      if (currentMode == 12)
      {
        copyDatetime(&editTime, &step8Time);
        editTemp = step8Temp;
        currentMode = 112;
      }
      if (currentMode == 13)
      {
        copyDatetime(&editTime, &step9Time);
        editTemp = step9Temp;
        currentMode = 113;
      }
      if (currentMode >= 4 && currentMode <= 13)
      {
        editTime.day = 0;
        editTime.month = 0;
        editTime.year = 0;
        if (editTime.seconds = 255) editTime.seconds = 0;
        if (editTime.minutes = 255) editTime.minutes = 0;
        if (editTime.hours = 255) editTime.hours = 0;
        if (editTemp = 255) editTemp = 0;
      } 
      if (currentMode == MENU_DATETIME)
      {
        dtPos++;
        if (dtPos > 5) dtPos = 0;
      }
      if (currentMode >= 104 && currentMode <= 113)
      {
        dtPos++;
        if (dtPos > 3) dtPos = 0;
      } 
      break;
    case BUTTON_UP:
      if (currentMode > 0 && currentMode < 100)
      { 
        currentMode++;
        if (currentMode > 13) currentMode = 1;
      }
      if (currentMode == MENU_DATETIME)
      {
        switch (dtPos)
        {
          case 0: editTime.day++;     if (editTime.day > 31)     editTime.day = 1;     break;
          case 1: editTime.month++;   if (editTime.month > 12)   editTime.month = 1;   break;
          case 2: editTime.year++;    if (editTime.year > 30)    editTime.year = 17;   break;
          case 3: editTime.hours++;   if (editTime.hours > 23)   editTime.hours = 0;   break;
          case 4: editTime.minutes++; if (editTime.minutes > 59) editTime.minutes = 0; break;
          case 5: editTime.seconds++; if (editTime.seconds > 59) editTime.seconds = 0; break;
        }
      }
      if (currentMode >= 104 && currentMode <= 113)
      {
        switch (dtPos)
        {
          case 0: editTime.hours++; break;
          case 1: editTime.minutes++; if (editTime.minutes > 59) editTime.minutes = 0; break;
          case 2: editTime.seconds++; if (editTime.seconds > 59) editTime.seconds = 0; break;
          case 3: editTemp++; break;
        }
      } 
      break;
    case BUTTON_DOWN:
      if (currentMode > 0 && currentMode < 100)
      { 
        currentMode--;
        if (currentMode < 1) currentMode = 13;
      }
      if (currentMode == MENU_DATETIME)
      {
        switch (dtPos)
        {
          case 0: editTime.day--;     if (editTime.day < 1)      editTime.day = 31;     break;
          case 1: editTime.month--;   if (editTime.month < 1)    editTime.month = 12;   break;
          case 2: editTime.year--;    if (editTime.year < 17)    editTime.year = 30;    break;
          case 3: editTime.hours--;   if (editTime.hours > 23)   editTime.hours = 23;   break;
          case 4: editTime.minutes--; if (editTime.minutes > 59) editTime.minutes = 59; break;
          case 5: editTime.seconds--; if (editTime.seconds > 59) editTime.seconds = 59; break;
        }
      }
      if (currentMode >= 104 && currentMode <= 113)
      {
        switch (dtPos)
        {
          case 0: editTime.hours--; break;
          case 1: editTime.minutes--; if (editTime.minutes > 59) editTime.minutes = 59; break;
          case 2: editTime.seconds--; if (editTime.seconds > 59) editTime.seconds = 59; break;
          case 3: editTemp--; break;
        }
      } 
      break;
  }
  if (!currentMode && buttonIndex == BUTTON_NONE)
  {
    lcdDisplay.clear();
    lcdDisplay.noCursor(); 
  }
}

// Отрисовка экрана.
void Draw(byte menu)
{
  char rowBuffer[16];
  switch(menu)
  {
    case MENU_MAIN:
      if (currTemp == DEVICE_DISCONNECTED_C)
      {
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("TEMP SENSOR:    ");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("DEVICE ERROR    ");
      } else {
        // Текущая Дата и Время.
        lcdDisplay.setCursor(8, 0);
        sprintf(rowBuffer, "%02d.%02d.%02d", currentTime.day, currentTime.month, currentTime.year);
        lcdDisplay.print(rowBuffer);
        lcdDisplay.setCursor(8, 1);
        sprintf(rowBuffer, "%02d:%02d:%02d", currentTime.hours, currentTime.minutes, currentTime.seconds);
        lcdDisplay.print(rowBuffer);
        // Текущая температура.
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print(currTemp, 1);
        lcdDisplay.write((uint8_t)0);
        lcdDisplay.print("C  ");
        // Уставка.
        lcdDisplay.setCursor(0, 1);
        if (workTemp != DEVICE_DISCONNECTED_C)
        {
          lcdDisplay.print(workTemp, 1);
          lcdDisplay.write((uint8_t)0);
          lcdDisplay.print("C  ");        
        } else lcdDisplay.print("        ");
      }
      break;
      case 1:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET DATE/TIME   ");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 2:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("PROCESS START   ");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 3:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("PROCESS STOP    ");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 4:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 1  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 5:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 2  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 6:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 3  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 7:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 4  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 8:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 5  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 9:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 6  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 10:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 7  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 11:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 8  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 12:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 9  CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case 13:
        lcdDisplay.setCursor(0, 0);
        lcdDisplay.print("SET STEP 10 CONF");
        lcdDisplay.setCursor(0, 1);
        lcdDisplay.print("RIG-SET  SEL-ESC");
      break;
      case MENU_DATETIME:
        lcdDisplay.setCursor(0, 0);
        sprintf(rowBuffer, "%02d.%02d.%02d LEF-SET", editTime.day, editTime.month, editTime.year);
        lcdDisplay.print(rowBuffer);
        lcdDisplay.setCursor(0, 1);
        sprintf(rowBuffer, "%02d:%02d:%02d SEL-ESC", editTime.hours, editTime.minutes, editTime.seconds);
        lcdDisplay.print(rowBuffer);
        switch (dtPos)
        {
          case 0: cursorBlink(1, 0); break;
          case 1: cursorBlink(4, 0); break;
          case 2: cursorBlink(7, 0); break;
          case 3: cursorBlink(1, 1); break;
          case 4: cursorBlink(4, 1); break;
          case 5: cursorBlink(7, 1); break;
        }
      break;
      case 104:
      case 105:
      case 106:
      case 107:
      case 108:
      case 109:
      case 110:
      case 111:
      case 112:
      case 113:
        lcdDisplay.setCursor(0, 0);
        sprintf(rowBuffer, "%02d:%02d:%02d LEF-SET", editTime.hours, editTime.minutes, editTime.seconds);
        lcdDisplay.print(rowBuffer);
        lcdDisplay.setCursor(0, 1);
        sprintf(rowBuffer, "%03d      SEL-ESC", editTemp);
        lcdDisplay.print(rowBuffer);       
        switch (dtPos)
        {
          case 0: cursorBlink(1, 0); break;
          case 1: cursorBlink(4, 0); break;
          case 2: cursorBlink(7, 0); break;
          case 3: cursorBlink(2, 1); break;
        }
      break;
  }
}

// Основной цикл программы (Датчики, Экран, Реле).
void work()
{
  currentTime = getDatetime();
  currTemp = tempSensor.getTempCByIndex(0);
  tempSensor.requestTemperatures();
  // Основная работа.
  workTemp = DEVICE_DISCONNECTED_C;
  if (procStart)
  {
    unsigned long cTime = makeDateTime(currentTime.seconds, currentTime.minutes, currentTime.hours, currentTime.day, currentTime.month, currentTime.year);
    unsigned long pTime = makeDateTime(procTime.seconds, procTime.minutes, procTime.hours, procTime.day, procTime.month, procTime.year);
    unsigned long dTime0 = makeTime(step0Time.seconds, step0Time.minutes, step0Time.hours);
    unsigned long dTime1 = makeTime(step1Time.seconds, step1Time.minutes, step1Time.hours);
    unsigned long dTime2 = makeTime(step2Time.seconds, step2Time.minutes, step2Time.hours);
    unsigned long dTime3 = makeTime(step3Time.seconds, step3Time.minutes, step3Time.hours);
    unsigned long dTime4 = makeTime(step4Time.seconds, step4Time.minutes, step4Time.hours);
    unsigned long dTime5 = makeTime(step5Time.seconds, step5Time.minutes, step5Time.hours);
    unsigned long dTime6 = makeTime(step6Time.seconds, step6Time.minutes, step6Time.hours);
    unsigned long dTime7 = makeTime(step7Time.seconds, step7Time.minutes, step7Time.hours);
    unsigned long dTime8 = makeTime(step8Time.seconds, step8Time.minutes, step8Time.hours);
    unsigned long dTime9 = makeTime(step9Time.seconds, step9Time.minutes, step9Time.hours);
    unsigned long lTime = 0;
    if (cTime >= pTime + lTime) workTemp = step0Temp; lTime += dTime0;
    if (cTime >= pTime + lTime) workTemp = step1Temp; lTime += dTime1;
    if (cTime >= pTime + lTime) workTemp = step2Temp; lTime += dTime2;
    if (cTime >= pTime + lTime) workTemp = step3Temp; lTime += dTime3;
    if (cTime >= pTime + lTime) workTemp = step4Temp; lTime += dTime4;
    if (cTime >= pTime + lTime) workTemp = step5Temp; lTime += dTime5;
    if (cTime >= pTime + lTime) workTemp = step6Temp; lTime += dTime6;
    if (cTime >= pTime + lTime) workTemp = step7Temp; lTime += dTime7;
    if (cTime >= pTime + lTime) workTemp = step8Temp; lTime += dTime8;
    if (cTime >= pTime + lTime) workTemp = step9Temp; lTime += dTime9;
    if (currTemp >= workTemp + deadzone) D13_High;
    if (currTemp <= workTemp - deadzone) D13_Low;
  } else D13_Low;
  // Отрисовка меню.
  Draw(currentMode);
}

// Настройки при запуске контроллера.
void setup()
{
  // Чтение из памяти значений.
  procStart = ReadEEPROM_Byte(1);
  readDatetime(10, &procTime); 
  readTime(100, &step0Time); step0Temp = ReadEEPROM_Byte(200);
  readTime(110, &step1Time); step1Temp = ReadEEPROM_Byte(210);
  readTime(120, &step2Time); step2Temp = ReadEEPROM_Byte(220);
  readTime(130, &step3Time); step3Temp = ReadEEPROM_Byte(230);
  readTime(140, &step4Time); step4Temp = ReadEEPROM_Byte(240);
  readTime(150, &step5Time); step5Temp = ReadEEPROM_Byte(250);
  readTime(160, &step6Time); step6Temp = ReadEEPROM_Byte(260);
  readTime(170, &step7Time); step7Temp = ReadEEPROM_Byte(270);
  readTime(180, &step8Time); step8Temp = ReadEEPROM_Byte(280);
  readTime(190, &step9Time); step9Temp = ReadEEPROM_Byte(290);
  // Дисплей.
  lcdDisplay.begin(16, 2);
  lcdDisplay.createChar(0, degree);
  lcdDisplay.clear();
  // Термодатчик.
  tempSensor.begin();
  tempSensor.setWaitForConversion(false);
  tempSensor.requestTemperatures();
  // Модуль часов.
  timeModule.begin();
  // Реле.
  D13_Out;
  D13_Low;
  // Запуск основной работы по прерыванию в 250мс.
  StartTimer1(work, 500000); 
}

// Основной цикл программы (Кнопки).
void loop()
{
  // Проверка нажатия кнопок.
  currentButtonState = getPressedButton();
  if(currentButtonState != previousButtonState)
  {
    // Антидребезг.
    delay_ms(10);
    currentButtonState = getPressedButton();
    if (currentButtonState != previousButtonState)
    {
      // Обработка нажатия кнопок.
      ButtonEventProc(currentButtonState);
      previousButtonState = currentButtonState;
    }
  }
  delay_ms(1);
}

Принцип работы.
В прошивке реализовано меню.
В меню есть 10 шагов. В каждом шаге можно задать температуру и время которое эту температуру нужно держать.
Процесс идет от первого шага к десятому.
Так же в меню есть настройки часов.
И два меню предназначенных для запуска процесса варки и его принудительного выключения.

Прошивка рабочая но не законченная, делалась на скорую руку по этому часть кода можно было сделать и получше.
Пишите если понадобится помощь.