#define pin 3 // 3 или 11 пин ардуины (используем второй таймер)
byte Val=100;// значение от 0 до 255
setup(){
TCCR2B = TCCR2B & 0b11111000 | 0x07; // таймер второй делим на 256 получаем 122.07
analogWrite(pin, Val);
}
loop(){
}
не компелируется скетч с поста #5 , ошибка EEPROM , скинте свои библиотеки на которых компелировали скетч
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void temp_setup()':
sketch_jul13a:189:27: error: 'EEPROM_read' was not declared in this scope
sketch_jul13a:196:36: error: 'EEPROM_write' was not declared in this scope
sketch_jul13a:204:36: error: 'EEPROM_write' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void hum_setup()':
sketch_jul13a:239:33: error: 'EEPROM_read' was not declared in this scope
sketch_jul13a:247:42: error: 'EEPROM_write' was not declared in this scope
sketch_jul13a:255:42: error: 'EEPROM_write' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void turn_setup()':
sketch_jul13a:289:31: error: 'EEPROM_read' was not declared in this scope
sketch_jul13a:297:38: error: 'EEPROM_write' was not declared in this scope
sketch_jul13a:305:38: error: 'EEPROM_write' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void alarm_setup()':
sketch_jul13a:340:29: error: 'EEPROM_read' was not declared in this scope
sketch_jul13a:348:36: error: 'EEPROM_write' was not declared in this scope
sketch_jul13a:356:36: error: 'EEPROM_write' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void vent_setup()':
sketch_jul13a:391:27: error: 'EEPROM_read' was not declared in this scope
sketch_jul13a:399:34: error: 'EEPROM_write' was not declared in this scope
sketch_jul13a:407:34: error: 'EEPROM_write' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void thermostat()':
sketch_jul13a:476:51: error: 'EEPROM_read_mem' was not declared in this scope
sketch_jul13a:477:27: error: 'EEPROM_read' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void humidifer()':
sketch_jul13a:522:58: error: 'EEPROM_read_mem' was not declared in this scope
sketch_jul13a:523:31: error: 'EEPROM_read' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void turn()':
sketch_jul13a:541:29: error: 'EEPROM_read' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void alarm()':
sketch_jul13a:564:27: error: 'EEPROM_read' was not declared in this scope
sketch_jul13a:565:47: error: 'EEPROM_read_mem' was not declared in this scope
C:\Users\саня\Desktop\sketch_jul13a\sketch_jul13a\sketch_jul13a.ino: In function 'void fan()':
sketch_jul13a:588:25: error: 'EEPROM_read' was not declared in this scope
Было время баловался с ардуинами. На сегодняшний день
я отказался от разработок на основе этого девайса. Детство это всё.
Учитывая потраченное время нервы и полную стоимость радиодеталей, получается что проще покупать промышленные модули. Тот же ПР100 от Овна стоит 50$. Есть и готовые терморегуляторы с ПИД. Термодатчик ds18b20 не годится для инкубаторов. Как ни калибруй всё равно плавает + -0.5гр. Замерял лабораторным ртутным термометром 10 откалиброванных образцов. У этого датчика точность +-0.5. Вот и считайте разброс в инкубаторе от 37 до 38 будет, если выставить 37.5. Так и получалось. И никакими калибровками это не исправить. Нужно применять терморезисторы или термопары. Это всего лишь моё личное мнение исходя из пройденного опыта.
Я только сейчас узнал что он 3,3в :) у меня нормально работает по 5в шине, кстати, может поэтому Дуня висла когда было одно питание? Сейчас у 5в потребителей и Дуни разное питание.
Поменять датчик просто, нужно найти пользовательский блок и вставить. или вручную код править.
Переворот делаю, шаговым двигателем с одним концевиком. И плату рисую что бы заказать в Китае.
Очень медленно, получается, учусь, времени мало.
Может кто помочь с EasyEda? Нарисовал схему, надо плату откорректировать и дорожки с полигонами... не врублюсь пока как.
Кстати, если нужно подобрать коэффициенты ПИД регулятора можно воспользоваться библиотекой PID_AutoTune_v0.h.
Подбор коэффициентов происходит очень долго, несколько часов. У меня за ночь подобрались коэффициенты.
#include <PID_v1.h>
#include <PID_AutoTune_v0.h>
#include <OneWire.h>
int DS18B20_Pin = 9; //DS18S20 Signal pin on digital 9
//Temperature chip i/o
OneWire ds(DS18B20_Pin); // on digital pin 9
#define RelayPin 10
int relayPin = 10;
int WindowSize = 3000;
unsigned long windowStartTime;
byte ATuneModeRemember=2;
double input=80, output=50, setpoint=37.81;
double kp=2,ki=0.5,kd=2;
double kpmodel=1.5, taup=100, theta[50];
double outputStart=5; //5
double aTuneStep=500, aTuneNoise=1, aTuneStartValue=500;
unsigned int aTuneLookBack=20; //200
boolean tuning = true;
unsigned long modelTime, serialTime;
PID myPID(&input, &output, &setpoint,kp,ki,kd, DIRECT);
PID_ATune aTune(&input, &output);
//set to false to connect to the real world
boolean useSimulation = false;
void setup()
{
//Setup the pid
myPID.SetOutputLimits(0, WindowSize);
myPID.SetMode(AUTOMATIC);
if(useSimulation)
{
for(byte i=0;i<50;i++)
{
theta[i]=outputStart;
}
modelTime = 0;
}
if(tuning)
{
tuning=false;
changeAutoTune();
tuning=true;
}
serialTime = 0;
Serial.begin(9600);
windowStartTime = millis(); //from pid test Relay
pinMode(RelayPin,OUTPUT); //from pid test Relay
}
void loop()
{
unsigned long now = millis();
float temperature = getTemp();
float tempF = temperature;// * 9/5 + 32;
if(!useSimulation)
{ //pull the input in from the real world
input = tempF;
}
if(tuning)
{
byte val = (aTune.Runtime());
if (val!=0)
{
tuning = false;
}
if(!tuning)
{ //we're done, set the tuning parameters
kp = aTune.GetKp();
ki = aTune.GetKi();
kd = aTune.GetKd();
myPID.SetTunings(kp,ki,kd);
AutoTuneHelper(false);
}
}
else myPID.Compute();
if(useSimulation)
{
theta[30]=output;
if(now>=modelTime)
{
modelTime +=100;
DoModel();
}
}
else
{
// analogWrite(0,output); // commented out by me
unsigned long now = millis();
if(now - windowStartTime>WindowSize)
{ //time to shift the Relay Window
windowStartTime += WindowSize;
}
if(output > now - windowStartTime) digitalWrite(RelayPin,HIGH);
else digitalWrite(RelayPin,LOW);
}
//send-receive with processing if it's time
if(millis()>serialTime)
{
SerialReceive();
SerialSend();
serialTime+=1000;
}
}
void changeAutoTune()
{
if(!tuning)
{
//Set the output to the desired starting frequency.
output=aTuneStartValue;
aTune.SetNoiseBand(aTuneNoise);
aTune.SetOutputStep(aTuneStep);
aTune.SetLookbackSec((int)aTuneLookBack);
AutoTuneHelper(true);
tuning = true;
}
else
{ //cancel autotune
aTune.Cancel();
tuning = false;
AutoTuneHelper(false);
}
}
void AutoTuneHelper(boolean start)
{
if(start)
ATuneModeRemember = myPID.GetMode();
else
myPID.SetMode(ATuneModeRemember);
}
void SerialSend()
{Serial.print("Temprege: ");Serial.println(input);
Serial.print("setpoint: ");Serial.print(setpoint); Serial.print(" ");
Serial.print("input: ");Serial.print(input); Serial.print(" ");
Serial.print("output: ");Serial.print(output); Serial.print(" ");
if(tuning){
Serial.println(" tuning mode ");
} else {
Serial.print("Temprege: ");Serial.println(input);
Serial.print("kp: ");Serial.print(myPID.GetKp());Serial.print(" ");
Serial.print("ki: ");Serial.print(myPID.GetKi());Serial.print(" ");
Serial.print("kd: ");Serial.print(myPID.GetKd());Serial.println();
}
}
void SerialReceive()
{
if(Serial.available())
{
char b = Serial.read();
Serial.flush();
if((b=='1' && !tuning) || (b!='1' && tuning))changeAutoTune();
}
}
void DoModel()
{
//cycle the dead time
for(byte i=0;i<49;i++)
{
theta[i] = theta[i+1];
}
//compute the input
input = (kpmodel / taup) *(theta[0]-outputStart) + input*(1-1/taup) + ((float)random(-10,10))/100;
}
float getTemp(){
//returns the temperature from one DS18S20 in DEG Celsius
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.println("CRC is not valid!");
return -1000;
}
if ( addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print("Deviceot recognized");
return -1000;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); //using two's compliment
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
Скажите вот тут подбирали коеффициенты. Вижу цикл 3 секунды. У автора цикл 1 секунда. Как с подбором?
Я сколько не бьюсь, подобрать не могу, все время перелет на кучу градусов с подобранными автотюнингом коеффициентами. Кто-то может помочь с autotune подбором даллас ds18b20 и нагревателем через реле?
Не нравяться вам кошки? Да вы их просто готовить не умеете :)) Всё нормально работает с терморезисторами и датчиком влажности на мокром термометре. И очень компактно при распайке Atmega328p на свою плату (вместо Ардуино) и отдельной силовой плате с мосфетами и симисторами, мощности то небольшие твердотелки не требуются. Как получу платы с JLCPCB бета версию могу выложить здесь.
Спасибо посмотрел. А как у тебя управление влажностью до 1%. У меня мокрый гигрометр по таблице дает точность только 5%, а управление происходит сбросом лишней влажности вентилятором проветривания.
Замечание, если хочешь, на продажу нужно делать более "красиво", это внушает клиенту уверенность что, он покупает не кота в мешке. И поддержка нужна, схемы, инструкции... Работы много, а выход мизер.
Это отладочный вариант контроллера, потом будет еще меньше. Силовая плата отдельно: два Мосфета, два Симистора и один H-мост. В бюджет 500р не вложился. :))
Контроллер универсальный как бы. Силовые платы предполагается можно менять. Начать хотел с контроллера полива :) Но там совсем просто - таймеры и всё. Потом будет Аквариум, Стиралка...
По конструкции замечание к гребенке, которая желтая. Ненадежный у них контакт однако :-( Одно время подключал через такую дисплей, намучался, отказался в итоге. Хотя на видео видно пайку, то есть планируется что будет не разъемное, а паяное соединение? Тогда проблемы с быстрой заменой будут.
У меня в этом сезоне сдох неожиданно БП на 5 вольт в инкубаторе во время инкубации. Если все на разъемах, то заменить минутное дело.
Ну и энкодер тоже штука не очень надежная. Со временем начнет чудить :-(. У меня в курятнике контроллер стоит, через три года начались пропуски и перескакивания, хотя пользуюсь очень редко. У меня он вынесен с платы, подключается шлейфом, заменить его не сложно, но это же надо менять :-) а мне лень.
В инкубаторе и брудере сенсорные кнопки, вот им сносу нет, очень доволен. реализовано на TTP223 и TTP224. В принципе 4 кнопки достаточно для полноценного управления.
Никола Мастер, отпишись какая версия у тебя IDE, на какой плате (у меня УНО) собран инкубатор, скетч из твоего поста #107. Чет у меня такое впечатление складывается, что у инкубаторщиков как у пчеловодов - друзья, объятия а как о тонкостях пчеловодства, так прям "Брянские партизаны", хрен чё узнаеш ))), извените за офтоп. java1050@ukr.net
Спасибо!!!
Интересный проект! А где взять рабочие библиотеки к нему и какая версия Arduino IDE?
Вот тут есть все. http://www.perepel.com/forum/viewtopic.php?f=28&t=3765
У них там зарегестрироваться не реально
Правленная платка под I2C датчик влажности.
Сделал такой переворот для лотков инкубатора
https://youtu.be/x45IxeaDJvM
Спасибо, а схемку аппарвтного шима подскажи, а то у меня тоже быстро вертится...
#define pin 3 // 3 или 11 пин ардуины (используем второй таймер) byte Val=100;// значение от 0 до 255 setup(){ TCCR2B = TCCR2B & 0b11111000 | 0x07; // таймер второй делим на 256 получаем 122.07 analogWrite(pin, Val); } loop(){ }lean_74, спасибо.
В прошлом сезоне отработал XM-18, но у него недостаток, нет режима суточного охлождения,
по тихоньку делаю своё устройство на ардуино, вот возник вопрос по настройке ШИМ :
//#include <SHT1x.h> #include <PID_v1.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <EEPROM2.h> #include "RTClib.h" #include <DallasTemperature.h> #include <OneWire.h> //#include <Sensirion.h> #include <avr/wdt.h> #include <Encoder.h> #include "Adafruit_HTU21DF.h" int del = 80; // переменная ожидания между выборами меню unsigned int interval = 300; // интервал сколько будет длиться цикл while, после чего перейдёт к следующему меню.(кол-во итераций) //#define EXT_HEATING // ИСПОЛЬЗУЕМ ДОП.НАГРЕВАТЕЛЬ ВМЕСТО УВЛАЖНИТЕЛЯ. Если нужен увлажнитель, просто закомментируйте эту строку. #define heater_pin 13 // нагреватель #define humidifer_pin 12 // увлажнитель #define fan_pin 11 // вентилятор #define alarm_pin 14 // пин аварии #define beeper_pin 9 //пищалка по аварии #define dataPin 5 //SHT10 #define clockPin 6 //SHT10 #define turn_pin 10 // управление поворотом #define extend_heater_pin 8 // дополнительный нагреватель //#define button_minus_pin 2 //пин кнопки "минус" //#define button_plus_pin 3 //пин кнопки "плюс" #define button_enter_pin 4 //пин кнопки "enter" #define DS18B20_Pin 7 //пин термометра #define setSampleTime 300 //время цикла ПИД #define voltmeter_pin 1 //вход А1 через делитель (22к/10к) подключен к питанию модуля. Измеряет до 16В. #define T_correction -0.1 // коррекция температуры SHT10 #define h_histeresis 1.0 // гистерезис влажности #define door_pin 16 // пин открытой двери (А2) //boolean button_minus; // статус нажатия кнопок //boolean button_plus; //boolean button_enter; boolean turnFlag = 0; // флаг поворота для случайного периода boolean heater_off; // флаг запрета нагреателя boolean needFan; // флаг аварийной вентиляции float humidity; // Влажность float temp1Ink; // Температура DS18B20 float temp2Ink; // Температура SHT10 float needTemp = 37.6; // нужная для текущего дня температура инкубации (по умолчанию) float needHum = 60.5; // ---- влажность //float dewpoint; // Точка росы unsigned char button_minus; // статус нажатия кнопок unsigned char button_plus; unsigned char button_enter; long oldPosition = 500; // позиция энкодера unsigned int rawData; unsigned long currentTime; // задаем переменные для тайминга поворота unsigned long loopTime; unsigned long serialTime; //this will help us know when to talk with processing unsigned long now; unsigned long trhMillis = 0; // период опроса датчиков //byte measActive = false; //byte measType = TEMP; const unsigned long TRHSTEP = 300UL; // Период опроса датчиков unsigned int currentDay; // текущий день в юникс-формате String birdPrint = "CHICK"; LiquidCrystal_I2C lcd(0x3F, 20, 4); // инициализация библиотеки дисплея //SHT1x sht1x(dataPin, clockPin); OneWire oneWire(DS18B20_Pin); DallasTemperature sensors(&oneWire); //Sensirion sht = Sensirion(dataPin, clockPin); Adafruit_HTU21DF htu = Adafruit_HTU21DF(); double Setpoint, Input, Output; //объявляем переменные для ПИД PID myPID(&Input, &Output, &Setpoint, 50, 0.5, 0.1, DIRECT); //Инициализируем ПИД-библиотеку и коэффициенты int WindowSize = 1000; // ширина окна терморегулятора 1 секунда. unsigned long windowStartTime; unsigned long alarmDelay; RTC_DS1307 RTC; Encoder myEnc(3, 2); //SimpleTimer timer; /* EEPROM1 - tempInk (float) EEPROM(13) - set_humidity (float) EEPROM5 - +-alarmTemp (float) EEPROM9 - alarm_fan (bool) EEPROM11 - turnPeriod (int) EEPROM17 - bird (int) */ //////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(9600); RTC.begin(); // Старт часов lcd.init(); // Старт дисплея Wire.begin(); // старт I2C lcd.backlight(); // Включаем подсветку дисплея windowStartTime = millis(); // byte stat; // byte error = 0; // float tempInk; // float set_humidity; // float alarmTemp; delay(15); wdt_enable (WDTO_8S); //взводим сторожевой таймер на 8 секунд. myPID.SetOutputLimits(0, WindowSize); //задаем лимиты ширины ПИД-импульса от 0 до 1 секунды. myPID.SetMode(AUTOMATIC); //включаем ПИД-регулирование myPID.SetSampleTime(setSampleTime); pinMode(extend_heater_pin, OUTPUT); //пин дополнительного нагревателя. Переводим в 1 чтобы не включать реле. digitalWrite(extend_heater_pin, HIGH); pinMode(heater_pin, OUTPUT); pinMode(turn_pin, OUTPUT); // устанавливаем выводы digitalWrite(turn_pin, HIGH); pinMode(humidifer_pin, OUTPUT); pinMode(fan_pin, OUTPUT); digitalWrite(fan_pin, HIGH); pinMode(alarm_pin, OUTPUT); digitalWrite(alarm_pin, HIGH); //pinMode(button_minus_pin, INPUT_PULLUP); //подтягиваем входы кнопок к плюсу встроенными резисторами //pinMode(button_plus_pin, INPUT_PULLUP); pinMode(button_enter_pin, INPUT_PULLUP); pinMode(door_pin, INPUT_PULLUP); alarmDelay = millis(); htu.begin(); sensors.begin(); sensors.setResolution(12); // установить разрешение (точность) sensors.setWaitForConversion(false); // отключить ожидание birdSelect(); // читаем птицу //windowStartTime = millis(); //RTC.adjust(DateTime(__DATE__, __TIME__)); //раскоментируйте для установки системмных даты и времени } ////////////////////////////////////////////////////////////////////////// void loop() { // Input = getTemp(); unsigned int startDayUnixtime; // хранящийся в памяти день старта программы в юникс-формате //float needTemp = 37.6; // нужная для текущего дня температура инкубации (по умолчанию) //float needHum = 60.5; // ---- влажность int ventTime = 2; // длительность проветривания boolean needTurn = false; // нужен ли поворот яиц? unsigned int currentTime_day; //текущий день в юникс-формате (сколько дней минуло с 1 января 1970) int bird; // выбор птицы int r_array[6][4][5] = { {{2, 382, 650, 0, 1}, {12, 377, 540, 5, 1}, {18, 374, 480, 20, 1}, {20, 371, 855, 10, 0}}, // chick {{2, 382, 600, 0, 1}, {12, 376, 600, 3, 1}, {15, 374, 480, 10, 1}, {18, 370, 855, 10, 0}}, // quail {{7, 381, 700, 0, 1}, {13, 376, 600, 3, 1}, {25, 373, 560, 20, 1}, {30, 370, 855, 10, 0}}, // duck {{15, 380, 610, 5, 1}, {26, 375, 520, 20, 1}, {27, 374, 690, 10, 0}, {35, 370, 800, 0, 0}}, // muskus {{2, 382, 600, 0, 1}, {11, 378, 600, 3, 1}, {15, 374, 480, 10, 1}, {18, 370, 855, 10, 0}}, // perepel {{6, 379, 560, 0, 1}, {12, 376, 530, 3, 1}, {26, 373, 520, 20, 1}, {30, 370, 855, 10, 0}}, // turkey }; DateTime now = RTC.now(); currentTime_day = (now.unixtime() / 86400L); //timer.run(); button_read(); if (button_enter) { delay(del); lcd.clear(); menu(); lcd.clear(); } if (button_minus) { delay(del); lcd.clear(); alarmDelay = millis(); // задержка аварии по нажатии кнопки Минус } if (button_plus) { delay(del); lcd.clear(); digitalWrite(turn_pin, !digitalRead(turn_pin)); // включаем/выключаем реле поворота по кнопке Плюс } if (button_plus && button_plus) { delay(del); lcd.clear(); // bottomView = !bottomView; // переключаем режим показа нижней строки. } //send-receive with processing if it's time if (millis() > serialTime * 5) { SerialReceive(); SerialSend(); serialTime += 500; } EEPROM_read(1, startDayUnixtime); currentDay = (currentTime_day - startDayUnixtime); EEPROM_read(17, bird); for (int d = 3; d >= 0; d--) { if (currentDay < r_array[bird][d][0]) { needTemp = float(r_array[bird][d][1] / 10.0); needHum = float(r_array[bird][d][2] / 10.0); ventTime = r_array[bird][d][3]; needTurn = r_array[bird][d][4]; } } getSensors(); thermostat(needTemp, needHum); // влажность передаем только для вывода на дисплей ))) humidifer(needHum); turn(needTurn); fan(ventTime); alarm(needTemp); ext_heater(needTemp); //outpuPower(); wdt_reset(); } /// чтиаем энкодер //////////////////////////////////////////////////////////////////////// void button_read() { long newPosition = myEnc.read(); if (newPosition != oldPosition) { if (newPosition >= oldPosition + 2) { button_plus = 1; } if (newPosition <= oldPosition - 2) { button_minus = 1; } oldPosition = newPosition; //Serial.println(newPosition); } else { button_plus = 0; button_minus = 0; } if (digitalRead(button_enter_pin) == LOW ) { delay(del / 2); button_enter = 1; } if (digitalRead(button_enter_pin) == HIGH ) { delay(del / 2); button_enter = 0; } if (button_minus || button_plus || button_enter) beeper(50); wdt_reset(); } ////меню//////////////////////////////////////////////////////////////// void menu() { bird_setup(); turn_setup(); alarm_setup(); vent_setup(); startInk(); //data_time_setup(); } // записываем в память день начала инкубации в юникс-формате//////////// void startInk() { unsigned int currentTime_day; unsigned int memoryDay; DateTime now = RTC.now(); currentTime_day = (now.unixtime() / 86400L); delay(del); button_read(); lcd.setCursor(4, 0); lcd.print("START INK"); delay(1000); lcd.clear(); int x = 0; while (1) { x++; if (x > interval) break; button_read(); EEPROM_read(1, memoryDay); //Serial.print(currentTime_day); //Serial.print("-"); //Serial.print(memoryDay); //Serial.print("="); //Serial.println(currentTime_day-memoryDay); if (button_enter) { delay(del); lcd.clear(); //очищаем экран break; } if (button_minus) { EEPROM_write(1, currentTime_day); lcd.clear(); } if (button_plus) { EEPROM_write(1, memoryDay - 1); lcd.clear(); } EEPROM_read(1, memoryDay); lcd.setCursor(5, 0); lcd.print("DAY = "); lcd.print(currentTime_day - memoryDay); lcd.setCursor(2, 1); lcd.print("ZERO START +1"); delay(del); } } //выбираем птицу ///////////////////////////////////////////////////////// void bird_setup() { int birdType; lcd.clear(); delay(del); button_read(); lcd.setCursor(4, 0); lcd.print("BIRD SETUP"); delay(1000); lcd.clear(); int x = 0; while (1) { x++; if (x > interval) { break; } button_read(); EEPROM_read(17, birdType); if (button_enter) { delay(del); lcd.clear(); //очищаем экран break; } if (button_plus) { x = 0; if (birdType >= 5) //проверяем, если выше или равно 5, EEPROM_write(17, 0); //пишем в память 0 else EEPROM_write(17, birdType + 1); lcd.clear(); } if (button_minus) { x = 0; if (birdType <= 0) //проверяем, если ниже или равно 0, EEPROM_write(17, 5); //пишем в память 5 else EEPROM_write(17, birdType - 1); lcd.clear(); } birdSelect(); lcd.setCursor(6, 0); lcd.print(birdPrint); lcd.setCursor(1, 1); lcd.print("minus NEXT plus"); delay(del); } } //выбираем из памяти птицу/////////////////////////////////////// void birdSelect() { int birdType; EEPROM_read(17, birdType); lcd.setCursor(2, 0); lcd.print("BIRD - "); switch (birdType) { case 0: //lcd.print("CHICK"); // курица birdPrint = "CHICK"; break; case 1: //lcd.print("QUAIL"); // перепелка birdPrint = "QUAIL"; break; case 2: //lcd.print("DUCK"); // утка birdPrint = "DUCK"; break; case 3: //lcd.print("MUSKUS"); // индоутка birdPrint = "MUSKUS"; break; case 4: //lcd.print("PEREPEL"); // перепел birdPrint = "PEREPEL"; break; case 5: //lcd.print("TURKEY"); // индюк birdPrint = "TURKEY"; break; } } //устанавливаем поворот///////////////////////////////////////////////// void turn_setup() { int turnPeriod; delay(del); button_read(); lcd.setCursor(4, 0); lcd.print("TURN SETUP"); delay(1000); lcd.clear(); int x = 0; while (1) { x++; if (x > interval) { break; } button_read(); EEPROM_read(11, turnPeriod); if (button_enter) { delay(del); lcd.clear(); //очищаем экран break; } if (button_plus) { x = 0; EEPROM_write(11, turnPeriod + 1); if (turnPeriod >= 13) { //проверяем, если выше 13, EEPROM_write(11, 13); //пишем в память 13 } lcd.clear(); } if (button_minus) { x = 0; EEPROM_write(11, turnPeriod - 1); if (turnPeriod <= 0) { //проверяем, если ниже 0, EEPROM_write(11, 0); //пишем в память 0 } lcd.clear(); } EEPROM_read(11, turnPeriod); lcd.setCursor(0, 0); lcd.print("PERIOD = "); if (turnPeriod < 13)lcd.print(turnPeriod); if (turnPeriod > 12) lcd.print("RND"); lcd.print(" Hour"); lcd.setCursor(1, 1); lcd.print("minus NEXT plus"); delay(del); } } //устанавливаем сигнализацию/////////////////////////////////////////////////////////////// void alarm_setup() { float alarmTemp; delay(del); button_read(); lcd.setCursor(4, 0); lcd.print("ALARM SETUP"); delay(1000); lcd.clear(); int x = 0; while (1) { x++; if (x > interval) break; button_read(); EEPROM_read(5, alarmTemp); if (button_enter) { delay(del); lcd.clear(); //очищаем экран break; } if (button_plus) { x = 0; if (alarmTemp >= 10.0) //проверяем, если больше или равно 10, EEPROM_write(5, 10.0); //пишем в память 10 else EEPROM_write(5, alarmTemp + 0.1); } if (button_minus) { x = 0; if (alarmTemp <= 1.0) //проверяем, если ниже 1, EEPROM_write(5, 1.0); //пишем в память 1 else EEPROM_write(5, alarmTemp - 0.1); } lcd.setCursor(1, 0); lcd.print("T.Alarm +-"); lcd.print(alarmTemp, 1); lcd.print((char)223); lcd.print("C "); lcd.setCursor(1, 1); lcd.print("minus NEXT plus"); delay(del); } } //устанавливаем вентиляцию/////////////////////////////////////////////////////////// void vent_setup() { boolean fanEnable; delay(del); button_read(); lcd.setCursor(3, 0); lcd.print("A.FAN SETUP"); delay(1000); lcd.clear(); int x = 0; while (1) { x++; if (x > interval) break; button_read(); EEPROM_read(9, fanEnable); if (fanEnable > 1) fanEnable = 1; if (button_enter) { delay(del); lcd.clear(); //очищаем экран break; } if (button_minus) { x = 0; EEPROM_write(9, 0); //пишем в память 0, не включаем принудительную вентиляцию при превышении температуры } if (button_plus) { x = 0; EEPROM_write(9, 1); //пишем в память 1, включаем принудительную вентиляцию при превышении температуры } lcd.setCursor(2, 0); lcd.print("Ext.Fan "); if (fanEnable == 0) lcd.print("disable"); else lcd.print("enable "); lcd.setCursor(2, 1); lcd.print("OFF NEXT ON"); delay(del); } } ///опрашиваем датчики ////////////////////////////////////////////////////////////////////////// void getSensors() { unsigned long curMillis = millis(); // Получаем текущее время работы if (curMillis - trhMillis >= TRHSTEP) { // время для нового измерения? Wire.beginTransmission(0x40); byte error = Wire.endTransmission(); if (error != 0) { Serial.println(F("Couldn't find sensor!")); lcd.clear(); lcd.setCursor(3, 0); lcd.print(F("ATTENTION!")); lcd.setCursor(4, 1); lcd.print(F("ALARM!")); delay(1000); lcd.clear(); lcd.setCursor(2, 0); lcd.print(F("sensor SHT21")); lcd.setCursor(3, 1); lcd.print(F("not found")); delay(1000); lcd.clear(); temp1Ink = 85.5; humidity = 85.6; beeper(10); } else { temp1Ink = (htu.readTemperature()); // Конвертируем сырые данные с сенсора humidity = (htu.readHumidity()); // конвертируем данные с сенсора } } } //используем терморегулятор //////////////////////////////////////////// void thermostat(float tempPoint, float set_humidity) { DateTime now = RTC.now(); unsigned long now1 = millis(); float alarmTemp; EEPROM_read(5, alarmTemp); if (digitalRead(door_pin)) { //дверь закрыта *для концевика закрыто - разомкнуто myPID.SetMode(AUTOMATIC); heater_off = false; } else { //дверь открыта heater_off = true; alarmDelay = millis(); myPID.SetMode(MANUAL); Output = 300; } Setpoint = tempPoint; myPID.Compute(); if (now1 - windowStartTime > WindowSize) { //время для перещелкивания периода окна windowStartTime = windowStartTime + WindowSize; //voltmeter(); //запускаем функцию измерения напряжения Input = temp1Ink; lcd.setCursor(0, 0); // устанавливаем курсор в 0-ом столбце, 0 строка (начинается с 0) lcd.print("T1="); lcd.print(temp1Ink, 1); // печать температуры на дисплей lcd.print((char)223); lcd.setCursor(9, 0); lcd.print("H="); lcd.print(humidity, 1); // печать влажности на дисплей //lcd.print("%"); lcd.print(" "); lcd.print("D"); if (currentDay > 100) lcd.print("99"); else lcd.print(currentDay); // текущий день инкубации lcd.setCursor(0, 1); lcd.print("t"); lcd.print(Setpoint, 1); lcd.setCursor(6, 1); lcd.print("h"); lcd.print(set_humidity, 1); lcd.setCursor(13, 1); lcd.print("["); if (RTC.isrunning()) { if (now.hour() < 10) lcd.print(" "); lcd.print(now.hour(), DEC); lcd.print(":"); if (now.minute() < 10)lcd.print(0); lcd.print(now.minute(), DEC); } lcd.setCursor(19, 1); lcd.print("]"); lcd.setCursor(0, 2); lcd.print("T2="); lcd.print(temp2Ink, 1); // печать температуры на дисплей lcd.print((char)223); lcd.setCursor(9, 2); lcd.print("*t"); lcd.print(temp1Ink - temp2Ink, 1); lcd.setCursor(16, 2); lcd.print("W"); if (Output > 990) lcd.print("99"); else lcd.print(Output / 10, 0); lcd.print("%"); lcd.setCursor(0, 3); lcd.print(birdPrint); lcd.setCursor(7, 3); lcd.print("Al+-"); lcd.print(alarmTemp, 1); } if (Output > (now1 - windowStartTime) && temp1Ink < 39.9 && heater_off == false) digitalWrite(heater_pin, HIGH); else digitalWrite(heater_pin, LOW); } //управляем влажностью/////////////////////////////////////////////////////////////// void humidifer(float set_humidity) { //float humidity; unsigned long humMillis = 0; unsigned long curMillis = millis(); // if (curMillis - humMillis >= humStep) { // humMillis = curMillis; // //humidity = sht1x.readHumidity(); // } if (set_humidity > humidity) digitalWrite(humidifer_pin, HIGH); //сравниваем измеренную влажность с заданной if (set_humidity < humidity + h_histeresis) digitalWrite(humidifer_pin, LOW); } //управляем поворотом/////////////////////////////////////////////////////////////////// void turn(boolean needTurn) { int turnPeriod; //период поворота лотков в часах int turnCommand; EEPROM_read(11, turnPeriod); //lcd.setCursor(10, 3); //lcd.print("P"); //lcd.print(turnPeriod); lcd.setCursor(15, 3); lcd.print("R"); if (turnPeriod == 0) { lcd.print(" OFF "); return; //если нулевой период поворота, то не поворачиваем яйца. } if (turnPeriod < 13) turnCommand = turnPeriod; else if (turnPeriod > 12 && turnFlag == 0) { //если произошел поворот (сброшен флаг) и значение в памяти 13, то turnCommand = random(1, 6); //берем случайное значение часов 1-6 turnFlag = 1; //защелкиваем флаг вычисления случайных значений до следующего поворота } currentTime = millis() / 1000; lcd.print((loopTime - currentTime + turnCommand * 3600UL) / 60UL); lcd.print("m"); if (needTurn == true) { if (currentTime > (loopTime + turnCommand * 3600UL)) { // 3600000 сравниваем текущий таймер с переменной loopTime + период поворота в часах. digitalWrite(turn_pin, !digitalRead(turn_pin)); // включаем/выключаем реле поворота loopTime = currentTime; // в loopTime записываем новое значение turnFlag = 0; //сбрасываем флаг поворота } //lcd.print((loopTime - currentTime + turnCommand * 3600UL) / 60UL); //lcd.print(" "); } } //управляем авариями/////////////////////////////////////////////////////////////// void alarm(float needTemp) { float tempInk = sensors.getTempCByIndex(0); float alarmTemp; boolean fanState; EEPROM_read(5, alarmTemp); EEPROM_read(9, fanState); //lcd.setCursor(0, 3); //lcd.print("A"); //lcd.print(needTemp + alarmTemp, 1); if ((millis() - alarmDelay) > 1800000) { if (tempInk > (needTemp + alarmTemp) || tempInk < (needTemp - alarmTemp)) { beeper(10); digitalWrite(alarm_pin, LOW); //если измеренная температура выше заданной на величину аварии } else digitalWrite(alarm_pin, HIGH); //то включаем аварийный сигнал. } if (tempInk > (needTemp + alarmTemp) && fanState == 1) needFan = 1; if (tempInk < (needTemp + alarmTemp - 2)) needFan = 0; } //пищалка//////////////////////////////////////////////////////////////////////// void beeper(int duration) { tone(beeper_pin, 2000, duration); } //управляем вентиляторами/////////////////////////////////////////////////////// void fan(int fanTime) { //float tempInk = sht1x.readTemperatureC(); DateTime now = RTC.now(); if ((now.hour() == 7 && now.minute() < fanTime) || (now.hour() == 19 && now.minute() < fanTime) || needFan == 1) { digitalWrite(fan_pin, LOW); //если наступило время проветривания или измеренная температура выше заданной на величину аварии, то включаем продувку. digitalWrite(extend_heater_pin, HIGH); // при этом отключаем обогрев digitalWrite(heater_pin, LOW); heater_off = true; } else { digitalWrite(fan_pin, HIGH); //иначе выключаем. heater_off = false; } } // вольтметр////////////////////////////////////////////////////////////////////////////// //void voltmeter() { // float outputValue = 0; // outputValue = float(analogRead(voltmeter_pin)) / 63, 9; // //if(outputValue < 4.5) beeper(50); // //Serial.print("Voltage = " ); // //Serial.println(outputValue); // lcd.setCursor(14, 3); // lcd.print("V"); // lcd.print(outputValue, 1); //} // //// Печать мощности нагрвателя //void outpuPower() { // lcd.setCursor(14, 3); // lcd.print("W"); // lcd.print(Output, 0); // lcd.print(" "); //} // дополнительный нагреватель ///////////////////////////////////////////////////////////// void ext_heater(float needTemp) { // управление дополнительным нагревателем на 8 ножке через блок реле. float tempInk = sensors.getTempCByIndex(0); if (tempInk < (needTemp - 3) && heater_off == false) digitalWrite(extend_heater_pin, LOW); else digitalWrite(extend_heater_pin, HIGH); } /******************************************** ПИД и отсылка данных в порт ********************************************/ union { // This Data structure lets byte asBytes[24]; // us take the byte array float asFloat[6]; // sent from processing and } // easily convert it to a foo; // float array void SerialReceive() { // read the bytes sent from Processing int index = 0; byte Auto_Man = -1; byte Direct_Reverse = -1; while (Serial.available() && index < 26) { if (index == 0) Auto_Man = Serial.read(); else if (index == 1) Direct_Reverse = Serial.read(); else foo.asBytes[index - 2] = Serial.read(); index++; } // if the information we got was in the correct format, // read it into the system if (index == 26 && (Auto_Man == 0 || Auto_Man == 1) && (Direct_Reverse == 0 || Direct_Reverse == 1)) { Setpoint = double(foo.asFloat[0]); //Input=double(foo.asFloat[1]); // * the user has the ability to send the // value of "Input" in most cases (as // in this one) this is not needed. if (Auto_Man == 0) // * only change the output if we are in { // manual mode. otherwise we'll get an Output = double(foo.asFloat[2]); // output blip, then the controller will } // overwrite. double p, i, d; // * read in and set the controller tunings p = double(foo.asFloat[3]); // i = double(foo.asFloat[4]); // d = double(foo.asFloat[5]); // myPID.SetTunings(p, i, d); // if (Auto_Man == 0) myPID.SetMode(MANUAL); // * set the controller mode else myPID.SetMode(AUTOMATIC); // if (Direct_Reverse == 0) myPID.SetControllerDirection(DIRECT); // * set the controller Direction else myPID.SetControllerDirection(REVERSE); // } Serial.flush(); // * clear any random data from the serial buffer } /// шлем данные в порт ////////////////////////////////////////////// void SerialSend() { //Serial.print(millis() / 1000); // Serial.print("PID "); // Serial.print(Setpoint); // Serial.print(" "); // Serial.print(Input); // Serial.print(" "); // Serial.print(Output); // Serial.print(" "); // Serial.print(myPID.GetKp()); // Serial.print(" "); // Serial.print(myPID.GetKi()); // Serial.print(" "); // Serial.print(myPID.GetKd()); // Serial.print(" "); // if (myPID.GetMode() == AUTOMATIC) Serial.print("Automatic"); // else Serial.print("Manual"); // Serial.print(" "); // if (myPID.GetDirection() == DIRECT) Serial.println("Direct"); // else Serial.println("Reverse"); delay(5); Serial.print("~Mink/set "); Serial.print(Setpoint); Serial.print("^~Mink/outpwr "); Serial.print(Output / 10); Serial.print("^~Mink/t1 "); Serial.print(temp1Ink); Serial.print("^~Mink/t2 "); Serial.print(temp2Ink); Serial.print("^~Mink/hum "); Serial.println(humidity); //Serial.print("^~Mink/alarm "); //Serial.print(digitalRead(alarm_pin)); //Serial.print("^~Mink/extheat "); //Serial.print(digitalRead(extend_heater_pin)); //Serial.print("^~Mink/fan "); //Serial.print(digitalRead(fan_pin)); //Serial.print("^~Mink/door "); //Serial.println(!digitalRead(door_pin)); }Братцы, помогите :)
Написано что это код для HTU21, но в скетче есть
Вы для этого весь скетч скопировали?
Да, что бы понятно было о чем речь.
В скетче библиотека SHT10 закоментирована а HTU21 открыта , подключай I2C и пользуйся
не компелируется скетч с поста #5 , ошибка EEPROM , скинте свои библиотеки на которых компелировали скетч
Там типовая библиотека. Попробуйте обновить её.
обновлял не помогает
Может скейч положить в другую папку без русского шрифта? Еще можно в нее же сдублировать библиотеки.
Было время баловался с ардуинами. На сегодняшний день
я отказался от разработок на основе этого девайса. Детство это всё.
Учитывая потраченное время нервы и полную стоимость радиодеталей, получается что проще покупать промышленные модули. Тот же ПР100 от Овна стоит 50$. Есть и готовые терморегуляторы с ПИД. Термодатчик ds18b20 не годится для инкубаторов. Как ни калибруй всё равно плавает + -0.5гр. Замерял лабораторным ртутным термометром 10 откалиброванных образцов. У этого датчика точность +-0.5. Вот и считайте разброс в инкубаторе от 37 до 38 будет, если выставить 37.5. Так и получалось. И никакими калибровками это не исправить. Нужно применять терморезисторы или термопары. Это всего лишь моё личное мнение исходя из пройденного опыта.
Мое бюджетное решение работает четко https://youtu.be/_Pho8txmL2g?t=799
ds18b20 просто имеет инерцию из за корпуса, а точность достаточная.
очень понравилось ваше решение ! но есть ряд вопросов
1 вы использовали датчик htu21d и даже ссылку привели , но он 3 вольта ему либо отдельно стабилизатор питания делать либо еще и согласование уровней
1.1 как поменять в flprog датчик на si7021 или скажем на aht10
2 зачем вторая кнопка меню если вполне достаточно одной и + -
3 можете добавить еще один таймер для поворота лотков ?
Привет.
Я только сейчас узнал что он 3,3в :) у меня нормально работает по 5в шине, кстати, может поэтому Дуня висла когда было одно питание? Сейчас у 5в потребителей и Дуни разное питание.
Поменять датчик просто, нужно найти пользовательский блок и вставить. или вручную код править.
Переворот делаю, шаговым двигателем с одним концевиком. И плату рисую что бы заказать в Китае.
Очень медленно, получается, учусь, времени мало.
Может кто помочь с EasyEda? Нарисовал схему, надо плату откорректировать и дорожки с полигонами... не врублюсь пока как.
А этот датчик пятивольтовый? Вроде стаб на борту
https://aliexpress.ru/item/32770816854.html?spm=a2g0o.cart.0.0.7d673c00HusL5K&mp=1
Там стаб, не парьтесь!
Кстати, если нужно подобрать коэффициенты ПИД регулятора можно воспользоваться библиотекой PID_AutoTune_v0.h.
Подбор коэффициентов происходит очень долго, несколько часов. У меня за ночь подобрались коэффициенты.
#include <PID_v1.h> #include <PID_AutoTune_v0.h> #include <OneWire.h> int DS18B20_Pin = 9; //DS18S20 Signal pin on digital 9 //Temperature chip i/o OneWire ds(DS18B20_Pin); // on digital pin 9 #define RelayPin 10 int relayPin = 10; int WindowSize = 3000; unsigned long windowStartTime; byte ATuneModeRemember=2; double input=80, output=50, setpoint=37.81; double kp=2,ki=0.5,kd=2; double kpmodel=1.5, taup=100, theta[50]; double outputStart=5; //5 double aTuneStep=500, aTuneNoise=1, aTuneStartValue=500; unsigned int aTuneLookBack=20; //200 boolean tuning = true; unsigned long modelTime, serialTime; PID myPID(&input, &output, &setpoint,kp,ki,kd, DIRECT); PID_ATune aTune(&input, &output); //set to false to connect to the real world boolean useSimulation = false; void setup() { //Setup the pid myPID.SetOutputLimits(0, WindowSize); myPID.SetMode(AUTOMATIC); if(useSimulation) { for(byte i=0;i<50;i++) { theta[i]=outputStart; } modelTime = 0; } if(tuning) { tuning=false; changeAutoTune(); tuning=true; } serialTime = 0; Serial.begin(9600); windowStartTime = millis(); //from pid test Relay pinMode(RelayPin,OUTPUT); //from pid test Relay } void loop() { unsigned long now = millis(); float temperature = getTemp(); float tempF = temperature;// * 9/5 + 32; if(!useSimulation) { //pull the input in from the real world input = tempF; } if(tuning) { byte val = (aTune.Runtime()); if (val!=0) { tuning = false; } if(!tuning) { //we're done, set the tuning parameters kp = aTune.GetKp(); ki = aTune.GetKi(); kd = aTune.GetKd(); myPID.SetTunings(kp,ki,kd); AutoTuneHelper(false); } } else myPID.Compute(); if(useSimulation) { theta[30]=output; if(now>=modelTime) { modelTime +=100; DoModel(); } } else { // analogWrite(0,output); // commented out by me unsigned long now = millis(); if(now - windowStartTime>WindowSize) { //time to shift the Relay Window windowStartTime += WindowSize; } if(output > now - windowStartTime) digitalWrite(RelayPin,HIGH); else digitalWrite(RelayPin,LOW); } //send-receive with processing if it's time if(millis()>serialTime) { SerialReceive(); SerialSend(); serialTime+=1000; } } void changeAutoTune() { if(!tuning) { //Set the output to the desired starting frequency. output=aTuneStartValue; aTune.SetNoiseBand(aTuneNoise); aTune.SetOutputStep(aTuneStep); aTune.SetLookbackSec((int)aTuneLookBack); AutoTuneHelper(true); tuning = true; } else { //cancel autotune aTune.Cancel(); tuning = false; AutoTuneHelper(false); } } void AutoTuneHelper(boolean start) { if(start) ATuneModeRemember = myPID.GetMode(); else myPID.SetMode(ATuneModeRemember); } void SerialSend() {Serial.print("Temprege: ");Serial.println(input); Serial.print("setpoint: ");Serial.print(setpoint); Serial.print(" "); Serial.print("input: ");Serial.print(input); Serial.print(" "); Serial.print("output: ");Serial.print(output); Serial.print(" "); if(tuning){ Serial.println(" tuning mode "); } else { Serial.print("Temprege: ");Serial.println(input); Serial.print("kp: ");Serial.print(myPID.GetKp());Serial.print(" "); Serial.print("ki: ");Serial.print(myPID.GetKi());Serial.print(" "); Serial.print("kd: ");Serial.print(myPID.GetKd());Serial.println(); } } void SerialReceive() { if(Serial.available()) { char b = Serial.read(); Serial.flush(); if((b=='1' && !tuning) || (b!='1' && tuning))changeAutoTune(); } } void DoModel() { //cycle the dead time for(byte i=0;i<49;i++) { theta[i] = theta[i+1]; } //compute the input input = (kpmodel / taup) *(theta[0]-outputStart) + input*(1-1/taup) + ((float)random(-10,10))/100; } float getTemp(){ //returns the temperature from one DS18S20 in DEG Celsius byte data[12]; byte addr[8]; if ( !ds.search(addr)) { //no more sensors on chain, reset search ds.reset_search(); return -1000; } if ( OneWire::crc8( addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return -1000; } if ( addr[0] != 0x10 && addr[0] != 0x28) { Serial.print("Deviceot recognized"); return -1000; } ds.reset(); ds.select(addr); ds.write(0x44,1); // start conversion, with parasite power on at the end byte present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad for (int i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } ds.reset_search(); byte MSB = data[1]; byte LSB = data[0]; float tempRead = ((MSB << 8) | LSB); //using two's compliment float TemperatureSum = tempRead / 16; return TemperatureSum; }Скажите вот тут подбирали коеффициенты. Вижу цикл 3 секунды. У автора цикл 1 секунда. Как с подбором?
Я сколько не бьюсь, подобрать не могу, все время перелет на кучу градусов с подобранными автотюнингом коеффициентами. Кто-то может помочь с autotune подбором даллас ds18b20 и нагревателем через реле?
Греете чем?
Alex130119 "Было время баловался с ардуинами."
Не нравяться вам кошки? Да вы их просто готовить не умеете :)) Всё нормально работает с терморезисторами и датчиком влажности на мокром термометре. И очень компактно при распайке Atmega328p на свою плату (вместо Ардуино) и отдельной силовой плате с мосфетами и симисторами, мощности то небольшие твердотелки не требуются. Как получу платы с JLCPCB бета версию могу выложить здесь.
Я тоже сделал свой вариант платы и прошивки, посмотрите что получилось.
ТЭНы - лампы накаливания 12в. Управление по ШИМ очень точное поддержание температуры.
https://youtu.be/Rip3yLcs34A
Спасибо посмотрел. А как у тебя управление влажностью до 1%. У меня мокрый гигрометр по таблице дает точность только 5%, а управление происходит сбросом лишней влажности вентилятором проветривания.
Замечание, если хочешь, на продажу нужно делать более "красиво", это внушает клиенту уверенность что, он покупает не кота в мешке. И поддержка нужна, схемы, инструкции... Работы много, а выход мизер.
Шас пофоткаю выложу свой отладочный вариант.
1% это конечно не совсем точно. Просто программа позволяет с таким гистерезисом работать а как там датчик отрабатывает это не много другое.
Бизнес на этом не сделаешь конечно, так для себя и знакомых сделать...
Это отладочный вариант контроллера, потом будет еще меньше. Силовая плата отдельно: два Мосфета, два Симистора и один H-мост. В бюджет 500р не вложился. :))
боюсь даже прецтавить, что там у этих плат с изнанки тварица. :)
Да ничего страшного :), индикатор на одном проводе по UART, на отдельном контроллере с произвольными символами. Входы выходы и скетч на 800строк.
А чоэта, фсе инкубасторы сабирать стали? Тренд хайп или мода ???
Контроллер универсальный как бы. Силовые платы предполагается можно менять. Начать хотел с контроллера полива :) Но там совсем просто - таймеры и всё. Потом будет Аквариум, Стиралка...
Потом будет Аквариум, Стиралка...
Дануна... ДатышО...
Ага, Чем еще на пенсии заняться. Ты наверно еще не родился когда я уже программировал. :)
Ты наверно еще не родился когда я уже программировал. :)
Верно мыслишь. Язык С сформировался в 1970-х годах и ты уже "кодил" ??? Крута!!!
Считам: ну школа + универ ~ 20. 20+30+20=70!!! Датышо, 70 лет??? Круто!!!
Мой из стиралки видели?
Я тоже сделал свой вариант платы и прошивки, посмотрите что получилось.
ТЭНы - лампы накаливания 12в. Управление по ШИМ очень точное поддержание температуры.
https://youtu.be/Rip3yLcs34A
По конструкции замечание к гребенке, которая желтая. Ненадежный у них контакт однако :-( Одно время подключал через такую дисплей, намучался, отказался в итоге. Хотя на видео видно пайку, то есть планируется что будет не разъемное, а паяное соединение? Тогда проблемы с быстрой заменой будут.
У меня в этом сезоне сдох неожиданно БП на 5 вольт в инкубаторе во время инкубации. Если все на разъемах, то заменить минутное дело.
Ну и энкодер тоже штука не очень надежная. Со временем начнет чудить :-(. У меня в курятнике контроллер стоит, через три года начались пропуски и перескакивания, хотя пользуюсь очень редко. У меня он вынесен с платы, подключается шлейфом, заменить его не сложно, но это же надо менять :-) а мне лень.
В инкубаторе и брудере сенсорные кнопки, вот им сносу нет, очень доволен. реализовано на TTP223 и TTP224. В принципе 4 кнопки достаточно для полноценного управления.
боюсь даже прецтавить, что там у этих плат с изнанки тварица. :)
Дет, если хочешь могу прислать как выгладит это вот чудо с обратной стороны, ну чтоб кошмары мучали ночами :-)
Дет, если хочешь могу прислать как выгладит это вот чудо с обратной стороны
Нет, я впечатлительный. Потом буду пить неделю.
Схема то хоть когда-нибудь будет выложена?
На какой проект? Здесь столько уже всего :)
Да на любой. Хочу "погонять" в симуляторе.
Никола Мастер, отпишись какая версия у тебя IDE, на какой плате (у меня УНО) собран инкубатор, скетч из твоего поста #107. Чет у меня такое впечатление складывается, что у инкубаторщиков как у пчеловодов - друзья, объятия а как о тонкостях пчеловодства, так прям "Брянские партизаны", хрен чё узнаеш ))), извените за офтоп. java1050@ukr.net