Здравсвуйте, представляю вашему вниманию проект на Arduino. Террариум, в котором живёт черепаха. Наше устройство служит для выполнения следующих задач:
1) включение и выключение лампы по расписанию (день-ночь);
2) поддержание температуры в террариуме путём включения и выключения нагревательного элемента;
3) отображение текущего времени суток и температуры воды в террариуме на четырёхсекционном светодиодном семисегментном дисплее (хорошо видно днём и ночью, выполняют функцию настенных часов), яркость дисплея меняется в зависимости от сотояния "день/ночь";
4) Все необходимые пользователю настоечные параметры (уставка температуры, гистерезис, первый и последний часы дня, текущее время) возможно легко задавать без подключения к ПК или иным устройствам, то есть с кнопок.
Вот результат решения этой задачи
Для этого проекта я использовал модули:
Arduino Pro Mini (ATmega328, 5В)
Реле э/м 1-канальное, 5В - 2 шт. Рекомендую вместо них использовать Реле электромеханическое 2-канальное - 1 шт.
Модуль часов реального времени DS1307
Цифровой дисплей TM1637
Кнопка - 4 шт.
термистор
резистор 10 кОм - пачка :)
Схему соединения выложу позже. Назначения пинов ясно из деректив #define в начале кода. Незабываем кнопки (включая reset) и термистор подключать с использованием резисторов.
программный код:
1) включение и выключение лампы по расписанию (день-ночь);
2) поддержание температуры в террариуме путём включения и выключения нагревательного элемента;
3) отображение текущего времени суток и температуры воды в террариуме на четырёхсекционном светодиодном семисегментном дисплее (хорошо видно днём и ночью, выполняют функцию настенных часов), яркость дисплея меняется в зависимости от сотояния "день/ночь";
4) Все необходимые пользователю настоечные параметры (уставка температуры, гистерезис, первый и последний часы дня, текущее время) возможно легко задавать без подключения к ПК или иным устройствам, то есть с кнопок.
Вот результат решения этой задачи
Arduino Pro Mini (ATmega328, 5В)
Реле э/м 1-канальное, 5В - 2 шт. Рекомендую вместо них использовать Реле электромеханическое 2-канальное - 1 шт.
Модуль часов реального времени DS1307
Цифровой дисплей TM1637
Кнопка - 4 шт.
термистор
резистор 10 кОм - пачка :)
Схему соединения выложу позже. Назначения пинов ясно из деректив #define в начале кода. Незабываем кнопки (включая reset) и термистор подключать с использованием резисторов.
программный код:
#include
#include
#include
#include
#include
#include
//номера пинов
#define LIGHT 2
#define TEN 3
#define DISPLAY_CLK 4
#define DISPLAY_DIO 5
#define BUTTON_MODE 9
#define BUTTON_MINUS 7
#define BUTTON_PLUS 8
// **************
//количество режимов настройки
#define MIN_TUNER_MODE 2
#define MAX_TUNER_MODE 6
#define TIMEOUT 10
// **************
//адрес настроек в Eeprom
#define EE_ADDRESS 0
// **************
class Timer
{
long int start_time;
public:
void start()
{
start_time = millis();
}
int seconds()
{
return (int)((millis() - start_time)/1000);
}
long int miliseconds();
Timer()
{
start();
}
};
struct Settings
{
float temp_ust,temp_hyst;//температура, поддерживаемая в аквариуме, гистерезис
int time_light_on,time_light_off;//время включения и выключения света
};
Settings settings;
int8_t DispMSG[] = {10, 16, 31, 6};
TM1637 clock_diplay(DISPLAY_CLK, DISPLAY_DIO);
bool ten_on=false;
Timer notclick;
double Thermister(int RawADC) {
double Temp;
Temp = log(((10240000/(1024-RawADC)) - 10000));
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
Temp = Temp - 273.15; // Kelvin to Celcius
//Temp = (Temp * 9.0)/ 5.0 + 32.0; // 1 способ Convert Celcius to Fahrenheit
//Temp = (Temp * 1.8) + 32.0; // 2 способ Convert Celcius to Fahrenheit
return Temp;
/*
float RT, VR, ln, TX, T0;
int VRT;
VRT=RawADC;
VRT = (5.00 / 1023.00) * VRT; //Преобразуем в напряжение
VR = VCC - VRT;
RT = VRT / (VR / R); //Сопротивление RT
ln = log(RT / RT0);
TX = (1 / ((ln / B) + (1 / T0))); //Температура с термистора
TX = TX - 273.15; //Преобразуем в цельсии
return TX;*/
}
void show_error(int8_t err_num)
{
DispMSG[0] = 14;
DispMSG[1] = 28;
DispMSG[2] = 28;
DispMSG[3]=err_num;
clock_diplay.display(DispMSG);
clock_diplay.point( false );
}
void relaySet(tmElements_t tm_)
{
if( (tm_.Hour >= settings.time_light_on)&&(tm_.Hour <= settings.time_light_off ) )
{
digitalWrite(LIGHT, LOW);
Serial.println("Light ON");
clock_diplay.set(7);
}
else
{
digitalWrite(LIGHT, HIGH);
Serial.println("Light OFF");
clock_diplay.set(1);
}
if( ten_on )
{
if (float(Thermister(analogRead(0)))> settings.temp_ust+settings.temp_hyst )
ten_on=false;
digitalWrite(TEN, LOW);
Serial.println("TEN ON");
}
else
{
if (float(Thermister(analogRead(0))) < settings.temp_ust-settings.temp_hyst )
ten_on=true;
digitalWrite(TEN, HIGH);
Serial.println("TEN OFF");
}
}
void clockDispSet(tmElements_t tm_)
{
if((tm_.Second%10)>4)
{
DispMSG[0]=tm_.Hour/10;
DispMSG[1]=tm_.Hour%10;
DispMSG[2]=tm_.Minute/10;
DispMSG[3]=tm_.Minute%10;
clock_diplay.display(0,DispMSG[0]);
clock_diplay.point( ((tm_.Second%2)>0) );
clock_diplay.display(1,DispMSG[1]);
clock_diplay.display(2,DispMSG[2]);
clock_diplay.display(3,DispMSG[3]);
}
else
{
int temp=int(Thermister(analogRead(0)));
DispMSG[0]=temp/10;
DispMSG[1]=temp%10;
DispMSG[2]=33;//17;
DispMSG[3]=12;
clock_diplay.point( false );
clock_diplay.display(DispMSG);
}
}
void mode1() {
tmElements_t tm;
Serial.print("Sensor_0: ");
Serial.println(float(Thermister(analogRead(0))), 1); // выводим показание 1 датчика
if (RTC.read(tm)) {
Serial.print("Time = ");
Serial.print(tm.Hour);
Serial.write(':');
Serial.print(tm.Minute);
Serial.write(':');
Serial.print(tm.Second);
Serial.print(", Date (D/M/Y) = ");
Serial.print(tm.Day);
Serial.write('/');
Serial.print(tm.Month);
Serial.write('/');
Serial.print(tmYearToCalendar(tm.Year));
Serial.println();
relaySet(tm);
clockDispSet(tm);
} else {
setHour();
Serial.println("There are problem whith DS1307RTC");
if (RTC.chipPresent()) {
Serial.println("The DS1307 is stopped. Please run the SetTime");
Serial.println("example to initialize the time and begin running.");
Serial.println();
} else {
Serial.println("DS1307 read error! Please check the circuitry.");
Serial.println();
}
delay(9000);
}
}
void show_mode(int mode)
{
tmElements_t tm;
switch(mode)
{
case -1: DispMSG[0] = 17; DispMSG[1] = 17; clock_diplay.point( false ); DispMSG[2] = 17; DispMSG[3] = 17; break;
case 2: DispMSG[0] = 29; DispMSG[1] = 33; clock_diplay.point( true ); DispMSG[2] = (int)settings.temp_ust/10; DispMSG[3] = (int)settings.temp_ust%10; break;
case 3: DispMSG[0] = 20; DispMSG[1] = 29; clock_diplay.point( true ); DispMSG[2] = (int)settings.temp_hyst; DispMSG[3] = (int)(10*settings.temp_hyst)%10; break;
case 4: DispMSG[0] = 34; DispMSG[1] = 17; clock_diplay.point( true ); DispMSG[2] = settings.time_light_on/10; DispMSG[3]=settings.time_light_on%10;break;
case 5: DispMSG[0] = 36; DispMSG[1] = 17; clock_diplay.point( true ); DispMSG[2] = settings.time_light_off/10; DispMSG[3]=settings.time_light_off%10;break;
case 6: DispMSG[0] = 29; DispMSG[1] = 21; clock_diplay.point( false ); DispMSG[2] = 26; DispMSG[3] = 14; break;
/*
case 6:
DispMSG[0] = 25; DispMSG[1] = 25; clock_diplay.point( true );
if (RTC.read(tm)) { DispMSG[2] = tm.Minute/10; DispMSG[3] = tm.Minute%10;}
else { DispMSG[2] = 0; DispMSG[3]=0;}
break;
case 7:
DispMSG[0] = 19; DispMSG[1] = 17; clock_diplay.point( true );
if (RTC.read(tm))
{
DispMSG[2] = tm.Hour/10;
DispMSG[3] = tm.Hour%10;
}
else { DispMSG[2] = 0; DispMSG[3]=0;}
break;
*/
}
clock_diplay.display(DispMSG);
}
void show_float(float f)
{
DispMSG[0]=(int)f/10;
DispMSG[1]=(int)f%10;
DispMSG[2]=35;
DispMSG[3]=(int)(f*10)%10;
clock_diplay.display(0,DispMSG[0]);
clock_diplay.point( false );
clock_diplay.display(1,DispMSG[1]);
clock_diplay.display(2,DispMSG[2]);
clock_diplay.display(3,DispMSG[3]);
}
void setFloat(float *var,float minimum,float maximum)
{
Serial.println("Set float");
show_float(*var);
Serial.println(*var);
delay(500);
while( (digitalRead(BUTTON_MODE) == LOW) &&(notclick.seconds(){
if(digitalRead(BUTTON_PLUS) == HIGH)
{
notclick.start();
*var = (*var) + 0.1;
// if( (*var)>maximum )
// (*var) = minimum;
Serial.println(*var);
show_float(*var);
delay(250);
}
if(digitalRead(BUTTON_MINUS) == HIGH)
{
notclick.start();
*var = (*var) - 0.1;
if( (*var)< minimum )
(*var) = maximum;
Serial.println(*var);
show_float(*var);
delay(250);
}
}
}
void show_int(int dm0,int dm1,int var)
{
DispMSG[0]=dm0;
DispMSG[1]=dm1;
DispMSG[2]=var/10;
DispMSG[3]=var%10;
clock_diplay.display(0,DispMSG[0]);
clock_diplay.point( true );
clock_diplay.display(1,DispMSG[1]);
clock_diplay.display(2,DispMSG[2]);
clock_diplay.display(3,DispMSG[3]);
}
void setInt(int dm0,int dm1,int *var,int minimum,int maximum)
{
Serial.println("Set int");
show_int(dm0,dm1,*var);
delay(500);
while(( digitalRead(BUTTON_MODE) == LOW)&&(notclick.seconds(){
if(digitalRead(BUTTON_PLUS) == HIGH)
{
notclick.start();
(*var)++;
if( (*var)>maximum )
(*var) = minimum;
show_int(dm0,dm1,*var);
Serial.println(*var);
delay(250);
}
if(digitalRead(BUTTON_MINUS) == HIGH)
{
notclick.start();
(*var)--;
if( (*var)< minimum )
(*var) = maximum;
show_int(dm0,dm1,*var);
Serial.println(*var);
delay(250);
}
}
}
void setTemp()
{
float temp = settings.temp_ust;
setFloat(&temp,10,40);
settings.temp_ust = temp;
EEPROM.put(EE_ADDRESS, settings);
}
void setHyst()
{
setFloat(&(settings.temp_hyst),0.1,3);
EEPROM.put(EE_ADDRESS, settings);
}
void setTimeLightOn()
{
setInt(0,26, &(settings.time_light_on),0,23 );
EEPROM.put(EE_ADDRESS, settings);
}
void setTimeLightOff()
{
setInt(0,15, &(settings.time_light_off),0,23 );
EEPROM.put(EE_ADDRESS, settings);
}
void setHour()
{
tmElements_t tm;
int h,m;
if(RTC.read(tm))
{
h = tm.Hour;
m = tm.Minute;
}
else
{
h = 12;
m = 0;
}
setInt(19,17,&h,0,23);
setInt(17,17,&m,0,59);
tm.Hour = h;
tm.Minute = m;
tm.Second = 0;
tm.Day = 1;
tm.Month = 1;
tm.Year = 18;
RTC.write(tm);
}
void mode2()
{
int mode=MIN_TUNER_MODE;//переменная выбора режима
show_mode(-1);
delay(500);
while( (mode<=MAX_TUNER_MODE)&&(notclick.seconds(){
if(digitalRead(BUTTON_MODE) == HIGH)
{
notclick.start();
mode++;
show_mode(-1);
delay(500);
}
if ( (digitalRead(BUTTON_PLUS) == HIGH) || (digitalRead(BUTTON_MINUS) == HIGH) )
{
notclick.start();
switch(mode)
{
case 2: setTemp();break;
case 3: setHyst();break;
case 4: setTimeLightOn();break;
case 5: setTimeLightOff();break;
case 6: setHour();break;
}
}
Serial.print("mode: ");
Serial.println(mode);
show_mode(mode);
}
}
void print2digits(int number) {
if (number >= 0 && number < 10) {
Serial.write('0');
}
Serial.print(number);
}
void loop()
{
if(digitalRead(BUTTON_MODE) == LOW)
{
mode1();
}
else
{
notclick.start();
mode2();
}
}
void setup() {
Serial.begin(9600);
while (!Serial) ; // wait for serial
delay(200);
Serial.println("Akvarium v6 geting settings and testing.");
Serial.println("-------------------");
EEPROM.get(EE_ADDRESS, settings);
if( !( (settings.temp_ust > -50. )&&(settings.temp_ust < 100. ) ) )
{
Serial.println("install default settings.");
settings.temp_ust = 22;
settings.temp_hyst = 1;
settings.time_light_on=9;
settings.time_light_off=21;
EEPROM.put(EE_ADDRESS, settings);
}
clock_diplay.init();
//Установка яркости горения сегментов
/*
* BRIGHT_TYPICAL = 2 Средний
* BRIGHT_DARKEST = 0 Тёмный
* BRIGHTEST = 7 Яркий
*/
clock_diplay.set(BRIGHT_TYPICAL);
//Задание на включение разделителя
clock_diplay.point(true);
//Выводим массив на дисплей
clock_diplay.display(DispMSG);
pinMode(LIGHT, OUTPUT);
pinMode(TEN, OUTPUT);
pinMode(A0, INPUT);
pinMode(BUTTON_MODE, INPUT);
pinMode(BUTTON_MINUS, INPUT);
pinMode(BUTTON_PLUS, INPUT);
/**/
digitalWrite(LIGHT, LOW);
delay(1500);
digitalWrite(LIGHT, HIGH);
delay(1500);
/**/
}