Приветствую, Хабр!
Начать нужно с того, а для чего все это вообще нужно? Ответ частично лежит на поверхности и исходит из названия, но все-таки не совсем очевиден. Все началось с того, что как-то я прочитал статью о благотворном влиянии белого и розового шума на процесс засыпания. Тема мне показалась интересной, так как с этим у меня есть некоторые проблемы. То есть я соблюдаю режим, не сижу перед сном с телефоном, стараюсь не есть на ночь, но факт остается фактом. Но при чем тут GPS, спросите вы! Давайте обо всем по порядку.
По правде говоря, есть и готовые варианты. Можно взять телефон с приложением, которое умеет генерить всевозможные звуки, начиная от шума волн и пения птиц, заканчивая классическими шумами. Существуют устройства, в основном использующиеся для детей, которые тоже все это умеют и даже работают от аккумулятора. Но как я не раз уже писал – это слишком просто и не интересно.
Первое, что я сделал – проверил на практике влияние белого шума на мой мозг. Теория состоит в том, что белый шум создает постоянный слуховой фон, маскируя звуки вокруг, и не дает сосредотачивать мысли на чем-то определенном. Нет, я не стал запускать файл с белым шумом и пытаться уснуть. Я надел наушники, выставил громкость ниже среднего и погрузился в работу. Точнее, попытался погрузиться. Работать оказалось практически невозможно – это не то же самое, что слушать музыку. Периодически я понимал, что просто сижу и смотрю на экран монитора. Эффект мне очень понравился. Не знаю, на всех ли такое влияние оказывает белый шум, но можете попробовать.
Второй этап. Еще из своего детского увлечения радиотехникой я помню, что лучше всего шумят стабилитроны. Есть варианты на транзисторах. Попробовал, поигрался и понял, что недостаточно просто включить устройство и лечь спать. Нужна регулировка уровня громкости (да хоть бы и переменным резистором), какой-никакой таймер, чтобы не всю ночь эта «музыка» играла (нашел информацию, что постоянное влияние несет больше вреда, чем пользы), ну и так далее.
Раз уж я собираюсь все это реализовывать, то тут практически не обойтись без микроконтроллера. Нет, можно, конечно, поставить две «крутилки», которыми регулировать громкость и длительность, но это как-то некрасиво. Хотя макет я испробовал как раз в корпусе от старой маленькой колонки для ПК.
Я ошибочно предположил, что проще простого будет реализовать генератор белого шума на Arduino. Что сложного выводить псевдорандомные значения на динамик? А вот и нет. Все началось с такой простой схемы.
Рис.1. Arduino nano.
Пробовал и так, и сяк, работает генератор, но шум был
недостаточно белый какой-то не такой. Решил поискать рабочие алгоритмы, но где-то глубоко задумался, что без стабилитрона будет не обойтись. Убил на это кучу времени. Провел множество экспериментов и все-таки нашел что искал.
volatile byte outsampl = 0x80;
volatile byte phase = 0;
volatile int error = 0;
ISR (TIMER2_OVF_vect)
{
if (phase == 0)
{
OCR2A = outsampl + 0x80;
int samp = stenzel_pink_sample() + error;
outsampl = samp >> 8;
error = samp - (outsampl<<8);
}
phase = 1 - phase;
}
byte bitrev(byte a)
{
byte r = 0;
for(byte i = 0; i < 6; i++)
{
r <<= 1;
r |= a & 1;
a >>= 1;
}
return r;
}
byte bitrevtab[0x40];
void build_revtab()
{
for(byte i = 0; i < 0x40; i++)
bitrevtab[i] = bitrev(i);
}
long lfsr = 0x5EED41F5;
int inc = 0xCCC;
int dec = 0xCCC;
int accum = 0;
int counter = 0xAAA;
void seed_stenzel(long seed)
{
lfsr += seed;
}
#include "firtables.h"
int stenzel_pink_sample()
{
int bit = lfsr < 0 ? 0xFFF : 0x000;
lfsr += lfsr;
if (bit)
lfsr ^= 0x46000001L;
counter += 1;
counter &= 0xFFF;
int bitmask = counter & -counter;
bitmask = bitrevtab [bitmask & 0x3F];
bitmask <<= 6;
bitmask |= bitrevtab [bitmask >> 6];
dec &= ~bitmask;
dec |= inc & bitmask;
inc ^= bit & bitmask;
accum += inc - dec;
int result = accum;
int twelve_bits = ((int)lfsr) & 0xFFF;
result += highfirtab [twelve_bits >> 6];
result += lowfirtab [twelve_bits & 0x3F];
return result;
}
Скажу честно, я очень далек от этого кода. Привел его только потому, что он работает. Я же из своего кода управляю запуском этого таймера.
Сидел я, слушал, и не мог ни о чем думать. Шучу. Как я сказал выше, я хочу регулировать уровень громкости и длительность выдачи сигнала.
Но при чем тут GPS? Все это удобно настраивать на дисплее, конечно, с кнопками управления и каким-никаким меню. Покопался и нашел у себя в закромах вот такой набор, на котором решил сделать макет.
Рис.2. Набор плат для макета.
Плата для Arduino от другого проекта, точечный дисплей 128х64 (очень надеялся, что он умеет работать в режиме SPI, ан нет) и динамик. Красная плата – это известная многим тач-кнопка на TTP223, думал использовать металлический корпус и включать/выключать генератор касанием, но потом передумал.
Не знал, в каком состоянии дисплей, поэтому нужно было что-то на него вывести для теста. Нашел библиотеку для часов с поддержкой русскоязычных символов. Так как на моей плате уже была микросхема RTC PCA2129T, немедленно решил ее задействовать и читать время из нее.
Рис.3. Подключение LCD к макету (фото из будущего).
Так как мне на прикроватной тумбочке катастрофически не хватает часов, решил, что это именно то, что мне нужно. Часы, со встроенным генератором шума – эврика!
Побежал получать патент. Хорошо, экран работает, время выводится, с кнопками что-нибудь придумаю. И тут я погрузился в долгое написание ПО, чтобы все было условно красиво прорисовано с учетом старого тормозного дисплея с зеленой подсветкой. Сразу отказался от показа «секунд» в часах и добавил визуализацию включенного генератора шума с помощью некой шкалы, которая заполняется рандомными значениями. Рядом со шкалой таймер обратного отсчета, после окончания которого я должен уже спать (но это не точно). Получилось симпатично.
Рис.4. Вывод даты, времени и шкалы отображения работы генератора шума.
Без кнопок (точнее только с одной), конечно – беда. Хорошо хоть время каждый раз ставить не нужно. Вообще я думал, что в таком виде все это упакую в корпус, на проводах припаяю кнопки и крепкий сон мне обеспечен. Выключил отображение шкалы генератора и понял, что нижнюю строку нужно чем-то занять, а то как-то пусто получилось. Можно, конечно, что-то типа «ПРИВЕТ, ХАБР» или «БУДИЛЬНИК.
Сделано в СССР», ну вы меня поняли. Есть как раз фото в тему. Макетировал усилитель на советском МП38 (не пригодился).
Рис.5. Эксперимент с усилителем на транзисторе.
Немного поразмыслив, пришел к выводу, что хочу сделать новую плату, где будет все компактно и питание от разъема USB-C, выведу нормально кнопки и кое-что добавлю.
На поверхности лежит вывод температуры воздуха в нижней строке. Знаю, что atmega328p имеет встроенный датчик температуры. А почему бы и нет? Попробовал и убедился, что он показывает
погоду очень неточно. Во-первых, есть большой разброс показаний, которые необходимо усреднять. Во-вторых, что для меня не так критично – это разброс от микросхемы к микросхеме. И, конечно, коэффициент вплоть до 15 градусов, что само по себе странно. В нескольких проектах имел дело с датчиком LM75, на нем и остановился. Температуру буду выводить в левый нижний угол.
Пока все это реализовывал в коде, вспомнил что у меня есть динамик, на который можно выводить не только шум, но и тон. Так как есть уже часы, то почему бы не сделать и будильник? Как раз есть свободное место в правом нижним углу. Нет, он мне, конечно, не нужен (пользуюсь будильником исключительно на наручных часах), но место на экране пропадает. Тут вообще все просто, пусть минуту пикает:
if((Alarm_EN == 1) && (now.hour() == Alarm_H) && (now.minute() == Alarm_M)){
tone(NOISE_PIN, 1000, 50);
}
Вот такой код я могу писать)
Рис.6. Примеры вывода на экран.
Все управление я реализовал четырьмя кнопками, как такового меню рисовать не стал. Одна кнопка включает/выключает генератор шума. Вторая входит в режим настроек, перебирая все пункты по очереди. После перебора даты/времени доступен еще ряд настроек: длительность вывода шума, уровень громкости, установка режима подсветки (Вкл/Выкл/Авто), корректировка значения температуры, включение/выключение и настройка будильника. Две оставшиеся кнопки для изменения выбранного пункта. Все просто, управлять удобно.
Наконец GPS. Как-то видел стрелочный будильник. Вставляешь в него батарейки, стрелки начинают крутиться и встают на нужное время. Магия. Валяются у меня модули GeoS-5M. Решил попробовать задействовать автоматическую установку времени. Для этого вывел отдельную кнопку управления питанием модуля GPS. Если подать питание с нажатой кнопкой включения генератора шума, то отобразится экран ожидания данных от приемника. Жму кнопку подачи питания на модуль и … ничего (еще делаю).
Рис.7. Общая схема.
Да, чуть не забыл. Для регулировки уровня громкости решил взять цифровой потенциометр AD5241BRZ10. Для микросхемы PCA2129T поставил преобразователь уровней RS0302YH8. Можно было и транзисторы, конечно. Все кнопки продублированы на разъем, так как на момент разработки схемы не было четкого понимания как будет выглядеть корпус. Для питания GPS – RT9193-18GB.
Рис.8. Распределение GPIO.
Занял все GPIO. Для пары кнопок пришлось даже использовать входы АЦП. Так как 12В питание не предполагается из платы Arduino nano выпаял LDO. Решил, что постоянная подсветка дисплея мне не нужна и добавил отслеживание освещенности фоторезистором (режим «Авто» в меню). Выведу его потом на корпус.
Рис.9. Спаянная плата часов.
Дисплей установил на штыревой линейке, Arduino пришлось впаять. Как ни странно, но после включения сразу все завелось (пришлось только поиграться с контрастом дисплея). Габариты платы и крепежные отверстия повторяют LCD.
Рис.10. Сборка плат в единое целое.
Есть очень интересная идея по корпусу, думаю, что расскажу в следующей статье. Также, конечно, отпишусь о результатах тестирования. Также не подумал, что боковой разъем, в данном случае, не очень удобен. Нужно как-то приспособить вертикальный на заднюю стенку устройства.
Спасибо за внимание и успехов!