"Умное" освещение на базе сенсора освещенности и расстояния APDS-9930. Часть 2, прошивка.

Продолжение 1ой части.

Ссылку на прошивку уже давал, повторю: https://github.com/N-Storm/autolight

В README.md описание есть, код более-менее прокомментировал. Но всё ес-но на английском.

В разделе Releases лежат скомпилированные прошивки с настройками по-умолчанию.


Прошивка написана под ATTiny10, который вписывается в эту задачу. В общем-то никаких особых сложностей, чтобы адаптировать прошивку под другой AVR нет. Кроме GPIO (ногодрыга) используется только прерывание INT0, Watchdog для сброса МК при ошибке, да и вроде всё.

Все настройки работы датчика и порогов срабатывания задаются жестко в прошивке. Все настройки в общем-то в файле autolight.h. Разберу их:


#define PROX_TH 30 - это порог срабатывания датчика приближения. В условных попугаях, потому что зависит от настроек ниже. Больше - ближе. При текущих настройках полностью прикрытый датчик вплотную пальцем выдает тут 1023. При снижении дальности ниже этого значения, считается сработало открытие. Выше - закрытие.


#define LIGHT_TH 100 - это порог срабатывания датчика освещения. Опять же в условных попугаях, да еще я использую жесткое округление при расчете. Потому что ДШ датчика приводит сложную формулу с делениями на дробные числа, это для тиньки 10 будет слишком много. Больше - ярче.


#define DELAY 600 - задержка в мс между проверками на уровень освещения и закрытие в рабочем состоянии (т.е. когда подсветка горит). Для экономии батарейки не слишком часто считаем, 600 мс реакция на такое событие для человеческого глаза вполне норм.


// #define RECHECK_AL - если раскомментировать эту строчку, слегка поменяется поведение прошивки. В рабочем состоянии помимо проверки на закрытие, будет также выполнятся проверка на изменение освещенности. Т.е. если подсветка работает, но вдруг включили свет в комнате, тогда подсветка выключится.


#define WTIME_DEFAULT 0xB6 - время ожидания между проверками расстояния датчиком в автономном режиме. Значение из ДШ и соответствует 202 мс между проверками. Потребление тока при этом будет копеечное. Порядка 66 мкА в среднем. Т.е. датчик раз в 202 мс "выстреливает" пульсами из ИК-светодиода и проверяет расстояние.


#define PPULSE_DEFAULT 4 - соб-но количество пульсов 4.


#define PERS_CON 0b00110000 - это то, о чем я говорил в прошлой части, настройка PERS. В ДШ даны значения, в данном случае это 3 раза подряд (202 мс * 3 + время на обработку) значение дальности должно быть ниже PROX_TH. Соб-но поэтому 3 и поставил, потому что 202 * 3 = 606, примерно тот же 600 мс отклик, как и на закрытие.


#define ATIME_DEFAULT 0xED, #define PTIME_DEFAULT 0xFF - время на обработку АЦП значений, тут взяты рекомендованные из ДШ на датчик.


Дальше всё уже идут определения констант адресов регистров датчика, битов и т.д.


I2C в Attiny10 нет аппаратного, используется софтовая либа, которую я чуть допилил. В i2csoft.h можно поменять пины SDA и SCL.


В autolight.c основная логика работы. Первым делом из main() вызывается функция init(), где мы вырубаем Watchdog и устанавливаем параметры МК. Включаем тактирование от внутреннего источника и ставим предделитель, чтобы получить итоговую тактовую частоту 250 кГц. Да, нам этого с головой тут, зато тайминги I2C можно делать просто одной инструкцией NOP.

Дальше вырубается не используемая аналоговая периферия для снижения потребления.  Ну и соб-но настраивается прерывание INT0.

После init() "инициализируется" I2C через SoftI2CInit() и через функцию apds_init() отправляем в датчик все описанные ранее настройки из .h. В случае ошибки тут и любой ошибки на I2C дальше, вызывается функция reset(), которая через Watchdog сбрасывает МК через 15 мс. Т.е. если связь с датчиком пропадет (отвалится линия или еще что), МК будет пытаться перезагружаться.


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


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


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

Arduino & Pi

1.4K постов20.6K подписчик

Добавить пост

Правила сообщества

В нашем сообществе запрещается:

• Добавлять посты не относящиеся к тематике сообщества, либо не несущие какой-либо полезной нагрузки (флуд)

• Задавать очевидные вопросы в виде постов, не воспользовавшись перед этим поиском

• Выкладывать код прямо в посте - используйте для этого сервисы ideone.com, gist.github.com или схожие ресурсы (pastebin запрещен)

• Рассуждать на темы политики

• Нарушать установленные правила Пикабу

Автор поста оценил этот комментарий

Забыл про заморочку написать. Оставлю тут, вдруг кто поиском по названию датчика позже найдет. Китайский датчик по I2C не выдает нормально последующие байты при считывании в режиме AUTO_INCREMENT, нули сыпет в байтах после 1го. Можно считывать только по 1 байту данных.

Автор поста оценил этот комментарий

Еще забыл:

// Control register flags
// #define PDRIVE 0 // 100mA of LED Power
#define PDRIVE 0x80 // 25mA of LED Power

По-умолчанию в прошивке ток на светодиод подсветки выставлен на 25мА (для экономии батарейки), если поставить PDRIVE в 0, то будет 100мА -> большая дальность срабатывания можно сделать (в паре с настройкой PROX_TH это влияет на расстояние срабатывания).