Нужна была печь, для запекания полимерной глины. После не долгих поисков выбор пал на электрическую печь для кухни «КЕДР». Мощностью 600 ватт, с максимальной температурой 250 градусов, без регулятора. На первое время был установлен термомеханический регулятор, так как температура для работы требовалась в диапазоне 100-130 градусов. Но вся проблема заключалась в том, что у печи очень большой разгон(после отключения нагревателя температура продолжала расти еще на 20-50 градусов), а у регулятора очень большой диапазон включения и отключения. То есть устанавливая температуру в 130 градусов я получал диапазон 100 — 160 градусов, что не является допустимым.
После нескольких месяцев разбора принципов работы с Arduino IDE и C++ родился проект, который полностью удовлетворяет требованиям. Устройство умеет удерживать установленную температуру от 100 до 150 градусов, по достижению которой срабатывает установка таймера на 5-35 минут, в зависимости от установки, по истечению срабатывает будильник.
Здесь блок-схема работы программы.

В состав устройства входит: четыре последовательных нагревателя установленных в печи по умолчанию, которые можно заменить на любой другой нагреватель соответственной мощности, твердотельное реле SSR-25 DA, Arduino Pro Mini, инкрементальный энкодер с кнопкой подключенного через инвертирующим триггер Шмитта, дисплей WH1602D и два NTC терморезисторов MF58 на 100кОм.
Здесь код скетча, с комментариями.
Так как это один из первых проектов, прошу побольше критики!
После нескольких месяцев разбора принципов работы с Arduino IDE и C++ родился проект, который полностью удовлетворяет требованиям. Устройство умеет удерживать установленную температуру от 100 до 150 градусов, по достижению которой срабатывает установка таймера на 5-35 минут, в зависимости от установки, по истечению срабатывает будильник.
Здесь блок-схема работы программы.

В состав устройства входит: четыре последовательных нагревателя установленных в печи по умолчанию, которые можно заменить на любой другой нагреватель соответственной мощности, твердотельное реле SSR-25 DA, Arduino Pro Mini, инкрементальный энкодер с кнопкой подключенного через инвертирующим триггер Шмитта, дисплей WH1602D и два NTC терморезисторов MF58 на 100кОм.
Здесь код скетча, с комментариями.
Листинг
#include <LiquidCrystal.h> #include "timer-api.h" const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 6; // сюда подключаем дисплей LiquidCrystal lcd(rs, en, d4, d5, d6, d7); int encCLK = 2 ; // сюда подключаем энкодер int encDT = 7; // сюда подключаем энкодер int button = 8 ; // сюда подключаем кнопку // в схеме энкодер подключен через инвертирующий триггер Шмитта!!! volatile bool button_not_press = true; // здесь храним состояние кнопки volatile int pinClkValue = 0; // переменные для хранения состояния энкодера volatile int pinDtValue = 0; // переменные для хранения состояния энкодера uint8_t temp_cel[8] = {B00111,B00101,B00111,B00000,B00000,B00000,B00000}; // символ градуса int temp_upside_pin = 14; // сюда подключаем первый термодатчик MF58 100k, расчет идет под него int temp_downside_pin = 15; // сюда второй термодатчик. Вторые ноги вместе и на землю(-), так же // два резисор делителя 100k на (+5v). volatile float temp_upside; // здесь хранятся временные значения с термодатчиков volatile float temp_downside; // здесь хранятся временные значения с термодатчиков #define B 3950 // B-коэффициент для рсчета температуры int heater_pin = 10; // сюда подключаем твердотельное реле SSR-25DA. volatile bool preheating_state = false; // состояние преднагрева, с учетом энертности нагреваемого объекта volatile bool heater_state = true; // состояние нагревателя volatile int hyst = 40; // учетом энертности нагреваемого объекта подбор опытным путем volatile int changeTemp; // состояние изменения температуры за 60 сек. volatile long timeHyst = 0; // переменная для хранения времени volatile long normalModeTime; // переменная для хранения времени volatile int curTemp = 0; // здесь храниться текущая температура, после всех вычислений volatile int setTemp = 0; // здесь храниться установленная температура int *pCurTemp = &curTemp; // указатели, может они и не нужны...? int *pSetTemp = &setTemp; // указатели, может они и не нужны...? volatile bool alarm; // будильник volatile int count = 0; // шаг изменения параметров state*5 volatile int state = 0; // счетчик импульсов энкодера volatile int setTimeMinute = 0; // переменная для хранения времени таймера в минутах volatile int second = 0; // переменная для хранения времени таймера в секундах int *pMinute = &setTimeMinute; // указатели, может они и не нужны...? volatile long currentTime = millis(); // переменная для хранения времени //======================================================= void setup() { // установка режима работы библиотеки timer-api.h, генерит прерывание один раз за секунду timer_init_ISR_1Hz(TIMER_DEFAULT); // режим работы заданного вход/выхода(pin) pinMode(encCLK, INPUT); // вход CLK энкодера pinMode(encDT, INPUT); // вход DT энкодера pinMode(button, INPUT); // вход button энкодера pinMode(temp_upside_pin, INPUT); // средняя точка делителя напряжения с термодатчика 1 pinMode(temp_downside_pin,INPUT); // средняя точка делителя напряжения с термодатчика 2 pinMode(heater_pin, OUTPUT); // выход на реле attachInterrupt(0, clkEnc, CHANGE);// прерывание для управление энкодером lcd.createChar(1, temp_cel); // создаем символ градуса // вывод на дисплей приветствия!!! lcd.begin(16, 2); lcd.setCursor(2, 0); lcd.print("Polimer Clay"); lcd.setCursor(0, 1); lcd.print("BURNER ver. 1.01"); delay(2000); // вывод на дисплей меню lcd.clear(); lcd.print("Set"); lcd.setCursor(11, 0); lcd.print("Timer"); lcd.setCursor(0, 1); lcd.print("Cur"); lcd.setCursor(9, 1); lcd.print(" NotSet"); setupTemp(); // заходим в режим установки температуры } //===================================================== void clkEnc(){ // обработчик прерывания энкодера типовой, взят на просторах pinClkValue = digitalRead(encCLK); pinDtValue = digitalRead(encDT); cli(); if (!pinClkValue && pinDtValue) state = 1; if (!pinClkValue && !pinDtValue) state = -1; if (pinClkValue && state != 0) { if (state == 1 && !pinDtValue || state == -1 && pinDtValue) { count += state*5; state = 0; }} sei(); } //===================================================== void setupTemp(){ // функция установки температуры count = 0; // обнулятор счетчика button_not_press = true; // без этого условия, сразу выходит из цикла while, когда заходим по нажатию кнопки while(button_not_press){ // пока кнопка не нажата... if (count <= 100) count = 100; // ограничиваем диаппазон изменения температуры минимум 100 if (count >= 151) count = 150; // ограничиваем диаппазон изменения температуры максимум 150 setTemp = count; // сохраняем значение температуры // вывод на дисплей lcd.setCursor(4, 0); if(*pSetTemp<10) lcd.print(" "); else if(*pSetTemp<100) lcd.print(" "); lcd.print(*pSetTemp); lcd.print("\1"); lcd.print("C"); lcd.print(" "); if(*pSetTemp !=0)button_not_press = digitalRead(button); // фиксируем установку preheating_state = true;}} // включаем нагрев с учетом инертности //===================================================== void setupTimer(){ // установка таймера lcd.setCursor(11, 0); //устанавливаем курсор в нужное положение lcd.print("Timer"); //вывод на дисплей count = 0; // обнулятор счетчика button_not_press = true; lcd.setCursor(9, 1); //стираем надпись lcd.print(" "); // NotSet while(button_not_press){ // пока кнопка не нажата... if (count <= -1) count = 0; // ограничиваем диаппазон изменения времени в минутах - минимум 0 if (count >= 36) count = 35; // ограничиваем диаппазон изменения времени в минутах - максимум 35 setTimeMinute = count; // сохраняем значение времени lcd.setCursor(11, 1); //устанавливаем курсор в нужное положение if(*pMinute<10)lcd.print("0"); lcd.print(*pMinute); //вывод на дисплей МИНУТЫ lcd.print(":00"); //вывод на дисплей СЕКУНДЫ формат 00:00 tempMonitor(); // мониторим температуру if(*pMinute !=0)button_not_press = digitalRead(button);} // фиксируем установку if (*pMinute != 0){second = 0; timerStart();} // если таймер установлен, переходим к счетчику времени timeEnd(); } // если время закончилось, будильник!!! //====================================================== void tempMonitor(){ //Тут вся соль проекта!!! // управление мощностью нагревателя путем изменения формы и времени подаваемого напряжения. if(millis() > normalModeTime + 10){ heater_state = !heater_state; normalModeTime = millis();} // измерение и вывод температуры на дисплей каждые пол секунды if(millis() > currentTime + 500){ lcd.setCursor(4, 1); if(*pCurTemp<10) lcd.print(" "); else if(*pCurTemp<100) lcd.print(" "); lcd.print(*pCurTemp); lcd.print("\1"); lcd.print("C"); lcd.print(" "); int US = analogRead(temp_upside_pin); // считываем значение 1 датчика int DS = analogRead(temp_downside_pin); // считываем значение 2 датчика int MID = (US+DS)/2; // считаем среднее значение float tr = (5 / 1023.0) * MID ; // преобразовываем в напряжение float VR = 5 - tr; // считаем среднее напряжение float RT = tr/(VR / 99000); // считаем среднее сопротивление float ln = log(RT / 100000); float TX = (1 / ((ln / B) + (1 / (25+273.15)))); // упрощенное уровнение Стейнхарта — Харта TX = round(TX - 273.15); // пересчет в градусы по Цельсию и округление *pCurTemp = int(TX); // сохраняем значение температуры currentTime = millis(); } //поднимаем тепмературу до температуры с компенсацией (установленная - hyst) if(preheating_state){ if(*pCurTemp < (*pSetTemp - hyst)) digitalWrite(heater_pin, HIGH); //если достигли температуры с компенсацией (установленная - hyst), //выключаем и ждем пока температура не достигнет установленного значения (pSetTemp). else if(*pCurTemp > (*pSetTemp - hyst)) digitalWrite(heater_pin, LOW); if (*pCurTemp >= *pSetTemp){ preheating_state = false; Serial.print(preheating_state); } //если негрев был не достаточен и температура начала падать не достигнув нужного значения //то включаем снова нагреватель, который будет выключаться условием предыдущего цикла //в результате чего напряжение будет подаваться импульсами, что не даст быстрого //роста температуры. Этот процес будет происходить, //пока температура снова не начнет увеличиваться. if (millis() > timeHyst + 30000){ changeTemp = *pCurTemp; //один раз в 30 сек, сохраняем температуру для сравнения timeHyst = millis(); } if(changeTemp >= *pCurTemp){ if(!digitalRead(heater_pin)){ digitalWrite(heater_pin, HIGH);}}} //если температура достигла указанного(pSetTemp) значения //переходим в режим поддержания температуры включая нагрев с ограничением мощности нагревателя //при падении температуры ниже 5 градусов от установленной if(!preheating_state){ if(*pCurTemp < *pSetTemp - 5) { digitalWrite(heater_pin, heater_state);} else digitalWrite(heater_pin, LOW); }} //==================================================== void timer_handle_interrupts(int timer){second--;} //==================================================== //таймер выводит на дисплей установленное время и осуществляет обратный отсчет //используя переменную second, которая уменьшаеться по прерыванию //по истечению установленного времени включаеться будильник. void timerStart(){ while(*pMinute+second != 0){ if (second == 0){(*pMinute)--; second = 59;} lcd.setCursor(11, 1); if(*pMinute<10)lcd.print(" "); lcd.print(*pMinute); lcd.print(":"); if(second<10)lcd.print("0"); lcd.print(second); lcd.print(" "); if(alarm){ noTone(9); if(!digitalRead(button)){ alarm = false; noTone(9); return;}} tempMonitor(); if(alarm) tone(9,100); }} //=================================================== // Будильник !!! void timeEnd(){ alarm = true; lcd.setCursor(11, 0); lcd.print("Alarm"); *pMinute = 1; //second = 30; //будильник работает установленное <- время, если его не timerStart(); //выключить, то произойдет сброс установленной температуры в 0 if(alarm){ //и запуститься режим установки температуры, нагреватель будет отключен *pSetTemp = 0; //если в течении работы будильника нажать на кнопку, снова включиться digitalWrite(heater_pin, LOW); //режим установки таймера, с поддержкой установленной ранее температурой lcd.setCursor(4, 0); if(*pSetTemp<10) lcd.print(" "); else if(*pSetTemp<100) lcd.print(" "); lcd.print(*pSetTemp); lcd.print("\1"); lcd.print("C"); lcd.print(" "); alarm = false; }} //==================================================== //основной цикл почти ни чего не делает void loop() { tempMonitor(); // <- запуск мониторинга температуры if(*pSetTemp == 0 && !digitalRead(button)) setupTemp(); // <- если будильник дотикал до 0 if(*pCurTemp == *pSetTemp) setupTimer(); } // <- если выключить будильник
Так как это один из первых проектов, прошу побольше критики!
