RSS блога
Подписка
esp32 - изучаем и попутно сравниваем датчики пыли
- Цена: $29.87 (за 3 штуки)
- Перейти в магазин
В обзоре я пробегусь по основным преимуществам esp32 над Ардуино и расскажу о своем первом проекте на этой платформе — программе сравнения двух наиболее популярных датчиков пыли — SDS-011 и PMSA003.
esp32 — совершенно новое поколение микроконтроллеров, пришедшее на смену Ардуино.
Поначалу меня отпугивали заморочки с переходом. Если полистать сайт производителя espressif, прямо руки опускаются: надо ставить кучу всякого софта, пайтон изучать. все конфигурировать. А после еще наверняка придется вытряхивать баги из своего кода, чтобы обеспечить совместимость скриптов для ATMega328 и ESP32.
А может овчинка и не стоит выделки? Смотрим
Архитектура — у esp — 32 бита, у Ардуино — 8.
Процессор совершенно новый, двухъядерный. Одно ядро занимается только связью, второе крутит пользовательский код.
Частота — 240 МГц, что в 15 раз выше, чем в Ардуино. И есть еще один ULP (ультра-маломощный) процессор, который работает на частоте всего 32 КИЛОгерца в режиме сна. У него есть своя небольшая (16 Кб) память, свой набор команд, многого он не умеет, но если что — разбудит основной проц. Полезная штука.
Оперативной памяти — 520 Кб, что в 260 раз больше, чем на Ардуино и почти дотягивает до сакраментального «640K ought to be enough for anybody!».
Энергонезависмая программная память — 448 Кб что тоже выгодно отличается от Ардуино, там 32 кб.
(Честно говоря, именно память и стала последней каплей, после которой для некоторых своих проектов я решил перебираться на esp32.)
Да, есть флеш в 4Мб, до 16 в некоторых версиях, и по слухам, там тоже можно размещать программный код.
Еще на борту есть WiFi, блютус с поддержкой BLE, поддерживаются всякие криптографические функции. В Ардуино всего этого нет, разумеется.
По входам-выходам тоже хороший привес: 36 штук, вместо 14 на Ардуино, а аналоговых — 18 вместо 6. Да, и оцифровка входящего сигнала 12-битным АЦП, а не 10-битным, что дает 4096 уровней, вместо 1024.
А еще ЦАП, чего в ардуине нет вовсе. И 4 SPI, 2 I2C, 2 I2S и 2 UART. Интерфейс для тачскрина и даже зачем-то датчик Холла. А вот датчика температуры в моих экземплярах нет, хотя по датшиту он предусмотрен. Скрипт выдает неизменные 53,33 градуса.
Схема модулей выглядит так:
Вот как выглядит краткое описание выводов этого контроллера:
Как выяснилось, перенастроить Arduino IDE для прошивки esp32 проще простого: Надо добавить в настойки адрес, где искать информацию о контроллерах:
dl.espressif.com/dl/package_esp32_index.json
Выглядит это вот так:
Потом запустить менеджер контроллеров и найти в нем esp32. Нажать кнопку «установить».
Все. Отныне ваша IDE поддерживает esp32. Только из списка плат надо выбрать ESP 32 Dev Module.
А в меню примеров появятся встроенные примеры скриптов для esp.
Все сложные инструкции, которые можно найти в сети, относятся к более старым версиям Arduino IDE. В новых названных мной шагов вполне достаточно.
С теорией понятно, можно переходить к практической части. Я заказал сразу три esp32.
Пришли они в стандартных антистатических пакетах.
Сделаны с адекватным качеством. Флюс кое-где не смыт, шелкография читается не идеально, но это не беда. Пайка хорошая.
На плате кроме собственно чипа esp32 есть пара светодиодов, степдаун на 3,3 вольта на ams1117, микросхема последовательного порта cp2102. Имеются две кнопки.
Обратная сторона занята только надписью «DoIt ESP32 DEVKIT V1 doit.am».
Заходил я на этот армянский сайт. Там все по-китайски.
Для теста можно залить очень мощную программу AMS, которая предоставляет роскошный веб интерфес для всех ваших проектов. При загрузке она выдает некоторую информацию о esp.
К вайфаю, к слову, подкдючились мгоновенно и на скорости 150 мб.
Затем я решил оценить прирост скорости. Контроллер этот будет использоваться в основном для создания отностельно серьезных подлок, разные там включения-выключения света и воды останутся для Ардуино. Стало быть, новому esp32 придется иметь дело с экраном. Я подключил ардуину и esp32 к двум экранам. У них разный физический размер, но размеры в пикселях и контроллеры одинаковые. Одинаковая и программная часть тест библиотеки Ucg. Запускаются совершенно синхронно, от одного блока питания.
Вот результат — ролик полторы минуты:
esp примерно в 2,5 раза быстрее Ардуины. И еще важный момент: выводы esp на 3,3 вольта, а у Ардуины 5. Таким образом, для сопряжения уровней для ардуины нужен либо конвертор уровней, либо батарея резисторов. А esp напрямую подключается ко входам экрана.
Но для настощего тестирования нужен проект поинтересней. Я недавно опубликовал сравнительный обзор четырех датчиков СО2.
И теперь хотелось бы сравнить два бытовых датчика пыли. — PMSA003 и SDS-011. О последнем я уже писал обзор (https://mysku.club/blog/china-stores/72041.html). Была написана программа, которая рисовала на экранчике вот такой график:
Да, SDS-011 — хороший датчик. Но вот беда — написанная программа для него занимала в ПЗУ 20 кб из 30 и 1,5 кб из 2 ОЗУ. Перенести ее на более просторный экран и добавить поддержку второго датчика не предсталялось возможным. С появлением esp32 мечты стали сбываться.
И вот теперь я решил ни в чем себе не отказывать. Подключил датчики и экран к esp32. Взял более мощную графическую библиотеку. Крупнее экран. Особенно не заморачиваясь с оптимизацией, написал код. Сделал так, чтобы статистики накапливалось втрое больше, чем в предыдущей версии программы. И вот что у меня получилось:
И все эти мигом скомпилировалось для esp.
Запускаем — работает!
Программа позволила сравнить два датчика. Оба оказались неплохими, показания обоих релевантны ситуации в квартире. SDS-011 более чутко реагирует на любой взмах тряпки. PMSA003 выдает больше информации и работает практически неслышно. И он компактнее раза в четыре.
Но вернемся к esp. При всех его достоинствах, один недостаток я все-таки обнаружил. Дело в том, что для заливания программы в контроллер требуется нажать на кнопку EN и удерживать ее несколько секунд. При частых сменах кода это начинает подбешивать. Кроме того, блокируется возможность обновления прошивки удаленно. Порывшись в интернете, я нашел простой рецепт избавления от этого недостатка. Надо всего лишь
припаять конденсатор между выводами кнопки EN. Одного микрофарада будет достаточно. У меня получилось.
Действительно, с этого момента прошиваться стал без дополнительных манипуляций. Все, я доволен.
Что в итоге?
Платы однозначно рекомендую к покупке. Программируются так же просто как Ардуино, но нет лишних ограничений, больше встроенных возможностей, больше потенциал интеграции с другими устройствами и масштабируемость. Хороший компромисс между примитивными задачами для Ардуины и совсем уж почти компьютером Raspberry PI.
Вы прочли обзор, который я писал дольше всех остальных моих обзоров.Самая большая трудность — выбрать из огромного моря информации в документации и на форумах то, о чем стоит упомянуть в кратком обзоре. Потому что если писать все, то никакой жизни не хватит, особенно если возможности esp проверять и иллюстрировать.
Основная мысль, которую я хотел донести — это то, что с появлением документации, библиотек и примеров, программировать esp32 стало так же просто, как и ардуино. А возможностей у esp в разы больше.
esp32 — совершенно новое поколение микроконтроллеров, пришедшее на смену Ардуино.
Поначалу меня отпугивали заморочки с переходом. Если полистать сайт производителя espressif, прямо руки опускаются: надо ставить кучу всякого софта, пайтон изучать. все конфигурировать. А после еще наверняка придется вытряхивать баги из своего кода, чтобы обеспечить совместимость скриптов для ATMega328 и ESP32.
А может овчинка и не стоит выделки? Смотрим
Архитектура — у esp — 32 бита, у Ардуино — 8.
Процессор совершенно новый, двухъядерный. Одно ядро занимается только связью, второе крутит пользовательский код.
Частота — 240 МГц, что в 15 раз выше, чем в Ардуино. И есть еще один ULP (ультра-маломощный) процессор, который работает на частоте всего 32 КИЛОгерца в режиме сна. У него есть своя небольшая (16 Кб) память, свой набор команд, многого он не умеет, но если что — разбудит основной проц. Полезная штука.
Оперативной памяти — 520 Кб, что в 260 раз больше, чем на Ардуино и почти дотягивает до сакраментального «640K ought to be enough for anybody!».
Энергонезависмая программная память — 448 Кб что тоже выгодно отличается от Ардуино, там 32 кб.
(Честно говоря, именно память и стала последней каплей, после которой для некоторых своих проектов я решил перебираться на esp32.)
Да, есть флеш в 4Мб, до 16 в некоторых версиях, и по слухам, там тоже можно размещать программный код.
Еще на борту есть WiFi, блютус с поддержкой BLE, поддерживаются всякие криптографические функции. В Ардуино всего этого нет, разумеется.
По входам-выходам тоже хороший привес: 36 штук, вместо 14 на Ардуино, а аналоговых — 18 вместо 6. Да, и оцифровка входящего сигнала 12-битным АЦП, а не 10-битным, что дает 4096 уровней, вместо 1024.
А еще ЦАП, чего в ардуине нет вовсе. И 4 SPI, 2 I2C, 2 I2S и 2 UART. Интерфейс для тачскрина и даже зачем-то датчик Холла. А вот датчика температуры в моих экземплярах нет, хотя по датшиту он предусмотрен. Скрипт выдает неизменные 53,33 градуса.
Схема модулей выглядит так:
Вот как выглядит краткое описание выводов этого контроллера:
Как выяснилось, перенастроить Arduino IDE для прошивки esp32 проще простого: Надо добавить в настойки адрес, где искать информацию о контроллерах:
dl.espressif.com/dl/package_esp32_index.json
Выглядит это вот так:
Потом запустить менеджер контроллеров и найти в нем esp32. Нажать кнопку «установить».
Все. Отныне ваша IDE поддерживает esp32. Только из списка плат надо выбрать ESP 32 Dev Module.
А в меню примеров появятся встроенные примеры скриптов для esp.
Все сложные инструкции, которые можно найти в сети, относятся к более старым версиям Arduino IDE. В новых названных мной шагов вполне достаточно.
С теорией понятно, можно переходить к практической части. Я заказал сразу три esp32.
Пришли они в стандартных антистатических пакетах.
Сделаны с адекватным качеством. Флюс кое-где не смыт, шелкография читается не идеально, но это не беда. Пайка хорошая.
На плате кроме собственно чипа esp32 есть пара светодиодов, степдаун на 3,3 вольта на ams1117, микросхема последовательного порта cp2102. Имеются две кнопки.
Обратная сторона занята только надписью «DoIt ESP32 DEVKIT V1 doit.am».
Заходил я на этот армянский сайт. Там все по-китайски.
Для теста можно залить очень мощную программу AMS, которая предоставляет роскошный веб интерфес для всех ваших проектов. При загрузке она выдает некоторую информацию о esp.
AMS for ESP32 SD started…
Module Random… started
Module EEPROM (NVS)…
Name: ESP32 SD
ID: W25D1-F08MJ-3KWLF
Address: 217
===========
Module Hardware…
Arduino IDE: 1.8.9
SDK version: v3.2.3
Chip revision: 1
Chip ID: 50BEC4BF713C
CPU freq: 240 MHz
Free memory: 313228 (109%)
Flash mode: 2
Flash speed: 80 MHz
Flash size: 4194304
Self temp: 53.3 C
===========
Module Wi-Fi…
Connecting to xxxxxxxx.
WiFi: connected
IP address: 192.168.1.70
===========
Module SD…
Init: OK
Type: SDSC
Size: 1947 MB
Check:…
Files: 138
Total: 2065241 B
Empty: 1
Index: found
===========
Module NTP…
Server: 129.6.15.30
Port: 123
===========
К вайфаю, к слову, подкдючились мгоновенно и на скорости 150 мб.
Затем я решил оценить прирост скорости. Контроллер этот будет использоваться в основном для создания отностельно серьезных подлок, разные там включения-выключения света и воды останутся для Ардуино. Стало быть, новому esp32 придется иметь дело с экраном. Я подключил ардуину и esp32 к двум экранам. У них разный физический размер, но размеры в пикселях и контроллеры одинаковые. Одинаковая и программная часть тест библиотеки Ucg. Запускаются совершенно синхронно, от одного блока питания.
Вот результат — ролик полторы минуты:
esp примерно в 2,5 раза быстрее Ардуины. И еще важный момент: выводы esp на 3,3 вольта, а у Ардуины 5. Таким образом, для сопряжения уровней для ардуины нужен либо конвертор уровней, либо батарея резисторов. А esp напрямую подключается ко входам экрана.
Но для настощего тестирования нужен проект поинтересней. Я недавно опубликовал сравнительный обзор четырех датчиков СО2.
И теперь хотелось бы сравнить два бытовых датчика пыли. — PMSA003 и SDS-011. О последнем я уже писал обзор (https://mysku.club/blog/china-stores/72041.html). Была написана программа, которая рисовала на экранчике вот такой график:
Да, SDS-011 — хороший датчик. Но вот беда — написанная программа для него занимала в ПЗУ 20 кб из 30 и 1,5 кб из 2 ОЗУ. Перенести ее на более просторный экран и добавить поддержку второго датчика не предсталялось возможным. С появлением esp32 мечты стали сбываться.
И вот теперь я решил ни в чем себе не отказывать. Подключил датчики и экран к esp32. Взял более мощную графическую библиотеку. Крупнее экран. Особенно не заморачиваясь с оптимизацией, написал код. Сделал так, чтобы статистики накапливалось втрое больше, чем в предыдущей версии программы. И вот что у меня получилось:
Несколько экранов скучного кода, не открывайте
//////////////////////////////////////////////////////////////////////////////////////
////////////// © tykhon, 2019 ////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
#include <SPI.h>
#include "Ucglib.h"
#include "HardwareSerial.h"
#define PMSSerial Serial2
#define SDSSerial Serial1
unsigned int SDS_Pm25;
unsigned int SDS_Pm100;
float SDS_Pm25mean;
float SDS_Pm100mean;
float SDS_Pm25f;
float SDS_Pm100f;
float PMS_Pm10mean;
float PMS_Pm25mean;
float PMS_Pm100mean;
float smoothing_factor = 0.3; // coeff for Kalman 0.01 - 0.99. Higher for less smoothing.
uint32_t start = millis();
uint32_t now = millis();
uint32_t nextrun = 0;
boolean PMSrun = false;
const int period = 180; // period of sensor poll, sec
const int sds_period = period/60;
int line_sds_25[200] = {};
int line_sds_100[200] = {};
int line_pms_10[200] = {};
int line_pms_25[200] = {};
int line_pms_100[200] = {};
byte lineIndex_pms;
byte lineIndex_sds;
unsigned int line_sds_100sum = 0;
unsigned int line_sds_25sum = 0;
Ucglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/ 16, /*cs=*/ 17, /*reset=*/ 5);
//////////////////////////////////////////////////////////////////////////
///////// SDS 011 ///////////////
//////////////////////////////////////////////////////////////////////////
void SDSworkmode(byte mode)
{
byte cs = 7 + mode;
uint8_t sleep_command[] = {0xAA, 0xB4, 0x08, 0x01, mode, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, cs, 0xAB};
// ^^ 0 for continuous, 1-30 for 1-30 min delay between turns on. ^^ checksum: 07 for 0x00, 08 for 0x01 and so on
for (uint8_t i = 0; i < 19; i++) {
SDSSerial.write(sleep_command[i]);
}
}
void SDSwakeup()
{
uint8_t wakeup_command[] = {0xAA, 0xB4, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0xAB};
for (uint8_t i = 0; i < 19; i++) {
SDSSerial.write(wakeup_command[i]);
}
}
boolean ProcessSerialData()
{
uint8_t mData = 0;
uint8_t i = 0;
uint8_t mPkt[10] = {0};
uint8_t mCheck = 0;
while (SDSSerial.available() > 0)
{
mData = SDSSerial.read(); delay(2);//wait until packet is received
if (mData == 0xAA) //head1 ok
{
mPkt[0] = mData;
mData = SDSSerial.read();
if (mData == 0xc0) //head2 ok
{
mPkt[1] = mData;
mCheck = 0;
for (i = 0; i < 6; i++) //data recv and crc calc
{
mPkt[i + 2] = SDSSerial.read();
delay(2);
mCheck += mPkt[i + 2];
}
mPkt[8] = SDSSerial.read();
delay(1);
mPkt[9] = SDSSerial.read();
if (mCheck == mPkt[8]) //crc ok
{
SDSSerial.flush();
SDS_Pm25 = (uint16_t)mPkt[2] | (uint16_t)(mPkt[3] << 8);
SDS_Pm100 = (uint16_t)mPkt[4] | (uint16_t)(mPkt[5] << 8);
if (SDS_Pm25 > 9999)
SDS_Pm25 = 9999;
if (SDS_Pm100 > 9999)
SDS_Pm100 = 9999;
return true;
} else {Serial.println('crc not ok');};
} else {Serial.println('head not ok');};
}
}
}
//////////////////////////////////////////////////////////////////////////
///////// PMSA003 ///////////////
//////////////////////////////////////////////////////////////////////////
void PMSworkmode(byte mode)
{
byte cs = 70 + mode;
uint8_t mode_command[] = {0x42, 0x4D, 0xE1, 0x00, mode, 0x01, cs};
// ^^ 0 for passive, 1 for active. The last byte - checksum: 70 for 0x00, 71 for 0x01 and so on
for (uint8_t i = 0; i < 7; i++) {
PMSSerial.write(mode_command[i]);
}
delay(100);
}
void PMSwakeup()
{
uint8_t wakeup_command[] = {0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74};
for (uint8_t i = 0; i < 7; i++) {
PMSSerial.write(wakeup_command[i]);
}
delay(100);
}
void PMSsleep()
{
uint8_t sleep_command[] = {0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73};
for (uint8_t i = 0; i < 7; i++) {
PMSSerial.write(sleep_command[i]);
}
delay(100);
}
void PMSpassive_mode_read()
{
uint8_t read_command[] = {0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71};
for (uint8_t i = 0; i < 7; i++) {
PMSSerial.write(read_command[i]);
}
delay(100);
}
///////////////////////////////////////////////////////////////////
struct pms5003data {
uint16_t framelen;
uint16_t pm10_standard, pm25_standard, pm100_standard;
uint16_t pm10_env, pm25_env, pm100_env;
uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
uint16_t unused;
uint16_t checksum;
};
struct pms5003data data;
boolean readPMSdata(Stream *s) {
if (! s->available()) {
Serial.println("data not available");
return false;
}
// Read a byte at a time until we get to the special '0x42' start-byte
if (s->peek() != 0x42) {
s->read();
Serial.println("no 42");
return false;
}
// Now read all 32 bytes
if (s->available() < 32) {
Serial.println("less than 32");
return false;
}
uint8_t buffer[32];
uint16_t sum = 0;
s->readBytes(buffer, 32);
// get checksum ready
for (uint8_t i=0; i<30; i++) {
sum += buffer[i];
}
/* debugging
Serial.println();
for (uint8_t i=0; i<32; i++) {
// was i=2
Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
}
Serial.println();
*/
// The data comes in endian'd, this solves it so it works on all platforms
uint16_t buffer_u16[15];
for (uint8_t i=0; i<15; i++) {
buffer_u16[i] = buffer[2 + i*2 + 1];
buffer_u16[i] += (buffer[2 + i*2] << 8);
}
// put it into a nice struct :)
memcpy((void *)&data, (void *)buffer_u16, 30);
while (s->available()) {s->read();};
if (sum != data.checksum) {
Serial.println("Checksum failure");
Serial.print(" sum = ");
Serial.print(sum, HEX);
Serial.print(" data.checksum = ");
Serial.println(data.checksum, HEX);
return false;
}
// success!
return true;
}
//////////////////////////////////////////////////////////////////////////////////
void math_PMS(){
if (!PMS_Pm10mean) PMS_Pm10mean = data.pm10_standard;
if (!PMS_Pm25mean) PMS_Pm25mean = data.pm25_standard;
if (!PMS_Pm100mean) PMS_Pm100mean = data.pm100_standard;
PMS_Pm10mean = PMS_Pm10mean - smoothing_factor*(PMS_Pm10mean - data.pm10_standard);
PMS_Pm25mean = PMS_Pm25mean - smoothing_factor*(PMS_Pm25mean - data.pm25_standard);
PMS_Pm100mean = PMS_Pm100mean - smoothing_factor*(PMS_Pm100mean - data.pm100_standard);
line_pms_10[lineIndex_pms] = int(PMS_Pm10mean*10.0);
line_pms_25[lineIndex_pms] = int(PMS_Pm25mean*10.0);
line_pms_100[lineIndex_pms] = int(PMS_Pm100mean*10.0);
lineIndex_pms++;
if (lineIndex_pms >= sizeof(line_pms_100)/sizeof(int)) {lineIndex_pms = 0;};
}
void math_SDS(){
if (!SDS_Pm25mean) SDS_Pm25mean = SDS_Pm25/10.0;
SDS_Pm25mean = SDS_Pm25mean - smoothing_factor*(SDS_Pm25mean - SDS_Pm25/10.0);
if (!SDS_Pm100mean) SDS_Pm100mean = SDS_Pm100/10.0;
SDS_Pm100mean = SDS_Pm100mean - smoothing_factor*(SDS_Pm100mean - SDS_Pm100/10.0);
line_sds_25[lineIndex_sds] = int(SDS_Pm25mean*10.0);
line_sds_100[lineIndex_sds] = int(SDS_Pm100mean*10.0);
lineIndex_sds++;
if (lineIndex_sds >= sizeof(line_sds_100)/sizeof(int)) {lineIndex_sds = 0;};
}
//////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// graph ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
void main_graph_sds(){
ucg.setColor(0, 0, 0); // clear field
ucg.drawBox(1, 1, 220, 119);
ucg.setColor(255, 255, 255); // half line
ucg.drawHLine(0, (ucg.getHeight()/2), ucg.getWidth());
ucg.setColor(250, 255, 10);
ucg.drawVLine(20, 5, 90); // y line
ucg.drawHLine(20, 95, 200); // x line
int maxvalue = 1; // y scale
for (int i = 0; i < (sizeof(line_sds_100)/sizeof(int)); i++){
maxvalue = max(maxvalue, line_sds_100[i]);
maxvalue = max(maxvalue, line_sds_25[i]);
};
maxvalue = int(ceil(float(maxvalue)/50.0)*50);
ucg.setFont(ucg_font_helvB12_hr);
ucg.setColor(255,255,255);
ucg.setPrintPos(1,20);
ucg.print(maxvalue/10);
int hours_count = sizeof(line_sds_100)/sizeof(int); // x scale
int step_in_min = sds_period;
hours_count = hours_count * step_in_min;
hours_count = hours_count / (-60);
int onestep = 1;
if (hours_count < -5) {onestep = 2;};
for (int i = 0; i >= hours_count; i = i - onestep) {
int posx = 20 +(sizeof(line_sds_100)/sizeof(int)) + i*(60/step_in_min);
ucg.setColor(250,255,10);
ucg.drawVLine(posx, 95, 5);
int shift = posx+1;
if (shift > 200) {shift = shift-10;};
ucg.setPrintPos(shift, 114);
ucg.setColor(255,255,255);
ucg.print(i);
};
int g = 20+(sizeof(line_sds_100)/sizeof(int)); // plot draw
for (int i = lineIndex_sds-1; i >= 0; i--){
int x1 = g;
g--;
int y1 = map(line_sds_100[i], 0, maxvalue, 0, 92);
int y2 = map(line_sds_25[i], 0, maxvalue, 0, 92);
ucg.setColor(10, 80, 250);
ucg.drawVLine(x1, 95-y1, y1);
ucg.setColor(250, 10, 80);
ucg.drawVLine(x1, 95-y2, y2);
};
for (int i = (sizeof(line_sds_100)/sizeof(int))-1; i >= lineIndex_sds; i--){
int x1 = g;
g--;
int y1 = map(line_sds_100[i], 0, maxvalue, 0, 92);
int y2 = map(line_sds_25[i], 0, maxvalue, 0, 92);
ucg.setColor(10, 80, 250);
ucg.drawVLine(x1, 95-y1, y1);
ucg.setColor(250, 10, 80);
ucg.drawVLine(x1, 95-y2, y2);
};
}
void main_graph_pms(){
ucg.setColor(0, 0, 0); // clear field
ucg.drawBox(1, 124, 220, 119);
ucg.setColor(255, 255, 255); // half line
ucg.drawHLine(0, (ucg.getHeight()/2), ucg.getWidth());
ucg.setColor(250, 255, 10);
ucg.drawVLine(20, 128, 90); // y line
ucg.drawHLine(20, 218, 200); // x line
int maxvalue = 1; // y scale
for (int i = 0; i < (sizeof(line_pms_100)/sizeof(int)); i++){
maxvalue = max(maxvalue, line_pms_100[i]);
maxvalue = max(maxvalue, line_pms_25[i]);
maxvalue = max(maxvalue, line_pms_10[i]);
};
maxvalue = int(ceil(float(maxvalue)/50.0)*50);
ucg.setFont(ucg_font_helvB12_hr);
ucg.setColor(255,255,255);
ucg.setPrintPos(1,143);
ucg.print(maxvalue/10);
int hours_count = sizeof(line_pms_100)/sizeof(int);
int step_in_min = sds_period;
hours_count = hours_count * step_in_min;
hours_count = hours_count / (-60);
int onestep = 1;
if (hours_count < -5) {onestep = 2;};
for (int i = 0; i >= hours_count; i = i - onestep) {
int posx = 20 +(sizeof(line_pms_100)/sizeof(int)) + i*(60/step_in_min);
ucg.setColor(250,255,10);
ucg.drawVLine(posx, 218, 5);
int shift = posx+1;
if (shift > 200) {shift = shift-10;};
ucg.setPrintPos(shift, 237);
ucg.setColor(255,255,255);
ucg.print(i);
};
int g = 20+(sizeof(line_pms_100)/sizeof(int)); // plot draw
for (int i = lineIndex_pms-1; i >= 0; i--){
int x = g;
g--;
int y1 = map(line_pms_100[i], 0, maxvalue, 0, 92);
int y2 = map(line_pms_25[i], 0, maxvalue, 0, 92);
int y3 = map(line_pms_10[i], 0, maxvalue, 0, 92);
ucg.setColor(10, 80, 250);
ucg.drawVLine(x, 218-y1, y1);
ucg.setColor(250, 10, 80);
ucg.drawVLine(x, 218-y2, y2);
ucg.setColor(80, 250, 10);
ucg.drawVLine(x, 218-y3, y3);
};
for (int i = (sizeof(line_pms_100)/sizeof(int))-1; i >= lineIndex_pms; i--){
int x = g;
g--;
int y1 = map(line_pms_100[i], 0, maxvalue, 0, 92);
int y2 = map(line_pms_25[i], 0, maxvalue, 0, 92);
int y3 = map(line_pms_10[i], 0, maxvalue, 0, 92);
ucg.setColor(10, 80, 250);
ucg.drawVLine(x, 218-y1, y1);
ucg.setColor(250, 10, 80);
ucg.drawVLine(x, 218-y2, y2);
ucg.setColor(80, 250, 10);
ucg.drawVLine(x, 218-y3, y3);
};
}
////////////////////////////////////////////////////////////////////////////
void print_SDS(){
SDS_Pm25f = SDS_Pm25/10.0;
SDS_Pm100f = SDS_Pm100/10.0;
String dataString = "SDS_2.5:\t"+String(SDS_Pm25f,0)+"\tSDS_10:\t"+String(SDS_Pm100f,0)+"\tSDS_2.5~:\t"+String(SDS_Pm25mean,1)+"\tSDS_10~:\t"+String(SDS_Pm100mean,1);
dataString.replace(".",",");
Serial.print(dataString);
}
void print_PMS(){
/*
Serial.print("\tPMS_1:\t"); Serial.print(data.pm10_standard);
Serial.print("\tPMS_2.5:\t"); Serial.print(data.pm25_standard);
Serial.print("\tPMS_10:\t"); Serial.print(data.pm100_standard);
Serial.print("\tPMS_1~:\t"); Serial.print(PMS_Pm10mean,1);
Serial.print("\tPMS_2.5~:\t"); Serial.print(PMS_Pm25mean,1);
Serial.print("\tPMS_10~:\t"); Serial.println(PMS_Pm100mean,1);
*/
String dataString = "\tPMS_1:\t"+String(data.pm10_standard)+"\tPMS_2.5:\t"+String(data.pm25_standard)+"\tPMS_10:\t"+String(data.pm100_standard)+"\tPMS_1~:\t"+String(PMS_Pm10mean,1)+"\tPMS_2.5~:\t"+String(PMS_Pm25mean,1)+"\tPMS_10~:\t"+String(PMS_Pm100mean,1);
dataString.replace(".",",");
Serial.println(dataString);
}
void print_PMS_full(){
Serial.println();
Serial.println("---------------------------------------");
Serial.println("Concentration Units (standard)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
Serial.println("---------------------------------------");
Serial.println("Concentration Units (environmental)");
Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
Serial.println("---------------------------------------");
Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);
Serial.println("---------------------------------------");
}
void lcd_print(){
ucg.setColor(0, 0, 0);
ucg.drawBox(270, 0, 80, 119);
ucg.drawBox(270, 121, 80, 240);
ucg.setFont(ucg_font_fub20_hf);
ucg.setColor(255, 255, 255);
ucg.setPrintPos(270,35);
ucg.print(SDS_Pm100f,0);
ucg.setPrintPos(270,90);
ucg.print(SDS_Pm25f,0);
ucg.setPrintPos(270,160);
ucg.print(data.pm100_standard);
ucg.setPrintPos(270,195);
ucg.print(data.pm25_standard);
ucg.setPrintPos(270,230);
ucg.print(data.pm10_standard);
}
void setup() {
Serial.begin(115200);
PMSSerial.begin(9600, SERIAL_8N1, 32, 33);
SDSSerial.begin(9600, SERIAL_8N1, 34, 35);
SDSwakeup();
delay(10);
SDSwakeup();
SDSworkmode(sds_period);
PMSwakeup();
PMSworkmode(0);
PMSwakeup();
ucg.begin(UCG_FONT_MODE_SOLID);
ucg.clearScreen();
ucg.setRotate270();
ucg.setFont(ucg_font_fub14_hf);
ucg.setColor(255, 255, 155);
ucg.setPrintPos(234,35);
ucg.print("10");
ucg.setPrintPos(234,90);
ucg.print("2.5");
ucg.setPrintPos(234,160);
ucg.print("10");
ucg.setPrintPos(234,195);
ucg.print("2.5");
ucg.setPrintPos(234,228);
ucg.print("1.0");
}
void loop() {
now = millis();
if ((now > nextrun)&(!PMSrun)) {
PMSwakeup();
PMSrun = true;
}
if (now > (nextrun + 30000)) {
if (ProcessSerialData()){
math_SDS();
print_SDS();
};
while (PMSSerial.available()) { PMSSerial.read(); };
PMSpassive_mode_read();
delay(1000);
if (readPMSdata(&PMSSerial)) {
math_PMS();
print_PMS();
};
PMSsleep();
PMSrun = false;
lcd_print();
main_graph_sds();
main_graph_pms();
nextrun = now + period*1000 - 30000;
};
delay(10);
}
И все эти мигом скомпилировалось для esp.
Sketch uses 231536 bytes (17%) of program storage space. Maximum is 1310720 bytes.
Global variables use 17868 bytes (5%) of dynamic memory, leaving 309812 bytes for local variables. Maximum is 327680 bytes.
Запускаем — работает!
Программа позволила сравнить два датчика. Оба оказались неплохими, показания обоих релевантны ситуации в квартире. SDS-011 более чутко реагирует на любой взмах тряпки. PMSA003 выдает больше информации и работает практически неслышно. И он компактнее раза в четыре.
Но вернемся к esp. При всех его достоинствах, один недостаток я все-таки обнаружил. Дело в том, что для заливания программы в контроллер требуется нажать на кнопку EN и удерживать ее несколько секунд. При частых сменах кода это начинает подбешивать. Кроме того, блокируется возможность обновления прошивки удаленно. Порывшись в интернете, я нашел простой рецепт избавления от этого недостатка. Надо всего лишь
припаять конденсатор между выводами кнопки EN. Одного микрофарада будет достаточно. У меня получилось.
Действительно, с этого момента прошиваться стал без дополнительных манипуляций. Все, я доволен.
Что в итоге?
Платы однозначно рекомендую к покупке. Программируются так же просто как Ардуино, но нет лишних ограничений, больше встроенных возможностей, больше потенциал интеграции с другими устройствами и масштабируемость. Хороший компромисс между примитивными задачами для Ардуины и совсем уж почти компьютером Raspberry PI.
Вы прочли обзор, который я писал дольше всех остальных моих обзоров.Самая большая трудность — выбрать из огромного моря информации в документации и на форумах то, о чем стоит упомянуть в кратком обзоре. Потому что если писать все, то никакой жизни не хватит, особенно если возможности esp проверять и иллюстрировать.
Основная мысль, которую я хотел донести — это то, что с появлением документации, библиотек и примеров, программировать esp32 стало так же просто, как и ардуино. А возможностей у esp в разы больше.
Самые обсуждаемые обзоры
+73 |
3498
145
|
+31 |
2702
52
|
+51 |
3694
67
|
+39 |
3088
42
|
Одна ESP32 стоит в районе 4$
https://aliexpress.com/item/item/32928267626.html
PS. Датчика температуры там нет, его выпилили в поздних версиях.
А h серия имеет конский ценник
Просто коммент что кит на основе stm32 интереснее звучит странно
Тем более что документациия на esp открыта
Кроме того, далеко не в каждой поделке нужен stm32 ;) Тут вот ниже за атмегу топят)
-реально необходимая физическая мощность (сюда я включаю объёмы памяти, частоту камня, наборы поддерживаемых инструкций, интерфейсы и т.п.)
-привычки и личных предпочтений (если не планируется массовый выпуск устройства, то на разницу в стоимости можно и не обращать внимания в некоторых случаях, особенно если привык к какой-то платформе и лень смотреть, как с другой работать).
Если же речь идёт о чём-то тиражируемом, чему достаточно мощности атмеги, то ясен пень — разница в цене, помноженная на объём, будет очень ощутимой.
Или STM32F103CBT6 за доллар.
А теперь сравните цены на атмеги.
И сравним время когда у вас и там и там замигает ws2812b
На атмегу за 3 минуты скачивается либа и правится только пин.
А под стм32 либ с свободном доступе не так и много и они часто не работают без правок
1. Arduino (ATmega328P) реально раза в три дешевле
2. Есть огромное количество проектов, для которого ресурсов Arduino более чем достаточно (количество ног, объём RAM и ROM, скорость работы, потребляемая энергия)
3. Arduino плата значительно компактнее. Что часто имеет весьма важное значение.
4. ESP32 во много раз прожорливее Arduino. Требования по питанию для ESP32 гораздо серьёзнее. Кроме того, требуется гораздо более высокий уровень программирования для ESP32, чтобы заставить ESP32 бережливее расходовать энергию.
5. У Arduino выводы не обязательно 5v. Есть версия с выводами и 3.3v.
6. Arduino ГОРАЗДО более дружественна по аппаратной части. Для Arduino совершенно не обязательно притягивать к земле не используемые ноги. Arduino реально практические не боится статики и даже низковольтная версия поддерживает гораздо более высокие напряжения без последствий. В общем, ATmega328P по надёжности это практически как автомат Калашникова. А вот всякие ESP8266, ESP32, STM32 часто глючат, дохнут и вообще гораздо более нежные девайсы.
7. Готовых библиотек для ESP32 мало. Если кто-то планируется на ESP32 цеплять какие-то устройства, то нужно сразу готовиться к тому, что для ESP32 придётся для многих внешних устройств писать самостоятельно драйвер/библиотеку. Это, на самом деле, не так уж и сложно. Но это точно требует гораздо более высокий уровень знаний.
В общем для меня вывод один. Автор обзора не слишком хорошо разбирается в программировании, и считает, что чем оптимизировать программу проще купить более мощный компьютер.
А вообще нормальный LDO линейник реально потребляем где-то 0.5mA и меньше. Но никак не 7mA.
Конечно, сделать микро-потребление — непростая задача, но не всегда оно и нужно. Чтобы измерять раз в 15 минут температуру на улице, достаточно Ардуино. А esp — это все-таки для более сложных задач. У меня вот она экраном рулит, два датчика вентиляторами крутят. Тут уж не важно, сколько там esp потребляет.
А то у 328й слишком мало ног, чтоб управлять 6 разрядным, 7 сегментным LED дисплеем.
Quiescent Current AMS1117-3.3 5-11 mA,
PS Выбор контроллера, я считаю, во многом определеется привычкой. Архитектуре AVR уже четверть века. Несомненным преимуществом контроллеров ATmega является проста, существует огромное кол-во обучающего материала, порог вхождения достаточно низкий. А использование абстракций платформы Arduino опускает его практически на детский уровень (в буквальном смысле дети могут писать программы).
STM32 и ESP это чипы другого поколения: более сложные но и более мощные и гибкие, но их уже нужно «уметь правильно готовить». (в этом плане, Arduino, в обмен на простоту, обычно приносит в жертву гибкость и оптимальность решений.) Это конечно не повод вычёркивать ATmeg-и из своих проектов, очень много простых задач, которые успешно ими решаются.
С Arduino, я считаю, можно стартовать, но если тема программирования МК «зацепила», засиживаться на этой платформе не стоит.
Насчёт гибкости утверждение ну очень спорное.
m.habr.com/ru/post/404075/
И у друга такие же часы работают
Вы хоть представляете какой тираж у esp8266?
Почти все умные розетки на этом чипе
Проблема ST-Link давным давно известна и уже много лет как решена, для сложных условий эксплуатации производитель настоятельно рекомендует использовать ISOL версию.
Может нужно дома что то изменить? а не валить на контроллер, и учиться работать с микропроцессорной техникой. Я за свои 25+ работой с электроникой не припомню, что бы что то статикой прибил.
Например rtt.
Кроме того jlink подходит для многих микроконтроллеров
хотя я в итоге на пилюле заменил проц на 072 — уж больно удобно с уартом в одном флаконе…
там все защиты есть и софтом он опознается и обновляется
зачем что-то напаивать на китайский ст линк, если можно купить нормальный 1 раз
Я видел как они меж сеткой эл проводов под током гуляют обходя их и не зацепив ни один!
Хотя заметил, что от прикосновения к проводу может зависнуть. Возможно та самая статика влият. Но для радио это не критично, лишь бы не сгорело.
Ну, и современные игры гораздо более сложные технически, чем предшественники, программистам есть чем заняться кроме оптимизаций.
Это чисто рыночная «фишка»: то, что дешевле — то и уходит в массы.
Дешевле купить 8-ядерный комп, чем оплачивать работу квалифицированного программиста.
Дешевле плодить бесконечные ремейки франшиз, чем творить новые шедевры — кино, песни.
Дешевле замутить тортик из пальмового масла — пусть полгода на прилавке стоит.
И т.д.
но при заказе от 2х штук с али выгоднее будет
Но я толком ничего сам не программировал, все по инструкциям.
Как быстрее что посчитать тут уж самому решать
Не занудствую, просто глаз зацепился… )))
За обзор — спасибо! Присмотрюсь получше. Нужно будет поискать реализацию на ней поделок для Apple Home Kit. Для предыдущей ESP 8266 давно есть.
У меня «трудятся» кастомные пошивки для Sonoff-а в HomeKit отсюда.
Не занудство, просто глаз зацепился. :)
А ещё О2 и водорода. И быстродействие жизненно необходимо.
А на ардуино производительности уже даже для паяльника не хватает для отработки формул.На лодке им делать нечего-утонет.
А теперь поймите и простите меня.
Кстати, вы уверены, что там присутствует датчик Холла (измерение магнитного поля)? Какой смысл в его существовании там, или просто, до кучи напихали, а дальше сами -всё сами?
Ведь они везде бывают
По крайней мере я такие устройства не разрабатывал и вряд ли хочу)
И это при том, что все поняли, речь о ядре АРМ в его бесчисленных исполнениях
void foo (uint8_t *ptr) {
*ptr =;
}
int32_t var;
foo ((uint8_t *)&var + 1);
И на М4 все пройдет на ура, а на M0 — hard fault
И такой код очень часто приходится писать в условиях сетевых протоколов побайтовых и т д.
А стеки задач для, например UCOS — надо выравнивать по 8 байтовой границе, и это тоже особенность архитектуры.И это надо знать, если претендуешь на что-то, особенно давать советы и говорить куда смотреть
Эта особенность свойственна некоторым архитектурам от ARM Holdings, причём не только микроконтроллерным, но и «взрослым».
Такое, кстати, было и у легендарного DEC Alpha.
Google: «Unaligned Memory Access».
ru.aliexpress.com/i/32868241470.html
ru.aliexpress.com/i/32982100489.html
Это как? :)
Я про Atom + PlatformIO. Работает быстро, подсветка кода, автообновление библиотек со своим пакетным менеджером, подсказки, прошивает огромное количество микроконтроллеров, есть дебаг (нужно купить отдельную плату для ESP32).
но вообще да, поражает, вроде есть интернет, куча людей занимается, а всё равно мается с этим дефолтным текстовым редактором
Замаялся я уже по инклюдам елозить.
Эклипс показывает какие то моменты, но не наглядно. И idf не учитывает. Или настроить надо?
Интересует именно прошаренный текстовый редактор.
В качестве сборщика/компилятора мне и msys'a хватает
я пробовал для стм32 и получлось очень не в сторону стм32
компилятор же показывает эти проценты
Сам не в состоянии сделать, убил кучу времени, так и не разобрался :( из железа ( ардуино нано, два датчика ds18b20, микросхема часов ds3231, дисплей oled 1.3, маленькая плата понижающая напряжение).
Буду безумно благодарен, если кто то откликнется, более детально расскажу, что я бы хотел реализовать
+
youtu.be/9D9381jkZrw
= ваш проект
при помощи этого реализуется за 5 минут без строчки кода
насчет олед не знаю, вроде на форуме кто-то делал модули под разные индикаторы
Это замена штатных часов, которые не удается восстановить. Купленный экран замечательно подходит вместо штатных. Я же Вас не заставляю помогать.
Кстати, сейчас удобно несложные вещи через Xod программировать, порог вхождения низкий и результат наглядно видно+отладка.
www.layoutit.com/cn
pingendo.com/
mobirise.com/bootstrap-builder/
P.S. Ваш код какой-то тяжелый, не осилил и 10-ой части (
«Фара́д (русское обозначение: Ф; международное обозначение: F; прежнее название — фара́да) — единица измерения электрической ёмкости в Международной системе единиц (СИ), названная в честь английского физика Майкла Фарадея[1].»
ULP coprocessor programming
Programming ULP coprocessor using C macros
Согласно даташиту, потребление в deep sleep без сопроцессора 10 мкА, с работающим сопроцессором — 150 мкА. Использовать сопроцессор без deep sleep особого смысла нет.
2. Мне понравилось как ребята делали генерацию звука на ESP32. Z не знаю на чем еще малогабаритном сделать такое с поддержкой BT и WiFi…
Автору отдельный плюс за юмор: ...;-)
Если обнаружите решение, то обязательно напишите тут.
Да, и css811 у меня показывал в основном погоду на марсе. Очухивался только если на него чем-то уж совсем химическим дунуть. Тогда мигом зашкаливал. А так — то потихоньку вверх уплывет. Перегрузишь — снова все чисто. То зависнет на одних показателях. Мутный датчик.
Здесь больше ног модуля выведено на штырьки — 38, а у автора — 32.
есть много полезного по измерению качества воздуха.
Вы не ошиблись? Ведь ams1117 — линейный стабилизатор, да и дросселя на плате нет…