#include <Wire.h>
#include "DFRobot_SHT20.h"
DFRobot_SHT20 sht20; // https://github.com/DFRobot/DFRobot_SHT20
#define MY_DEBUG
//#define MY_DISABLED_SERIAL
#define MY_RADIO_RF24
#define MY_PASSIVE_NODE
#define MY_NODE_ID 200
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
//#define MY_OTA_FIRMWARE_FEATURE
//#define MY_SIGNING_ATSHA204
//#define MY_SIGNING_ATSHA204_PIN A3
//#define MY_SIGNING_REQUEST_SIGNATURES
#define TEMP_SENS_ID 1
#define HUM_SENS_ID 2
#define SETTING_LED_SENS_ID 100
#define DELAY_TIME_SENS_ID 101
#define BATTARY_SEND_SENS_ID 102
#define BATTARY_DATA_SENS_ID 103
#define BAT_COOF 3.04
#define BAT_MIN 195
#define BAT_MAX 295
#define ON 1
#define OFF 0
float humd;
float temp;
float oldhumd;
float oldtemp;
float tempThreshold = 0.5;
float humThreshold = 10.0;
static uint32_t lightMillis;
static uint32_t previousMillis;
uint32_t send_batteryTime;
uint32_t w_battetyTime = 0;
static uint8_t led_pin = 4;
static uint8_t mode_pin = 2; // interrupt
uint32_t delayTime;
int8_t battery;
int8_t old_battery;
uint8_t set_led;
boolean sleep_mode;
boolean configMode = 0;
int8_t timer_status = 0;
bool flag_mode_button = 0;
bool sleep_flag = 0;
bool listen_flag = 0;
#include <MySensors.h>
MyMessage msg_temp(TEMP_SENS_ID, V_TEMP);
MyMessage msg_hum(HUM_SENS_ID, V_HUM);
MyMessage msg_setting_led(SETTING_LED_SENS_ID, V_VAR1);
MyMessage msg_delay_time(DELAY_TIME_SENS_ID, V_VAR1);
MyMessage msg_battary_send(BATTARY_SEND_SENS_ID, V_VAR1);
MyMessage powerMsg(BATTARY_DATA_SENS_ID, V_VAR1);
void preHwInit()
{
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, OFF);
pinMode(mode_pin, INPUT_PULLUP);
}
void before()
{
set_led = loadState(100);
if (set_led > 1) {
set_led = 1;
saveState(100, set_led);
}
delayTime = loadState(101);
if (delayTime > 60) {
delayTime = 3;
saveState(101, delayTime);
}
send_batteryTime = loadState(102);
if (send_batteryTime > 48) {
send_batteryTime = 6;
saveState(102, send_batteryTime);
}
digitalWrite(led_pin, ON);
}
void presentation()
{
sendSketchInfo("Temp & Hum Sensor CR2477", "1.0");
wait(100);
present(TEMP_SENS_ID, S_TEMP, "TEMPERATURE DATA");
wait(100);
present(HUM_SENS_ID, S_HUM, "HUMIDITY DATA");
wait(100);
present(SETTING_LED_SENS_ID, S_CUSTOM, "LED MODE");
wait(100);
present(DELAY_TIME_SENS_ID, S_CUSTOM, "DELAY TIME/MIN");
wait(100);
present(BATTARY_SEND_SENS_ID, S_CUSTOM, "BATTERY SEND TIME/H");
wait(100);
present(BATTARY_DATA_SENS_ID, S_CUSTOM, "BATTERY DATA");
}
void setup()
{
//attachInterrupt(0, configListener, RISING);
digitalWrite(led_pin, OFF);
wait(500);
digitalWrite(led_pin, ON);
wait(75);
digitalWrite(led_pin, OFF);
wait(50);
digitalWrite(led_pin, ON);
wait(75);
digitalWrite(led_pin, OFF);
wait(50);
digitalWrite(led_pin, ON);
wait(75);
digitalWrite(led_pin, OFF);
TRANSPORT_DEBUG(PSTR("MyS: OPERATING MODE\n"));
wait(100);
readBatLev();
wait(100);
sht20.initSHT20();
wait(100);
send_data();
wait(100);
send(msg_delay_time.set(delayTime));
wait(100);
send(msg_setting_led.set(set_led));
wait(100);
send(msg_battary_send.set(send_batteryTime));
}
void loop()
{
if (configMode == 0) {
if (sleep_flag == 0) {
timer_status = sleep(digitalPinToInterrupt(mode_pin), FALLING, delayTime * 60 * 1000, false);
//timer_status = sleep(digitalPinToInterrupt(mode_pin), RISING, delayTime * 60 * 1000, false);
sleep_flag = 1;
}
if (timer_status == -1) {
w_battetyTime = w_battetyTime + (delayTime * 60 * 1000);
if (w_battetyTime >= send_batteryTime * 60 * 60 * 1000) {
readBatLev();
w_battetyTime = 0;
}
send_data();
sleep_flag = 0;
}
if (timer_status == 0) {
if (digitalRead(2) == LOW && flag_mode_button == 0) //если кнопка нажата
{
flag_mode_button = 1;
previousMillis = millis();
wait(50);
}
if (digitalRead(2) == LOW && flag_mode_button == 1) {
if ((millis() - previousMillis > 0) && (millis() - previousMillis <= 2000)) {
if (millis() - lightMillis > 50) {
lightMillis = millis();
digitalWrite(led_pin, !digitalRead(led_pin));
}
}
if ((millis() - previousMillis > 2000) && (millis() - previousMillis <= 2500)) {
digitalWrite(led_pin, OFF);
}
if ((millis() - previousMillis > 2500) && (millis() - previousMillis <= 4500)) {
if (millis() - lightMillis > 25) {
lightMillis = millis();
digitalWrite(led_pin, !digitalRead(led_pin));
}
}
if (millis() - previousMillis > 4500) {
digitalWrite(led_pin, OFF);
}
}
if (digitalRead(2) == HIGH && flag_mode_button == 1) //если кнопка НЕ нажата
{
if ((millis() - previousMillis > 0) && (millis() - previousMillis <= 2000)) {
configMode = !configMode;
flag_mode_button = 0;
TRANSPORT_DEBUG(PSTR("MyS: CONFIGURATION MODE\n"));
sleep_flag = 0;
digitalWrite(led_pin, OFF);
}
if ((millis() - previousMillis > 2000) && (millis() - previousMillis <= 2500)) {
flag_mode_button = 0;
sleep_flag = 0;
}
if ((millis() - previousMillis > 2500) && (millis() - previousMillis <= 4500))
{
flag_mode_button = 0;
sleep_flag = 0;
digitalWrite(led_pin, OFF);
}
if (millis() - previousMillis > 4500) {
flag_mode_button = 0;
sleep_flag = 0;
wait(50);
}
}
}
} else {
if (listen_flag == 0) {
RF24_startListening();
listen_flag = 1;
}
if (millis() - lightMillis > 1000) {
lightMillis = millis();
digitalWrite(led_pin, !digitalRead(led_pin));
}
if (digitalRead(2) == LOW && flag_mode_button == 0) //если кнопка нажата
{
flag_mode_button = 1;
//previousMillis = millis();
wait(50);
}
if (digitalRead(2) == LOW && flag_mode_button == 1) {
}
if (digitalRead(2) == HIGH && flag_mode_button == 1) //если кнопка НЕ нажата
{
configMode = !configMode;
listen_flag = 0;
flag_mode_button = 0;
TRANSPORT_DEBUG(PSTR("MyS: OPERATING MODE\n"));
digitalWrite(led_pin, OFF);
wait(50);
}
}
}
void receive(const MyMessage & message)
{
if (message.sensor == SETTING_LED_SENS_ID) {
if (message.type == V_VAR1) {
if (message.getByte() <= 1) {
set_led = message.getBool();
saveState(100, set_led);
send(msg_setting_led.set(set_led));
if (set_led == 0) {
TRANSPORT_DEBUG(PSTR("MyS: STATUS LED: OFF\n"));
}
if (set_led == 1) {
TRANSPORT_DEBUG(PSTR("MyS: STATUS LED: ON\n"));
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
}
}
}
if (message.sensor == DELAY_TIME_SENS_ID) {
if (message.type == V_VAR1) {
if (message.getULong() <= 60 && message.getULong() != 0) {
delayTime = message.getULong();
saveState(101, delayTime);
send(msg_delay_time.set(delayTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
} else if (message.getULong() > 60) {
delayTime = 60;
saveState(101, delayTime);
send(msg_delay_time.set(delayTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
} else if (message.getULong() == 0) {
delayTime = 1;
saveState(101, delayTime);
send(msg_delay_time.set(delayTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL TEMP&HUM SEND VALUE IS SET: %d MIN.\n"), delayTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
}
}
if (message.sensor == BATTARY_SEND_SENS_ID) {
if (message.type == V_VAR1) {
if (message.getULong() <= 168) {
send_batteryTime = message.getULong();
saveState(102, send_batteryTime);
send(msg_battary_send.set(send_batteryTime));
TRANSPORT_DEBUG(PSTR("MyS: THE NEW INTERVAL BATTERY SEND IS SET: %d HOUR\n"), send_batteryTime);
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
}
}
}
void send_data()
{
humd = sht20.readHumidity();
temp = sht20.readTemperature();
int t_humd = (int)humd;
int t_temp = (int)temp;
if (abs(temp - oldtemp) >= tempThreshold) {
send(msg_temp.set(temp, 1));
oldtemp = temp;
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
wait(100);
if (abs(humd - oldhumd) >= humThreshold) {
send(msg_hum.set(humd, 1));
oldhumd = humd;
if (set_led == 1) {
digitalWrite(led_pin, ON);
wait(50);
digitalWrite(led_pin, OFF);
}
}
TRANSPORT_DEBUG(PSTR("MyS: DATA - TEMPERATURE: %d, HUMIDITY %d\n"), t_temp, t_humd);
}
void readBatLev() {
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX0);
wait(100);
RF24_startListening();
wait(200);
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA, ADSC));
uint8_t low = ADCL;
uint8_t high = ADCH;
long temp = (high << 8) | low;
float vcc = temp * 1.1 / 1023 * BAT_COOF * 100;
battery = map((int)vcc, BAT_MIN, BAT_MAX, 0, 100);
if (battery < 0) {
battery = 0;
}
if (battery > 100) {
battery = 100;
}
TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL: %d, PREVIUS BATTERY LEVEL: %d\n"), battery, old_battery);
TRANSPORT_DEBUG(PSTR("MyS: BATTERY LEVEL ADC: %d\n"), temp);
/*
if (old_battery != battery) {
if (battery < old_battery) {
old_battery = battery;
wait(100);
sendBatteryLevel(battery);
wait(100);
send(powerMsg.set(temp));
TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
} else {
battery = old_battery;
}
}
*/
wait(100);
sendBatteryLevel(battery);
wait(100);
send(powerMsg.set(temp));
TRANSPORT_DEBUG(PSTR("MyS: SEND BATTERY LEVEL\n"));
}
+53 |
2351
67
|
+165 |
3643
48
|
С другой стороны, использовать SLA для корпусов крупнее пары см — это несколько странно :)
Хотя, может быть, имеет смысл использовать их и для мелких корпусов типа брелков или часов.
Всякие панельки для экранчиков или кнопок/датчиков на стену аккуратные.
FDM — для функциональности, для более крупных и/или массовых изделий :)
Мне печатать много и не надо и пока склоняюсь к такому.
Плюсы — хорошее качество печати, особенно это проявляется на моделях с высокой детализацией.
На самом деле я тоже давно уже поглядываю на тот же Аникубик Фотон-С, но на вопрос своей жабы «И что ты будешь на нем печатать, чего не можешь напечатать на имеющемся FDM?» я пока ответа не нашел :)
Но это я так, по слухам, вычитанным в инете, лучше сами поройтесь по этому вопросу на тематических ресурсах :)
работает в основном тексте обзора. В комментариях нет
mysku.club/blog/aliexpress/72638.html
О, вроде и в комментарии сработало
Посмотрите на тот же esphome, намного понятнее выглядит, хотя тоже не идеален.
вэлкам
Кстати, на Хабре один комментатор спросил про описание протокола обмена сообщениями между нодами и центром, оказалось, что такого описания вообще нет :)
:)))
Хотя нередко все работает сразу и по инструкциям, которых у них все же полно.
Хотя окружение диктует, конечно, но бороться можно, я вот всю родню от вайбера отвадил…
Классная тема! Сложновато для меня, но потенциал весьма и весьма
Датчик температуры в комнате весьма условен и сильно зависит от его расположения. А когда делаешь климат, то настраиваешь систему один раз и забываешь про него
Нравится Вам занятие, занимайтесь… какого… Вы с выпученными глазами пытаетесь загрузить им по шею других?
Если задача понтануться перед пацанами дворовыми, то тут свистелки и перделки с выводом на телефон и эротическим массажем. Вобщем кому что надо :)
8 ядер, 6-12 гигов памяти, 3-6 камер в сосвременных смартфонах не смущают? Где большинство только смотрит «ленту» ВК и «чатится в чатиках».
Почему Вы считаете критерием «востребованности» частоту, объём flash и Wi-Fi?
А не себестоимость, время разработки, поддержки, и т. д.?
Вот я хочу счётчик воды. Казалось бы, импульсы можно на NE555 считать. Удобно это? Нет. Нужен экран. Хочется хороший экран. Нужно иметь возможность считывать данные удалённо и, наоборот, передавать их на сервер. Arduino и «шильды»? Зачем? Всё практически есть в ESPxx.
Можно делать самому, можно просто взять один из множества готовых «конструкторов» и просто реализовать то, что нужно.
Не нужно свои цели, критерии, пути с непоколебимым максимализмом распространять на всех.
Про счетчик воды с красивым экраном даже комментировать не буду :)
«Скачал скетч NNN, а он не работает, помогите!» — самый распространенный метод отладки в такой «разработке» :)
Ну и не нужно сравнивать теплое с мягким — знание архитектурных особенностей платформы и знание того что и почему делает программа :)
Правильно, потому что ехать — это шофер. А спроектировать машину — это разработчик, и там уже не получится не знать как устроена машина :)
Ну, я не знаю… Это как самому сделать в доме отопление: трубы вкривь и вкось, из половины соединений капает вода, батареи стоят на полу на кирпичах… И выставить это в инет «Во, оказывается делать отопление — легко, я за пару дней справился! Вот проект для желающих повторить: ...» :)
habr.com/ru/post/452558/
Счетчик импульсов заинтересовал люто. Обзор планируется?
www.openhardware.io/view/658/EFEKTA-Two-channel-Pulse-Counter-or-nRF52
Из обзора не ясно как дела с автономностью.
Я сейчас только понял что у вас снял показания отправил и все. У меня просто все в онлайне скажем так, по сему видимо такие отличия.
Инфа о статусе будет в группе…
меня прям печалят индивидуумы, типа кул программеры,… покажите ваши
Замер датчиков каждую минуту, передача через GSM-канал каждые 15 минут. Без единого скетча :) И обратите внимание на правый нижний график — напряжение батареи. Это при том, что до 15-16 числа станция работала от аккумулятора без подзарядки от солнечной панельки :)
Но в общих чертах так:
— аккумулятор NiMH из трех элементов по 4200 мА*ч (последовательно)
— микроконтроллер серии STM32L с подключенными кварцами 8 МГц для рабочей частоты и 32.768 кГц для часов реального времени (RTC)
— GSM-модем SIM-800
— 10 аналоговых входов
— отдельный вход датчика направления ветра
— 2 цифровых — для импульсов анемометра и датчика дождя
— модуль питания, следящий за зарядом аккумулятора и подключающий или отключающий солнечную панель для подзарядки аккумулятора, все это в аппаратном виде, на компараторах и мосфетах
— счетчик анемометра — отдельная микросхема, ширина счетчика — 32 бит, в ней же пара сотен байт памяти для хранения данных во время спички микроконтроллера
— счетчик дождя — по прерыванию на микроконтроллере
— встроенный (на плате) барометр BMP180
— 4-мегабайтная флэш (AT45DB321) для сохранения измерений
— небольшой OLED-дисплей 128х64 для настройки
— солнечная панель (вроде на 0.2 Ватта)
К аналоговым входам подключаются всевозможные датчики — влажности, температуры, влажности почвы, увлажнения листа и т.п. У всех у них выходное значение — аналоговый сигнал 0-2 В. Питание на все аналоговые датчики коммутируемое, микроконтроллер включает его перед измерением и отключает после считывания показаний.
Большую часть времени микроконтроллер в глубокой спячке с потреблением меньше 1 мкА — отключено все кроме вачдога и RTC, все выводы в третьем состоянии, содержимое памяти теряется (кроме нескольких ячеек RTC). Вообще вся станция в этот период потребляет около 40 мкА, из которых половина — модуль питания со своими компараторами и стабилизаторами, почти все остальное — флэш, барометр, счетчик анемометра. Все это (кроме счетчика) вводится в глубокий сон. Модему, дисплею и аналоговым датчикам питание отрубается.
Через заданный промежуток времени контроллер просыпается по будильнику (RTC), включает питание датчиков, будит барометр и снимает показания. После этого опять все отключает и засыпает. Когда приходит время отправки данных на сервер, включается питание модема, он заводится и данные всех измерений (минимум, максимум, среднее) с последней передачи отправляются серверу. Если не получилось отправить — сохраняются во флэш. Если отправились, то проверяется нет ли во флэш неотправленных данных и если есть — отправляются и они. После чего станция несколько секунд ждет команды от сервера и если команды не поступают, то опять засыпает.
Все параметры могут быть заданы с сервера. Тем же путем может прилететь обновление прошивки станции.
Сама станция (без внешних датчиков) — это одна плата размером примерно 8х12 см (много места занимают разъемы для внешних датчиков).
Вот как-то так :)
Да, я использую SPL, в основном для настройки переферии. Иначе все равно придется или изобретать свою SPL или запоминать битовые маски в разных регистрах. В критичных ко времени выполнения местах работаю напрямую с регистрами. Пару раз использовал CUBE, но использовал так — создал в CUBE проект, в нем настроил нужную мне периферию, а потом просто выдернул нужный файл исходников из проекта CUBE в свой проект :) Так было, например, когда я делал подключение своего девайса по USB как HID-устройства, без драйверов. Потом мне еще пришлось нормально перелопатить этот кубовский исходник (и информацию по USB HID) чтобы заставить его работать как мне нужно :)
Исходники библиотек я всегда сразу копирую в свой проект, потому что иногда приходится менять в них какие-то моменты. Плюс к этому я копирую в проект файлы настройки линкера и стартовый файл на ассемблере — они в IAR обычно лежат в общих папках среды и по умолчанию среда работает с ними оттуда, не предполагая, что они будут меняться пользователем. У меня — часто меняются :) Например, для бутлодера и для приложения, работающего на контроллере с таким бутлодером.
RTOS — нет, не использую. Пока не было задачи, в которой ее использование было бы оправдано.
Среда разработки — IAR. Понятно, что денег на ее покупку у меня никогда не было и вряд ли когда-то будут, так что… :)
У меня тоже куча девайсов и у каждого куча графиков.
Visual Studio еще никто не сделал.
Code — неплохая, но еще игрушечная
В Студии — и под Линукс, и по Виндовс хоть на ++ хоть на C#, и для Андроида, и для iOS и на Phyton и вообще для всего-всего
Да и Ардуина есть с ESP32
Но сама работа — в целом хорошо.
— программа для проектирования платы
— компоненты
— микроконтроллер и радиомодуль
— изготовление платы
— программа для проектирования корпуса
— 3д принтер для изготовления корпуса
— припой/паяльник (наверняка)
— программа для разработки микропрограммы
— 99% кода микропрограммы (библиотека mysensors)
— фотоаппарат
— холодильник (возможно российская сборка около 20%)
— ютюб
— ПК+компоненты/монитор/ОС, использованные для разработки
Российское
— разработка платы/работа (в принципе важный пункт)
— 0.1% кода микропрограммы
— 20% холодильника
— пластик для принтера (вероятно)
Но, естественно, не отменяет того, что автор молодец.
при том там не весь мой функционал добавлен
// *************************** master slave mode is not initialized in this version, ..stub *******************************
У меня есть и мои проекты, которые даже посложнее этого коммерческого. Вот, например, просто из интереса ковырялся с одной штукой:
Выделенные файлы — полностью мои :)
У меня к Вам один вопрос — почему диптрейс, а не easyeda? Попробовал диптрейс — ужас, а не инструмент, в easyeda все гораздо проще.
Почему не изидата, хз, я там пробовал, не сложилось у меня с ней, не то что бы не освоил, просто почему то неудобно мне в ней, не моя, а Диптрейс зашел. Вот Альтиум еще ничего… Впринципе по этому и Солид а не Фьюжин например, пробовал второе, тоже не мое.
Тем паче, с полезными ссылками и практическими наглядными примерами. И-своими руками и головой.
Как-то тыкал палочкой MajorDoMo, но он вроде только Modbus TCP умеет.
4pda.ru/2019/05/20/357569/
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.