Контроллер пелетного котла
- Войдите на сайт для отправки комментариев
Всем привет, меня зовут Дима, и я сварщик:) живу я в Украине, в городе Харьков. Когда то газ был дешевый и некого не парило отопление дома, но в 2008 он подорожал почти на 100% и я утеплил дом пенопластом, стало легче:) жил дальше... но пришел 2014 год и газ подорожал в 7 раз, что стало очень накладно с расходом 300-500 кубометров в месяц и я сварил себе котел на дровах шахтного типа. но через две зимы пришел к тому что дрова топливо хоть и дешевое но очень не стабильное... заинтересовался пеллетами и сделал "гравитационную" горелку, стало лучше. качество топлива стабильное, засыпал в бункер и нагрел теплоаккамулятор но напрягало что гравитационная горелка вредная к тяге в дымоходе и получалось что нужно 2-4 часа в день что бы нагреть ТА, и без присмотра её не оставить... и сделал свою первую факельную горелку, управление сделал на модулях из китая, выставил время подачи и паузы подкрутил вентилятор и работает:) но хотелось сделать "автоматику" которая была бы автоматической и знала что делать с нештатными ситуациями но знания мои в програмировании не позволяли... потом я сделал котел в мастерскую и тоже контроллер на модулях, но в мастерской ТА нет, и котел греет радиаторы на прямую. а хотелось чтоб он мог поддерживать заданную темературу и не палил лишнего, и конце 2019 года понеслось... напряг своих друзей кто понимал больше меня начать контроллер, что то получалось, как я думал, но к весне 2020 года я таки понял как надо сделать и теперь только "допиливаю" свое детище:) в общем вот:
#define PID_INTEGER
#define PID_INTEGRAL_WINDOW 50
#define BTN1 4
#define BTN2 5
#define BTN3 2
#define BTN4 3
#define BTN5 A0
#include <GyverPID.h>
#include <GyverButton.h>
#include <GyverTimer.h>
#include <GyverTM1637.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define CLK A4
#define DIO A5
#define ONE_WIRE_BUS 11
GyverTM1637 disp(CLK, DIO);
GyverPID pid(1, 0.05, 0.8, 10000);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer {0x28, 0xB8, 0x86, 0xD5, 0x33, 0x20, 0x01, 0xCA }; //УКАЗАТЬ имя датчика
////////////////////кнопки////////////////////////////////////////////
GButton startButtonPin(BTN1); //пин кнопки Старт
GButton stopButtonPin(BTN2); //пин кнопки Стоп
GButton plusButtonPin(BTN3); //пин кнопки "+"
GButton minusButtonPin(BTN4); //пин кнопки "-"
GButton disp_ButtonPin(BTN5); //пин кнопки дисплея
////////////////////датчики///////////////////////////////////////////
const int photoresistorPin = 12; //пин фоторезистора
const int infraredSensorPin = A3; //пин ИК датчика
////////////////////иполнители////////////////////////////////////////
const int feederAugerPin = 6; //пин шнека питателя
const int pumpPin = 7; //пин цикуляционного насоса
const int heatingElementPin = 8; //пин зажигалки
const int stokerAugerPin = 9; //пин шнека стокера
const int pwmPin = 10; //пин для ШИМ
const int firebarPin = 13; //пин подвижного колосника
////////////////////переменные///////////////////////////////////////
int desiredTemperature;
int currentTemp;
byte working;
byte start_count;
byte photoresistor;
int p_pause;
int w_pause;
byte start1;
int val_f;
int val[3];
int index;
byte starting;
byte plusButton;
byte minusButton;
byte dispButton;
int dose;
byte displ;
signed char fan_value;
int PWM_val;
byte fanspeed_pr;
byte pid_out_last;
int switch_start;
int switch_stop;
int stop_FPB;
int startpwm;
int disp_on;
uint8_t start_1;
uint8_t stop_1;
int fire_off;
int reg1;
GTimer start_timer0(MS);
GTimer start_timer1(MS);
GTimer start_timer2(MS);
GTimer start_timer3(MS);
GTimer stop_timer1(MS);
GTimer stop_timer2(MS);
int middle_of_3(int a, int b, int c) {
int x[2];
if (a > b) {x[0] = b; x[1] = a;}
else {x[0] = a; x[1] = b;}
if (x[1] > c) {return (x[0]< c) ? c : x[0];}
else {return x[1];}
}
void setup() {
start_1=0;
stop_1=0;
disp_on=1;
switch_stop=9;
switch_start=9;
pid_out_last=100;
PWM_val=0;
displ=0;
working=0;
start1=0;
start_count=0;
desiredTemperature=500;
stop_FPB=1;
startpwm=0;
fire_off=0;
disp.clear();
disp.brightness(0); // яркость, 0 - 7 (минимум - максимум)
startButtonPin.setTickMode(AUTO);
stopButtonPin.setTickMode(AUTO);
plusButtonPin.setTickMode(AUTO);
minusButtonPin.setTickMode(AUTO);
disp_ButtonPin.setTickMode(AUTO);
pinMode(photoresistorPin, INPUT);
pinMode(infraredSensorPin, INPUT);
pinMode(pumpPin, OUTPUT);
pinMode(feederAugerPin, OUTPUT);
pinMode(stokerAugerPin, OUTPUT);
pinMode(pwmPin, OUTPUT);
pinMode(heatingElementPin, OUTPUT);
pinMode(firebarPin, OUTPUT);
digitalWrite(feederAugerPin, HIGH);
digitalWrite(stokerAugerPin, HIGH);
digitalWrite(heatingElementPin, HIGH);
digitalWrite(pumpPin, HIGH);
digitalWrite(firebarPin, HIGH);
pid.setDirection(NORMAL);
pid.setLimits(1,9);
pid.setpoint = desiredTemperature;
sensors.begin();
start_timer0.setTimeout(10000);//время продувки перед запуском горелки
start_timer1.setTimeout(20000);//время загрузки пеллет на розжиг
start_timer2.setTimeout(180000);//время работы зажигалки
start_timer3.setTimeout(25000);//время стабилизации пламени
stop_timer1.setTimeout(100000);//время дожига пеллет перед останокой горелки
stop_timer2.setTimeout(300000);//время продувки перед останокой горелки
//Serial.begin(9600);
}
void loop() {
/*static uint32_t timer_ser;
if(millis() - timer_ser >= 2000){
timer_ser = millis();
Serial.println(pid.output);
Serial.println(reg1);
}
*/
button();
fillPillets();
pid.input = currentTemp;
pid.setpoint = desiredTemperature;
pid.getResultTimer();
reg_limits();
average_fire();
temp();
work();
startWork();
finishWork();
auto_start();
//fire_bar();
startPWM();
screen();
}
void reg_limits(){
reg1=desiredTemperature-currentTemp;
if(reg1>=40){
pid.setLimits(1,9);
}else if(reg1>=30){
pid.setLimits(1,7);
}else if(reg1>=20){
pid.setLimits(1,5);
}else if(reg1>=10){
pid.setLimits(1,3);
}
}
void fire_bar(){ //Функция таймера работы подвижного колосника
static uint32_t oldMillis = millis();
static uint32_t onOffTime=500000;
uint32_t newMillis = millis();
boolean firebar_On = digitalRead(firebarPin);
if(newMillis-oldMillis>=onOffTime){
oldMillis=millis();
firebar_On=!firebar_On;
onOffTime=5000+(300000*firebar_On);//!firebar_On для мосфета, firebar_On для реле управление по LOW.
digitalWrite(firebarPin,firebar_On);
}
}
void temp(){ //Функция обработки сигнала датчика температуры
static uint32_t temp_timer;
sensors.requestTemperatures();
if(millis()-temp_timer>1000){
temp_timer=millis();
currentTemp = sensors.getTempC(insideThermometer)*10;}
}
void average_fire(){ //Функция обработки сигнала датчика огня
if (++index > 2) index = 0;
val[index] = analogRead(A3);
val_f = middle_of_3(val[0], val[1], val[2]);
}
void startPWM() { //функция управления ШИМ вентилятора
static int fanspeed;
if(startpwm==1){
fan_value=constrain(fan_value,-30,30);
fanspeed_pr = PWM_val+fan_value;
fanspeed_pr = constrain(fanspeed_pr, 0, 100);
fanspeed = map(fanspeed_pr, 0, 100, 0, 253);
analogWrite(pwmPin, fanspeed);
}
}
void button(){ //Функция обработки кнопок
desiredTemperature = constrain(desiredTemperature, 300, 800);
if(disp_ButtonPin.isClick()){
displ+=1;
if(displ >= 4)displ=0;
}
if(startButtonPin.isClick() and photoresistor==1){
startpwm=1;
switch_start=0;
}
if(stopButtonPin.isClick()){
startpwm=1;
stop_FPB=0;
working=0;
start1=0;
switch_stop=0;
}
if(currentTemp>=800 and working==1){
startpwm=1;
stop_FPB=0;
working=0;
start1=0;
switch_stop=0;
}
if(currentTemp>=350){
digitalWrite(pumpPin, LOW);}
else{digitalWrite(pumpPin, HIGH);
}
if(currentTemp<50 and start_count>=3){
digitalWrite(pumpPin, LOW);
}
}
void auto_start(){ //Функция автостарта горелки при потере огня
static uint32_t timer_fire;
if(millis() - timer_fire >= 100){
timer_fire = millis();
if(val_f>1000 and start1==1){
fire_off+=1;
}
else{fire_off=0;
}
}
if(fire_off==600 and start1==1){
start1=0;
working=0;
pid_out_last=100;
switch_start=5;
}
}
void screen(){ //функция вывода информации на дисплей
static int for_disp;
if(disp_on==1){
switch (displ){
//вывод температур, изменение заданной температуры
case 0 :
for_disp = desiredTemperature * 10;
for_disp = for_disp + currentTemp/10;
disp.displayInt(for_disp);
disp.point(true);
if(plusButtonPin.isClick()){
desiredTemperature+=50;
plusButtonPin.resetStates();
}
if(minusButtonPin.isClick()){
desiredTemperature-=50;
minusButtonPin.resetStates();
}
break;
//вывод расхода грамм\час
case 1 :
disp.displayInt(dose);
disp.point(false);
break;
//вывод скорости вентилятора в процентах с возможностью корректировки
case 2 :
disp.displayInt(fanspeed_pr);
disp.displayByte(0, 0x71);
disp.point(false);
if(plusButtonPin.isClick() and fanspeed_pr<100){
fan_value+=5;
plusButtonPin.resetStates();
}
if(minusButtonPin.isClick()){
fan_value-=5;
minusButtonPin.resetStates();
}
break;
//вывод уровня пламени 0-1000 или таймер если огня нет
case 3 :
if(val_f<1000){
disp.displayInt(val_f);
disp.point(false);
}else{
disp.displayInt(fire_off/10);
disp.point(false);}
break;
}
}
}
void fillPillets() { //Функция подачи пеллет из бункера в стокер
static uint32_t timer_photo;
if(millis() - timer_photo >= 500){
timer_photo = millis();
photoresistor = digitalRead(photoresistorPin);
}
if(stop_FPB==1){
if (photoresistor == 0) {
digitalWrite(feederAugerPin, LOW);}
else {
digitalWrite(feederAugerPin, HIGH);}
}
}
void startWork(){ //функция розжига
switch(switch_start){
case 0:
PWM_val=100;
if(val_f<900){
switch_start=4;}
break;
case 1:
PWM_val=20;
digitalWrite(stokerAugerPin, LOW);
if(val_f<600){
switch_start=2;}
break;
case 2:
digitalWrite(stokerAugerPin, HIGH);
switch_start=3;
break;
case 3:
PWM_val=90;
digitalWrite(heatingElementPin, LOW);
break;
case 4:
digitalWrite(heatingElementPin, HIGH);
p_pause=3750;
w_pause=200;
PWM_val=60;
work_timer();
break;
case 5:
digitalWrite(heatingElementPin, HIGH);
start_count+=1;
if(start_count<=3){
switch_start=0;}
else{
switch_start=9;
start1=0;
working=0;
}
break;
case 6:
start1=1;
working=1;
switch_start=8;
break;
}
if(switch_start==0){
if(start_timer0.isReady())switch_start=1;}else{start_timer0.start();}
if(switch_start==1){
if(start_timer1.isReady())switch_start=2;}else{start_timer1.start();}
if(switch_start==3){
if(val_f<750)switch_start=4;}
if(switch_start==3){
if(start_timer2.isReady())switch_start=5;}else{start_timer2.start();}
if(switch_start==4){
if(start_timer3.isReady())switch_start=6;}else{start_timer3.start();}
}
void work() { //Функция выбора режима мощности работы горелки
if (working == 1) {
start_count = 0;
if (pid_out_last != pid.output){
digitalWrite(stokerAugerPin,HIGH);
switch (pid.output) {
//p_pause=пауза подачи. w_pause=подача. PWM_val=вентилятор в процентах. dose=расход грамм\час.
case 0 :p_pause=10000;w_pause=100;PWM_val=35;dose = 180;break;
case 1 :p_pause=8520;w_pause=100;PWM_val=40;dose = 210;break;
case 2 :p_pause=7500;w_pause=100;PWM_val=45;dose = 240;break;
case 3 :p_pause=6000;w_pause=100;PWM_val=50;dose = 300;break;
case 4 :p_pause=5000;w_pause=100;PWM_val=60;dose = 360;break;
case 5 :p_pause=4500;w_pause=100;PWM_val=65;dose = 400;break;
case 6 :p_pause=3000;w_pause=155;PWM_val=75;dose = 850;break;
case 7 :p_pause=3750;w_pause=200;PWM_val=80;dose = 1000;break;
case 8 :p_pause=3300;w_pause=200;PWM_val=90;dose = 1630;break;
case 9 :p_pause=3000;w_pause=300;PWM_val=100;dose = 2000;break;
}
}
pid_out_last = pid.output;
work_timer();
}
}
void work_timer(){ //Функция таймер работы горелки
static uint32_t oldMillis = millis();
static uint16_t onOffTime;
uint32_t newMillis = millis();
boolean soker_On = digitalRead(stokerAugerPin);
if(newMillis-oldMillis>=onOffTime){
oldMillis=millis();
soker_On=!soker_On;
onOffTime=w_pause+((p_pause - w_pause)*soker_On);//!soker_On для мосфета, soker_On для реле управление по LOW.
digitalWrite(stokerAugerPin,soker_On);
}
}
void finishWork(){ //Функция остановки работы горелки
switch(switch_stop){
case 0:
disp_on=0;
stop_FPB=0;
p_pause=3000;
w_pause=250;
PWM_val=100;
disp.displayByte(0x6d, 0x78, 0x3f, 0x73);
disp.point(false);
work_timer();
break;
case 1:
digitalWrite(stokerAugerPin, HIGH);
stop_FPB=0;
PWM_val=100;
break;
case 2:
disp_on=1;
PWM_val=0;
startpwm=0;
stop_FPB=1;
switch_stop=3;
break;
}
if(switch_stop==0){
if(stop_timer1.isReady())
switch_stop=1;}else{stop_timer1.start();}
if(switch_stop==1){
if(stop_timer2.isReady()){
PWM_val=0;
switch_stop=2;}
}else{stop_timer2.start();}
}
контроллеру нужно задать режимы работы в скетче, а затем он управляется при помощи четырех кнопок. пуск, стоп, плюс и минус температура. есть еще кнопка которая переключает дисплей, показывать температуру, расход пеллет, значение вентилятора (с возможностью коррекции), и значение датчика огня но то уже я делал для себя... основные это температура и вентилятор.
в планах сделать что бы режимы задавались не рукописно, а вводить контроллеру например вес некого объема пеллет и он относительно этого веса перещитывал режимы подачи и паузы.
у меня есть канал на ютубе где я делаю это все https://www.youtube.com/channel/UCW6PoUoch5vHGwUPKVOn-cA
сделал новую версию, теперь контроллер универсальный, настраивается из меню. задаются 3 основных параметра и контроллер на их основании расчитывает время подачи
#define PID_INTEGER #define BTN1 A0 //пин кнопки Enter #define BTN2 A1 //пин кнопки Exit #define BTN3 A3 //пин кнопки "+" #define BTN4 A2 //пин кнопки "-" #include <AC_Dimmer.h> #include <EEPROM.h> #include <GyverPID.h> #include <GyverButton.h> #include <GyverTimer.h> #include <OneWire.h> #include <DallasTemperature.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #define Dimmer_1 0 #define ONE_WIRE_BUS 11 //пин датчика ds18b20 LiquidCrystal_I2C lcd(0x27,20,4); //пины А4 и А5 GyverPID pid(1.3, 0.01, 4.3, 30000); OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress insideThermometer {0x28, 0x55, 0xA9, 0x2C, 0x33, 0x20, 0x01, 0xDC }; //УКАЗАТЬ имя датчика ////////////////////кнопки//////////////////////////////////////////// GButton enterButtonPin(BTN1); //пин кнопки Enter GButton exitButtonPin(BTN2); //пин кнопки Exit GButton plusButtonPin(BTN3); //пин кнопки "+" GButton minusButtonPin(BTN4); //пин кнопки "-" ////////////////////датчики/////////////////////////////////////////// const int photoresistorPin = A6; //пин фоторезистора const int infraredSensorPin = A7 ; //пин ИК датчика ////////////////////иполнители//////////////////////////////////////// const int feederAugerPin = 7; //пин шнека питателя const int pumpPin = 6; //пин цикуляционного насоса const int heatingElementPin = 8; //пин зажигалки const int stokerAugerPin = 9; //пин шнека стокера const int firebarPin = 12; //пин подвижного колосника ////////////////////переменные/////////////////////////////////////// uint16_t currentTemp; boolean working; uint8_t start_count; uint16_t w_pause; boolean start1; uint16_t val_f; uint16_t val[3]; uint16_t index; uint16_t val_foto; uint16_t val_fot[3]; uint16_t index2; uint8_t PWM_val; uint8_t switch_start; uint8_t switch_stop; boolean startpwm; uint16_t fire_off; uint32_t displ; uint8_t fanspeed; uint8_t cursor_; uint8_t kwt; boolean feeder_On; boolean flag; uint32_t counter; boolean f_load; boolean f_loading; boolean f_m; boolean f_work; boolean stoker_On; uint8_t min_power; uint8_t max_power; uint16_t desiredTemperature; signed char fan_value; uint8_t min_fan; uint8_t max_fan; float pr; float kkal; uint16_t p_pause; bool pid_start; uint32_t counter2; uint8_t gramm; uint32_t time_stabilize; uint32_t time_blow; uint16_t fire_Ok; uint32_t time_stop; uint32_t time_stop_blow; uint32_t load_ms; uint32_t load_counter; uint32_t ms_g; uint8_t percent; GTimer start_timer0(MS); GTimer start_timer2(MS); GTimer start_timer3(MS); GTimer stop_timer1(MS); GTimer stop_timer2(MS); int middle_of_3(int a, int b, int c) { int x[2]; if (a > b) {x[0] = b; x[1] = a;} else {x[0] = a; x[1] = b;} if (x[1] > c) {return (x[0]< c) ? c : x[0];} else {return x[1];} } int middle_of_3_1(int a, int b, int c) { int x[2]; if (a > b) {x[0] = b; x[1] = a;} else {x[0] = a; x[1] = b;} if (x[1] > c) {return (x[0]< c) ? c : x[0];} else {return x[1];} } void setup() { Dimmer_init_begin(); Dimmer_pin_assign(Dimmer_1, 3); Dimmer_init_end(); int adc_read; val_f=1000; val_foto=1000; /* min_power = 1; max_power = 15; desiredTemperature = 500; fan_value = 1; min_fan = 30; max_fan = 80; pr = 10000; kkal = 4.65; p_pause = 15000; pid_start = 1; counter2 = 0; gramm = 150; time_stabilize = 300000; time_blow = 30000; fire_Ok = 700; */ percent=0; load_ms=0; ms_g=0; stoker_On=0; feeder_On=0; load_counter=0; f_work=0; f_loading=0; f_load=0; cursor_=0; switch_stop=9; switch_start=9; working=0; start1=0; start_count=0; startpwm=0; fire_off=0; displ=0; ///* EEPROM.get(20, min_power); EEPROM.get(22, max_power); EEPROM.get(24, desiredTemperature); EEPROM.get(28, fan_value); EEPROM.get(32, min_fan); EEPROM.get(34, max_fan); EEPROM.get(36, pr); EEPROM.get(40, kkal); EEPROM.get(46, p_pause); EEPROM.get(48, pid_start); EEPROM.get(50, counter2); EEPROM.get(56, gramm); EEPROM.get(58, time_stabilize); EEPROM.get(64, time_blow); EEPROM.get(70, fire_Ok); EEPROM.get(74, time_stop); EEPROM.get(80, time_stop_blow); //*/ lcd.init(); // initialize the lcd lcd.backlight(); lcd.clear(); enterButtonPin.setTickMode(AUTO); exitButtonPin.setTickMode(AUTO); plusButtonPin.setTickMode(AUTO); minusButtonPin.setTickMode(AUTO); pinMode(photoresistorPin, INPUT); pinMode(infraredSensorPin, INPUT); pinMode(pumpPin, OUTPUT); pinMode(feederAugerPin, OUTPUT); pinMode(stokerAugerPin, OUTPUT); pinMode(heatingElementPin, OUTPUT); pinMode(firebarPin, OUTPUT); digitalWrite(feederAugerPin, HIGH); digitalWrite(stokerAugerPin, HIGH); digitalWrite(heatingElementPin, HIGH); digitalWrite(pumpPin, HIGH); digitalWrite(firebarPin, HIGH); pid.setMode(ON_RATE); pid.setDirection(NORMAL); pid.setLimits(min_power,max_power); pid.setpoint = desiredTemperature; sensors.begin(); start_timer0.setTimeout(time_blow);//время продувки перед запуском горелки start_timer2.setTimeout(300000);//время работы зажигалки start_timer3.setTimeout(time_stabilize);//время стабилизации пламени stop_timer1.setTimeout(time_stop);//время дожига пеллет перед останокой горелки stop_timer2.setTimeout(time_stop_blow);//время продувки перед останокой горелки } void loop() { menu(); rgs(); startPWM(); //average_fire(); temp(); pump(); pidstart(); startWork(); finishWork(); auto_start(); fire_bar(); eeprom(); } void rgs(){ //функция счета пеллеты ms_g = 3600000/pr; if(feeder_On==0)flag=1; if(feeder_On==1 and flag==1){ counter2+=w_pause; flag=0; } counter=counter2/ms_g; load_ms=gramm*ms_g; percent=load_counter/(load_ms/100); if(switch_start==1){ if(feeder_On==0)f_load=1; if(feeder_On==1 and f_load==1){ switch_start=1; load_counter+=w_pause; f_load=0; } if(load_counter>=load_ms)f_loading=0; } } void eeprom(){ //функция обработки EEPROM памяти min_power=constrain(min_power,0,max_power); max_power=constrain(max_power,min_power,100); w_pause =(((kwt/kkal)*1000)/(pr/3600000))/((3600000-((kwt/kkal)*1000)/(pr/3600000))/p_pause); EEPROM.put(20, min_power); EEPROM.put(22, max_power); EEPROM.put(24, desiredTemperature); EEPROM.put(28, fan_value); EEPROM.put(32, min_fan); EEPROM.put(34, max_fan); EEPROM.put(36, pr); EEPROM.put(40, kkal); EEPROM.put(46, p_pause); EEPROM.put(48, pid_start); EEPROM.put(50, counter2); EEPROM.put(56, gramm); EEPROM.put(58, time_stabilize); EEPROM.put(64, time_blow); EEPROM.put(70, fire_Ok); EEPROM.put(74, time_stop); EEPROM.put(80, time_stop_blow); } void pidstart(){ //функция запуска ПИД регулятора //if(working==1){ pid.input = currentTemp; pid.setpoint = desiredTemperature; pid.setLimits(min_power,max_power); if(pid_start==1 and working==1){ pid.getResultTimer(); kwt=pid.output;//} digitalWrite(heatingElementPin, HIGH); work_timer(); work_timer2(); } } void fire_bar(){ //Функция таймера работы подвижного колосника static uint32_t oldMillis = millis(); static uint32_t onOffTime=500000; uint32_t newMillis = millis(); boolean firebar_On = digitalRead(firebarPin); if(newMillis-oldMillis>=onOffTime){ oldMillis=millis(); firebar_On=!firebar_On; onOffTime=5000+(300000*firebar_On);//!firebar_On для мосфета, firebar_On для реле управление по LOW. digitalWrite(firebarPin,firebar_On); } } void temp(){ //Функция обработки сигнала датчика температуры static uint32_t temp_timer; static bool flag=0; if(millis()-temp_timer>1000){ temp_timer=millis(); lcd.clear(); flag=!flag; if(flag=0){ //sensors.requestTemperatures(); }else{ //currentTemp = sensors.getTempC(insideThermometer)*10; } } } void average_fire(){ //Функция обработки сигнала датчика огня if (++index > 2) index = 0; val[index] = analogRead(A7); val_f = middle_of_3(val[0], val[1], val[2]); if (++index2 > 2) index2 = 0; val_fot[index2] = analogRead(A6); val_foto = middle_of_3_1(val_fot[0], val_fot[1], val_fot[2]); } void startPWM() { //функция управления ШИМ вентилятора static int fann; if(startpwm==1){ fan_value=constrain(fan_value,-20,20); if(working==1){ fanspeed = PWM_val+fan_value; }else{fanspeed=PWM_val;} if(working==1){ fanspeed=map(kwt,min_power,max_power,min_fan,max_fan); fanspeed = constrain(fanspeed, min_fan, max_fan); } fann = map(fanspeed, 0, 100, 0, 250); ////////////////////////// Dimm_value(Dimmer_1,fann); ////////////////////////// } } void pump(){ //функция включения циркуляционного насоса if(currentTemp>=350){ digitalWrite(pumpPin, LOW);} else{digitalWrite(pumpPin, HIGH); } if(currentTemp<50 and start_count>=3)digitalWrite(pumpPin, LOW); } void main_screen(){ //функция обработки главного экрана lcd.setCursor(0, 0); lcd.print("Ty."); lcd.setCursor(4, 0); lcd.print(desiredTemperature/10); lcd.setCursor(6, 0); lcd.print("C"); lcd.setCursor(0, 1); lcd.print("Tk."); lcd.setCursor(4, 1); lcd.print(currentTemp/10); lcd.setCursor(6, 1); lcd.print("C"); lcd.setCursor(0, 2); lcd.print("kWt"); lcd.setCursor(4, 2); lcd.print(kwt); lcd.setCursor(0, 3); lcd.print("Fan"); lcd.setCursor(4, 3); lcd.print(fanspeed); if(fanspeed<10){ lcd.setCursor(5, 3); lcd.print("%"); }else if(fanspeed<100){ lcd.setCursor(6, 3); lcd.print("%"); }else if(fanspeed>99){ lcd.setCursor(7, 3); lcd.print("%"); } lcd.setCursor(16, 0); lcd.print("Fire"); lcd.setCursor(16, 1); lcd.print("Fire"); lcd.setCursor(12, 0); lcd.print(val_f); lcd.setCursor(12, 1); lcd.print(val_foto); if(working==1){ lcd.setCursor(8, 2); lcd.print(F("W.pause")); lcd.setCursor(15, 2); lcd.print(w_pause); lcd.setCursor(8, 3); lcd.print(F("P.pause")); lcd.setCursor(15, 3); lcd.print(p_pause); } if(displ==0)cursor_=0; } void menu(){ //функция обработки меню desiredTemperature = constrain(desiredTemperature, 400, 800); ////////////////////////////////////////////////////////////////////////////////////////// if(displ==0 and enterButtonPin.isHold()){startpwm=1;switch_start=0;} if(displ==0 and exitButtonPin.isHold()){startpwm=1;working=0;start1=0;switch_stop=0;} ////////////////////////////////////////////////////////////////////////////////////////// if(f_work==0){ if(pid_start==1){ if(displ==0 and plusButtonPin.isClick())desiredTemperature+=10; if(displ==0 and minusButtonPin.isClick())desiredTemperature-=10; if(displ==0 and plusButtonPin.isHold())desiredTemperature+=10; if(displ==0 and minusButtonPin.isHold())desiredTemperature-=10; }else{ if(displ==0 and plusButtonPin.isClick())kwt+=1; if(displ==0 and minusButtonPin.isClick())kwt-=1; if(displ==0 and plusButtonPin.isHold())kwt+=1; if(displ==0 and minusButtonPin.isHold())kwt-=1; } ////////////////////////////////////////////////////////////////////////////////////////// if(displ==0)main_screen(); if(displ==0 and enterButtonPin.isClick())displ+=10; if(displ>0 and exitButtonPin.isDouble())displ=0; if(displ!=0 and enterButtonPin.isClick())displ*=10; if(displ!=0 and exitButtonPin.isClick())displ/=10; if(displ!=0 and f_m==0 and minusButtonPin.isPress())displ+=1; if(displ!=0 and f_m==0 and plusButtonPin.isPress())displ-=1; if(displ!=0){cursor_ = constrain(cursor_, 0, 3);lcd.setCursor(0,cursor_);lcd.print(">");} } /////////////////////////////////////////////////////////////////////////////////////////// if(displ>=10 and displ<=13){ //menu lcd.setCursor(1,0); lcd.print(F("Setings")); lcd.setCursor(1,1); lcd.print(F("setting burner")); lcd.setCursor(1,2); lcd.print(F("setting power")); lcd.setCursor(1,3); lcd.print(F("Count pellet")); lcd.setCursor(14,3); lcd.print(counter/1000); lcd.setCursor(18,3); lcd.print(F("KG")); if(displ==13 and plusButtonPin.isHold())counter2=0; cursor_=displ-10; displ=constrain(displ,10,13); } if(displ>=100 and displ<=103){ //setings lcd.setCursor(1,0); lcd.print(F("set start")); lcd.setCursor(1,1); lcd.print(F("set stop")); lcd.setCursor(1,2); lcd.print(F("set fan")); lcd.setCursor(1,3); lcd.print(F("set PID")); cursor_=displ-100; } if(displ>=1000 and displ<=1003 or displ>=10000 and displ <=10030){ //set_start set_start(); lcd.setCursor(1,0); lcd.print(F("time blow sec")); lcd.setCursor(16,0); lcd.print(time_blow/1000); lcd.setCursor(1,1); lcd.print(F("fire Ok")); lcd.setCursor(16,1); lcd.print(fire_Ok); lcd.setCursor(1,2); lcd.print(F("load gramm")); lcd.setCursor(15,2); lcd.print(gramm); lcd.setCursor(18,2); lcd.print(F("g")); lcd.setCursor(1,3); lcd.print(F("time stab sec")); lcd.setCursor(16,3); lcd.print(time_stabilize/1000); cursor_=displ-1000; } if(displ>=1010 and displ<=1013 or displ>=10100 and displ <=10130){ //set stop set_stop(); lcd.setCursor(1,0); lcd.print(F("time stop sec")); lcd.setCursor(16,0); lcd.print(time_stop/1000); lcd.setCursor(1,1); lcd.print(F("time sblow sec")); lcd.setCursor(16,1); lcd.print(time_stop_blow/1000); cursor_=displ-1010; } if(displ>=1020 and displ<=1023 or displ>=10200 and displ <=10230){ //set fan set_fan(); lcd.setCursor(3,0); lcd.print(F("Settingis fan")); lcd.setCursor(1,1); lcd.print(F("min power fan")); lcd.setCursor(17,1); lcd.print(min_fan); lcd.setCursor(1,2); lcd.print(F("max power fan")); lcd.setCursor(17,2); lcd.print(max_fan); lcd.setCursor(1,3); lcd.print(F("correction fan")); lcd.setCursor(17,3); lcd.print(fan_value); cursor_=displ-1020; } if(displ>=1030 and displ<=1033 or displ>=10300 and displ <=10330){ //set pid set_pid(); lcd.setCursor(1,0); lcd.print(F("set work PID")); if(pid_start==1){lcd.setCursor(15,0); lcd.print(F("ON"));} else{lcd.setCursor(15,0); lcd.print(F("OFF"));} lcd.setCursor(1,1); lcd.print(F("set pid.Kp")); lcd.setCursor(15,1); lcd.print(pid.Kp); lcd.setCursor(1,2); lcd.print(F("set pid.Ki")); lcd.setCursor(15,2); lcd.print(pid.Ki); lcd.setCursor(1,3); lcd.print(F("set pid.Kd")); lcd.setCursor(15,3); lcd.print(pid.Kd); cursor_=displ-1030; } if(displ>=110 and displ<=113 or displ>=1100 and displ<=1130){ //set burner set_gor(); lcd.setCursor(1,0); lcd.print(F("TEST performans")); lcd.setCursor(1,1); lcd.print(F("set Kkal")); //качество пеллет lcd.setCursor(11,1); lcd.print(kkal*1000); lcd.setCursor(1,2); lcd.print(F("set pause")); //пауза между подачами lcd.setCursor(11,2); lcd.print(p_pause); lcd.setCursor(1,3); lcd.print(F("set perfo")); //производительность шнека грамм\час lcd.setCursor(11,3); lcd.print(pr); cursor_=displ-110; } if(displ>=120 and displ<=123 or displ>=1200 and displ<=1230){ //set min/max power set_pow(); lcd.setCursor(1,0); lcd.print(F("set Power")); lcd.setCursor(1,1); lcd.print(F("Max power Kwt")); lcd.setCursor(15,1); lcd.print(max_power); lcd.setCursor(1,2); lcd.print(F("Min power Kwt")); lcd.setCursor(15,2); lcd.print(min_power); cursor_=displ-120; } } void set_start(){ //функция настройки старта if(displ==10000 and exitButtonPin.isHold())time_blow=0; if(displ==10000 and plusButtonPin.isClick())time_blow+=1000; if(displ==10000 and plusButtonPin.isHold())time_blow+=1000; if(displ==10000 and minusButtonPin.isClick())time_blow-=1000; if(displ==10000 and minusButtonPin.isHold())time_blow-=1000; if(displ==10000){lcd.setCursor(19,0);lcd.print("<");} if(displ==10010 and exitButtonPin.isHold())fire_Ok=0; if(displ==10010 and plusButtonPin.isClick())fire_Ok+=10; if(displ==10010 and plusButtonPin.isHold())fire_Ok+=10; if(displ==10010 and minusButtonPin.isClick())fire_Ok-=10; if(displ==10010 and minusButtonPin.isHold())fire_Ok-=10; if(displ==10010){lcd.setCursor(19,1);lcd.print("<");} if(displ==10020 and exitButtonPin.isHold())gramm=0; if(displ==10020 and plusButtonPin.isClick())gramm+=10; if(displ==10020 and minusButtonPin.isClick())gramm-=10; if(displ==10020 and plusButtonPin.isHold())gramm+=10; if(displ==10020 and minusButtonPin.isHold())gramm-=10; if(displ==10020){lcd.setCursor(19,2);lcd.print("<");} if(displ==10030 and exitButtonPin.isHold())time_stabilize=0; if(displ==10030 and plusButtonPin.isClick())time_stabilize+=1000; if(displ==10030 and plusButtonPin.isHold())time_stabilize+=1000; if(displ==10030 and minusButtonPin.isClick())time_stabilize-=1000; if(displ==10030 and minusButtonPin.isHold())time_stabilize-=1000; if(displ==10030){lcd.setCursor(19,3);lcd.print("<");} if(displ>=10000 and displ<=10030){f_m=1;}else{f_m=0;} } void set_stop(){ //функция настройки остановки if(displ==10100 and exitButtonPin.isClick())time_stop=0; if(displ==10100 and plusButtonPin.isClick())time_stop+=1000; if(displ==10100 and plusButtonPin.isHold())time_stop+=1000; if(displ==10100 and minusButtonPin.isClick())time_stop-=1000; if(displ==10100 and minusButtonPin.isHold())time_stop-=1000; if(displ==10100){lcd.setCursor(19,0);lcd.print("<");} if(displ==10110 and exitButtonPin.isClick())time_stop_blow=0; if(displ==10110 and plusButtonPin.isClick())time_stop_blow+=1000; if(displ==10110 and plusButtonPin.isHold())time_stop_blow+=1000; if(displ==10110 and minusButtonPin.isClick())time_stop_blow-=1000; if(displ==10110 and minusButtonPin.isHold())time_stop_blow-=1000; if(displ==10110){lcd.setCursor(19,1);lcd.print("<");} if(displ>=10100 and displ<=10110){f_m=1;}else{f_m=0;} } void set_fan(){ //функция настройки вентилятора if(displ==10210 and exitButtonPin.isHold())min_fan=0; if(displ==10210 and plusButtonPin.isClick())min_fan+=1; if(displ==10210 and plusButtonPin.isHold())min_fan+=1; if(displ==10210 and minusButtonPin.isClick())min_fan-=1; if(displ==10210 and minusButtonPin.isHold())min_fan-=1; if(displ==10210){lcd.setCursor(19,1);lcd.print("<");} if(displ==10220 and exitButtonPin.isHold())max_fan=0; if(displ==10220 and plusButtonPin.isClick())max_fan+=1; if(displ==10220 and plusButtonPin.isHold())max_fan+=1; if(displ==10220 and minusButtonPin.isClick())max_fan-=1; if(displ==10220 and minusButtonPin.isHold())max_fan-=1; if(displ==10220){lcd.setCursor(19,2);lcd.print("<");} if(displ==10230 and exitButtonPin.isHold())fan_value=0; if(displ==10230 and plusButtonPin.isClick())fan_value+=1; if(displ==10230 and plusButtonPin.isHold())fan_value+=1; if(displ==10230 and minusButtonPin.isClick())fan_value-=1; if(displ==10230 and minusButtonPin.isHold())fan_value-=1; if(displ==10230){lcd.setCursor(19,3);lcd.print("<");} if(displ>=10210 and displ<=10230){f_m=1;}else{f_m=0;} } void set_gor(){ //функция настройки параметров работы горелки if(displ==1100){ lcd.setCursor(19,0); lcd.print("<"); } if(displ==1100 and enterButtonPin.isHolded()){ digitalWrite(feederAugerPin,LOW); displ= 1131; lcd.clear(); delay(100); lcd.setCursor(3,0); lcd.print(F("Runing test!")); lcd.setCursor(3,1); lcd.print(F("Wait 10sec!")); delay(10000); digitalWrite(feederAugerPin,HIGH); displ=1100;} if(displ==1110 and exitButtonPin.isHold())kkal=0; if(displ==1110 and plusButtonPin.isClick())kkal+=0.05; if(displ==1110 and plusButtonPin.isHold())kkal+=1; if(displ==1110 and minusButtonPin.isClick())kkal-=0.05; if(displ==1110 and minusButtonPin.isHold())kkal-=1; if(displ==1110){lcd.setCursor(19,1);lcd.print("<");} if(displ==1120 and exitButtonPin.isHold())p_pause=0; if(displ==1120 and plusButtonPin.isClick())p_pause+=100; if(displ==1120 and plusButtonPin.isHold())p_pause+=1000; if(displ==1120 and minusButtonPin.isClick())p_pause-=100; if(displ==1120 and minusButtonPin.isHold())p_pause-=1000; if(displ==1120){lcd.setCursor(19,2);lcd.print("<");} if(displ==1130 and exitButtonPin.isHold())pr=0; if(displ==1130 and plusButtonPin.isClick())pr+=50; if(displ==1130 and plusButtonPin.isHold())pr+=1000; if(displ==1130 and minusButtonPin.isClick())pr-=50; if(displ==1130 and minusButtonPin.isHold())pr-=1000; if(displ==1130){lcd.setCursor(19,3);lcd.print("<");} if(displ>=1110 and displ<=1130){f_m=1;}else{f_m=0;} } void set_pid(){ //функция настройки ПИД регулятора if(displ==10300 and plusButtonPin.isClick())pid_start=1; if(displ==10300 and minusButtonPin.isClick())pid_start=0; if(displ==10300){lcd.setCursor(19,0);lcd.print(F("<"));} if(displ==10310 and plusButtonPin.isClick())pid.Kp=+0.1; if(displ==10310 and minusButtonPin.isClick())pid.Kp-=0.1; if(displ==10310){lcd.setCursor(19,1);lcd.print(F("<"));} if(displ==10320 and plusButtonPin.isClick())pid.Ki=+0.01; if(displ==10320 and minusButtonPin.isClick())pid.Ki-=0.01; if(displ==10320){lcd.setCursor(19,2);lcd.print(F("<"));} if(displ==10330 and plusButtonPin.isClick())pid.Kd=+0.1; if(displ==10330 and minusButtonPin.isClick())pid.Kd-=0.1; if(displ==10330){lcd.setCursor(19,3);lcd.print(F("<"));} if(displ>=10300 and displ<=10330){f_m=1;}else{f_m=0;} } void set_pow(){ //функция настройки ограничения мощности if(displ==1210 and plusButtonPin.isClick())max_power+=1; if(displ==1210 and minusButtonPin.isClick())max_power-=1; if(displ==1210 and plusButtonPin.isHold())max_power+=1; if(displ==1210 and minusButtonPin.isHold())max_power-=1; if(displ==1210){lcd.setCursor(19,1);lcd.print("<");} if(displ==1220 and plusButtonPin.isClick())min_power+=1; if(displ==1220 and minusButtonPin.isClick())min_power-=1; if(displ==1220 and plusButtonPin.isHold())min_power+=1; if(displ==1220 and minusButtonPin.isHold())min_power-=1; if(displ==1220){lcd.setCursor(19,2);lcd.print("<");} if(displ>=1210 and displ<=1220){f_m=1;}else{f_m=0;} } void auto_start(){ //Функция автостарта горелки при потере огня static uint32_t timer_fire; static int time_no_fire; if (kwt==1 or kwt==2 or kwt==3 or kwt==4 or kwt==5){ time_no_fire = 1400;} else{time_no_fire = 600;} if(millis() - timer_fire >= 100){ timer_fire = millis(); if((val_f>1000) and start1==1){ fire_off+=1; } else{ fire_off=0; } } if(fire_off==time_no_fire and start1==1){ start1=0; working=0; switch_start=5; } } void startWork(){ //функция розжига static uint32_t timer_start; static uint8_t tt1=time_blow/1000; static uint16_t tt3=300; static uint8_t tt4=time_stabilize/1000; switch(switch_start){ case 0: PWM_val=99; if(millis() - timer_start >= 1000){ timer_start = millis(); tt1-=1; } if(displ==0){ lcd.setCursor(14, 2); lcd.print(tt1); lcd.setCursor(17, 2); lcd.print(F("sec")); lcd.setCursor(9, 2); lcd.print(F("mode:")); lcd.setCursor(9, 3); lcd.print(F("Blow..."));} break; case 1: PWM_val=50; if(displ==0){ lcd.setCursor(9, 2); lcd.print(F("mode:")); lcd.setCursor(17, 3); lcd.print(percent); lcd.setCursor(19, 3); lcd.print("%"); lcd.setCursor(9, 3); lcd.print(F("Loading")); } digitalWrite(heatingElementPin, LOW); kwt=15; if(f_loading==1){ work_timer(); work_timer2(); } break; case 2: digitalWrite(stokerAugerPin, HIGH); digitalWrite(feederAugerPin, HIGH); switch_start=3; break; case 3: PWM_val=60; if(millis() - timer_start >= 1000){ timer_start = millis(); tt3-=1; } if(displ==0){ lcd.setCursor(14, 2); lcd.print(tt3); lcd.setCursor(17, 2); lcd.print(F("sec")); lcd.setCursor(9, 2); lcd.print(F("mode:")); lcd.setCursor(9, 3); lcd.print(F("Heating..."));} //digitalWrite(heatingElementPin, LOW); break; case 4: digitalWrite(heatingElementPin, HIGH); startpwm=1; if(millis() - timer_start >= 1000){ timer_start = millis(); tt4-=1; } if(displ==0){ lcd.setCursor(14, 2); lcd.print(tt4); lcd.setCursor(17, 2); lcd.print(F("sec")); lcd.setCursor(9, 2); lcd.print(F("mode:")); lcd.setCursor(9, 3); lcd.print(F("Stabilize.."));} kwt=4; work_timer(); work_timer2(); break; case 5: digitalWrite(heatingElementPin, HIGH); start_count+=1; if(start_count<=3){ switch_start=0;} else{ switch_start=9; start1=0; working=0; tt1=time_blow/1000; tt3=300; tt4=time_stabilize/1000; } break; case 6: digitalWrite(heatingElementPin, HIGH); start1=1; working=1; tt1=time_blow/1000; tt3=300; tt4=time_stabilize/1000; switch_start=8; break; } if(switch_start==0){ if(val_f<900 or val_foto<900)switch_start=6; if(start_timer0.isReady()){ switch_start=1; f_loading=1; } }else{start_timer0.start();} if(switch_start==1){ if(val_f<900 or val_foto<900)switch_start=6; if(f_loading==0)switch_start=2; } if(switch_start==3){ if(val_f<fire_Ok or val_foto<fire_Ok)switch_start=4; if(start_timer2.isReady())switch_start=5; }else{start_timer2.start();} if(switch_start==4){ if(start_timer3.isReady())switch_start=6; }else{start_timer3.start();} } void work_timer(){ //Функция таймер работы горелки static uint32_t oldMillis = millis(); static uint16_t onOffTime; uint32_t newMillis = millis(); stoker_On = digitalRead(stokerAugerPin); if(newMillis-oldMillis>=onOffTime){ oldMillis=millis(); stoker_On=!stoker_On; onOffTime=(w_pause*2)+(((p_pause - w_pause)/2)*stoker_On);//!soker_On для мосфета, soker_On для реле управление по LOW. digitalWrite(stokerAugerPin,stoker_On); } } void work_timer2(){ //Функция таймер работы горелки static uint32_t oldMillis = millis(); static uint16_t onOffTime; uint32_t newMillis = millis(); feeder_On = digitalRead(feederAugerPin); if(newMillis-oldMillis>=onOffTime){ oldMillis=millis(); feeder_On=!feeder_On; onOffTime=w_pause+((p_pause - w_pause)*feeder_On);//!soker_On для мосфета, soker_On для реле управление по LOW. digitalWrite(feederAugerPin,feeder_On); } } void finishWork(){ //Функция остановки работы горелки static uint32_t timer_stop; static int tt=time_stop/1000; static int tt1=time_stop_blow/1000; switch(switch_stop){ case 0: f_work=1; startpwm=1; PWM_val=99; kwt=10; if(millis() - timer_stop >= 1000){ timer_stop = millis(); tt-=1; } lcd.setCursor(14, 2); lcd.print(tt); lcd.setCursor(17, 2); lcd.print(F("sec")); lcd.setCursor(9, 2); lcd.print(F("mode:")); lcd.setCursor(9, 3); lcd.print(F("STOPing...")); work_timer(); break; case 1: digitalWrite(stokerAugerPin, HIGH); digitalWrite(feederAugerPin, HIGH); f_work=1; startpwm=1; PWM_val=99; if(millis() - timer_stop >= 1000){ timer_stop = millis(); tt1-=1; } lcd.setCursor(14, 2); lcd.print(tt1); lcd.setCursor(17, 2); lcd.print(F("sec")); lcd.setCursor(9, 2); lcd.print(F("mode:")); lcd.setCursor(9, 3); lcd.print(F("Shutdown...")); break; case 2: PWM_val=0; startpwm=0; f_work=0; tt=time_stop/1000; tt1=time_stop_blow/1000; switch_stop=3; break; } if(switch_stop==0){ if(stop_timer1.isReady()) switch_stop=1;}else{stop_timer1.start();} if(switch_stop==1){ if(stop_timer2.isReady()){ PWM_val=0; switch_stop=2;} }else{stop_timer2.start();} }Какая плата и схема?
я еще не умею делать схему, все собрано на модулях...
11 задач крутить в лупе, это, канеш крута, но, код бы значительно упростился при использовании любой ртос. имхо.
Что такое ртос?
Сделай фото модулей которые используются для работы котла.
Присоединюсь.
Из всего котла интересует:
1) Механика (мотор - редуктор - шнек)
2) КПД
3) Котёл в разрезе
4) Цена 1 кг пеллет?
5) Цена 1 кВт электроэнергии?
Поделюсь своим опытом:
В результате изысканий сделал себе котёл + батареи + насос + разводку. Уложился в 100 баксов:
https://youtu.be/WKGTGtQIwkk?list=PLWPGkgnA_YMaTwBM0gq4aywByMRI9SBjY
работает на дровах.
https://www.youtube.com/channel/UCW6PoUoch5vHGwUPKVOn-cA
Присоединюсь.
Из всего котла интересует:
1) Механика (мотор - редуктор - шнек)
2) КПД
3) Котёл в разрезе
4) Цена 1 кг пеллет?
5) Цена 1 кВт электроэнергии?
Поделюсь своим опытом:
В результате изысканий сделал себе котёл + батареи + насос + разводку. Уложился в 100 баксов:
https://youtu.be/WKGTGtQIwkk?list=PLWPGkgnA_YMaTwBM0gq4aywByMRI9SBjY
работает на дровах.
1. моторы 68ktyz
2. хз.
3. на канале есть видео по его сборке.
4. хз. было 2-3грн\кг, в том году подорожало 8-10грн\кг, в этом не узнавал.
5. 1.68грн