Моя версія доопрацювання відомого освіжувача на мікроконтролері Atmel ATtiny13A.
Доопрацювання полягає в підключенні контролера з датчиком спрацьовування до рідної схемою, використовуючи з неї двигун з обв'язкою, світлодіоди і підключенні всього цього до блоку живлення. Є лічильник спрацьовувань для попередження про підхід рідини в балоні у кінці.
Вимикач самого освіжувача повинен бути в вимкненому положенні.
Алгоритм роботи освіжувача ставати такою:
1. При спрацьовування датчика перевіряється, що попереднє спрацьовування було раніше таймаута (за замовчуванням 15 хвилин),
2. Вичікують пауза (за замовчуванням 16 секунд), блимає світлодіод для інформації,
3. Натискається клапан балона з освіжувачем.
Додана кнопка, якою можна скасувати спрацьовування під час фази 2 або запустити спрацьовування в будь-який час.
Також за допомогою її задаються настройки і проводиться скидання лічильника.
У програму вбудований лічильник спрацьовувань і максимальну кількість спрацьовувань одного балона (за замовчуванням 2300).
На сайті виробника вказано приблизне значення - 2400.
Перший балон відпрацював десь 2340 спрацьовувань.
Значення, поділене на 10, зберігається в EEPROM. Після зміни балона змінюється осередок пам'яті для збільшення терміну її служби.
Для більш-менш точного відліку часу проведена калібрування вбудованого генератора через OSCCAL (при включенні береться з 0 осередку EEPROM), частота задана відповідна - 2621440.
Час вважається в перериванні по переповнення таймера 0 (спрацьовує 10 раз в секунду).
Кнопка обробляється в PCINT0 зі зміни стану Піна, далі використовується таймер для затримки, щоб виключити брязкіт контактів.
Датчик - інфрачервоний світлодіод і фотодіод, спрямовані один на одного над кнопкою зливу унітазу. На фотодиод надітий кембрік, щоб виключити помилкові спрацьовування. Спрацювання по перетинанню променя.
Вирішив спробувати такий спосіб, але можна і датчик руху прикрутити.
Спрацювання INT0 - по спадающему фронту.
Рідні батарейки використовуються для збереження живлення контроллера при відключенні світла.
Програма написана на C в Atmel Studio 6.1.
Ну, тоді чекайте несподіванок. Можу розповісти приблизно як це буде.
Нехай, як Ви і кажете, Ваша 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: «цю Змінна не оптимізуй».
Див нижче, це так було задумано.
Першою заповнюється молодший байт змінної, і якщо навіть до заповнення старшого байта відбудеться спрацьовування переривання і зменшення змінної, то це не на що не вплине.
Угу. Для версії компілятора 123454321FF це буде так. А вже для версії 23454321AA - Ви можете ручатися що компілятор буде так само?
А коли Ви все-таки напишете volatile - цей порядок збережеться. )
Мінлива ця була обгорнута спеціально - пам'яті мало.
Я тут на асемблері переривання переписав, щоб в кілобайт вміститися ...
EasyEDA: безкоштовний Хмарний CAD