27.03.2014, 21:48 | #1 |
Member
Регистрация: 24.03.2014
Сообщений: 38
Вес репутации: 0 |
Акваконтроллер
Что имеется:
Arduino Mega 2560 LCD Keypad Shield 1602 c 5-ю кропками Блок реле (двухканальное) Часы DS1307 Tiny RTC I2C module, 24C32 EEPROM Датчик температуры DS18B20 LCD Keypad Shield подключен к пинам 4,5,6,7,8,9, кнопки к А0, подсветка к 10 пину. Датчик температуры DS18B20 подключен к пину 53. Блок реле к пинам 40,41 К пинам 3,11,12 подключены LED через мосфеты. 1). Реле будут включать обогрев (назовём Н1 и Н2), т.е. Н1 управляется по 40 пину, а Н2 - по 41. При температуре 28 включаются оба нагревателя. При достижении температуры 28,3 нагреватель Н1 отключается. При 28,5 отключается Н2. 2). LED подсветка (назовём LR – pin3, LW – pin11 и LB – pin12) включается и выключается по времени. Т.е. например в 17:00 плавно в течении 3 минут включается LW и LR, далее в 21:55 начинает плавно гаснуть ( минуты), а в это время плавно включается LB. Затем в 23:00 плавно гаснет (3 минуты) LB. Главный экран отображает: Т=28,4° 14:53 Н1-Off H2-On т.е. отображается текущая температура, текущее время и состояние нагревателей. Что ещё нужно: возможность включения и выключения света LW и LR кнопками (UP-Вкл., DOWN-Выкл.), независимо от времени. А также возможность включения и выключения нагревателя Н2 кнопками (LEFT-Вкл., RIGHT-Выкл.), независимо от температуры. Вот код: Код HTML:
#include <Wire.h> //Подключаем библиотеку для использования I2C интерфейса с модулем RTC #include "RTClib.h" //Подключаем библиотеку для использования модуля часов реального времени RTC #include <OneWire.h> #include <DallasTemperature.h> // библиотека экрана #include "LiquidCrystal.h" LiquidCrystal lcd(8, 9, 4, 5, 6, 7); OneWire ds(53); // Подключаем датчик к 53 цифровому пину int lcd_key = 0; int adc_key_in = 0; #define btnRIGHT 0 #define btnUP 1 #define btnDOWN 2 #define btnLEFT 3 #define btnSELECT 4 #define btnNONE 5 // read the buttons int read_LCD_buttons() { adc_key_in = analogRead(0); // read the value from the sensor // my buttons when read are centered at these valies: 0, 142, 328, 504, 741 // we add approx 50 to those values and check to see if we are close if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result if (adc_key_in < 50) return btnRIGHT; if (adc_key_in < 250) return btnUP; if (adc_key_in < 400) return btnDOWN; if (adc_key_in < 600) return btnLEFT; if (adc_key_in < 850) return btnSELECT; return btnNONE; // when all others fail, return this... } #define PWM_LW_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LW_MAX 128 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LW_PIN 11 //Пин порта, где будет ШИМ LW #define PWM_LR_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LR_MAX 200 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LR_PIN 3 //Пин порта, где будет ШИМ LR #define PWM_LB_MIN 0 //Если необходим ток покоя на LED - изменить эту константу #define PWM_LB_MAX 235 //Если необходимо ограничить максимальную яркость - уменьшить значение #define PWM_LB_PIN 12 //Пин порта, где будет ШИМ LB #define mn 60UL //Дополнительные константы для удобства #define hr 3600UL //Отражают соответствующие количества секунд #define d 86400UL int Relay_Off = HIGH; int Relay_On = LOW; RTC_DS1307 RTC; long sunrise_start = 17*hr+00*mn; //Начало восхода в 9 - 45 long sunrise_duration = 3*mn; //Длительность восхода 30 минут long sunset_start = 22*hr+00*mn; //начало заката в 21-15 long sunset_duration = 3*mn; //Длительность заката 30 минут long moonrise_start = 22*hr+00*mn ; //Начало луны в 9 - 45 long moonrise_duration = 3*mn; //Длительность восхода long moonset_start = 23*hr+00*mn; //Конец луны в 11 long moonset_duration = 3*mn; //Длительность заката луны //******************************************************************************************** void setup(){ Serial.begin(9600); lcd.begin(16, 2); // запускаем библиотеку экрана pinMode(40, OUTPUT); // Включаем кипятильник pinMode(41, OUTPUT); digitalWrite(40, Relay_On); digitalWrite(41, Relay_On); Wire.begin(); //Инициируем I2C интерфейс RTC.begin(); //Инициирум RTC модуль analogWrite(PWM_LW_PIN, PWM_LW_MIN); //Пишем в порт минимальное значение analogWrite(PWM_LR_PIN, PWM_LR_MIN); analogWrite(PWM_LB_PIN, PWM_LB_MIN); if (! RTC.isrunning()) { Serial.println("RTC is NOT running!"); RTC.adjust(DateTime(2014, 7, 12, 22, 48, 1)); } //RTC.adjust(DateTime(__DATE__, __TIME__)); } // КОНЕЦ ИНИЦИАЛИЗАЦИИ //******************************************************************************************** void loop() // ПРОГРАММЫй безусловный ЦИКЛ { analogWrite(10, 100); lcd.setCursor(0, 1); long pwm_LW; long pwm_LR; long pwm_LB; DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла long Day_time = myTime.unixtime() % 86400; //сохраняем в переменную - время в формате UNIX lcd.setCursor(11,0); if(myTime.hour()<10)lcd.print(0); lcd.print(myTime.hour(),DEC); lcd.print(":"); if(myTime.minute()<10)lcd.print(0); lcd.print(myTime.minute(),DEC); //********************************************************************************************* // обработка интервала до восхода и после заката //********************************************************************************************* if ((Day_time<sunrise_start) || //Если с начала суток меньше чем начало восхода (Day_time>=sunset_start+sunset_duration)) { //Или больше чем начало заката + длительность pwm_LW = PWM_LW_MIN; //Величина для записи в порт равна минимуму pwm_LR = PWM_LR_MIN; //********************************************************************************************* // обработка интервала восхода //********************************************************************************************* }else if ((Day_time>=sunrise_start) && //Если с начала суток больше чем начало восхода (Day_time<sunrise_start+sunrise_duration)){ //И меньше чем начало восхода + длительность pwm_LW = ((Day_time - sunrise_start)*(PWM_LW_MAX-PWM_LW_MIN)) / sunrise_duration; //Вычисляем для рассвета величину для записи в порт ШИМ pwm_LR = ((Day_time - sunrise_start)*(PWM_LR_MAX-PWM_LR_MIN)) / sunrise_duration; //********************************************************************************************* // обработка интервала заката //********************************************************************************************* }else if ((Day_time>=sunset_start) && //Если начала суток больше чем начало заката и меньше чем (Day_time<sunset_start+sunset_duration)){ //начало заката плюс длительность pwm_LW = ((sunset_start+sunset_duration - Day_time)*(PWM_LW_MAX-PWM_LW_MIN)) / sunrise_duration; //Вычисляем для заката величину для записи в порт ШИМ pwm_LR = ((sunset_start+sunset_duration - Day_time)*(PWM_LR_MAX-PWM_LR_MIN)) / sunrise_duration; //******************************************************************************************** // обработка интервала от конца рассвета и до начала заката, // когда свет должен быть включен на максимальную яркость //******************************************************************************************** }else { pwm_LW = PWM_LW_MAX; //Устанавливаем максимальную величину для записи в порт ШИМ pwm_LR = PWM_LR_MAX; } analogWrite(PWM_LW_PIN, pwm_LW); //Пишем в порт вычисленное значение analogWrite(PWM_LR_PIN, pwm_LR); // обработка интервала до восхода луны и после заката //********************************************************************************************* if ((Day_time<moonrise_start) || //Если с начала суток меньше чем начало восхода (Day_time>=moonset_start+moonset_duration)) { //Или больше чем начало заката + длительность pwm_LB = PWM_LB_MIN; //Величина для записи в порт равна минимуму //********************************************************************************************* // обработка интервала восхода луны //********************************************************************************************* }else if ((Day_time>=moonrise_start) && //Если с начала суток больше чем начало восхода (Day_time<moonrise_start+moonrise_duration)){ //И меньше чем начало восхода + длительность pwm_LB = ((Day_time - moonrise_start)*(PWM_LB_MAX-PWM_LB_MIN)) / moonrise_duration; //Вычисляем для рассвета величину для записи в порт ШИМ //********************************************************************************************* // обработка интервала заката луны //********************************************************************************************* }else if ((Day_time>=moonset_start) && //Если начала суток больше чем начало заката и меньше чем (Day_time<moonset_start+moonset_duration)){ //начало заката плюс длительность pwm_LB = ((moonset_start+moonset_duration - Day_time)*(PWM_LB_MAX-PWM_LB_MIN)) / moonrise_duration; //Вычисляем для заката величину для записи в порт ШИМ //******************************************************************************************** // обработка интервала от конца рассвета и до начала заката луны, // когда свет должен быть включен на максимальную яркость //******************************************************************************************** }else { pwm_LB = PWM_LB_MAX; //Устанавливаем максимальную величину для записи в порт ШИМ } analogWrite(PWM_LB_PIN, pwm_LB); //Пишем в порт вычисленное значение byte i; byte type_s; byte data[12]; byte addr[8]; float celsius, fahrenheit; // Ищем алрес датчика if ( !ds.search(addr)) { Serial.println("No more addresses."); Serial.println(); ds.reset_search(); delay(250); return; } // Проверяем не было ли помех при передаче if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); return; } Serial.println(); // Определяем серию датчика switch (addr[0]) { case 0x10: Serial.println(" Chip = DS18S20"); type_s = 1; break; case 0x28: Serial.println(" Chip = DS18B20"); type_s = 0; break; case 0x22: Serial.println(" Chip = DS1822"); type_s = 0; break; default: Serial.println("Device is not a DS18x20 family device."); return; } ds.reset(); ds.select(addr); // Выбираем адрес ds.write(0x44, 1); // Производим замер, в режиме паразитного питания delay(750); ds.reset(); ds.select(addr); ds.write(0xBE); // Считываем оперативную память датчика for ( i = 0; i < 9; i++) { data[i] = ds.read(); // Заполняем массив считанными данными } // Данные о температуре содержатся в первых двух байтах, переведем их в одно значение и преобразуем в шестнадцатиразрядное число unsigned int raw = (data[1] << 8) | data[0]; // Переводим температуру в шкалы по Цельсию и Фаренгейту if (type_s) { raw = raw << 3; } if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; } else { byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw << 3; else if (cfg == 0x20) raw = raw << 2; else if (cfg == 0x40) \ raw = raw << 1; } // Вывод текущего значения температуры на дисплей celsius = (float)raw / 16.0; lcd.setCursor(0, 0); lcd.print("T="); lcd.setCursor(2, 0); lcd.print(celsius); delay (10); celsius = (float)raw / 16.0; fahrenheit = celsius * 1.8 + 32.0; Serial.print("Temp = "); Serial.print(celsius); Serial.print(" C, "); Serial.print(fahrenheit); Serial.println(" F"); // Если температура достигает 28,3 (с погрешностью), отключаем кипятильник if (celsius > 28.3) { digitalWrite(40, Relay_Off); lcd.setCursor(0, 1); lcd.print("H1-Off"); } if (celsius < 28.0) { digitalWrite(40, Relay_On); lcd.setCursor(0, 1); lcd.print("H1-On "); digitalWrite(41, Relay_On); lcd.setCursor(7, 1); lcd.print("H2-On "); } // Если температура достигает 28,5 (с погрешностью), отключаем кипятильник if (celsius > 28.5) { digitalWrite(41, Relay_Off); lcd.setCursor(7, 1); lcd.print("H2-Off"); } lcd_key = read_LCD_buttons(); // read the buttons switch (lcd_key) // depending on which button was pushed, we perform an action { case btnRIGHT: { digitalWrite(41, Relay_Off); lcd.setCursor(7, 1); lcd.print("H2-Off"); break; } case btnLEFT: { digitalWrite(41, Relay_On); lcd.setCursor(7, 1); lcd.print("H2-On "); break; } case btnUP: { lcd.print("UP "); break; } case btnDOWN: { lcd.print("DOWN "); break; } } }//------------Конец ЦИКЛА----------------------------- Последний раз редактировалось kirex; 27.03.2014 в 21:50. |
27.03.2014, 22:21 | #2 |
Administrator
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,618
Вес репутации: 9823 |
Re: Акваконтроллер
Для простого варианта реализации кнопки, можно использовать прерывания
|
27.03.2014, 22:39 | #3 |
Member
Регистрация: 24.03.2014
Сообщений: 38
Вес репутации: 0 |
Re: Акваконтроллер
Извините, а можно поподробнее. И кнопки хотелось бы использовать те которые на LCD Keypad Shield 1602
Последний раз редактировалось kirex; 27.03.2014 в 22:46. |
27.03.2014, 23:19 | #4 |
Administrator
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,618
Вес репутации: 9823 |
Re: Акваконтроллер
А куда они подключены? К каким пинам?
|
27.03.2014, 23:28 | #5 |
Member
Регистрация: 24.03.2014
Сообщений: 38
Вес репутации: 0 |
Re: Акваконтроллер
Кнопки подключены к одному пину А0, т.е. через резистивный делитель.
В моём коде пока кнопку держу реле срабатывает, отпускаю - возвращается в первоначальное положение. Последний раз редактировалось kirex; 27.03.2014 в 23:34. |
28.03.2014, 03:01 | #6 |
Senior Member
Регистрация: 02.04.2012
Адрес: Питер
Сообщений: 1,125
Вес репутации: 1311 |
Re: Акваконтроллер
Если не нажата, то нажимаем и держим, если нажата, то отпускаем.
|
28.03.2014, 11:10 | #7 |
Administrator
Регистрация: 12.04.2010
Адрес: Москва
Сообщений: 9,618
Вес репутации: 9823 |
Re: Акваконтроллер
Вот функция в которой читаются нажатия кнопок
PHP код:
PHP код:
|
28.03.2014, 12:06 | #8 |
Member
Регистрация: 24.03.2014
Сообщений: 38
Вес репутации: 0 |
Re: Акваконтроллер
|
28.03.2014, 12:08 | #9 | |
Member
Регистрация: 24.03.2014
Сообщений: 38
Вес репутации: 0 |
Re: Акваконтроллер
Цитата:
|
|
28.03.2014, 14:40 | #10 |
Senior Member
Регистрация: 20.01.2013
Адрес: Уфа
Сообщений: 444
Вес репутации: 799 |
Re: Акваконтроллер
этого мало - я уже ранее писал -да написания программы нужно продумать алгоритм действий. Его ты так и не описал. Допустим у тебя нагреватели включаются и выключаются по температуре. Кнопкой ты принудительно его включаешь - а дальше что? когда автомат снова должен включиться?
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1) | |
|
|