Контроль влажности подвала ver.2.0 (stm32 + сеть)

pav2000
Offline
Зарегистрирован: 15.12.2014

Осушитель подвала ver.2.0 stm32, доступ через сеть

Потребовалось мне еще один осушитель, для предполья бани. Решил сделать версию с удаленным управлением.

Вся информация размещена на гитхабе https://github.com/pav2000/Dehumidifier-2.0

Короткий ролик поясняющий работу и конструкцию. https://youtu.be/ywdXSmak6OI

Данный проект - дальнейшее развитие проекта:  http://arduino.ru/forum/proekty/kontrol-vlazhnosti-podvala-arduino-pro-mini

Принцип работы остался прежним - Идея контроля влажности подвала была подсмотрена на http://geektimes.ru (http://geektimes.ru/post/255298/) Вся идея состоит в том чтобы измерить температуру и относительную влажность в подвале и на улице, на основании температуры и относительной влажности рассчитать абсолютную влажность и принять решение о включении вытяжного вентилятора в подвале. Теория для расчета изложена здесь - https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/

Аппаратная часть полностью переделана. Теперь используется STM32 и сетевой чип wiznet w5500. На самом чипе поднят простейший веб сервер, через который проводится настройка устройства и его контроль. Разрабатывая этот блок я планировал сделать универсальный модуль для домашней автоматизации, и заложил избыточность в схеме для реализации будущих устройств. Сам блок реализован на плате maple mini (STM32F103CBT6). 

Для упрощения программирования используется free RTOS 8 немного заточенная под себя

Схема платы:

На схеме (и плате) разведены следующие узлы:

  • кварц для часов реального времени stm32
  • батарейка для часов
  • два порта i2c для подключения внешних устройств
  • флеш память spi (можно установить до 32 мбит)
  • разъем sd карты (режим spi)
  • дисплей 2.8 дюйма на контроллере ili9341 подключение spi
  • модуль питания 220->5в
  • два ssr реле со схемами гашения помех и варисторами
  • датчик переменного тока (0-50A) для измерения токов нагрузки 220
  • разъем для подключения отладчика
  • разъем для подключения nrf24f01 - для работы с беспроводными датчиками
  • два светодида на отдельных gpio
  • мост i2c oneWire со схемой защиты для подключения OneWire датчиков
  • пищалка
  • разъем расширения (uart+gpio)

Под этот проект была разработана и изготовлена печатная плата. Плата предназначена для установки в корпус G212C (https://www.chipdip.ru/product/g212c)

Сборка.

Косяки разводки:

  • шелкография - на разъеме отладчика SWD перепутаны надписи DIO CLK
  • шелкография - на разъеме 220 и реле перепутаны надписи ssr1 ssr2
  • разводка - надо бросить сигнальный провод (почему то не развелся) от датчика тока до maple mini
  • дополнительно было распаяно (частично учтено на схеме) RC фильтр на датчик тока, конденсатор на ножку питания, резистор 6.8к между землей и DO usb (без него и без подключения к usb МК переходил в режим загрузчика)

Работа.

Первоначально планировалось использовать датчики температуры и влажности AHT10 на шине i2c. Два датчика отказывались работfь на одной шине (хотя были разнесены по разным адресам), т.е. работают корректно 20-30 минут а потом отваливаются от шины и шину клинит, было лень разбираться. Один датчик работает хорошо. При переходе на программный i2c (ногодрыг) оба датчика нормально заработали.
НО при увеличении длины провода более 1.5 метра на программном i2c датчики отказались работать (в принципе это ожидаемо). По этому принято решение использовать проверенные временем DHT22 (шина типа 1-wire). Разъем i2c имеет 4 контакта (питание SDA SCL) и был перепрограммирован для подключения двух датчиков DHT22. Длина проводов: внутренний датчик 3 метра, внешний 8 метров, все работает с разумным количеством ошибок.
Датчик тока ACS758 (диапазон 50A - применен для универсальности) позволяет измерять ток потребления устройством (есть задумка в его использовании в других устройствах). При этом при работающем вентиляторе вытяжки можно измерить общий ток и сделать вывод об работоспособности вентилятора. Обычно вентиляторе есть термо предохранитель, который срабатывает при их отказе. Так можно следить за работой вентилятора через инет. Единственная проблема, что устройство потребляет достаточно мало и много шумов, но эту проблему удалось побороть усреднением и дополнительной обработкой данных.

Web морда устройства:
Графики используют google chart api, по этому без инета они работать не будут.

Установка на объекте.

Исходники почти 150к по просьбе модератора напрягся и вставил сюда -)):

Podval20.ino

control.ino

Podval20.h

webserver.ino

tft.ino

util.ino

webserver.h

DHT.h

DHT.ino

Конструктивная критика приветствуется, особенно по коду.

 

 

-NMi-
Offline
Зарегистрирован: 20.08.2018

Классно, конечно, но интернет зачем? Имхо без нета кошернее.

pav2000
Offline
Зарегистрирован: 15.12.2014

-NMi- пишет:
Классно, конечно, но интернет зачем? Имхо без нета кошернее.

Мне проще сделать управление и настройку прибора через веб морду, чем на экране менюшки городить. И кнопок не надо-)))

Скорость разработки выше, плюс бонусом удалённый мониторинг.

DetSimen пишет:

Это не код, это лютый писец какой-то. 

А чем код то не нравиться? 

 

b707
Offline
Зарегистрирован: 26.05.2017

DetSimen пишет:

за printf(...), dtostrf() и другие стандартные функции слышал чонить? 

да что printf ...

Pv2000 - вы в курсе, что для вывода на печать шестнадцатиричных чисел достаточно написать

 Serial.print(value, HEX) ?

К чему у вас там эти зубодробительные функции типа uint32_to_HEX ? :)

pav2000
Offline
Зарегистрирован: 15.12.2014

Маленькое задание для шибко умных

Сделайте маленькую программу со стандартными функциями и потом с моими.

Выпишите на листок размер кода и максимальный размер стека для обоих вариантов. 

Медитируете на эти числа и наступит Вам просветление, зачем это сделано. 

По поводу вывода hEX  посмотрите что выводит ваш вариант и что мой, если разницы нет то конечно все равно, но разница есть.

 

Ихмо Вот как раз использование стандартной printf в микроконтроллерах это боль.

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

какая то доля истины в ваших словах конечно есть, но писать три функции uintXXToHex вместо одной мне кажется перебор

 

b707
Offline
Зарегистрирован: 26.05.2017

pav2000 пишет:

По поводу вывода hEX  посмотрите что выводит ваш вариант и что мой, если разницы нет то конечно все равно, но разница есть.

а поподробнее?  что там стандартный принт не выводит? "0x" в начале числа не ставит? :)

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

нолик в начале не выводит если количество символов не четное и нолик перед x тоже не выводит

ЗЫ. И то не факт, может я ей просто пользоваться не умею

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:

нолик в начале не выводит если количество символов не четное и нолик перед x тоже не выводит

беда :)

и ради этого надо писать отдельное преобразование для каждого hex разряда? (8 одинаковых строк для uint32 ?) Циклы уже не модны?

b707
Offline
Зарегистрирован: 26.05.2017

pav2000 пишет:

Конструктивная критика приветствуется, особенно по коду.

просили - получите

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

b707 пишет:

и ради этого надо писать отдельное преобразование для каждого hex разряда? (8 одинаковых строк для uint32 ?) Циклы уже не модны?

ну может человеку каждый такт и байт МК на вес золота, не хочет цикл делать :)

b707
Offline
Зарегистрирован: 26.05.2017

andycat пишет:

ну может человеку каждый такт и байт МК на вес золота, не хочет цикл делать :)

а не проще было написать что-нить типа

1void hex_to_print(uint32_t val) {
2 Serial.print("0x");
3 Serial.print(val, HEX);
4}

 

Upper
Offline
Зарегистрирован: 23.06.2020

b707 пишет:

andycat пишет:

ну может человеку каждый такт и байт МК на вес золота, не хочет цикл делать :)

а не проще было написать что-нить типа

1void hex_to_print(uint32_t val) {
2 Serial.print("0x");
3 Serial.print(val, HEX);
4}

Так вам уже писали - попробуйте и сравните результат.

b707
Offline
Зарегистрирован: 26.05.2017

Upper пишет:

Так вам уже писали - попробуйте и сравните результат.

что я должен там увидеть?

У меня сейчас нет под рукой ардуины. но предположу, что всей разницы то

print("0x"); print(255, HEX);

выдаст на выходе 0xFF. а функция ТС - 0x00FF в случае uint16

Вы правда считаете, что ради этого надо было городить три отдельных функции с повторяющимися строчками?

Что мешало написать нормальный вывод с нужным число нулей, независмый, кстати, от типа входящей переменной?

 

pav2000
Offline
Зарегистрирован: 15.12.2014

b707 пишет:

Upper пишет:

Неужели вы на полном серьезе считаете реплики DetSemen конструктивной критикой?

ну может быть резковато, но вообще все по теме. Человек просил покритиковать код - критикуем.

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

DetSemen - это вообще не критика а просто балаган. По поводу hex критику принимаю, перепишу функцию.

по hex -мне нужно три варианта работы 1,2,4 (3,5 байт не интересно) байта с результатом в буфере.

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

Вариант b707 не подходит мне нужно в буфер

По поводу printf добавлю (в стиле DetSemen без пояснений) посмотрите механизм  распределение памяти задач для free RTOS, и тогда поймете вредность функций с большим стеком.

 

 

 

 

-NMi-
Offline
Зарегистрирован: 20.08.2018

А в этой rtos всё по честному со всякими там потоками, семафорами и тд?

b707
Offline
Зарегистрирован: 26.05.2017

pav2000 пишет:

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

посмотрите механизм  распределение памяти задач для free RTOS, и тогда поймете вредность функций с большим стеком.

pav2000, Вы не обижайтесь - подскажите, какой у вас опыт в программировании на Си вообще и микроконтроллеров в частности? По коду я бы сделал предположение, что вы любитель, освоивший Си не так давно.
 Вы такими словами оперируете, как скорость процедур, и размер кода и размер стека... и все это в условиях RTOS. Вы эти парметры чем-то измеряли или просто на глазок прикинули, какая больше а какая меньше? Скорость исполнения как замерена? Загрузку стека чем смотрите?
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

DetSimen пишет:

особенно понравился util.ino.  До слёз пробирает. 

ПыСы: Ты за printf(...), dtostrf() и другие стандартные функции слышал чонить? 

Вот смех смехом, а я недавно попытался в одном из своих проектов воспользоваться printf(). Прошивка сразу увеличилась на 14к и вылезла за пределы 64к. В общем, от printf() я отказался и заменил его самописной функцией на 300 байт, которая делает ровно то, что мне нужно, и ничего сверх этого.

Так что использование в МК написанных для ПК "стандартных функций" не всегда целесообразно, а иногда и совершенно невозможно.

pav2000
Offline
Зарегистрирован: 15.12.2014

b707 пишет:

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

 Вы такими словами оперируете, как скорость процедур, и размер кода и размер стека... и все это в условиях RTOS. Вы эти параметры чем-то измеряли или просто на глазок прикинули, какая больше а какая меньше? Скорость исполнения как замерена? Загрузку стека чем смотрите?

На критику не обижаюсь она весьма полезна но она должна быть обоснованной и корректной.

Опыт написания на Си более 10 лет, микроконтроллеры 4-5 лет, но не в очень интенсивном режиме. Да мой стиль далек от идеала. И я допустил ошибку портируя старый проект в новый, надо было с нуля писать (хотелось  просто побыстрее написать код).

Размер кода можно оценить по изменению бинарника, (с нужным кодом и без) именно так и был выявлен объем кода printf. 

Размер стека можно оценить отладочными средствами ОС.    Вот пример (фрагмент вебморды с четырех поточным web сервером) правда из другого проекта но он отражает возможности отладки freeRTOS

Быстродейстие - на глазок.

-NMi-

"А в этой rtos всё по честному со всякими там потоками, семафорами и тд?"

Да это присутствует, есть еще и очереди. Более того скажу что без семафоров и мютексов не обойтись при делении аппаратных ресурсов (в этом проекте spi делится между двумя задачами).

andriano

"Вот смех смехом, а я недавно попытался в одном из своих проектов воспользоваться printf(). Прошивка сразу увеличилась на 14к и вылезла за пределы 64к. В общем, от printf() я отказался и заменил его самописной функцией на 300 байт, которая делает ровно то, что мне нужно, и ничего сверх этого."

Вот и я про это, у меня тоже есть самописный принтф который реализует только то что мне нужно и имеет размер 1-1.5кб и стек бережно расходует.

Для понимания еще добавлю о распределении памяти в rtos.

1. Каждая задача имеет свой стек. Размер которого задается при создании задачи:

1xTaskCreate(vReadSensor, "ReadSensor",150,NULL,4,&hReadSensor);

150 это размер стека в 4 байтных словах. Размер стека определяется опытным путем, и надо понимать что это сложная задача т.к. алгоритм может быть сложным и по некоторым веткам при отладке можно не пройтись. По этому нужен запас.

2. Если стек по факту получается больше отведенного то все падает или есть не адекватное поведение.

3. В RTOS есть механизм контроля стека (включается отдельно) и при отладке можно получить минимальный размер (зарезервировано-максимальный стек по факту) стека (включается отдельно) см. картинку выше.

4. Из все выше сказанного получается следующее: Допустим есть три задачи с требуемыми объемами стеков 100 слов (4 байта). Есть функция printf которая требует 250-300 слов на стек. Мы эту функцию используем для вывода отладочных сообщений и используем во всех трех задачах.  Как итог получается что требуемый объем стеков для всех трех задач 100+250 слов как минимум.

Уж если мы полезли в такие дебри скажу что реализация spi в ардуиновской версии не совсем адекватная.

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

DetSimen

"Ладно, pav-лик, я больше не буду лезть с бессмысленными комментариями кода, извини."

принимается.

 

 

Marx81
Offline
Зарегистрирован: 02.12.2019

Подскажите пожалуйста как можно приобрести плату для сборки вашего устройства?

pav2000
Offline
Зарегистрирован: 15.12.2014

Пишите на почту nscalp@mail.ru, договоримся

-Nord_Air-
Offline
Зарегистрирован: 21.08.2021

pav2000 пишет:
Принцип работы остался прежним - Идея контроля влажности подвала

Аппаратная часть полностью переделана. Теперь используется STM32 и сетевой чип wiznet w5500.

Звучит как, Arduino UNO меня не устроил, решил все запилить на Intel Core 2 Duo. Нужно а с b сравнить? и принять решение о включении RELE 1 :)

 

pav2000 пишет:
Конструктивная критика приветствуется, особенно по коду.

 Для начала были бы не плохо описать,  а что именно вы собираетесь делать?

 Обсуждать равно ли 2+2 четыре, неинтересно и некоструктивно.  Что касается кода.  Если скетч комилируется, значит код верный что тут обсуждать.?

 

То есть подвал сухой силами одного вентелятора и датчика DHT? ;) И это тоже возможно, я просто уточняю:)