Постоянный посетитель


693 78
Выкса
1 г. назад

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

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

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

Пример 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

Постоянный посетитель


693 78
Выкса
1 г. назад
Дядька-рыбомор
Аппаратное решение сразу приходит на ум: через реле. В одном положении (ВКЛ) на кулер подается, к примеру, 12 В, а в другом (ВЫКЛ) - 5 В. За программным решением - к топикастеру

Если поменять логику реле - то можно. Ну это первое что в голову приходит.
Делаем делитель напряжения на 2 резисторах, один параллельно двигателю куллера, а другой последовательно в цепь питания 12В.
Резисторы необходимо рассчитать таким образом, чтобы на куллере падало напряжение 5 В, тогда если контактами реле замкнуть резистор который последовательно, то на куллере упадет 12 вольт.
Это позволит использовать источник питания с одним напряжением, а если есть 2 источника и 5 и 12 вольт, то реле имеет переключающий контакт, тут вообще проблем - нет.
2014-04-03 добавлено 02/04/2014 23:44:00#1958378

Посетитель


460 39
Москва
11 мес. назад
А тут пока копался такое нарыл 4-pin:
Общий - "минус" питания (черный провод).
Плюс питания - 12 В из БП (желтый провод).
Датчик - сенсор оборотов (2 импульса лог. 0 на один оборот крыльчатки).
Управление - сигнал PWM для управления скоростью.

У трех проводного тоже управление шим модуляцией оказывается (раньше думал, что напряжением) но по питающему проводу (12V).

Вывод - надо искать 4-pin кулеры. Ими рулить удобней.
2014-04-03 добавлено 03/04/2014 08:44:19#1958408

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07
А тут пока копался такое нарыл


Это Вы про что? ЧТо за куллеры?

Потом, про OneWire удалось что-нибудь нарыть?

Я вот выяснил одну интересную проблему:

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

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

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

По-эксперементирую тут пару - тройку дней....потом посмотрим что получится....
2014-04-03 добавлено 03/04/2014 10:23:25#1958428

Посетитель


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

По питанию onewire разобрался. Понравилось питание по проводу данных за счет паразитных токов.
Интересно, что DS18S20 обрабатывает температуру 750 мс. т.е. достаточно долго. Пробиться в анализ передаваемой информации не смог. И так пол-ночи просидел.
А как задержка может сказаться на удобрениях? В смысле при вызове опроса датчика температуры замрет главный цикл, а работа насоса подачи удобрений реализована через millis()??? Но это относится только к перильстатическим насосам с коллекторным двигателем.
Вариант подачу удобрений организовать циклическим насосом - мне понравился из этой темы: Простенький акваконтроллер на ARDUINO Тут задержка не критична. Или шаговый двигатель перильстатического насоса на даст передозировать.

А опрос температуры проводить не в каждом цикле, а каждые 30 сек. Тогда сократится число задержек.

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

Что-то у меня контроллер обрастает перифирией

P.S. При внимательном изучении даташита DS18B20 оказался предпочтительнее DS18S20 т.к.
- Thermometer Resolution is User Selectable from 9 to 12 Bits
- Converts Temperature to 12-Bit Digital Word in 750ms (Max)
т.е. при использовании 9 bit - ной разрядности время конвертации температуры сокращается в 8 раз. с 750 мс до 98 мс.
ИМХО существенное уменьшение.


Изменено 3.4.14 автор arch07
2014-04-03 добавлено 03/04/2014 13:38:59#1958489

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07
Понравилось питание по проводу данных за счет паразитных токов.

Да...шина IC весьма оригинальна....и питание и процесс передачи данных.

arch07
А как задержка может сказаться на удобрениях? В смысле при вызове опроса датчика температуры замрет главный цикл...


Смотря как организован процесс подачи растворов УДО. Если будут использоваться перистальтич. помпы и концентрированные растворы - то потребуется очень точное измерение времени в теле главного цикла. Если так, организовывать -
arch07
Вариант подачу удобрений организовать циклическим насосом - мне понравился из этой темы: Простенький акваконтроллер на ARDUINO

То, конечно, точность измерения времени может быть ниже ...значительно. И это

arch07
А опрос температуры проводить не в каждом цикле, а каждые 30 сек. Тогда сократится число задержек.

также можно реализовать.


arch07
При внимательном изучении даташита ....

А....я как понимаю - Вы на правильном пути....
2014-04-03 добавлено 03/04/2014 16:09:19#1958541

Посетитель


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

ага вкурил я по вами приведенной функции. Немного напрягает HEX запись в даташитах - я ее плохо читаю, но там дублируется в двоичном коде и вроде все понятно после переваривания.
Только вызывает недоумение - датчики ds18х20 вроде достаточно популярны, но на на них нет своей библиотеки.

А по функции. Я в инете нашел похожий пример с одним отличием:

....
ds.reset();
ds.select(addr);
ds.write(0x44,1); // запускаем конвертацию

delay(1000); // скорее всего достаточно 750ms
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.select(addr);
ds.write(0xBE); // считываем ОЗУ датчика
....

у вас в коде выделенной строчки нет. И ведь работает. Значит задержка не нужна? Все равно ведь работает. Но даташит говорит, что нужно. Тогда получается что вы получаете температуру сконвертированную в предыдущем запросе?
Или наша система настолько медленная, что датчик успевает сформировать ответ.


P.S. Нашел библиотечку под термометры:
http://milesburton.c...
https://github.com/m...

Изменено 3.4.14 автор arch07
2014-04-03 добавлено 03/04/2014 20:03:02#1958662

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07
у вас в коде выделенной строчки нет. И ведь работает. Значит задержка не нужна? Все равно ведь работает. Но даташит говорит, что нужно. Тогда получается что вы получаете температуру сконвертированную в предыдущем запросе?
Или наша система настолько медленная, что датчик успевает сформировать ответ.


Необходимо разделять, процесс конвертации температуры - в результате которого значение температуры записывается в регистр оперативной памяти датчика. Это процесс длительный и требует наличия высокого уровня на проводе DQ на протяжении времени, требуемого для конвертации - для обеспечения необходимого тока для аналогоцифрового преобразователя датчика.
Для датчика класса ds1820 - это ток около 1,5 мА.

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

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

Весь "финт" в использовании нескольких датчиков на шине OneWire - это развести по времени задания на конверсию и вычитывание данных, таким образом, чтобы МК делал как можно меньше бестолковой работы, и чтобы главный цикл, не был бы слишком загружен. И вот это "разведение" по времени, необходимо сделать, без использования функции delay().
2014-04-03 добавлено 03/04/2014 22:39:21#1958723

Посетитель


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

Ага - я это понял. Итого по термометрам:
1. Т.к. у нас все - таки нет проблем с подводом 3 проводов, то лучше питать датчик полноценно.
2. Избавится от запроса в каждом цикле, даже 5-10 сек периода будет имхо достаточно - все-таки аквариум не такая шустрая система, даже если контролировать этими датчиками охлаждение светильника.
3. Если есть возможность брать серию DS18B20, а не DS18S20. Только выставить для нее разрешение в 0,5 градуса - максимальное. Это позволяет библиотека что я приводил. Причем в даташите сказано, что точность измерения без доп корректировок 0,5 градуса - получается 12 бит избыточны для передачи и 9 бит правильный размер пакета.
2014-04-04 добавлено 04/04/2014 06:47:08#1958769

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07
Причем в даташите сказано, что точность измерения без доп корректировок 0,5 градуса - получается 12 бит избыточны для передачи и 9 бит правильный размер пакета


В обоих случаях принимать придется 2 байта....поэтому снижать дискретность, по большому счету, нет смысла.
2014-04-04 добавлено 04/04/2014 11:01:40#1958813

Посетитель


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

Есть - я приводил по даташиту при снижении дискретности на 1 бит время конвертации снижается вдвое
с 12 до 9 бит - в 8 раз. с 750 мс до 98 мс. Дискретность надо только 1 раз прописать - потом она в ПЗУ запоминается.
Все равно надо будет считывать номер датчика для его расстановки по использованию. Тогда и "инициализировать".

А пример правильного меню скоро будет?
2014-04-04 добавлено 04/04/2014 12:12:57#1958834

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07

Вот здесь есть интересная библиотека для DS1820:
https://github.com/m...
А...вообщето Вы ее и указали...
Я ее не пробовал еще, но судя по описанию - "самое оно" ...

Здесь пример ее использования со множеством датчиков температуры
http://blockduino.bl...


arch07
А пример правильного меню скоро будет?


Вообще, я цель, такую не ставил. Основная цель - показать как работает связка клавиатура + I2C интерфейс. И это я постараюсь показать, как придет железо.

А меню, это так.... бесплатное приложение...можете и сами написать любое, тем более, что в учебном примере будет все очень упрощено.

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

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

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


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

Изменено 4.4.14 автор Z0RS
2014-04-04 добавлено 04/04/2014 14:32:22#1958874

Посетитель


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

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

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

Но как то это все громоздко, конструкции что зреют в голове какие-то слишком не "кошерные"... К тому же почитав правильный код, осознав логику намного легче применить его к себе. Примеры из библиотек мало того, что слишком простые, так еще и не кошерные - т.к. почему-то постоянно там используется delay(). Еще и дребезг этот...

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

А еще можно узнать - что за железо вы ждете? Клавиатура на шину I2C? Может мне тоже ее стоит использовать? I2C мне понравилась. Может там еще и дребезг аппаратно обрабатывается?

P.S. Последний вопрос снимается - почитал даташиты по PCF8575 и PCF8575 - получается на PCF8574 - можно максимум 4х4 клаву замутить, а на PCF8575 - 8х8. Интересные штучки.

Изменено 4.4.14 автор arch07
2014-04-04 добавлено 04/04/2014 15:27:43#1958889

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07
но каждую кнопку вешать на прерывание - при нажатии поднимать флаг, потом в главном цикле обрабатывать это нажатие и снимать флаг по выполнении.

Да, а во время обработки изменять флаг, через который будет делаться управление портом. А может и не через один флаг, а несколько.

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

arch07
Но тогда надо настройки хранить не в коде, а где-то в файле или в энергонезависимой памяти. И в момент старта программы читать оттуда. А через меню писать туда. Иначе при сбое питания все наши настройки полетят к чертям.

Естественно. И вариантов много. Даже в RTC на DS1307 - есть возможность хранить данные в энергонезависмой памяти. Можно в EEPROM микроконтроллера хранить, можно в присоединенной SD карте. Последний вариант - сложнее.

arch07
А сейчас прям дефицит аппаратных прерываний вырисовывается.

Не нужно очень сильно увлекаться использованием прерываний. Это сильный источник "блуждающих" ошибок - которые очень сложны в отладке...и требуют хороших знаний архитектуры МК.
Вообще - идеальная программа - это относительно плоский главный цикл, с ветвлением, выполненным таким образом, что время выполнения любой ветки не превышает 110 - 115% среднестатистического времени выполнения главного цикла. Без каких либо прерываний. Либо с минимумом прерываний...
Потом, с прерываниями тоже нужно научится работать. Необходимо оценивать возможность возникновения прерывания даже во время выполнения функции обработки самого прерывания, также во время выполненя других веток главного цикла, и где есть сомнения в возможности совмещения прерывания - необходимо запрещать прерывания а потом по ходу кода - разрешать, и т.д.
Правил, работы с прерываниями - много, также как и для правильного кода с точки зрения использования памяти....Мы многое в коде не пишем, т.к. считаем, что компилятор вставит это за нас, и бывают разочарования...., особенно когда несколько часов или дней ищется источник утечки памяти.


arch07
А еще можно узнать - что за железо вы ждете?
Клавиатура на шину I2C? Может мне тоже ее стоит использовать? I2C мне понравилась. Может там еще и дребезг аппаратно обрабатывается?

[/q]
Не...я использую обычные клавиатурки - кнопочные или пленочные с организацией выводов по столбцам и строкам. А для того, чтобы сократить количество цифровых входов - можно использовать сдвиговые регистры. Классикой считается использование сдвигового регистра с последовательным выводом значений в порт с TTL уровнем.
Например можно использовать при расширении количества - для входов 74HC165N , а для выходов 74HC595.

А теперь хочу попробовать микросхему сдвигового регистра с I2C интерфейсом - PCF8574. Это микросхема двунаправленный экспандер портов ввода/вывода с I2C интерфейсом и возможностью организации апп.прерываний. Вот заказал десяток микросхем, да еще всякого "железа" для разных экспериментов...и использований.
2014-04-04 добавлено 04/04/2014 16:21:10#1958922

Посетитель


460 39
Москва
11 мес. назад
Остался вопрос по дребезгу подключенной PCF8574 клавы - он все равно будет?

Изменено 4.4.14 автор arch07
2014-04-04 добавлено 04/04/2014 20:18:12#1959025

Постоянный посетитель


693 78
Выкса
1 г. назад
arch07
стался вопрос по дребезгу подключенной PCF8574 клавы - он все равно будет?


Смотря как подключенной....если классическим образом - то да...
2014-04-04 добавлено 04/04/2014 20:52:25#1959062

Кандидат в Советники



1268 400
Ростов-на-Дону
3 дн. назад
Привожу практические результаты экспериментов со временем, точнее его коррекции в некорректных RTC. Может оказаться полезным таким дубам в программировании, как я, коих тут приличное кол-во.
Сначала установил, что часики спешат на 36 сек/сут, получается ровно 1,5 сек/час.
Как советовал ZORS, задал период коррекции и время коррекции
uint32_t TimeAdjustPeriod = 3600;
uint32_t TimeCorrection = -1.5;
т.е. сдвиг часов назад каждый час на полторы секунды. Запустил - и ничего, как спешили, так и спешат (проверял по часикам в программе "Время", хоть какая-то польза от зомбоящика).
Решил, что дробные отрицательные величины в секундах UNIX контроллеру непонятны, поэтому надо задавать целые секунды. Сделал так
uint32_t TimeAdjustPeriod = 7200;
uint32_t TimeCorrection = 3; "3" без минуса
А в функции цикла void loop {} написал так:
RTC.adjust(DateTime(UTime-TimeCorrection));
т.е. тупо поменял "+" на "-". И все заработало! Поргешность минимальная, по крайней мере точно меньше целой секунды, но такая точность меня вполне устроит. Китайские таймеро-розетки убегают по 5-10 минут в год, кстати.

Изменено 6.4.14 автор Дядька-рыбомор
2014-04-06 добавлено 06/04/2014 12:12:08#1959615

Постоянный посетитель


693 78
Выкса
1 г. назад
Дядька-рыбомор
uint32_t TimeCorrection = -1.5;


Я конечно...прошу прощения, но нельзя же так не уважать основы языка СИ.

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

В нашем случае объявлена переменная типа
uint32_t - в данном случае "u" - unsigned - то есть беззнаковое, "int" - integer - целое. занимающее 32 бита.

При присвоении вы сделали несколько ошибок....наверное уже понятно каких. По идее компилятор должен бы ругнуться. И на нормальной платформе - так бы и было...а видимо, в IDE ARDUINO - многое чего из компиллера было изъято, для компактности. И в нашем случае похоже, что компиллер сделал преобразование типа при присвоении значения данной переменно, и что он в итоге присвоил - я не знаю....можно проверить - выведя значение данной переменной, например, в компорт.
2014-04-06 добавлено 06/04/2014 15:09:27#1959689

Кандидат в Советники



1268 400
Ростов-на-Дону
3 дн. назад
сообщение Z0RS
Я конечно...прошу прощения, но нельзя же так не уважать основы языка СИ.

Чтобы их уважать, их надо знать, а я уже признался их незнании. За пару месяцев всего сразу не постигнешь, только учась на конкретных примерах, копируя их и подгоняя под свои нужды.

uint32_t - в данном случае "u" - unsigned - то есть беззнаковое, "int" - integer - целое. занимающее 32 бита.

Ну вот до этого я интуитивно и методом тыка и дошел.

Изменено 6.4.14 автор Дядька-рыбомор
2014-04-06 добавлено 06/04/2014 15:30:06#1959693

Постоянный посетитель


693 78
Выкса
1 г. назад
Дядька-рыбомор

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

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

Очень неплохо знать как хранятся в памяти переменные разных типов, как происходят над ними операции. Тогда на Си программировать легче, легче понять операции с указателями - а это основа эффективности языка.

Сейчас этому в школах стали учить...в некоторых....
2014-04-06 добавлено 06/04/2014 16:39:16#1959734

Посетитель


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

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

Вот я сейчас столкнулся с тем, что система опять уперлась в концептуальный вопрос - сколько насосов для подачи удобрений надо контролировать.
И проект встал до того как я разберусь в этом вопросе. Причем профи дают уклончивые советы - "в зависимости от многих факторов", воинствующие дилетанты - "тока как у меня иначе все плохо", но им доверия меньше.
Пока остановился на системе http://www.aqua-bota...
Получается: азот, фосфор, микро, магний, калий.
5 леек или 6 (+ кальций). Но тут я уперся в аппаратную проблему - я просто не представлял что вносить потребуется столько много разных растворов - думал ну три-четыре максимум. И просто не имею приводов. А Китай до-о-о-олго шлет.
И в голове бродит - а оно надо? может я перезаложился? 6 каналов для удо тупо займут слишком много места. - 6 литровых (или по пол-литра взять?) бутылок плюс насосы.
2014-04-06 добавлено 06/04/2014 21:40:14#1959886

Посетитель


94 1
Москва
1 мес. назад
Наконец-то пришли все компоненты Arduino. сегодня собрал схему, припаял где надо. Подключаю к компу (Mac OS), через программу для мака устанавливаю библиотеки из первого поста. Далее вставляю скетч ARDUINO для автоматизации аквариума нажимаю загрузить, идет загрузка в память и на дисплеи в нижнем ряду одни квадраты. Где косяк?

Вопрос еще таков что при добавлении билиотек у меня там три файла всегда например для RTS%
-datecalc
-ds1307
-softrts
что открывать?
2014-04-06 добавлено 06/04/2014 21:54:33#1959897

Посетитель


94 1
Москва
1 мес. назад
с добавлением билиотеки разобралс но не до конеца. При добавлении библиотеки пв программе пишет
#include <LiquidCrystal_I2C.h> //Подключаем библиотеку для использования I2C интерфейса с модулем RTC

а далее где инициализация там написано

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


при попытке заменить на LiquidCrystal_I2C пишет ошибку. да и вообще не хочет записывать в плату
2014-04-06 добавлено 06/04/2014 22:21:46#1959912

Постоянный посетитель


693 78
Выкса
1 г. назад
Bwzs

Начните с более простых вещей. Залейте на плату скетч-пример с названием Blink, из стандартного пакета примеров.
Или можете скопировать вот этот код. Далее, необходимо откомпилировать его и залить на плату. Кстати, какая у вас модель платы?

int led = 13;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
delay(1000);
digitalWrite(led, LOW);
delay(1000);
}
В результате, на 13 пине должен моргать светодиод с частотой 0,5 герца примерно. На разных платах, это светодиод находится в разных местах и он может быть разного цвета, посмотрите инфо по вашей плате.

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

Изменено 6.4.14 автор Z0RS
2014-04-06 добавлено 06/04/2014 22:57:36#1959924

Посетитель


460 39
Москва
11 мес. назад
Bwzs

У вас должны быть на компе установлены библиотеки.
Как на маке не в курсе, но вроде от других операционок - не особо отличается.

в папке с установленной программой Arduino есть подпапка libraries.
В ней лежат файлы библиотек.
Вы подгружаете библиотеки. Вернее автоматом подгружаются в среду все библиотеки, лежащие в папке libraries при запуске среды программирования, а вы их вставляете в собственный скетч.
Wire (для работы с шиной I2C). - для шины, только для шины. Конкретно файл Wire.h, который среда сама находит в папке Wire (если он там есть).
RTClib - для работы с часами по протоколу I2C. Соответственно файл RTClib.h
LiquidCrystal_I2C - для работы с жк экраном по I2C, т.е. файл LiquidCrystal_I2C.h


Проверьте наличие этих файлов. Содержимое их можно прочитать в любом текстовом редакторе, возможно они подгружают еще файлы, которые должны быть доступны (обычно лежат с ними в одной папке). Так же в каждой хорошей папке с библиотекой обычно находится папка с примерами скетчей с использованием данных библиотек. Ссылки на библиотеки давал уважаемый Z0RS, в постах, где описывал примеры кода. А вообще проверьте работоспособность системы, по совету нашего гуру.

И не забудьте после добавления библиотек, а добавляются они простым разархивированием папки библиотеки в папку libraries, презапустить среду программирования. И еще один ньюанс - папка должна иметь простое название без русских букв и пробелов - иначе будет ругаться среда при запуске.
Удачи!

Изменено 6.4.14 автор arch07
2014-04-07 добавлено 06/04/2014 23:13:10#1959932

Посетитель


94 1
Москва
1 мес. назад
Z0RS


Все работает.ну всмысле мигает на 13 пине. Как я понял в данном скетче нет обращения к модулю дисплея, правильно? при добавлении библиотеки LiquidCrystal_I2C он выдает ошибку.
2014-04-07 добавлено 07/04/2014 08:02:25#1959997



Аквариум и аквариумные рыбки на АКВА.ру