Перейти к содержимому

Алкогометр на ESP32 с дистанционным управлением с дивана

Добрый день, уважаемые читатели!

В данной статье изложено руководство по сборке и программированию простого одноканального термометра самогонщика. Ещё одно иногда встречающееся название для такого прибора – “электронный попугай“. Я же называю этот прибор просто – “алкогометр” или “электронный спиртометр“. Прибор имеет двухстрочный LCD дисплей 16 * 2 символов и 4 кнопки для управления и настройки.  

Для чего был создан данный прибор?

Создан он для одной единственной цели – измерять температуру спиртосодержащих паров на выходе из самогонного аппарата и “на лету” пересчитывать эти данные в процентное содержание спирта. Это позволяет просто и удобно контролировать начало различных этапов дробной перегонки (“головы” – “основной продукт” – “хвосты“) и не заморачиваться с постоянным контролем крепости продукта с помощью стеклянных (или иных) спиртометров.

То есть это не полная автоматика управления самогонным аппаратом начиная от нагрева до переключения емкостей для сбора, а всего лишь довольной простой электронный спиртометр, который имеет один основной датчик (DS18B20 в гильзе) для контроля температуры только “на выходе” из колонны самогонного аппарата. В текущей версии он “не умеет” контролировать мощность нагрева, не считает остаток спирта в баке, и не умеет переключать клапана или менять емкости. Но тем не менее – прошивка прибора “открытая”, и вы всегда при желании (и соответствующем умении) можете добавить в проект новые датчики и функции по своему желанию.

Когда-то достаточно давно я уже публиковал описание offline-алкогометра, собран он был на базе arduino nano, и имел полностью автономное управление. Новая версия собрана на базе микроконтроллера ESP32, что позволило подключить устройство к сети WiFi, добавить уведомления в telegram и удаленное управление параметрами прибора со смартфона. Дополнительно в новой версии оптимизирован и исправлен процесс пересчета температуры в спирт, так как в оригинальной версии присутствуют некоторые ошибки. Немного более простой и понятной стала настройка и калибровка прибора.

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

 


Основные функциональные возможности

Краткий обзор функциональности новой версии спиртометра:

  • Спиртометр собран на базе микроконтроллера ESP32 классической линейки, а точнее “отладочной” платы ESP32-DevKitC-v4
  • Подключение микроконтроллера к сети позволило контролировать процесс перегонки со смартфона и отправлять уведомления о каких-либо событиях в чат telegram – всё это позволяет в некоторой степени не сильно отвлекаться от телевизора в соседней комнате.
  • Подключение микроконтроллера к сети позволило перенести основную часть настраиваемых параметров на смартфон и значительно упростить экранное “меню”. Одновременно сам процесс настройки стал немного проще (несмотря на то, что общее количество настраиваемых параметров заметно выросло).
  • Использование ESP32 позволило исключить из схемы модуль часов реального времени – теперь точное время получается из сети интернет при запуске устройства. Хотя он и раньше не очень нужен был…
  • В качестве основного измерительного инструмента используется цифровой датчик температуры DS18B20 в металлической гильзе. Я использовал оригинальный датчик, купленный в небезызвестном российском магазине. Поскольку датчик в схеме один, микроконтроллер общается с ним в безадресном режиме – теперь нет необходимости прописывать адрес датчика в коде (по сравнению с предыдущей версией для Arduino).
  • Для компенсации температуры кипения воды при изменении давления используется вспомогательный датчик – любой Bosch-евский измеритель давления (BMP180, BMP280, BME280). У меня стоит BME280, других просто не было. В принципе, это датчик можно исключить из прибора.
  • Все данные отображаются на популярном и недорогом дисплее LCD1602. Дисплей подключен по шине I2C, причем можно использовать как 3.3В версии, так и 5В версии (в схеме может быть установлен конвертер логических уровней).
  • Управление основными функциями – с помощью четырех кнопок: “режим“, “меню” (настройки), “плюс” и “минус“.
  • Кроме собственно пересчета температуры в алкоголь устройство может контролировать границы температуры для уведомления о необходимости смены режим отбора (головы – тело – хвосты) и аварийных ситуациях (быстрый рост температуры или слишком высокая температура с начала отбора).
  • Звуковое уведомление о событиях с помощью встроенного зуммера (активного или пассивного).
  • Все измеренные и рассчитанные данные отправляются на сервис open-monitoring.ru для дальнейшего анализа при необходимости (опционально). Возможна отправка данных на Народный мониторинг и ThingSpeak, но зачем?
  • Поддержка OTA-обновлений прошивки без необходимости снимать прибор с аппарата и подключать к компьютеру проводами.

Проект написан для ESP32 на платформе ESP-IDF (не Arduino!). Для разработки программы использовалась связка VSCode + PlatformIO + ESP-IDF (на момент написания статьи 5.1.2). Как это сделать – будет описано ниже. Также этот проект достаточно легко можно портировать в Espressif IDE, а вот в Arduino IDE перенести, увы, не получится. Исходный код проекта и инструкции приведены ниже по тексту статьи, вы можете скачать его уже в почти полностью готовом к употреблению виде.

Важное предупреждение! Процесс перегонки – потенциально опасное занятие, и его нельзя оставлять без присмотра надолго. По этой причине (но не только) я не стремился создать “полную автоматику”. Всегда может что-то пойти не так, поэтому никогда не оставляйте самогонный аппарат без вашего внимания надолго. Данный прибор лишь облегчает процесс и добавляет некоторый контроль процесса, но не сможет предотвратить аварийную ситуацию без вашего вмешательства.

 


Как это работает? Руководство пользователя

Начнем с того, как собственно пользоваться прибором (а вдруг вам это не подходит и читать статью далее нет смысла).

Как я уже упомянул, спиртометр имеет только один датчик, который вы должны разместить “на выходе” из колонны перед холодильником. Например в моем случае это примерно так:

Не удивляйтесь синему экрану – это фото от первой версии спиртометра. Положение датчика ничуть не изменилось.

Сразу после включения спиртометр подключается к вашей WiFi-сети (её параметры необходимо предварительно “прописать” в настройках проекта), получает текущее время с SNTP-сервера и в принципе почти сразу готов к работе. На текущий момент прошивка поддерживает три режима работы:

  1. Основной режим – в этом режиме на экране отображается:
    • в верхней строке:
      • текущее время,
      • стадия перегонки (буква),
      • время, прошедшее с начала запуска нагрева (чч:мм:сс)
    • во второй строке:
      • текущая температура датчика, причем в зависимости от выбранного режима этом может быть
        • измеренные данные (R),
        • скорректированные по давлению (P),
        • учетом калибровки (N)
        • учетом калибровки в расширенном виде ( P + K )
      • пересчитанное значение спирта в парах, которые поступают на холодильник. То есть то самое нужное нам значение.

Пример информации на дисплее в основном режиме

Обратите внимание: преобразование температуры в крепость спирта начинается с ~ 78°С, и пока температура датчика ниже этого значения, на дисплее отображается –.-%.

2. Режим настройки значения калибровки температуры для текущего температурного диапазона. Всего имеется 15 таких диапазонов: 0-78, 78-81, 81-84, 84-87, 87-90, 90-91, 91-92, 92-93, 93-94, 94-95, 95-96, 96-97, 97-98, 98-99, 99-110 °С. Зачем так много – будет подробно объяснено в следующей главе.

Пример информации на дисплее в режиме установки коррекции температуры

В прежней версии прибора для каждого из этих диапазонов был предусмотрен свой экран-меню, в данной версии с кнопочной панели управления можно корректировать только значение корректировки для активного в данный момент диапазона. Это сильно упрощает работу. А при необходимости можно подкорректировать любое значение со смартфона в любой момент.

3. Режим установки температуры кипения чистой воды (точки кипения). Необходим для установки смещения датчика по известной температуре со школьных времен – 100 °С. Это общее значение калибровки, и оно применяется во всех температурных диапазонах.

Пример информации на дисплее в режиме установки точки кипения воды

Этот параметр также можно изменить с помощью MQTT-панели управления со смартфона.

Переключение режимов экрана (меню) осуществляется с помощью красной кнопкименю” или “настройки“. Кроме указанных параметров, описываемый спиртометр имеет еще множество параметров, доступных только через MQTT-интерфейс. 

 

Прибор поддерживает четыре основных стадии перегонки, которые отображаются соответствующей буквой в верхней части экрана в основном режиме:

  • Н – нагрев
  • Г – головы
  • Т – тело, основной продукт
  • Х – хвосты

Переключение этапов перегонки осуществляется зеленой кнопкой в основном режиме. После включения режима “нагрев” начинает считать счетчик времени наработки (просто для удобства, например я знаю, что мой куб греется около 40-45 минут).

Зачем нужно это переключение этапов?

Да, можно не переключать никакие этапы, при достижении температуры пересчета прибор и без этого будет показывать нужные данные на экране. Но переключение этапов позволяет автоматически контролировать граничную температуру для каждого этапа и сам оповестит вас о необходимости смены емкости или включения воды для охлаждения. Для этого предусмотрены звуковые уведомления и сообщения в telegram. Граничные температуры для каждого из этапов настраиваются через MQTT-интерфейс со смартфона.

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

 

Локальное управление с помощью кнопок:

  • красная – “настройка” – переключает режимы “основной режим” – “настройка корректировки температуры в текущем температурном диапазоне” – “настройка точки кипения чистой воды“. В дальнейшем могут быть добавлены и другие меню / экраны.
  • зеленая – “режим” – её поведение меняется в зависимости от режима:
    • в основном режиме эта кнопка переключает этапы перегонки “нагрев” – “головы” – “основной продукт” – “хвосты” – “стоп
    • в режиме корректировки температуры сохраняет измененные значения на “диск” (flash-память, конечно же)
    • в режиме настройки точки кипения краткое нажатие (до 3 секунд) сохраняет измененные значения на flash, длинное нажатие (более 3 секунд) – автоматически вычисляет смещение так, чтобы в результате получалось 100,0 °С.
  • белые – ” + ” и ” ” соответственно изменяют значения:
    • в основном режиме переключает режим отображения температуры
      • R – raw – полученные с сенсора данные
      • P – pressure – значение, скорректированное по датчику давления
      • N – normal – нормализованное значение, скорректированное по поправочным коэффициентам (калибровкам) = именно оно и используется для расчетов
      • E – extended – расширенный вид, на котором одновременно видно и температуру с учетом давления и действующее корректировочное значение
    • в режиме настройки (любой) краткое нажатие (до 3 секунд) изменяет само значение, а длинное нажатие (более 3 секунд) – переключает шаг изменения – 0,01 / 0,10 / 1,00.

 

Удаленное управление со смартфона

Как я уже написал – все параметры прибора можно корректировать с помощью любого MQTT-клиента со смартфона. Я использую довольно удобный клиент MQTT DASH, про который уже писал. Как его настроить будет рассказано ниже. Но вы можете использовать тот, который вам больше по душе, главное – чтобы ваш клиент умел работать с JSON-пакетами.

 


Принцип работы и точность измерений

Принцип работы данного спиртометра простейший: измеряем температуру водно-спиртовых паров на выходе колонны (перед холодильником) с максимально-возможной точностью и по таблице преобразования “превращаем” эти данные в относительное количество спирта в смеси, которые собственно и отображаем на экране.

Таблицы пересчета температуры в спирт

Формула перевода температуры в спирт мне не известна, но в интернете легко можно найти выдержки из справочников:

Кликните для увеличения

или на различных специализированных сайтах и форумах:

Кликните для увеличения

Поэтому мы просто “загоняем” нужные данные в двухмерный массив (на самом деле в программе используется два одномерных, просто так удобнее) и пользуемся им для пересчета. Далее по тексту я буду называть этот массив данных таблицей пересчета или просто таблицей.

Как я уже писал выше, в данном проекте таблица пересчета почти полностью взята из проекта с форума http://forum.homedistiller.ru/index.php?topic=108287.0. На текущий момент в данном топике форума выложено 4 версии исходного проекта с разными таблицами пересчета, однако я вновь решил остановиться на таблице из второй версии, как наиболее полной (198 записей). Хотя в процессе расчета и применяется аппроксимация (значение рассчитывается на основе сразу двух опорных точек), но чем больше – тем лучше. И самое главное – потому, что данная таблица успешно отработала несколько лет на практике, то есть у меня нет оснований сомневаться в том, что она не работает.

Но! В исходных данных проекта с форума и в самой таблицы мной были обнаружены некоторые ошибки. Во первых цикл поиска по таблице do { i++ } while … – отработает хотя бы 1 раз всенепременно. То есть первая запись в таблице всегда игнорируется. Но это не беда. Во-вторых – на графике таблицы пересчета были обнаружены некоторые неоднородности.

Для проверки я загрузил таблицу пересчета в excel и построил по ней график (файл есть в архиве с проектом). Получилась примерно такая зависимость:

Это уже исправленный “сглаженный” вариант без флуктуаций

На рисунке выше – уже исправленный вариант без флуктуаций. На исходном варианте (к сожалению, скриншота не осталось) были небольшие отклонения, которые я исправил банальным “ручным” подбором, полагая, что график должен быть максимально “гладким”. Впрочем, в области высоких температур (справа) я не стал особо стараться. Можно было бы попробовать внести в excel книжный вариант таблицы и сравнить их, но я банально не стал тратить на это кучу времени. Если у вас есть такое желание – можете сделать это сами и поделиться результатом.

Как видите – зависимость явно не линейная. На краях диапазона зависимость концентрации спирта в парах более нелинейная, чем в середине:

  • в области низких температур (примерно до 80 ~ 82 °C) концентрация спирта в парах меняется на 0,4 ~ 0,5 % на каждый 0,1 °C
  • в середине графика зависимость концентрации спирта от температуры более линейная и составляет порядка 0,15 ~ 0.25% на каждые 0,1 °C
  • в области высоких температур (начиная весьма приблизительно с 95 °C) концентрация спирта в парах становится опять нелинейной и может достигать аж до 1,5 ~ 1.7% на каждые 0,1 °C (при концентрациях ниже 20%)

Это говорит о том, что на каждое изменение температуры отклонение пересчитанной температуры будет как минимум в почти 2 раза больше.

Это уже вполне приемлемая точность. Действительно, для того чтобы принять решение о том, что пора бы уже сменить банку и начать отбор “хвостов” – данной точности хватит с избытком. Простейшие средства измерения типа бытовых спиртометров “из хозмага” обладают куда меньшей точностью. Но – давайте вспомним про средство измерения.

Датчик для изменения температуры

Существует достаточно много точных и хороших датчиков температуры. Но далеко не все из них годятся для измерения температуры в условиях насыщенного нагретого водяного пара. Из цифровых и широко распространенных я знаю только один – DS18B20 в металлической гильзе (ссылка ведет на другую статью). Термопары я отметаю сразу из-за не очень высокой точности и некоторых специфичных им проблем.

Шаг измерения для DS1820 в 12-битном режиме составляет 0,0625 °C, что в принципе, весьма приемлемо. Причем, нам даже не очень важно – абсолютно точно откалиброван датчик на производстве или нет – ведь “сдвинуть” его показания в ту или иную сторону с помощью калибровки мы можем достаточно просто даже без точных приборов: по температуре водяного пара 100 °C. Для этого в программе предусмотрено поправочное значение по точке кипения чистой воды (без спирта).

Но вот погрешность измерения данного датчика в зависимости от температуры весьма нелинейна, и в нужном нам диапазоне до 110 °C может достигать ±1.0°C. Что уже значительно снижает шансы на выигрыш точность измерений.

Поэтому для компенсации нелинейности самого датчика в разных температурных диапазонах (обычно каждый 1 или 2 °C) предусмотрены индивидуальные корректировочные значения. Всего их 15: 0-78, 78-81, 81-84, 84-87, 87-90, 90-91, 91-92, 92-93, 93-94, 94-95, 95-96, 96-97, 97-98, 98-99, 99-110 °С. Причем учитываться эти самые поправочные калибровочные данные могут двояко: фиксировано и с плавной аппроксимацией и учетом следующего по температуре диапазона.

double getTempCorrection(double temp, bool smooth_transition)
{
  float correction = 0.0;
  if (!isnan(temp)) {
    // Поиск по таблице корректировок до предпоследнего элемента, иначе расчет "сломается"
    for (uint8_t i = 0; i < temp_correction_count - 2; i++) {
      if (temp < (double)temp_correction_boundaries[i+1]) {
        correction = smooth_transition ? 
          // Плавный переход к следующему диапазону
          temp_correction_offsets[i] 
            + (temp_correction_offsets[i+1] - temp_correction_offsets[i]) 
            * (temp - (double)temp_correction_boundaries[i])
            / (double)(temp_correction_boundaries[i+1] - temp_correction_boundaries[i]) 
          // Фиксированные значения в каждом диапазоне
          : temp_correction_offsets[i]; 
        rlog_d(logTAG, "Select temperature correction: temp=%f, index=%d, range=%d-%d, offset=%f", 
          temp, i, temp_correction_boundaries[i], temp_correction_boundaries[i+1], correction);
        return correction;
      };
    };
    // Это последний элемент таблицы корректировок
    correction = temp_correction_offsets[temp_correction_count - 2];
    rlog_d(logTAG, "Select temperature correction: temp=%f, index=%d (last), range=%d-%d, offset=%f", 
      temp, temp_correction_count - 2, temp_correction_boundaries[temp_correction_count - 2], temp_correction_boundaries[temp_correction_count - 1], correction);
  };
  return correction;
}

Кроме того, не забываем что иногда повторяемость изменений для цифровых датчиков бывает весьма невысока, особенно для истинных китайцев. То есть выходные данные могут “скакать аки тыгыдымские кони” вокруг некоторых средних значений, что, само собой, приводит и к разнице в выходных показаниях в еще большей степени (за счет пересчетов). Для борьбы с этим эффектом я применяю фильтр “скользящее среднее” с буфером на 32 или даже 64 значения. Особенно эффективно применение данного фильтра на краях диапазона.

Но и это ещё не все. Как мы знаем из курса физики, температура кипения воды 100 °C справедлива только для среднего давления примерно в 1 Атм или 759,94 мм рт.ст. При росте атмосферного давления температура кипения воды увеличивается, при снижении – падает. Даже подъем на 5 этаж обычной многоэтажки немного изменяет атмосферное давление  и следовательно – точку кипения воды. То же самое справедливо и для спиртовой смеси.

Поэтому нам необходимо измерять давление воздуха, чем и будет заниматься электронный барометр BMP280 / BME280. Засунуть внутрь бака с “исходниками” его не представляется возможным, но зато мы можем легко и просто измерять давление снаружи бака – ведь изменение атмосферного давления будет действовать примерно одинаково и на жидкость вне бака и внутри (погрешность конечно будет, но мы ей пренебрежем). Пересчет температуры кипения производится по приблизительной формуле (я проверил её работу в excel – в нужном нам диапазоне давлений она работает в хорошей точностью): temp_pressure_compensated = temp_measured + (759.94 - pressure_in_mm_hg) * 0.0385. Впрочем, если вы уверены, что этот фактор слишком незначителен – что ж, BMP можно не ставить.

Вот теперь, учитывая все эти факторы, мы можем с достаточной на практике точностью посчитать нужные нам % об. Но на практике и температура и выходные данные все равно будут “плавать” из-за внешних причин, которые мы все равно не сможем учесть – например мощность нагрева.

Например, а провожу процесс перегона на газовой плите. Даже давление газа в трубе не всегда остается постоянным, а значит и подводимая к горелке мощность, что в свою очередь приводит к изменениям температуры в баке и на выходе. Обычно я не стремлюсь к быстрой перегонке, так как более медленный и низкотемпературный процесс способствует качеству продукта и более высокой крепости. Но в процессе перегона ещё и приходится периодически добавлять мощность горелки, так как по мере выхода основной массы спирта из бака процесс сильно замедляется. 

Вот например график последней перегонки “второго этапа”. То есть это была перегонка второй раз спирта-сырца, предварительно уже однажды полученного из браги, разбавленного чистой водой и очищенного коксовым углем. Второй этап всегда получается существенно дольше первого. Я не являюсь экспертом-самогонщиком, и все эти процессы давным-давно описаны на специальных сайтах, но если вам будет интересно – могу кратко описать мой технологический процесс и самодельное оборудование – пишите в комментариях.

Всплески на графиках – это небольшое уменьшение мощности нагрева (горелки). Как видите даже небольшое изменение температуры приводит к существенным изменениям в выходных данных, что вполне соответствует теоретическим обоснованиям, изложенным выше. 

Но, тем не менее, получаемых “на выходе” прибора данных оказалось вполне достаточно (как минимум для моих целей). Работу он облегчает существенно, особенно если перегонку контролирует супруга, например. Прибор полезный, однозначно. Следует только периодически калибровать его повторно, с помощью точных спиртометров с учетом поправки на температуру. Как это делается – будет рассказано ниже.

Если вы почитаете форум,  то наверняка заметите спор автора того проекта с некоторым профи в области самогоноварения, который на нескольких страницах форума утверждал, что “точности не хватит, это все “…ня”, не работает”… Работает, проверено многократно!

 


Что вам потребуется для того, чтобы собрать такой спиртометр?

Перечислю список основных компонентов. Ссылки не привожу, так как они очень быстро устаревают. Впрочем, все детали не редкие и легко находятся.

1. Плата ESP32-DevKit (любой версии) или модуль микроконтроллера (если вы планируете создать печатную плату под поверхностный монтаж SMD). Главное – чтобы модуль, установленный на плате, был из классической серии ESP32-WROOM-32 – иначе номера выводов могут не совпадать, да и настройки проекта потребуется немного изменить. Я использовал модуль с внешней антенной, так как плат с печатной антенной у меня просто не осталось, но вы можете использовать любой вариант. Но если вы уверены в своих силах и знаниях – можно использовать почти любые модули ESP32 из того, что есть у вас в наличии. Подробнее об этом здесь.

Например такой

 

2. Цифровой датчик температуры Dallas (maxim) DS18B20. Конкретно для данного устройства я приобретал оригинальный датчик в одном российском магазине и качественной гильзой и кабелем в силиконовой защите. Однако и китайские “подделки” служат вполне надежно – предыдущая версия отработала несколько лет, пока не умер сам микроконтроллер. Минимальный шаг измерения такого датчика – 0.0625°C (12bit), погрешность в диапазоне от -30 до +110°C : до ±1.0°C.

 

3. Цифровой датчик давления Bosch, например BME280. Необходим для пересчета температуры кипения с учетом изменяющегося атмосферного давления. Не обязателен к применению, но желателен. Подробнее об необходимости его применения описано выше в разделе, посвященном точности измерений. Поскольку микроконтроллер у нас трех-вольтовый, то и модуль желателен так же на 3.3В. Впрочем – не обязательно, пяти-вольтовые модули тоже прекрасно работают. Само собой BME280 здесь явно избыточен (но у меня не осталось BMP) – если вы только собираетесь заказывать, имеет смысл заказать BMP, если он дешевле. Но придется немного подправить код проекта.

 

4. Дисплей LCD1602 с I2C-интерфейсом. Можно без русификации, используется программная русификация в коде. Я использую самый стандартный цвет – “желто-зеленый”, как показала практика он самый четкий и легкочитаемый. Впрочем, вы можете использовать любой – на функциональность это никак не влияет. Дисплей должен быть оснащен преобразователем интерфейса на I2C – для этого либо используйте стандартный китайский модуль на PCF8574, либо микросхему PCF8574 как в моем случае (плата будет ниже). Желательно использовать версию дисплея для 3,3В (она отличается дополнительным чипом и элементами на плате дисплея). Но у меня остались только версии на 5В, поэтому я применил схему согласования логических уровней на двух полевых транзисторах 2N7000 (можно использовать готовую плату-модуль на 2 или 4 линии, только будьте внимательны при заказе).

 

5. Блок питания на 5В. Любой “стандартный” блок питания на 5В и хотя-бы 0,5А в корпусе. У меня достаточно много блоков питания на 8В 2А, поэтому я дополнительно установил линейный стабилизатор L1117-5В на печатную плату (чертеж печатной платы будет ниже). Фото не привожу, их много и все разные.

 

6. Кнопки любого типа без фиксации. В моем случае они остались со старого проекта, хотя они мне и не очень нравятся. Но если сразу дегустировать продукт и проверять его крепость на вкус – то чем больше кнопки, тем лучше. Например такие:

7. Разъемы для подключения датчика и питания. Любые приемлемые для вас. У меня, опять же остались от прошлого проекта, например такие:

Можно еще поставить на плату разъемы XH2.54 для подключения проводов и кнопок (как у меня – см. фото ниже), но это строго опционально и при их наличии – можно просто впаять их в нужные точки платы.

 

8. Резисторы 10 кОм 6 шт. и 4,7 ~ 5.1 кОм 4 шт. Любой удобный светодиод и резистор 470 ~ 510 ом для него. Парочку конденсаторов 100 nF (0.1 uF) для дополнительной фильтрации помех (не обязательно). 

 

9. Любой активный или пассивный зуммер, рассчитанный на 3,3В. Можно выдрать из старого компьютера. Я вообще забыл про него, когда разводил палату, пришлось приколхозить прямо к выводам DevKit проводками. Но в архиве под статьей чертеж уже исправлен.

 

10. Плата (фольгированный текстолит или “монтажка”) и корпус. Корпус я покупал на ali, мне он в принципе, очень даже понравился – компактный и удобный, собирается на саморезах, есть стойки под плату. Но тут всё на ваш вкус и цвет. Первую версию я вообще “паутинкой” сделал. Сейчас – на печатной плате. 

А также понадобятся немного проводов, паяльник, и материалы для пайки. И ещё чуть-чуть крепежа, отвертка и самое главное – относительно прямые передние конечности. Как видите, автор сего опуса излишней точностью и аккуратностью не страдает.

 


Схема, печатная плата и сборка

В качестве сердца устройства использована плата ESP32-DevKitC-v4 со стандартным и самым распространенным модулем ESP32-WROOM-32 (классическая линейка, 4Мб flash).  Выводы платы ESP32-WROOM-32 использованы следующим образом:

Как видите, в схеме задействованы две шины I2C – это не обязательно, просто мне так было удобнее развести печатную плату. Если вы будете собирать проект, например, на макетке, вы можете задействовать только одну шину, да и GPIO изменить на совершенно другие. Как внести изменения в программу – будет рассказано ниже.

В самом простейшем случае, при использовании только готовых трех-вольтовых модулей схема соединений может выглядеть так:

Обратите внимание – резисторы подтяжки на шины I2C здесь не нужны, так как они уже есть и на датчике давления и на модуле I2C – интерфейса для дисплея. Да и на кнопки – тоже не строго обязательны, так как вполне можно воспользоваться встроенной в чип подтяжкой. Также на схеме никак не обозначены линии питания самой платы.

Также вы можете ориентироваться на мой чертеж печатной платы, или даже изменить его под свои потребности. Если вы решите самостоятельно сделать печатную плату, под такой же корпус, то чертеж платы для Sprint Layout 6 вы можете скачать вместе с архивом проекта в папке docs. Мой вариант выглядит так (несмотря на отличия, по функциональности он полностью повторяет схему выше):

Примечания к рисунку платы:

  • Печатная плата рассчитана под использование отдельной микросхемы PCF8574 вместо готового китайского модуля I2C для дисплея (потому что он попросту не помещался в корпус). Здесь же размещен подстроечный резистор регулировки контрастности и транзистор включения подсветки. Впрочем – уже после сборки я понял, что транзистор тут явно лишний – подсветку можно включить “навсегда” без транзистора. Резистор контрастности я расположил неудобно, под дисплеем, его лучше сместить правее (по рисунку).
  • Печатная плата разведена под 5-вольтовый дисплей LCD1602, поэтому на ней разведена схема согласования уровней. Если вы будете использовать дисплей на 3,3В, то необходимость в двух резисторах 2N7000 и двух резисторах отпадает, а на PCF8574 нужно подать 3,3В вместо пяти.
  • Резисторы подтяжки кнопок можно не устанавливать, а использовать встроенную в чип подтяжку, для наших целей вполне сойдет.
  • Я использую блок питания на 8 вольт, поэтому мне потребовался дополнительный стабилизатор, дабы понизить напряжение питания до 5В. Если у вас внешний БД уже с выходом на 5В, то стабилизатор нужно исключить.
  • Дисплей подключен к плате через разъем для удобства сборки-разборки. 

Ну а немного фотографий внутри корпуса спиртометра вы можете полистать тут:

  • Вид сверху

 


Настройка и компиляция проекта

Прошивка спиртометра создана для ESP32 и платформы ESP-IDF в Visual Studio Code + PlatformIO. Но прежде чем мы начнем настройку проекта, необходимо подготовить кое-какие инструменты и данные (ссылки ведут на соответствующие статьи данного сайта):

Если у вас всё это готово, продолжим….

 

Скачайте и распакуйте архив с проектом

Скачать архив с проектом можно по ссылке ниже. Файл архива уже включает в себя все необходимые библиотеки. Ничего дополнительно устанавливать не придется.

Значок
alco2_v20240217-008.zip - прошивка для алкогометра

Проект прошивки для алкогометра на ESP32 для платформы ESP-IDF и VSCode + PlatformIO

 

После того, как архивный файл был успешно скачан, необходимо распаковать его содержимое в каталог С:\PlatformIO. Конечно, для проектов PlatformIO можно использовать любую другую, удобную вам структуру каталогов, но этот проект (и другие мои проекты) настроены так:

  • С:\PlatformIO\libs – каталог с общими библиотеками
  • С:\PlatformIO\esp32-alcoholometer – каталог проекта

Таки да, Вы можете использовать другие папки, но тогда вам потребуется перенастроить проект самостоятельно!!!

 

Настройка проекта

Если все это готово, открываем папку проекта в Visual Studio Code, ищем каталог \include, а в нем файл project_config.h – именно в нем собраны основные “прикладные” настройки проекта. Подробнее об этом файле можно почитать тут.

1. Во первых проверяем GPIO, которые вы использовали в своем устройстве.

Кликните для увеличения

Если изменений с моей схемой не было, то оставляем все как есть.

2. Далее настраиваем подключение к WiFi-сети:

 

3. После этого прописываем в файле параметры выбранного вами MQTT-сервера:

На этом этапе стоит остановиться поподробнее. Здесь вам нужно указать следующие параметры:

  • CONFIG_MQTT1_HOST – здесь указываем имя или адрес сервера (без префиксов “ssl://” и ‘tcp://’)
  • CONFIG_MQTT1_PORT_TCP – здесь указываем порт сервера по протоколу TCP без использования шифрования (стандартное значение 1888)
  • CONFIG_MQTT1_PORT_TLS – здесь указываем порт сервера по протоколу TLS c использованиtv шифрования (стандартное значение 8888)
  • CONFIG_MQTT1_USERNAME – укажите логин подключения к брокеру
  • CONFIG_MQTT1_PASSWORD – укажите пароль подключения к брокеру
  • CONFIG_MQTT1_TLS_ENABLED – поставьте 1, если нужно использовать безопасное подключение или 0 – передавать всё в открытом виде. Параметры сертификата сервера пока не трогаем, для большинства облачных брокеров подходят настройки “по умолчанию”. Проверка TLS серnификатов в ESP-IDF довольно заумная тема, она требует отдельной большой статьи
  • CONFIG_MQTT1_PUB_LOCATION – локация для публичных топиков. Локация определяет, где установлено устройство, например “office” или “village”, в нашем случае предполагается, что прибор “носимый” поэтому я поставил “other”
  • CONFIG_MQTT1_LOC_LOCATION – локация локальных топиков. Локальные топики используются только для взаимного обмена данными между устройствами и не должны быть использованы внешним пользователем
  • CONFIG_MQTT1_PUB_DEVICE и CONFIG_MQTT1_LOC_DEVICE – название устройства для публичных и локальных топиков. В нашем случае “alco”. Если Вам нужна более сложная структура, чем “location/device/…”, вы можете прописать здесь что-то вроде “home/toilet” или “home/kitchen”
  • CONFIG_MQTT1_PUB_PREFIX и CONFIG_MQTT1_LOC_PREFIX – постоянный префикс всех топиков для данного брокера. Некоторые публичные брокеры требуют, чтобы топик начинался с определенной строки, например “/” или “user1233445/” – вот эти данные и следует здесь указать, если необходимо. Если такой необходимости нет – закомментируйте эти строки.

 

4. После этого настраиваем контроллер open-monitoring.online: 

Сам контроллер у меня создан с такими полями:

Более подробно об данном сервисе было написано здесь. Если он вам не требуется, его можно отключить с помощью макроса #define CONFIG_OPENMON_ENABLE 0

 

5. Настраиваем параметры бота telegram:

Можно использовать один и тот же идентификатор чата и для main, и для service. Но лучше два отдельных – надо ли вашим домашним, к примеру, читать всякую техническую чушь?

6. Ну и в заключение – после того, как проект будет вами отлажен, можно подавить логи с помощью макроса CONFIG_RLOG_PROJECT_LEVEL – установите уровень RLOG_LEVEL_ERROR или RLOG_LEVEL_NONE. Это сэкономит ресурсы контроллера и память.

 

7. Если вы решите подключить BME280 и дисплей к одной и той же шине I2C, то измените I2C_NUM_1 на I2C_NUM_0 в sensors.h:

 

На этом настройку проекта можно считать законченной, можно попробовать нажать build. Если все было настроено правильно, через какое-то время вы должны получить примерно следующее:

 

Если у вас все получилось как на скриншоте (ну или почти) – можете заливать прошивку в собранное устройство и проверять его работоспособность. С чем вас и поздравляю!

 


Топики MQTT

Ecли прибор правильно собран и успешно подключился к сети и MQTT-брокеру, то он через пару-тройку минут создаст на нем целую кучу топиков. В большинстве из них используется JSON-формат для “упаковки” данных. Посмотреть их можно, например, с помощью программы MQTT Explorer:

  • Основной топикother/alco/alcohol. В нем публикуются “сводные” данные о текущем состоянии процесса: {"stage":0,"alcohol":0,"temperature":{"measured":38.545, "compensated":40.137,"correction":0.226,"corrected":40.363},"display":"---%\n40.36°С"}.
  • Данные, непосредственно считанные с датчиковother/alco/ds18b20 и оther/alco/bme280. Из них можно получить данные без какой-либо обработки и пересчета в алкоголь.
  • Служебные (системные) топики:
    • other/alco/status – здесь отображается состояние вашего устройства. Это один из немногих топиков, публикуемых в открытом виде (без JSON).
    • other/alco/sysinfo – в этот топик периодически публикуется подробная системная информация, предназначенная по большей части для отладки устройства.
    • other/alco/tasklist – в этом топике вы найдете список задач FreeRTOS, запущенных на ESP с указанием размера свободного стека. Пригодится для возможного подбора размера стека для ваших задач.
    • other/alco/time – в этот топик в начале каждой минуты публикуется системное время и дата в различных форматах в виде JSON-пакета.
    • other/alco/system/ota – в этот топик вы должны отправить ссылку на прошивку (BIN-файл) для обновления “по воздуху” (ОТА). Подробнее об этом можно почитать тут.
    • other/alco/system/terminal – в этот топик можно отправлять служебные команды для выполнения каких-либо действий, например перезагрузки. Подробнее об этом можно почитать тут.
  • Топики параметров и настроек. Эта группа топиков разделена на две части: управляющие топики other/alco/config/... и подтверждающие топики other/alco/confirm/....  Это необходимо, дабы быть уверенным, что вашу устройство получило команду и выполнило её (так как само по себе протокол MQTT не гарантирует доставку сообщений в некоторых случаях). То есть на каждый из перечисленных ниже параметров существует своя пара топиков config/confirm. По большому счету, не обязательно использовать топики confirm в вашем mqtt клиенте, работать всё равно будет.
    • Интервалы отправки данных на различные сервисы (в секундах)
      • other/alco/confirm/sensors/intervals/mqtt – для MQTT-брокера
      • other/alco/confirm/sensors/intervals/openmon – для Open Monitoring-а
    • Оповещения
      • other/alco/config/alco/buzzer – звуковые уведомления с помощью зуммера (можно использовать 0 или 1)
      • other/alco/config/alco/notify – уведомления в telegram (можно использовать 0 – отключено, 1 – тихо, 2 – со звуком)
    • Коррекция температуры
      • other/alco/config/alco/corrections/wboiling – смещение значения температуры для точки кипения воды
      • other/alco/config/alco/corrections/range_0-78 ( ... 99-110)  – смещение значения температуры в конкретном температурном диапазоне (min <= t < max)
      • other/alco/config/alco/corrections/smooth – использовать “плавный” расчет смещения температуры “по двум точкам” (можно использовать 0 или 1)
    • Контроль быстрого изменения температуры
      • other/alco/config/alco/rchanges/enabled – разрешить работу функции контроля быстрого изменения температуры (можно использовать 0 или 1)
      • other/alco/config/alco/rchanges/threshold – пороговое значение изменения температуры за 1 секунду, свыше которого выдается уведомление
    • Границы температуры для выдачи уведомлений о необходимости смены режима
      • other/alco/config/alco/stages/heads – при этом значении температуры пора начинать отбор голов
      • other/alco/config/alco/stages/body – при этом значении температуры пора начинать отбор основного продукта (тело)
      • other/alco/config/alco/stages/tails – при этом значении температуры пора начинать отбор хвостов
      • other/alco/config/alco/stages/stop – при этом значении температуры завязываем с перегонкой и отключаем нагрев
      • other/alco/config/alco/stages/interval – интервал повторения предупреждений о необходимости смены режима отбора в секундах.
    • Контроль температуры по времени с начала отбора – экспериментальный режим контроля температуры по времени, начиная с отбора голов. Служит для предотвращения слишком быстрой перегонки при высокой температуре, но в деле я его ещё не испытал (мало статистических данных).
      • other/alco/config/alco/temp-on-time/enabled – разрешить работу данной функции ( 0 или 1 )
      • other/alco/config/alco/temp-on-time/interval – интервал повторения предупреждений о повышенной температуре в секундах
      • other/alco/config/alco/temp-on-time/time_30 (... 300) – максимальные пороговые значения температуры через каждые полчаса
    • Параметры сенсоров
      • other/alco/config/sensors/ds18b20/temperature/filter_mode – режим фильтрации данных (0 – без фильтра, 1 – скользящее среднее, 2 – медианный (убирает резкие отклонения, но вносит некоторое запаздывание при изменении)
      • other/alco/config/sensors/ds18b20/temperature/filter_size – размер буфера фильтра, см выше. У меня сейчас настроено 64, то есть данные плавно изменяются примерно за минуту
      • other/alco/config/sensors/ds18b20/temperature/offset – смещение измеряемых данных, по большому счету это то же самое что и other/alco/config/alco/corrections/wboiling, но на это смещение будет применяться поправка на давление
    • Такие же параметры есть и для BME280, для каждого измеряемого значения отдельно
      • other/alco/confirm/sensors/bme280/humidity/... – для влажности
      • other/alco/confirm/sensors/bme280/temperature/... – для температуры
      • other/alco/confirm/sensors/bme280/pressure/... – для давления

В принципе, там есть и ещё топики, но в данном приборе они нам мало интересны. Более подробно обо всей этой замудреной структуре вы можете почитать здесь.

 


Создание панели управления на Android-клиенте MQTT Dash

Как я уже писал выше, для создания виртуальных панелей управления устройствами с зачатками разума я использую простое приложение для Android – MQTT Dash. Про него я уже писал на данном сайте: статья раз и статья два. В случае с данным устройством я не стал отступать от традиционных ценностей и настроил себе вот такую удобную панель управления самогонщика:

Здесь можно увидеть:

  • текущее значение крепости спирта на выходе из аппарата и температуру со всеми коррекциями
  • текущий этап перегонки
  • различные дополнительные данные

а также быстренько подправить настройки (всё, что мелким шрифтом):

  • Головы, Продукт, Хвосты, Стоп – это настраиваемые границы этапов перегонки по температуре (с учетом калибровок, разумеется)
  • Контроль – это пороговое изменение температуры за 1 секунду, свыше которого выдается предупреждение о слишком быстром росте температуре.
  • Корр. 100°C – параметр корректировки температуры по точке кипения чистой воды
  • Корр. XX-YY° – значение калибровки температуры в указанном температурном диапазоне
  • Фильтр (тип) – тип фильтра датчика температуры DS18B20: 0 – фильтра нет, 1 – скользящее среднее, 2 – медианный фильтр
  • Фильтр (буфер) – размер буфера фильтра (для типа > 0) в четырехбайтных float-значениях
  • Обновление – ссылки на OTA-обновление прошивки (пропишите свои)

Вы можете довольно просто создать себе такую же или весьма похожую, на основе списка MQTT – топиков, который я привел выше. В данной статье я не буду повторять описание, как это сделать – вместо этого еще раз приведу ссылки: статья раз и статья два.

 

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

  1. Найдите файл mqtt-dash.json в папке docs проекта.
  2. Исправьте в нем ссылки на файл(ы) обновления прошивки (можно пропустить этот шагэто можно сделать и потом прямо на смартфоне)
  3. Скачайте и установите программу MQTT Explorer на вашем ПК. Настройте подключение к вашему MQTT серверу и подключитесь к нему.
  4. Настройте подключение к MQTT серверу на смартфоне и подключитесь к нему.
  5. Нажмите в верхнем правом углу панели MQTT Dash кнопочку со стрелочками, а затем “Подписаться и ждать метрики”
  6. Опубликуйте содержимое файла из 1-го шага в топик metrics/exchange
  7. Наслаждайтесь результатом

Включите устройство и проверьте работу всех систем. Можно переходить к калибровке.

 


Настройка и калибровка

Спиртометр предусматривает два этапа калибровки: по точке кипения воды и по нескольким температурным диапазонам. По большому счету, калибровку “по воде” можно и не выполнять, так как её значение складывается с данными калибровки “по диапазонам”. Но, тем не менее, возможность есть, и её можно использовать, дабы определить, на сколько врет датчик DS18B20 в условиях высоких температур.

Калибровка по точке кипения воды

Процесс калибровки по точке кипения воды очень прост. Заливаем в металлическую кастрюльку чистую воду, и включаем нагрев. После того, как вода закипит, булькаем туда датчик так, чтобы он по возможности не касался стенок. Затем переводим прибор в режим “КОРР 100°C” и кнопками [ + ] и [ – ] подгоняем смещение так, чтобы в результате получилось 100°C с минимальным отклонением. После чего нажмите кнопку “Режим” (зеленая), чтобы сохранить значение на flash-память. А можно сделать ещё проще: нажмите и удерживайте кнопку “Режим” (зеленая) примерно 3 секунды, после чего отпустите – в момент отпускания программа сама рассчитает нужный параметр и сохранит его в памяти.

 

Калибровка по нескольким температурным диапазонам

Заранее необходимо запастись “образцовыми” средствами измерения концентрации спирта.  При высоких концентрациях пирта (свыше 50% об. спирта) удобнее пользоваться стеклянными спиртометрами АСП-3 с термометром, а когда концентрация падает – температура изменяется слишком быстро, тогда на помощь приходит китайский оптический рефрактомер ATC – точность на высоких значениях у него, увы, “никакая”. Переключаем прибор в режим корректировки температуры, и как только он начинает выдавать концентрацию спирта – измеряем её и с помощью кнопок добиваемся примерно таких же показаний на дисплее. Повторяем эту процедуру в течение всего процесса перегонки, причем нужно стараться сделать замеры в середине “подгоняемого” диапазона, он отображается на экране.

Однако это не всегда получается с первого раза (особенно с АСП-3, ведь нужно набрать достаточное количество продукта для замера), поэтому рекомендую повторить калибровку 2-3 раза.

После этого спиртометры для перегонки вам, в общем-то, и не понадобятся (но понадобятся для разбавления спирта, например). Не плохо будет периодически повторять процесс калибровки – но это строго по желанию.

Процесс перегонки с этим прибором существенно упрощается – не нужно помнить примерные значения температур для этапов, не нужно возиться со спиртометрами и т.д. Например с ним я смело поручаю проводить процесс перегонки супруге, например, без необходимости обучения “тонкостям профессии”.

 


Разбор некоторых участков кода (если вам интересно)

Все “спиртовые” функции находятся в файле sensors.cpp в папке \lib\sensors проекта. Константы и некоторые глобальные переменные – в файле sensors.h. И таки да – я иногда использую глобальные переменные, но только строго в контексте одной задачи. Таки правильнее было бы объявить их в самом начале sensors.cpp, но чисто при разработке удобнее переключаться между файлами, а “крутить” файл вверх-вниз, поэтому из за своей лени я часто выношу их в хедер.

Функция пересчета “температура -> спирт” в моей редакции выглядит так:

double temp2strengths(double temp)
{
  if (!isnan(temp) && ((temp * 10) >= t2s_temps[0])) {
    uint16_t temp_val = temp * 10;
    // Поиск по таблице соответствия до предпоследнего элемента, иначе расчет "сломается"
    for (uint8_t i = 0; i < t2s_size - 1; i++) {
      if (temp_val < t2s_temps[i+1]) {
        double S1 = t2s_strengths[i];
        double S2 = t2s_strengths[i + 1];
        double T1 = t2s_temps[i];
        double T2 = t2s_temps[i + 1];
        double Sout = (S1 + (S2 - S1) * (temp_val - T1) / (T2 - T1)) / 100.0;
        rlog_d(logTAG, "Convert temperature -> strength: temp=%f, index=%d, strength=%f", temp, i, Sout);
        return Sout;
      };
    };
    // Это последний элемент таблицы соответствия
    double Sout = t2s_strengths[t2s_size - 1] / 100.0;
    rlog_d(logTAG, "Convert temperature -> strength: temp=%f, index=%d (last), strength=%f", temp, t2s_size - 1, Sout);
    return Sout;
  };
  return NAN;
}
static void sensorsCalcAlcohol()
{
  // Вычисляем спирт в парах
  temp_correction = getTempCorrection(temp_pressure_compensated, temp_correction_smooth_transition);
  alcohol_content = temp2strengths(temp_pressure_compensated + temp_correction);
  
  rlog_d(logTAG, "Calculated data: temp_measured = %f, water_boiling_offset = %f, temp_compensated = %f, temp_correction=%f, alcohol_content=%f",
    temp_measured, water_boiling_offset, temp_pressure_compensated, temp_correction, alcohol_content);

  // Контроль максимальной температуры этапа
  sensorsCheckTempRanges();

  // Контроль максимальной температуры по времени с начала отбора голов
  if ((check_temp_on_time > 0) && (stage > STAGE_HEATING)) {
    sensorsCheckTempOnTime();
  };
}

Основной механизм пересчета реализован в функции sensorsReadSensors():

static void sensorsReadSensors()
{
  sensorColumn.readData();
  if (sensorColumn.getStatus() == SENSOR_STATUS_OK) {
    rlog_i(SENSOR_COLUMN_NAME, "Values raw: %.3f °С | out: %.3f °С | min: %.3f °С | max: %.3f °С", 
      sensorColumn.getValue(false).rawValue, 
      sensorColumn.getValue(false).filteredValue,
      sensorColumn.getExtremumsDaily(false).minValue.filteredValue,
      sensorColumn.getExtremumsDaily(false).maxValue.filteredValue);
    // Запоминаем измеренные значения
    rapid_changes_curr = sensorColumn.getValue(false).rawValue;
    temp_measured = sensorColumn.getValue(false).filteredValue;
  };

  sensorPressure.readData();
  if (sensorPressure.getStatus() == SENSOR_STATUS_OK) {
    rlog_i(SENSOR_PRESSURE_NAME, "Values raw: %.2f °С / %.2f %% / %.0f Pa | out: %.2f °С / %.2f %% / %.2f mmHg | min: %.2f °С / %.2f %% / %.2f mmHg | max: %.2f °С / %.2f %% / %.2f mmHg", 
      sensorPressure.getValue2(false).rawValue, sensorPressure.getValue3(false).rawValue, sensorPressure.getValue1(false).rawValue, 
      sensorPressure.getValue2(false).filteredValue, sensorPressure.getValue3(false).filteredValue, sensorPressure.getValue1(false).filteredValue, 
      sensorPressure.getExtremumsDaily2(false).minValue.filteredValue, sensorPressure.getExtremumsDaily3(false).minValue.filteredValue, sensorPressure.getExtremumsDaily1(false).minValue.filteredValue, 
      sensorPressure.getExtremumsDaily2(false).maxValue.filteredValue, sensorPressure.getExtremumsDaily3(false).maxValue.filteredValue, sensorPressure.getExtremumsDaily1(false).maxValue.filteredValue);
    // Пересчитываем температуру по датчику давления и добавляем смещение температуры кипения при 760 мм.рт.ст.
    if (!isnan(temp_measured)) {
      temp_pressure_compensated = temp_measured + (759.94 - sensorPressure.getValue1(false).filteredValue) * 0.0385 + water_boiling_offset;
    };
  } else {
    // Кое-какая работа в случае выхода BME280 из строя
    temp_pressure_compensated = temp_measured;
  };

  // Контроль быстрого изменения температуры
  if (!isnan(rapid_changes_curr)) {
    if (rapid_changes_enabled && !isnan(rapid_changes_prev) && ((rapid_changes_curr - rapid_changes_prev) >= rapid_changes_threshold)) {
      sensorsMessageRapidChanges(rapid_changes_prev, rapid_changes_curr);
      notifyBuzzerRapidChanges();
    };
    rapid_changes_prev = rapid_changes_curr;
  };
}

Поскольку все общение с прикладной “периферией” (датчик, дисплей) осуществляется из одной задачи, то никаких средств синхронизации (семафор или мьютекс) например для их защиты не требуется. Однако обработка нажатий на кнопки осуществляется в контексте прерывания. Дабы передать сигнал из обработчика прерывания в основную задачу в данном случае я применил группу флагов EventGroup (про них я писал здесь).

Возможно, я тут немного “перемудрил” с флагами – можно было сделать проще, но тут я просто перенес часть флагов из одного из предыдущих проектов, да так и оставил. Через группу событий передаются так же и “служебные” сигналы – минутные отметки времени, необходимость сохранить данные сенсоров на flash, изменение параметров.

Дабы отмерять интервал времени между измерениями применим обычное ожидание установки флагов:

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

Все это (и не только), вы сможете скачать по ссылкам ниже абсолютно бесплатно. 

 


Скачать архив с проектом можно по ссылке ниже. Файл архива уже включает в себя все необходимые библиотеки. Ничего дополнительно устанавливать не придется.

Значок
alco2_v20240217-008.zip - прошивка для алкогометра

Проект прошивки для алкогометра на ESP32 для платформы ESP-IDF и VSCode + PlatformIO

 

На этом разрешите откланяться, до встречи на сайте и на telegram-канале! 

💠 Полный архив статей вы найдете здесь


Пожалуйста, оцените статью:
[ 5 из 5, всего 6 оценок ]

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *