У моего друга какие-то непонятные проблемы со здоровьем. Врачи говорят, что это «криптогенная эпилепсия». Суть в том, что иногда у него ночью во сне начинается приступ «трясучки». В итоге меня попросили сделать устройство, которое должно надеваться на руку и противно пищать, если его трясти секунд десять, чтобы оповестить близких и своевременно помочь.
Самое очевидное решение — использовать акселерометр. Я купил один из первых попавшихся — BMA150 от Bosch.
Маленький, зараза, всего 3x3мм, но мы и не такое паяли.
Сразу скажу, что занимаюсь этим исключительно на любительском уровне, поэтому сильно не критикуйте.
После чтения даташита выяснилось, что общаться с акселерометром можно по I²C или SPI, но ко всему прочему у него есть специальный вывод под внешнее прерывание. Т.е. можно один раз настроить его так, чтобы он при определённых условиях выводил туда логическую единицу. В нашем случае это идеально — не надо постоянно опрашивать датчик, он сам будет выводить микроконтроллер из спящего режима при наличии тряски определённой силы. Это очень важно, учитывая, что нужно сделать устройство максимально экономным в плане питания.
Настройка акселерометра
Для экспериментов и настройки я вытравил плату, чтобы можно было легко подпаяться:
Почему-то по I²C акселерометр не захотел работать. Возможно, что я где-то ошибся. А вот по SPI всё заработало без проблем. Датчик доступен как массив памяти, который делится на две части:
- EEPROM с настройками по умолчанию, т.е. которые используются в момент включения
- Операционные регистры с текущими настройками и самими показаниями датчика
Радости моей не было предела, когда я наконец-то получил данные:
Акселерометр умеет автоматически генерировать внешнее прерывание в самых разных случаях. Нам нужно простейшее событие — любое достаточно сильное движение. Датчик делает это, если верно следующее условие по любой из осей:
|acc(t0)-acc(t0+3/(2*bandwidth))| >= any_motion_thres
any_motion_thres задаётся в специальном регистре. Опытным путём я выяснил, что при частоте обновления в 25Гц оптимальным значением является 20h. При таком раскладе флаг прерывания устанавливается, если легко потрясти датчиком. Снимается же флаг автоматически, если условие перестаёт выполняться в течении некоторого времени.
Убедившись, что все параметры выставлены оптимально, я сохранил эти настройки уже в EEPROM. Таким образом, акселерометр сразу же после включения будет выводить на INT вывод логическую единицу, если есть движение, и SPI больше не нужен.
Разработка платы
Я выбрал микроконтроллер ATMEGA8A. Он имеет два внешних прерывания (одно из них я решил использовать для кнопки, а другое для самого акселерометра), работает в диапазоне напряжений 2.7-5.5В, и в самом глубоком режиме сна «power down» потребляет всего 0.5мкА. Предполагается, что почти всё время микроконтроллер будет спать, ведь очень важно энергосбережение. Однако, для пробуждения из такого спящего режима необходимо замкнуть INT0/INT1 ногу на землю, а акселерометр при наличии движения наоборот даёт высокий уровень, поэтому для инвертирования нужно поставить транзистор. Сам датчик я решил питать прямо от ног самого микроконтроллера, чтобы можно было без лишних потерь его включать и выключать. Динамик тоже подключил напрямую. Для отладки было решено поставить ещё и один светодиод. Схему я не рисовал, а плата в итоге выглядела так:
Готовая плата:
Увы, в наличии у меня была только пищалка, которая оказалась больше самой платы:
Прошивка
Тут всё достаточно просто. У устройства два режима работы:
- Выключенное. В этом состоянии мы не подаём питание на акселерометр и просыпаемся только по нажатию кнопки. В таком виде микроконтроллер может проработать не менее года (проверено), разряд батарейки близок к саморазряду.
- Включенное. Когда же устройство включено, мы питаем акселерометр и просыпаемся как от нажатия кнопки, так и от сигнала со стороны датчика. Если кнопка держится полторы секунды, устройство переходит назад в выключенное состояние. Если же прерывание сгенерировал сигнал от датчика, и он повторяется в течении 10 секунд как минимум один раз за две секунды, то трубим тревогу, пока не будет нажата кнопка.
У акселерометра, кстати, тоже есть режим сна, из которого он может просыпаться через заданные интервалы времени, но я решил его не использовать, чтобы не повлиять на точность и надёжность. По документации этот датчик потребляет 200мкА, этого должно хватит на много ночей.
Создание корпуса
Корпус было решено напечатать на 3D принтере.
В итоге внутри всё выглядело так:
Увы, в конце концов устройство получилось очень громоздким и колхозным: