Доработка на AVR автоматического освежителя воздуха Air Wick Freshmatic

Air Wick Freshmatic

Моя версия доработки известного освежителя на микроконтроллере Atmel ATtiny13A.

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


Выключатель самого освежителя должен быть в выключенном положении.

Алгоритм работы освежителя становиться такой:
1. При срабатывания датчика проверяется, что предыдущее срабатывание было раньше таймаута (по умолчанию 15 минут),
2. Выжидается пауза (по умолчанию 16 секунд), мигает светодиод для информации,
3. Нажимается клапан баллона с освежителем.
фото платы освежителя
Добавлена кнопка, которой можно отменить срабатывание во время фазы 2 или запустить срабатывание в любое время.
Также с помощью ее задаются настройки и производится сброс счетчика.

В программу встроен счетчик срабатываний и максимальное количество срабатываний одного баллона (по умолчанию 2300).
На сайте производителя указано приблизительное значение — 2400.
Первый баллон отработал где-то 2340 срабатываний.

Значение, деленное на 10, сохраняется в EEPROM. После смены баллона меняется ячейка памяти для увеличения срока ее службы.

Когда содержимое баллона подходит к концу начинает мигать красный светодиод освежителя. После замены баллона нажатием кнопки более 5 секунд, но менее 10 осуществляется обнуление счетчика.
Вход в настройку — нажатие кнопки более 10 секунд.
Подробное описание в исходнике.

Для более-менее точного отсчета времени произведена калибровка встроенного генератора через OSCCAL (при включении берется из 0 ячейки EEPROM), частота задана соответствующая — 2621440.
Время считается в прерывании по переполнению таймера 0 (срабатывает 10 раз в секунду).

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

Датчик — инфракрасный светодиод и фотодиод, направлены друг на друга над кнопкой слива унитаза. На фотодиод надет кембрик, чтоб исключить ложные срабатывания. Срабатывание по пересечению луча.
Решил попробовать такой способ, но можно и датчик движения прикрутить.
Срабатывание INT0 — по спадающему фронту.

Родные батарейки используются для сохранения питания контроллера при отключении света.
Программа написана на C в Atmel Studio 6.1.

Схема:
схема
  • 0
  • 29 июля 2013, 15:10
  • vad7
  • 1
Файлы в топике: AirFresher.zip

Комментарии (15)

RSS свернуть / развернуть
Опять AirWick. Искусители.
0
  • avatar
  • Vga
  • 29 июля 2013, 15:28
Реально полезная штука, у них еще ароматов вагон — на все вкусы…
0
когда-то тоже так думал
0
И что произошло?
0
да все просто
стал действовать как ремонтник бывший и не стал удалять последствия, а стал разбираться, почему гавно так воняет
ну вот выяснил причины и устранил их, теперь никакого освежителя мне не надо
0
А если кто-то пукнет?
0
кто именно? устранив причину вони отходов автоматически устраняется причина образования пука
0
Анекдот №398110.
0
Ну что. Имеем.
Есть двухбайтовая переменная MinRepeatTime которая изиеняется в прерывании TIM0_OVF но кроме того совершенно неатомарно присваивается в функции DoNow, которая дважды вызывается в main. Представляю, что будет, если посреди присваивания этой переменной произойдет прерывание TIM0_OVF. Фобос упадет в грунт. Или нет? :)
0
Нет, в DoNow она равна 0.
0
Ну, тогда ждите неожиданностей. Могу рассказать примерно как это будет.
Пусть, как Вы и говорите, Ваша MinRepeatTime равно 0. В неатомарном присваивании в функции DoNow есть строка MinRepeatTime = EEPROM_read(EPROM_MinRepeatTime) * 60;
Чему будет равно новое вычисленное значение MinRepeatTime — неважно, пусть 0x0100. Важно, что присваивание произойдет неатомарно, побайтно «за 2 приема»: 01 и 00. Теперь следите за моей рукой: после присваивания старшего
байта 01 произошло прерывание. Поскольку наше «недоприсвоенная» MinRepeatTime теперь якобы равна 0x0100, то в прерывании выполнится строка if(MinRepeatTime) MinRepeatTime--; и MinRepeatTime станет равно 0х0100 — 1 = 0x00FF. После этого прерывание «благополучно» закончится и управление вернётся в DoNow. Там произойдет финал трагедии: к переменной MinRepeatTime присобачится младший байт и она станет равна 0х0000.

Сами понимаете, числа условные и ситуация может быть круче.

PS. Кстати, описанный случай — не единственная неожиданность. Оптимизатор может вообще неаккуратно обойтись с переменной MinRepeatTime — например, вовсе выкинуть ее или заоптимизтровать до неузнаваемости, поскольку оптимизатор и знать не знает что она применяется где-то еще в совершенно другом «потоке» — прерывании(особенно если обработчик будет находиться в другом файле). Вы же не указали компилятору для переменной MinRepeatTime слово volatile: «эту переменную не оптимизируй».
+1
См ниже, это так было задумано.
0
Первой заполняется младший байт переменной, и если даже до заполнения старшего байта произойдет срабатывания прерывания и уменьшение переменной, то это не на что не повлияет.
0
Угу. Для версии компилятора 123454321FF это будет так. А уже для версии 23454321AA — Вы можете ручаться что компилятор будет так же?
А когда Вы всё-таки напишете volatile — этот порядок сохранится? :)
0
Переменная эта была не обернута специально — памяти мало.
Я тут на ассемблере прерывание переписал, чтоб в килобайт уместиться…
-1
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.