ARDUINO для автоматизации аквариума

<< 1234 6789101112 >>

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
ARDUINO для автоматизации аквариума
Создал отдельную тему по вопросам использования простых и не дорогих плат ARDUINO для целей автоматизации аквариума.
Идея такая - довести это устройство до полнофункционального контроллера для аквариума, в итоге - с WEB сервером для управления по сети в т.ч. Интернет, и GSM модулем с отправкой SMS.
Начало обсуждения в теме про дозатор :
http://www.aqa.ru/fo...

Информация будет, в основном, в виде конкретных примеров.

Пример 1. Использоание плат Arduino UNO и Arduino NANO для управления по времени суток устройствами в 2-х каналах посредством релейного модуля.
Предполагается использование для создания 2-х канального дозатора, но и для включения света, например подойдет, и для многих других целей также.

Используется модуль часов реального времени, для точного планирования по времени суток, и релейный модуль. В данном примере используется 4-канальный, но 2 канала не используются...

Схема коммутации в случае использования платы UNO R3:


Схема коммутации в случае использования платы NANO:


Программа для среды программирования Arduino:
//***************************************************
// Скетч для управления релейным модулем, в котором *
// использовано два канала. Используется также RTC *
// Релейный модуль - с инверсной логикой на входе *
// Автор: ZORS *
// Версия 1. Дата 21.12.2013 02:40 *
//***************************************************
//----------ИМПОРТ БИБЛИОТЕК-------------------------
#include <Wire.h> //Подключаем библиотеку для использования I2C интерфейса с модулем RTC
#include <RTClib.h> //Подключаем библиотеку для использования модуля часов реального времени RTC

RTC_DS1307 RTC; //Создаем переменную класса - для использования RTC

//----------Объявляем разные переменные------------
const int RelayChn1 = 6; //Используем цифровой ПОРТ 6 для ПЕРВОГО канала релейного модуля
const int RelayChn2 = 7; //Используем цифровой ПОРТ 7 для ВТОРОГО канала релейного модуля
//----------Настройки времени и продолжительности включения реле

//----------ПЕРВЫЙ канал----------------------------
const long StartRelCn_1 = 25200; //Время срабатывания в ПЕРВОМ канале релейного модуля (в секундах от начала суток)
//в данном случае 25200 - это 7 часов 00 минут = ( 60секунд *60 минут *7 = 25200)
const long DurationCh_1 = 10; //ДЛИТЕЛЬНОСТЬ срабатывания реле в ПЕРВОМ канале (в секундах)

//----------ВТОРОЙ канал----------------------------
const long StartRelCn_2 = 37800; //Время срабатывания во ВТОРОМ канале релейного модуля (в секундах от начала суток)
//В данном случае 10 часов 30 минут = (60 секунд * 60 минут * 10 часов + 60сек*30мин = 37800)
const long DurationCh_2 = 15; //ДЛИТЕЛЬНОСТЬ срабатывания реле во ВТОРОМ канале (в секундах)

//----------Модуль инициализации setup() - выполняется один раз при инициализации платы при подаче напряжение (и аналогичных событиях)
void setup(){

pinMode(RelayChn1,OUTPUT); //Инициализируем порт для ПЕРВОГО канала как ВЫХОД
pinMode(RelayChn2,OUTPUT); //Инициализируем порт для ВТОРОГО канала как ВЫХОД

digitalWrite(RelayChn1,HIGH); //Устанавливаем на входах релейного модуля ВЫСОКИЙ уровень
digitalWrite(RelayChn2,HIGH); //Т.к. используемый релейный модуль с опторазвязкой - управляется инверсной логикой



Wire.begin(); //Инициируем I2C интерфейс
RTC.begin(); //Инициирум RTC модуль

// RTC.adjust(DateTime(__DATE__, __TIME__)); //С этой строки необходимо убрать комментарии один раз в начале,
//для того, чтобы загрузить в RTC дату и время на момент компиляции программы
//Иногда необходимо заливать СКЕТЧ на плату со снятым комментарием - для поправки
//времени в RTC, НО оставлять такой СКЕТЧ в работе НЕЛЬЗЯ !!!!!!!!!!!!!

} // КОНЕЦ ИНИЦИАЛИЗАЦИИ

//--------------------------------------------------
void loop() // ПРОГРАММЫй безусловный ЦИКЛ
{
DateTime myTime = RTC.now(); //Читаем данные времени из RTC при каждом выполнении цикла

//----------Раздел обработки реле по времени ----
long utime = myTime.unixtime(); //сохраняем в переменную - время в формате UNIX
utime %= 86400; //Сохраняем в этой же переменной остаток деления на кол-во секнд в сутках,
//Это дает количество секунд с начала текущих суток

//------------КАНАЛ 1------------------------------
if ((utime >= StartRelCn_1) &&
(utime < (StartRelCn_1+DurationCh_1)))
//Если секунд с начала суток больше, чем задано для включения
//Но, одновременно и меньше, чем задано для включения + длительность
{
digitalWrite(RelayChn1,LOW); //Устанавливаем на ПЕРВОМ входе релейного модуля НИЗКИЙ уровень - реле срабатывает
}
else //во всех остальных случаях
{
digitalWrite(RelayChn1,HIGH); //Устанавливаем на ПЕРВОМ входе релейного модуля ВЫСОКИЙ уровень - реле выключается
}

//------------КАНАЛ 2 - все аналогично -----------
if ((utime >= StartRelCn_2) &&
(utime < (StartRelCn_2+DurationCh_2)))
{
digitalWrite(RelayChn2,LOW); //Устанавливаем на ВТОРОМ входе релейного модуля НИЗКИЙ уровень - реле срабатывает
}
else
{
digitalWrite(RelayChn2,HIGH); //Устанавливаем на ВТОРОМ входе релейного модуля ВЫСОКИЙ уровень - реле выключается
}

}//------------Конец ЦИКЛА-----------------------------


(Редактор текста на данном сайте - к сожалению, "ломает" красивое форматирование.

PS: Выложил этот скетч на файлообменник :
http://my-files.ru/h...

В данной программе реализован, довольно-таки простой подход, а простота - основа надежности.

Каждое из 2-х реле срабатывают один раз в сутки в указанное время, причем время указывается в количестве секунд от начала суток, и удерживается указанное количество времени в секундах.
Такой способ задания времени - несколько сложен для понимания, но за это - не нагружает программу и процессор лишним функционалом, который понадобится всего один раз.
Для определения времени наступления события начала включения и выключения реле - используется время в формате UNIX.

Такой подход хорош тем, что даже если включение или перезагрузка платы произойдет в промежутке времени включения, то реле включится в оставшееся время.
В случае с дозированием, это не много что дает, но в случае, если по аналогии будет сделано управление светом, то при подаче напряжения на плату, например, после пропадания напряжения питания, или после посадки напряжения, или др. аналогичных событий, включение и выключение реле произойдет корректно.

У комплектных минутных и секундных таймеров "с розеткой" - об этом можно только мечтать....не реализован такой функционал, и еще у них есть один минус. Реле в таких таймерах - не удерживаемое, а переключаемое, со всеми вытекающими последствиями....

Для программирования нескольких включений каждого реле в течение суток - естественно, потребуется несколько другой подход....спрашивайте когда кому-то потребуется, пока не хочу все усложнять...
В принципе, можно добавить константных переменных, содержащих время и длительность срабатывания, и соответственно добавить проверку на условия.
Если количество необходимых срабатываний каждого реле в сутках больше чем 2 - лучше оформить проверку условий в отдельной функции. Как, говорил человек, учивший меня программированию - "все, что ты делаешь в программе больше двух раз - оформляй отдельной процедурой, или функцией".

Главное ограничение этого подхода - включение и выключение реле - должно произойти в одних сутках. Если необходимо чтобы, реле включилось в одних сутках, а выключилось в других - необходимо разбить это задание на 2 задания, или применить другой метод проверки условий наступления событий включения и выключения.

Весь этот пример тестировался на "живом" железе :

Для наглядности отладки был еще подключен LCD дисплей 16 сим в 2 строках.
Схема итоговая была такая:

Обратите внимание, что при использовании I2C последовательного интерфейса - соединения значительно упрощаются. И LCD дисплей подключен транзитом через модуль RTC (часов реального времени). Никаких паяных соединений нет вообще....все скоммутировано - проводами с разъемами.
Скетч - естественно, несколько другой использовался с добавлением строк инициализации и использования LCD 16x2.

Плата использовалась типа такой:
http://www.ebay.com/...
цена примерно 350 руб.

Релейный модуль
http://www.ebay.com/...
цена примерно 150 руб.

Модуль часов реального времени:
http://www.ebay.com/...
Цена примерно 55 руб.

Для сокращения бюджета можно использовать плату проще:
http://www.ebay.com/...
Цена примерно 200 руб.

Если есть потребность подключить ЖК дисплейчик, то лучше брать ЖК дисплей (LCD) c I2C интерфейсом - это сильно упрощает коммутацию, и сокращает количество использованных портов на микроконтроллере.
Например такой можно использовать :
http://www.ebay.com/...
цена около 180 руб.

На ЖК можно выводить статусную информацию, информацию об ошибках, диагностическую информацию. Все это, конечно, можно и в последовательный порт компьютера выводить, но это не всегда удобно (скорее наоборот), поэтому я всегда использую какой-нибудь девайс для вывода информации.

Для использования I2C интерфейса - необходима библиотека Wire. Она есть в стандартном дистрибутиве среды программирования Arduino.
Для использования модуля RTC на микросхеме DS1307 нужна библиотека RTClib.
Если ее не будет в стандартном дистрибутиве, то ее можно взять в интернет. Например здесь :
http://arduino-info....

Необходимо, скачать, и разархивировать zip-файл в папку с понятным названием, например RTCLib. Затем эту папку поместить в папку, где среда Arduino хранит свои библиотеки. Если ставили среду программирования с настройками по умолчанию, то этой папкой будет :
C:\Program Files\Arduino\libraries
Сюда и помещайте папки с подключаемыми библиотеками. Если на этот момент, среда программирования была запущена - ее необходимо закрыть, и запустить заново. После этого библиотека будет доступна в меню Скетч/Импортировать библиотеку.

Микросхема RTC модуля DS1307, как правило использует адрес на шине I2C равный 0x68
поэтому, необходимо проверить в библиотечных файлах, библиотеки RTClib наличие строки типа этой:
#define DS1307_ADDRESS 0x68

Если будет использоваться LCD 16x2 с I2C интерфейсом, то - понадобиться библиотека LiquidCrystal_I2C. Можно скачать здесь :
http://dvrobot.ru/lc...
Как подключить к среде программирования Arduino - см. выше

ВАЖНО : при использовании I2C устройств - в скетче, библиотека Wire - должна быть объявлена первой, иначе - будут ошибки компиляции.

По этому примеру - все....

в следующем - присоединение термо-датчика DS18B20, и создание несложного терморегулятора.....


Изменено 24.12.13 автор Z0RS
2013-12-21 добавлено 21/12/2013 15:57:48#1907148

Новичок




46
Germany
2 г. назад
сообщение Z0RS
kirex05
Мне нужна только возможность включения и выключения света LW и LR кнопками (UP-Вкл., DOWN-Выкл.), независимо от времени


Понимаете, включая или выключая свет принудительно нажатием кнопки, вы должны потом как-то вернутся в автоматический режим, либо по нажатию кнопки либо по другому событию.
По какому событию вы хотите восстанавливать автоматический режим?


Смысл вот в чём:
Допустим в автомате свет включается в 17.00 и выключается в 22.00. Иногда, особенно когда на улице пассмурно, необходимо включить свет например на час, для того чтобы поменять воду или покормить рыб. А потом опять в автомат.
Тоже самое с обогревом Н2. Когда меняю воду мне его надо выключить, а потом например через пол часа или через час опять включить в автомат.

Может быть возврат в автоматический режим кнопкой SELECT?
Изменено 28.3.14 автор kirex05

Изменено 28.3.14 автор kirex05
2014-03-28 добавлено 28/03/2014 16:03:35#1956119

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
kirex05
Может быть возврат в автоматический режим кнопкой SELECT?


Ну Вы уж определитесь, как будете режимы переключать, причем выбор режима АВТОМАТ. / РУЧНОЙ - можно сделать для каждой нагрузки свой, а можно общий для всех нагрузок...определяйтесь.
2014-03-28 добавлено 28/03/2014 22:11:24#1956323

Новичок




46
Germany
2 г. назад
сообщение Z0RS
kirex05
Может быть возврат в автоматический режим кнопкой SELECT?


Ну Вы уж определитесь, как будете режимы переключать, причем выбор режима АВТОМАТ. / РУЧНОЙ - можно сделать для каждой нагрузки свой, а можно общий для всех нагрузок...определяйтесь.


Выбор режима АВТОМАТ. / РУЧНОЙ общий для всех нагрузок. Переключение режимов кнопкой SELECT.
2014-03-29 добавлено 28/03/2014 23:53:18#1956347

Завсегдатай




460 39
Москва
3 мес. назад
Z0RS

День добрый. Я тут копаюсь с проектом - возник вопрос по датчику потока:
На крыльчатке одет кольцевой магнитик. Снаружи (вернее через перегородочку от воды) такая платка.

Внутри я так и не понял что за треног. (датчик холла? - на геркон не похож)
Написано
W12
38L4
Подключено слева направо:
1. Красный через резистрор.
2. Черный
3. Желтый

Я так понял красный - плюс. черный - минус. Желтый на ардуинку. (цифровой ввод?)
А как получить значения от него? что писать в коде?
2014-03-29 добавлено 29/03/2014 11:36:11#1956465

Новичок




46
Germany Frauenau
2 г. назад
Z0RS


Сделал вот так:

#include <LiquidCrystal.h>

/*******************************************************

This program will test the LCD panel and the buttons
Mark Bramwell, July 2010

********************************************************/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int Relay_Off = HIGH;
int Relay_On = LOW;
int reg=0;// вводим флаг для автоматического (при значении-0) или ручного регулирования -1

// define some values used by the panel and buttons
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, 144, 329, 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
// For V1.1 us this threshold
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 250) return btnUP;
if (adc_key_in < 450) return btnDOWN;
if (adc_key_in < 650) return btnLEFT;
if (adc_key_in < 850) return btnSELECT;

// For V1.0 comment the other threshold and use the one below:
/*
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
*/


return btnNONE; // when all others fail, return this...
}

void setup()
{
pinMode(41, OUTPUT);
lcd.begin(16, 2); // start the library
lcd.setCursor(0,0);
lcd.print("Push the buttons"); // print a simple message
}

void loop()
{
lcd.setCursor(0,1); // move to the begining of the second line
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;
}
case btnSELECT:
{
if(reg==1)
{reg=0;
lcd.setCursor(13, 1);
lcd.print("Aut");}
else
{reg=1;
lcd.setCursor(13, 1);
lcd.print("Man");}
break;
}
case btnNONE:
{
lcd.print("NONE ");
break;
}
}
}

Так кнопкой RIGHT выключается, а кнопкой LEFT включается.
Кнопкой SELECT выбирается режимм.
2014-03-30 добавлено 30/03/2014 01:17:05#1956807

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
arch07

Ну...то, что это датчик Холла - это точно.
Не совсем понятно какая именно модель...а напряжение питания где-нибудь указано?

На выходе всего скорее - аналоговый сигнал пропорциональный силе воздействующего магнитного поля...но дискретный вход, по идее должен срабатывать без применения дополнительного усиления. Это будет необходимо проверить....когда придет плата, в худшем случае потребуется дополнительный каскад усиления. А может быть и дискретный выход с TTL уровнями.

У датчика Холла - нет дребезга и это огромное преимущество перед герконами.

Срабатывание датчика лучше отлавливать прерыванием.

В принципе, как оформить простейшее аппаратное прерывание - я уже приводил пример.

В прерывании, все что нужно сделать - установить флаг того, что произошел импульс, а дальше этот флаг обрабатывать внутри главного цикла, или в теле прерывания увеличивать переменную для зафиксированных импусльсов, а в теле главного цикла - делать обработку и уменьшать переменную до нуля. Какой вариант лучше - я не знаю, это зависит от многих факторов.

Уж что за логику использования данного устройства Вы придумаете я не знаю...можно например, включать клапан подмены воды, затем - считать импульсы до тех пор, пока не насчитаете требуемое количество, после чего выключать клапан...да мало ли чего можно придумать. НО сначала - необходимо четко представить себе что вы хотите...после этого - программировать.
2014-03-30 добавлено 30/03/2014 01:24:33#1956809

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
kirex05
Сделал вот так:


Я так понимаю, что ....заработало? Ну и хорошо....
2014-03-30 добавлено 30/03/2014 01:28:51#1956810

Новичок




46
Germany Frauenau
2 г. назад
сообщение Z0RS
kirex05
Сделал вот так:


Я так понимаю, что ....заработало? Ну и хорошо....


Да нет не заработало. Это я просто пробовал в отдельном коде, а как это сделать в моём ума пока не проиложу.
2014-03-30 добавлено 30/03/2014 01:32:47#1956811

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
kirex05
Да нет не заработало. Это я просто пробовал в отдельном коде, а как это сделать в моём ума пока не проиложу.


Ну для одного порта это работает?

А для остальных потребуется сделать процедуру выбора, т.е. написать меню...о чем я и говорил...
А меню вещь своеобразная, тем более для микроконтроллеров.
2014-03-30 добавлено 30/03/2014 01:39:43#1956815

Новичок




46
Germany Frauenau
2 г. назад
сообщение Z0RS
kirex05
Да нет не заработало. Это я просто пробовал в отдельном коде, а как это сделать в моём ума пока не проиложу.


Ну для одного порта это работает?

А для остальных потребуется сделать процедуру выбора, т.е. написать меню...о чем я и говорил...
А меню вещь своеобразная, тем более для микроконтроллеров.


Ну да работает, только как это впихнуть в мой код я пока не пойму. А меню, это для меня вообще полный лес.
2014-03-30 добавлено 30/03/2014 01:44:15#1956818

Завсегдатай




460 39
Москва
3 мес. назад
Z0RS

Ага - понял. Попробую подключить.
сайт по счетчику есть, но сильно китайский http://gd-sbs.com/
Логику использования понял. Но пока в моем проекте буду использовать только как датчик - т.к. насос плохо держит давление после суток-других простоя, то в начале надо добиться заполнения системы водой - вот тут и пригодится агрегат. Уже сделал одну позицию с обраткой.
Потом мне достаточна точность отмерять полив по времени. Разница между максимальным и минимальным уровнем в резервуаре пренебрежительно мала. По замерам насос дает 200 гр за 10-11 сек. Т.е. по 10-20 секунд на горшок (зависит от размера) самый раз.

Немного напрягло, что сервомашинки очень неточно позиционируются, если задавать угол градусами. - 0 и 180 откалибровал, но между ними у меня 11 позиций (по 15 градусов) - так вот гуляет +- 10 градусов.
Благо можно задавать позицию напрямую частотой - я пока подбираю частоту-угол, а потом создам массив частот под конкретную машинку и буду в цикле его перебирать.
Немного доделаю и выложу тут проект с чертежем, фотками и кодом - на рецензию. Внимательно читаю про кнопки - т.к. планирую сделать проект совсем автономным - корректировку времени RTC модуля и задание время и цикла срабатывания без перепрошивки.
2014-03-30 добавлено 30/03/2014 12:14:20#1956901

Свой на Aqa.ru




1148 187
Ростов-на-Дону
13 час. назад
Z0RS

Подскажите, пожалуйста, а можно ли подать ШИМ-сигнал с одного выхода сразу на несколько диммируемых светодиодных драйвера, скажем MW LDD1000(H), для экономии и выходов контроллера, и программного кода?
2014-03-30 добавлено 30/03/2014 13:28:10#1956917

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
Дядька-рыбомор
Подскажите, пожалуйста, а можно ли подать ШИМ-сигнал с одного выхода сразу на несколько диммируемых светодиодных драйвера, скажем MW LDD1000(H), для экономии и выходов контроллера, и программного кода?

Вообще если делать правильно, то необходимо выяснить какой ток на диммируемом входе предусмотрен производителем микросхемы драйвера LED, затем умножить этот ток, на количество драйверов, которое Вы хотите одновременно диммировать с одного выхода платы ARDUINO, и выяснить не превышает ли вычесленный ток значение предусмотренное для того порта микроконтрноллера, на котором Вами организован ШИМ. Это в теории...можете эту нехитрую проверку сами сделать...

Но на практике, выяснилось, что диммирующие входа на драйверах - имеют весьма высокое сопротивление, и соответственно не большой ток диммирования от 5 мкА до 1 мА.
Т.е. с десяток драйверов можно "не глядя" присоединять к одному выходу микроконтроллера.

ПС: Посмотрел в даташите ток на диммирующем входе драйвере = 1 мА. Максимальный ток для одного порта например, для ATMega 328 = 40 мА. Выводы понятны надеюсь....

arch07
Потом мне достаточна точность отмерять полив по времени.

Так зачем тогда импульсный датчик потока....делайте по времени...

arch07
Немного напрягло, что сервомашинки очень неточно позиционируются, если задавать угол градусами. - 0 и 180 откалибровал, но между ними у меня 11 позиций (по 15 градусов) - так вот гуляет +- 10 градусов.


А Вы сервы то для чего используете?

arch07
Внимательно читаю про кнопки - т.к. планирую сделать проект совсем автономным - корректировку времени RTC модуля и задание время и цикла срабатывания без перепрошивки.


Вообще, у коллеги, кнопки, про которые вы читаете - не очень типичные - с опросом по аналоговому сигналу, это видимо, придумано для сокращения используемых портов...
Лучше использовать что-нибудь стандартное, обычную кнопочную или пленочную клавиатурку, а для сокращения используемых портов - использовать I\O экспандеры с I2C интерфейсом, как правило это микросхемы сдвиговых регистров, для клавы 4Х4 подойдет, например - PCF8574 За 50-60 рублей, зато ее можно посадить на уже используемую шину I2C интерфейса.

У меня просто сейчас нет свободного железа, скоро подойдут экспандеры PCF8574 и PCF8575 - сделаю пример с клавиатурой на I2C, основами построения меню, и написания собственных библиотек...
Задумка уже есть такая...

Да и еще о RTC. Как выяснилось RTC на DS1307 - не очень точны...и единственное их преимущество это "смешная" цена. А вот точность хода - очень не большая, и в месяц может до минуты накапливаться погрешность....Но это можно исправить без того, чтобы лазить в меню, и поправлять вручную время. Можно вычислить поправку и вносить ее в промежуток времени, который равен периоду времени когда накапливается погрешность = одна секунда. Т.е. RTC необходимо "эджастить" на одну секунду в период, за который эта секнда накапливается. Это будет правильнее...У меня когда-то были электронные часы наручные, наши Российские с такой функцией...можно было поправки вносить...с поправкой в год накапливалось всего несколько секунд...А это уже совсем другое дело....

kirex05
Ну да работает, только как это впихнуть в мой код я пока не пойму. А меню, это для меня вообще полный лес.


Поймите простое правило - "закодить" готовый алгоритм работы чего либо, в том числе и меню - это "нет ничто" по сравнению с трудностью разработки самого алгоритма.
Поэтому...разработайте и опишите для себя хоть своими словами на бумаге - как должно работать меню и как должны реагировать нагрузки...потом все это закодите за пару тройку часов..

Изменено 30.3.14 автор Z0RS

Изменено 30.3.14 автор Z0RS
2014-03-30 добавлено 30/03/2014 15:46:40#1956960

Новичок




46
Germany Seubersdorf
2 г. назад
Z0RS


С обогревом разобрался, теперь нужно как-то тоже самое со светом LW и LR проделать.

#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;
int reg=0;// вводим флаг для автоматического (при значении-0) или ручного регулирования -1

#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");

if (reg==0){ // Если регулирование автоматическое -регулируем по температуре
lcd.setCursor(15, 1);
lcd.print("A");

// Если температура достигает 28,3 (с погрешностью), отключаем кипятильник Н1
if (celsius > 28.3)
{
digitalWrite(40, Relay_Off);
lcd.setCursor(0, 1);
lcd.print("H1-Off");
}

// Если температура достигает 28,5 (с погрешностью), отключаем кипятильник Н2
if (celsius > 28.5)
{
digitalWrite(41, Relay_Off);
lcd.setCursor(7, 1);
lcd.print("H2-Off");
}
// Если температура падает до 28 (с погрешностью), включаем оба кипятильника
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 ");
}
}
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;
}
case btnSELECT:
{
if(reg==1)
{reg=0;
lcd.setCursor(15, 1);
lcd.print("A");}
else
{reg=1;
lcd.setCursor(15, 1);
lcd.print("M");}
break;
}
case btnNONE:
{
break;
}
}
}
//------------Конец ЦИКЛА-----------------------------
2014-03-30 добавлено 30/03/2014 20:07:57#1957092

Завсегдатай




460 39
Москва
3 мес. назад
Z0RS, опишу проект - а то задаю вопросы, а народу не понятно.

Задача - полив по времени 12 горшков разного объема.
Периодичность раз в 2-3 дня. В каждый горшок свою порцию.
Сделать возможность запуска полива по аппаратной кнопке.

1 этап. Сделать железо, запрограммировать МК. Задавать все переменные в программе.
2 этап. Прикрутить кнопки, экран. Перенести управление на них.

Насос - вибрационка от моющего пылесоса, ардуино нано из китая, реле с опторазвязкой, сервомашинка, RTS I2C платка, датчик потока.

Докупается - I2C экран 1602, кнопочки (пока в голове 4 шт - одна на запуск полива, 3 на управление меню - меню, вверх, вниз).

Идет реализация 1 этапа:
Готово железо "в черне" - испытывается надежность.
Есть все для программирования управления - пишется код.
И для наглядности - вот примерно вся система:
резервуар с водой, распределительная система на сервомашинке и обрезков одноразовых бокалов, ардуинка "на соплях".
Пока насос запитан от розетки напрямую, в будущем будет через реле.

А вот датчик потока на 1-ой лейке. К ней подключена трубка "обратки", идущая обратно в резервуар с водой. Используется для определения того, что система наполнилась водой. Ну и поиграться с датчиком, конечно - потом при удачном его использовании буду применять для контроля автоподмен в аквариуме.
2014-03-30 добавлено 30/03/2014 20:50:53#1957110

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
arch07


Слишком уж сложно Вы все затеваете....но "дело ваше".

Для полива я применяю систему по-проще.

Сердце системы - такие насосики:



Это из автомагазина запчастей для ВАЗ. Цена 96 руб за шт. Я их купил уже немеряно...но попадаются и плохие....нужно проверять производителя... Насосы 12 вольтовые, создают приличное давление, и даже опрыскивать можно автомобильными же форсунками для омывания ветрового стекла...только дорабатывать надо, или из головок аэрозолей можно наделать.

У насосов будут довольно стабильные показатели если их на выходе воды немного "поджать" вентилем.

Расход просчитывается. Никаких дополнительных датчиков, мне например - не требуется....Поливаю и кофейные деревья, и розы и разное другое, полив из разных по составу жидкости емкостей...
Система получается простая - блок питания 12 вольт, насосы, плата управления + релейный модуль....все. Никаких датчиков потока. Хотел поставить датчики влажности почвы....может для кофе и поставлю и то, только для того, чтобы сухой период соблюсти, но и не засушить дерево совсем...а для остального - без надобности.
2014-03-30 добавлено 30/03/2014 21:37:22#1957134

Завсегдатай




460 39
Москва
3 мес. назад
Z0RS

Система полива больше как "игрушка не на полку" и задача ставилась не сколько полить, а сколько освоить как можно больше девайсов, управляемых ардуиной. Кроме ардуинки и датчиков ничего не покупал и извлек из "закромов" - такое вот "слепило из того, что было".
К тому же мне нравится её стимпанковость .
А работать она будет не постоянно, а только при долгосрочном отъезде из дома, когда все растения собираются в одном месте - на солнечной стороне. В остальное время все горшки разлетаются по комнатам и поливаются женой в ручную "для души".
Для того и требуется подводка часов и настройка

Насосы от ВАЗ хорошая мысль для практики - приму на заметку. И напряжение небольшое и цена вкусная.

Чего-то у меня часы заводится не хотят на плате.

P.S. Завел часы. Получил данные с датчика потока - осталось откалибровать, но нечем точно измерить прошедший объем. Найду мерный кувшин и откалибрую. Настроил механику и серву - позиционирование достаточно точное стало.
Решил переставить датчик потока на входную магистраль и отмерять точное количество жидкости в каждую лейку. Заодно проверять наличие воды и отключать все если вода не идет.

Задумался над алгоритмом меню. И еще гложит мысль - надо записывать значения измененные в процессе настройки иначе при пропадании напряжения все сбросится на прошитые в скетче, а как это делать я не пока не знаю.

Изменено 31.3.14 автор arch07
2014-03-30 добавлено 30/03/2014 22:03:52#1957146

Свой на Aqa.ru




1148 187
Ростов-на-Дону
13 час. назад
сообщение Z0RS
диммирующие входа на драйверах - имеют весьма высокое сопротивление, и соответственно не большой ток диммирования от 5 мкА до 1 мА.

Тоже нашел даташит, действительно - диммирующий ток 1 мА. Придут драйверы с e-bay - проверю миллиамперметром, хотя и правда опасаться нечего.

Да и еще о RTC. Как выяснилось RTC на DS1307 - не очень точны... RTC необходимо "эджастить" на одну секунду в период, за который эта секнда накапливается. Это будет правильнее...У меня когда-то были электронные часы наручные, наши Российские с такой функцией...можно было поправки вносить...

А как кстати практически организовать такую поправку программным способом? Уже задумался об этом...
ЗЫ. У меня тоже такие часики были, еще советские, из серии "Электроника 5" или что-то подобное. Подарили в 1986-87 году на ДР. В инструкции помню было очень подробно расписано, как вычислить поправку по "сигналам точного времени". Лепота! Вот умели же делать, не то что китаёзы.
2014-03-30 добавлено 30/03/2014 22:25:06#1957160

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
arch07
И еще гложит мысль - надо записывать значения измененные в процессе настройки иначе при пропадании напряжения все сбросится на прошитые в скетче, а как это делать я не пока не знаю.


Вариантов есть несколько: можно использовать EEPROM (EEPROM микроконтроллера; отдельную EEPROM, подключенную например по I2C; EEPROM какого нибудь модуля - типа RTC) или подключить FLASH в виде стандартной SD карты - тем более, что модулей-слотов для SD на ебее - навалом по цене от 36 рублей...Но в случае с SD - есть сложности. Если к карте обращаться через файловую систему - то подключение и использование библиотеки функций, организующее работу через FAT - съедает очень много программной памяти микропроцессора. А прямой доступ к адресному пространству подключенной карты - не каждый запрограммирует. Кстати SD карта - ничто иное, как микросхема FLASH-памяти с SPI интерфейсом, и ее можно "параллелить" с модулем EtherNet, например разведя только cs (chip select) сигнал на отдельный дискретный порт.

Вообще, с EEPROM - проще...Только необходимо помнить про ограничения количества записи. Есть еще варианты, но они все больше экзотические...

Дядька-рыбомор
А как кстати практически организовать такую поправку программным способом? Уже задумался об этом...

Так.... библиотечную функцию RTC.adjust() - необходимо использовать...она вызывается с аргументом в виде указателя на экземпляр класса DateTime. Конструктор класса - это перегруженная функция, т.е. может вызываться с разным набором аргументов.
Все это есть в заголовочном файле библиотеки, вот три варианта объявления функции конструктора класса DataTime:

DateTime (uint32_t t =0);

DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour =0, uint8_t min =0, uint8_t sec =0);

DateTime (const char* date, const char* time);

Например, вызывая функцию установки времени равному системному времени компьютера, на котором происходит компиляция скетча

RTC.adjust(DateTime(__DATE__, __TIME__));

мы используем третий вариант. А для установки времени внутри программного кода с произвольными значениями времени, т.е. для той же поправки времени - необходимо использовать 2 вариант. Можно и первый - но он программно ( в теле реализации функции) сводится ко второму, и ничего, кроме увеличения размера кода, использование этого варианта - не даст.
Т.е. для поправки времени нужно сформировать переменные, указанные в аргументах данной функции, и в нужный момент вызвать функцию

RTC.adjust(DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour =0, uint8_t min =0, uint8_t sec =0));

...понятно, что со своими переменными-аргументами.

Дядька-рыбомор
ЗЫ. У меня тоже такие часики были, еще советские, из серии "Электроника 5" или что-то подобное. Подарили в 1986-87 году на ДР. В инструкции помню было очень подробно расписано, как вычислить поправку по "сигналам точного времени". Лепота! Вот умели же делать, не то что китаёзы.


Вот про эти самые часы я и имел ввиду....Они у меня также примерно в этоже время появились....с введенной поправкой ходили очень точно....

Да...еще помню в 87 сделал свой первый компьютер - Радио 86РК. Потом было собрано еще несколько клонов различных....На первый комп - я потратил денег, соизмеримо со стоимостью хорошего мотоцикла, что за время было....да.....мать меня чуть не убила...правда, потом не пожалела ни разу....
2014-03-31 добавлено 31/03/2014 10:41:29#1957279

Свой на Aqa.ru




1148 187
Ростов-на-Дону
13 час. назад
сообщение Z0RS
Т.е. для поправки времени нужно сформировать переменные, указанные в аргументах данной функции, и в нужный момент вызвать функцию

RTC.adjust(DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour =0, uint8_t min =0, uint8_t sec =0));


Ну, к примеру, RTC спешат (или отстают) на 1 сек в сутки. Как будет выглядеть команд ?

RTC.adjust(DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour =0, uint8_t min =0, uint8_t sec =-1)); это спешат на секунду

RTC.adjust(DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour =0, uint8_t min =0, uint8_t sec =1)); а это отстают.
Правильно?



Изменено 31.3.14 автор Дядька-рыбомор
2014-03-31 добавлено 31/03/2014 12:06:19#1957312

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
Дядька-рыбомор
Правильно?


Неет....Вы уж очень просто захотели....

Сначала необходимо прочитать время, затем сформировать новые переменные, оставив все поля такими как и прочитали, а секунды увеличить, а потом уж установить новое время, вызвав указанную мной конструкцию из 2 функций.

Изменено 31.3.14 автор Moderator
2014-03-31 добавлено 31/03/2014 12:38:59#1957323

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
Дядька-рыбомор


Теперь по подробнее.
Попробовал простенькую процедуру коррекции времени - как бы все работает...

Принцип простой. Сначала определяем константу макроподстановки - которая определит период времени в секундах, по истечению которого, к текущему времени будет прибавлена еще одна секунда. Я для примера вычисли поправку таким образом, чтобы за один месяц прибавлялась примерно одна минута...так мои часики ходят....Ваши могут ходить по-другому.
Вообще данную константу можно и в виде переменной в энергонезависимой памяти оформить, но это будет сложнее, да и нужно ли - это необходимо определять, для конкретного случая.

#define TimeAdjustPeriod 43200UL

Эта строка должна быть вне функции инициализации и вне функции главного цикла...лучше вверху где-нибудь.
Там же где нибудь определим вспомогательну переменную:

unsigned long nextAdjustTime =0;

Ну в функции setup должны присутствовать стандартные для использования RTC строки:
Wire.begin();
RTC.begin();

В функции главного цикла loop() мы проверяем не наступило ли время по-править часы и поправляем на одну секунду вперед....ну да на деле может потребоваться и в другую сторону по-править. И тут же вычисляем и назначаем время следующей по-правки времени.

DateTime myTime = RTC.now();
unsigned long UTime = myTime.unixtime();

if (UTime > nextAdjustTime){
nextAdjustTime = UTime+TimeAdjustPeriod;
RTC.adjust(DateTime(myTime.year(),myTime.month(),myTime.day(),myTime.hour(),myTime.minute(),myTime.second()+1));
}

Вообще...это так...для пробы...процедуру коррекции часов, конечно, можно сделать куда более интеллектуальной...
Кстати обратите внимание, какие довольно простые конструкции используются в проверке условий - это потому, что работаем с форматом времени UNIX, и тут же используем формат в виде класса DateTime с набором полей...

Вообщем, где как удобно - такой формат и применяйте...


Изменено 31.3.14 автор Z0RS
2014-03-31 добавлено 31/03/2014 14:24:05#1957358

Свой на Aqa.ru




1148 187
Ростов-на-Дону
13 час. назад
сообщение Z0RS

Спасибо, все разжевали. Осталось проглотить
Т.е. в вашем примере добавляется секунда каждые 12 часов, итого в месяц около 1 мин..
А если наоборот - RTC спешат - то ставим минус. ОК.
RTC.adjust(DateTime(myTime.year(),myTime.month(),myTime.day(),myTime.hour(),myTime.minute(),myTime.second()-1));
}
2014-03-31 добавлено 31/03/2014 16:12:07#1957392

Свой на Aqa.ru




693 77
Выкса
8 мес. назад
Дядька-рыбомор
Т.е. в вашем примере добавляется секунда каждые 12 часов, итого в месяц около 1 мин..
А если наоборот - RTC спешат - то ставим минус. ОК.


Да...НО...не все так просто если вспомнить, что в минуте всего лишь 60 секунд, а именно от 0 до 59. Вообщем в реальной программе - необходимо чуть усложнить проверкой на 2 условия.
Количество секунд после прибавления не должно превышать 59, или если речь идет об убавлении то не должно быть меньше 0.
Я думаю, математикой можно эти условия упростить - надо будет подумать на досуге как сделать проверку этого условия очень простой.....
2014-03-31 добавлено 31/03/2014 16:30:25#1957397

Завсегдатай




460 39
Москва
3 мес. назад
Z0RS

А обязательно все это в RTC.adjust писать?
там юникс формат нельзя использовать? - тогда секунды проверять смысла нет. все равно мы периодом ввода поправок на 1 сек задаем.
2014-03-31 добавлено 31/03/2014 21:39:48#1957554

<< 1234 6789101112 >> Создать новую темуБыстрый ответ