У меня дома газовая плита, термометр в духовке которой показывает, может быть, освещённость на Марсе, или артериальное давление Байдена - я не знаю. А в сети полно рецептов, где написано: "Готовьте 40 минут при температуре 180 градусов, потом 15 минут при 160...". И тому подобное. Сам я повар - так себе, мне важно выполнить требование инструкции.  А тут подошли очередные "железки" с Али...
Идея такая: нано-168, несколько светодиодов, max6675, энкодер, дисплей 1602. Задаём температуру и время. Если температура не та - пищим каждые две минуты, издалека цветом светодиода показываем "холодно/горячо" или "норм" (тогда не пищим). По окончании времени - играем мелодию из Тетриса.
На фото будет видно, что я хотел замутить включение всего прибора кнопкой, а выключение автоматически (через мосфет), или по длинному нажатию энкодера, но купив мосфет, припаяв его с кнопкой - что-то у меня не задалось. Я на свалке отрыл какие-то советские полевые транзисторы - тоже не срослось, психанул и на китайские сопли приклеил выключатель, который нашёл. Заставил конструкцию противно пищать, когда всё закончилось, а её не выключили. Как куплю нужный мосфет - перепаяю (Ха-ха. Сам в это мало верю. Но кнопку и неисправный мосфет пока на плате оставил.)
Сам проект для себя назвал "технопорно", поскольку собирал всё на макетной плате, постарался чтобы все детали с проводами торчали наружу.
	
	
		
			
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
		
	
На фотке что-то страшное, круглое и серое - не пугайтесь, это крутилка для энкодера от какой-то авиационной фигни. А если кто-то увидит чёрные провода припаянные к микросхеме MAX6674 - это я пытался выпаять "гребёнку", припаянную в Китае не в ту сторону, намаялся, поотрывал дорожки, плюнул, припаялся к ногам микросхемы.
Ну и большое спасибо AlexGyver за библиотеки. И вообще за популяризацию всего вотэтого.
Если вдруг гуру подскажут как оптимизировать код - буду рад. Что-то из школьного QBasic (который был 30 лет назад) у меня в голове еще держится, но в остальном... Как получается - так и "кодю".
								Идея такая: нано-168, несколько светодиодов, max6675, энкодер, дисплей 1602. Задаём температуру и время. Если температура не та - пищим каждые две минуты, издалека цветом светодиода показываем "холодно/горячо" или "норм" (тогда не пищим). По окончании времени - играем мелодию из Тетриса.
На фото будет видно, что я хотел замутить включение всего прибора кнопкой, а выключение автоматически (через мосфет), или по длинному нажатию энкодера, но купив мосфет, припаяв его с кнопкой - что-то у меня не задалось. Я на свалке отрыл какие-то советские полевые транзисторы - тоже не срослось, психанул и на китайские сопли приклеил выключатель, который нашёл. Заставил конструкцию противно пищать, когда всё закончилось, а её не выключили. Как куплю нужный мосфет - перепаяю (Ха-ха. Сам в это мало верю. Но кнопку и неисправный мосфет пока на плате оставил.)
Сам проект для себя назвал "технопорно", поскольку собирал всё на макетной плате, постарался чтобы все детали с проводами торчали наружу.
			
				C++:
			
		
		
		/*Код для кухонного таймера.
* Устройство состоит из: ардуино нано, дисплей 1602, энкодер, термопара max6675, трёх светодиодов, 4 сопротивления, пищалка, мосфет.
* Задача устройства: контролировать время приготовления таймером обратного отсчета, сравнивать показания термопары в духовке с
* заранее заданым значением температуры.
* Ввод/вывод: значения температуры и времени (минут) приготовления задаются энкодером. Одинарный "клик" уводит "вглубь меню", двойной - возвращает.
* Светодиоды меняют свой цвет в зависимости от температуры духовки +- 5 градусов. При несоответствии раз в 2 минуты звучит двухсекундный сигнал.
*/
// это для дисплея
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <GyverPower.h>
//это для термопары
#include "max6675.h"
int thermoSCK = 8; //D2
int thermoSO = 2;  //D3
int thermoCS = 4; //D4
int TempCook = 160; //Начальное значение
int TempReal;
int Timer = 60; //Начальное значение
int Sec = 0; //для получения секунд из millis
int Min = 0; //для получения минут из millis
int MinOFF = 0; //для получения минут из millis
int ShowTime; // для вывода данных через интервал времени (мерцание экрана)
unsigned long Proctime; // для работы с millis
MAX6675 thermocouple(thermoSCK, thermoCS, thermoSO);
//это для энкодера
#define CLK 10
#define DT 11
#define SW 9
#include "GyverEncoder.h"
Encoder encoder(CLK, DT, SW, TYPE2);  // для работы c кнопкой
//это светодиоды
int LedB = 7; //голубой
int LedG = 6; //зеленый
int LedR = 5; //красный
bool Final = false; //флаг для однократного проигрывания финальной мелодии
//это музыка
#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978
#define REST 0
int tempo = 144; //можно увеличить темп
int buzzer = 3; //номер пина пьезопищалки
int melody[] = {
  NOTE_E5, 4,  NOTE_B4, 8,  NOTE_C5, 8,  NOTE_D5, 4,  NOTE_C5, 8,  NOTE_B4, 8,
  NOTE_A4, 4,  NOTE_A4, 8,  NOTE_C5, 8,  NOTE_E5, 4,  NOTE_D5, 8,  NOTE_C5, 8,
  NOTE_B4, -4,  NOTE_C5, 8,  NOTE_D5, 4,  NOTE_E5, 4,
  NOTE_C5, 4,  NOTE_A4, 4,  NOTE_A4, 8,  NOTE_A4, 4,  NOTE_B4, 8,  NOTE_C5, 8,
  NOTE_D5, -4,  NOTE_F5, 8,  NOTE_A5, 4,  NOTE_G5, 8,  NOTE_F5, 8,
  NOTE_E5, -4,  NOTE_C5, 8,  NOTE_E5, 4,  NOTE_D5, 8,  NOTE_C5, 8,
  NOTE_B4, 4,  NOTE_B4, 8,  NOTE_C5, 8,  NOTE_D5, 4,  NOTE_E5, 4,
  NOTE_C5, 4,  NOTE_A4, 4,  NOTE_A4, 4, REST, 4,
};
int notes = sizeof(melody) / sizeof(melody[0]) / 2;
int wholenote = (60000 * 4) / tempo;
int divider = 0, noteDuration = 0;
void setup() {
// Пины для светодиодов
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  // pinMode(13, OUTPUT);
  //digitalWrite(13, LOW);
//начальное заполнение экрана
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("CookT:");
  lcd.setCursor(0, 1);
  lcd.print("RealT:");
  lcd.setCursor(10, 0);
  lcd.print("Timer:");
//проверка светодиодов на свечение
  digitalWrite(LedB, HIGH);
  digitalWrite(LedG, HIGH);
  digitalWrite(LedR, HIGH);
  delay(2000);
  digitalWrite(LedB, LOW);
  digitalWrite(LedG, LOW);
  digitalWrite(LedR, LOW);
  Proctime = millis();
}
void loop() {
  if (millis() - Proctime > 1000) {
    TempReal = thermocouple.readCelsius();
    Proctime = millis();
    Sec = Sec + 1;              //здесь из millis делаем секунды
    ShowTime = ShowTime + 1;    //эта переменная используется для того, чтобы обновлять значения на экране раз в 5 секунд
    if (ShowTime == 5) {
      lcd.setCursor(6, 0);
      lcd.print(TempCook);
      lcd.setCursor(6, 1);
      lcd.print("   ");
      lcd.setCursor(6, 1);
      lcd.print(TempReal);
      lcd.setCursor(13, 1);
      lcd.print("   ");
      lcd.setCursor(13, 1);
      lcd.print(Timer);
      ShowTime = 0;
    }
    if (Sec > 59) {           
      Min = Min + 1;            //здесь из секунд получаются минуты
      if (Final) {              //это условие отвечает за пищание прибора после окончания таймера
        MinOFF = MinOFF + 1;
      }
      Sec = 0;
      Timer = Timer - 1;        //здесь значение таймера уменьшается каждую минуту
      if (Timer <= 0) {
        if (!Final) {           //это условие проигрывает мелодию по окончанию таймера и включает флаг окончания работы
          song();
          Final = true;
        }
        Timer = 0;
      }
    }
    if (Final == true and MinOFF == 1) {  //это условие заставляет пищать прибор каждую минуту после окончания работы
      tone(buzzer, 500, 500);
      tone(buzzer, 800, 500);
      MinOFF = 0;
    }
  }
  encoder.tick();
  //  if (encoder.isHolded()) { //этот блок - неудача с электронным отключением прибора
  //    digitalWrite(13, LOW);
  //  }
 
  /*
   *Весь этот блок - работа с энкодером. При нажатии на энкодер появляется курсор, который поворотом энкодера
   *можно перемещать между изменяемыми величинами: температурой приготовления или таймером.
   *При двукратном клике из этого режима выходит, при однократном клике курсор мигает на изменяемой позиции и поворотом
   *энкодера значения изменяются. Двукратный клик выводит курсор из режима редактирования значений в режим выбора значений,
   *повторный двойной клик выводит систему из режима выбора изменяемых значений.
   */
  bool flag1 = true;    //эти два флага нужны для последовательного входа в "подменю" и выхода из него
  bool flag2 = true;
  int CursorPos;
  if (encoder.isSingle()) {
    lcd.setCursor(6, 0);
    lcd.cursor();
    while (flag1) {
      encoder.tick();
      if (encoder.isLeft()) {
        lcd.setCursor(6, 0);
        lcd.cursor();
        CursorPos = 1;
      }
      if (encoder.isRight()) {
        lcd.setCursor(13, 1);
        lcd.cursor();
        CursorPos = 2;
      }
      if (encoder.isDouble()) {
        flag1 = false;
        lcd.noCursor();
      }
      if (encoder.isSingle()) {
        while (flag2) {
          encoder.tick();
          lcd.blink();
          if (encoder.isRight()) {
            if (CursorPos == 1) {
              TempCook = TempCook + 1;
              lcd.setCursor(6, 0);
              lcd.print("   ");
              lcd.setCursor(6, 0);
              lcd.print(TempCook);
            }
            if (CursorPos == 2) {
              Timer = Timer + 1;
              lcd.setCursor(13, 1);
              lcd.print("   ");
              lcd.setCursor(13, 1);
              lcd.print(Timer);
              Final = false;
            }
          }
          if (encoder.isLeft()) {
            if (CursorPos == 1) {
              TempCook = TempCook - 1;
              lcd.setCursor(6, 0);
              lcd.print("   ");
              lcd.setCursor(6, 0);
              lcd.print(TempCook);
            }
            if (CursorPos == 2) {
              Timer = Timer - 1;
              lcd.setCursor(13, 1);
              lcd.print("   ");
              lcd.setCursor(13, 1);
              lcd.print(Timer);
            }
          }
          if (encoder.isDouble()) {
            flag2 = false;
            lcd.noBlink();
          }
        }
        flag2 = true;
      }
    }
    flag1 = true;
  }
 
  /*
   * Этот блок отвечает за свечение светодиодов. И пищание прибора при неверной температуре каждые 2 минуты.
   */
    if (TempReal < TempCook - 5) {
    digitalWrite(LedB, HIGH);
    digitalWrite(LedG, LOW);
    digitalWrite(LedG, LOW);
    if (Min == 2 and !Final) {
      tone(buzzer, 1000, 1000);
      Min = 0;
    }
  } else if (TempReal > TempCook + 5) {
    digitalWrite(LedG, LOW);
    digitalWrite(LedR, HIGH);
    digitalWrite(LedB, LOW);
    if (Min == 2 and !Final) {
      tone(buzzer, 1000, 1000);
      Min = 0;
    }
  } else {
    digitalWrite(LedR, LOW);
    digitalWrite(LedG, HIGH);
    digitalWrite(LedB, LOW);
  }
}
void song() {
  for (int thisNote = 0; thisNote < notes * 2; thisNote = thisNote + 2) {
    divider = melody[thisNote + 1];
    if (divider > 0) {
      noteDuration = (wholenote) / divider;
    } else if (divider < 0) {
      noteDuration = (wholenote) / abs(divider);
      noteDuration *= 1.5; // increases the duration in half for dotted notes
    }
    tone(buzzer, melody[thisNote], noteDuration * 0.9);
    delay(noteDuration);
    noTone(buzzer);
  }
}
	На фотке что-то страшное, круглое и серое - не пугайтесь, это крутилка для энкодера от какой-то авиационной фигни. А если кто-то увидит чёрные провода припаянные к микросхеме MAX6674 - это я пытался выпаять "гребёнку", припаянную в Китае не в ту сторону, намаялся, поотрывал дорожки, плюнул, припаялся к ногам микросхемы.
Ну и большое спасибо AlexGyver за библиотеки. И вообще за популяризацию всего вотэтого.
Если вдруг гуру подскажут как оптимизировать код - буду рад. Что-то из школьного QBasic (который был 30 лет назад) у меня в голове еще держится, но в остальном... Как получается - так и "кодю".
Вложения
- 
		
			
	
			
		
		
		55.2 KB Просмотры: 31