Доработка на AVR автоматического освежителя воздуха 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
да все просто
стал действовать как ремонтник бывший и не стал удалять последствия, а стал разбираться, почему гавно так воняет
ну вот выяснил причины и устранил их, теперь никакого освежителя мне не надо
стал действовать как ремонтник бывший и не стал удалять последствия, а стал разбираться, почему гавно так воняет
ну вот выяснил причины и устранил их, теперь никакого освежителя мне не надо
- kalobyte-ya
- 30 июля 2013, 13:10
- ↑
- ↓
Ну что. Имеем.
Есть двухбайтовая переменная MinRepeatTime которая изиеняется в прерывании TIM0_OVF но кроме того совершенно неатомарно присваивается в функции DoNow, которая дважды вызывается в main. Представляю, что будет, если посреди присваивания этой переменной произойдет прерывание TIM0_OVF. Фобос упадет в грунт. Или нет? :)
Есть двухбайтовая переменная MinRepeatTime которая изиеняется в прерывании TIM0_OVF но кроме того совершенно неатомарно присваивается в функции DoNow, которая дважды вызывается в main. Представляю, что будет, если посреди присваивания этой переменной произойдет прерывание TIM0_OVF. Фобос упадет в грунт. Или нет? :)
Ну, тогда ждите неожиданностей. Могу рассказать примерно как это будет.
Пусть, как Вы и говорите, Ваша 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: «эту переменную не оптимизируй».
Пусть, как Вы и говорите, Ваша 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: «эту переменную не оптимизируй».
Первой заполняется младший байт переменной, и если даже до заполнения старшего байта произойдет срабатывания прерывания и уменьшение переменной, то это не на что не повлияет.
Комментарии (15)
RSS свернуть / развернуть