• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Баги/глюки/проблемы в каком-то конкретном примере из пакета Sming

Nikita

New member
Добрый день!

Проблема с WDT. Пример Temperature_DS1820. С самим примером все более менее корректно, он выполняется один раз, выбирает первый датчик, выводит температуру с него. В случае если датчиков несколько модифицировал пример так, чтобы выводилась информация не с одного а с нескольких датчиков по таймеру и за один раз. В моем случае имею 3 подключенных датчика. Столкнулся с проблемой, приложение вылетает по wdt reset, уже после чтения данных со второго датчика. Каждая итерация и правда выполняется долго, там задержка на 1 сек перед чтением каждого датчика. В случае, если за одну итерации выполняется чтение только одного датчика, в моем случае 1 - 1, 2 - 2, 3 - 3, 4 -1, и т.д. то проблем нет, все работает. Пожалуйста, подскажите, есть ли варианты решения проблемы с WDT кроме отключения его или разнесения выполнения чтения датчиков DS18B20 в разные итерации?

PS Не уверен, что выбрал правильную тему, прошу модераторов перенести вопрос в правильную, если не прав.
Система: Mac OS, устанавливал по инструкции пару недель назад, после этого обновлял только примеры.

*** Updated ***
Отвечу на свой вопрос сам, помогли расставленные в коде WDT.alive().
 
Последнее редактирование:

Nikita

New member
Пример Pressure_BMP180. Работает, но не понятно, как выбрать другие контакты для I2C? Это актуально для модулей с большим количеством контактов чем у esp-01, в частности, у меня esp-12. По умолчанию, SDA - GPIO2, SCL - GPIO0, но это не прописано в примере.
 

Okadzaki

New member
Пример Pressure_BMP180. Работает, но не понятно, как выбрать другие контакты для I2C? Это актуально для модулей с большим количеством контактов чем у esp-01, в частности, у меня esp-12. По умолчанию, SDA - GPIO2, SCL - GPIO0, но это не прописано в примере.
Wire.pins(SCL,SDA) задаёте, перед Wire.begin()
 

verzi

New member
В примере Temperature_DS1820 если оставить все как есть, то не работает. Или я не успеваю консоль открыть что бы увидеть вывод :(.
Если сделать так
Код:
#include <user_config.h>
#include <SmingCore/SmingCore.h>
#include <Libraries/OneWire/OneWire.h>

#define WORK_PIN 13 // GPIO0

OneWire ds(WORK_PIN);
Timer procTimer;
float heatsinktemp;

void getTemp()
{
        byte i;
        byte present = 0;
        byte type_s;
        byte data[12];
        byte addr[8];

        ds.begin(); // It's required for one-wire initialization!

        if (!ds.search(addr))
        {
            Serial.println("No addresses found.");
            Serial.println();
            ds.reset_search();
            delay(250);
            return;
        }

        Serial.print("Thermometer ROM =");
        for( i = 0; i < 8; i++)
        {
            Serial.write(' ');
            Serial.print(addr[i], HEX);
        }

        if (OneWire::crc8(addr, 7) != addr[7])
        {
          debugf("OneWire CRC is not valid!");
          return;
        }
        Serial.println();

        // the first ROM byte indicates which chip
        switch (addr[0]) {
        case 0x10:
          Serial.println("  Chip = DS18S20");  // or old DS1820
          type_s = 1;
          break;
        case 0x28:
          Serial.println("  Chip = DS18B20");
          type_s = 0;
          break;
        case 0x22:
          Serial.println("  Chip = DS1822");
          type_s = 0;
          break;
        default:
          Serial.println("Device is not a DS18x20 family device.");
          return;
        }

        ds.reset();
        ds.select(addr);
        ds.write(0x44, 1);        // start conversion, with parasite power on at the end

        delay(1000);     // maybe 750ms is enough, maybe not
        // we might do a ds.depower() here, but the reset will take care of it.

        present = ds.reset();
        ds.select(addr);
        ds.write(0xBE);         // Read Scratchpad

        Serial.print("  Data = ");
        Serial.print(present, HEX);
        Serial.print(" ");
        for ( i = 0; i < 9; i++)
        {
            // we need 9 bytes
            data[i] = ds.read();
            Serial.print(data[i], HEX);
            Serial.print(" ");
        }
        Serial.print(" CRC=");
        Serial.print(OneWire::crc8(data, 8), HEX);
        Serial.println();

        // Convert the data to actual temperature
        // because the result is a 16 bit signed integer, it should
        // be stored to an "int16_t" type, which is always 16 bits
        // even when compiled on a 32 bit processor.
        int16_t raw = (data[1] << 8) | data[0];
        if (type_s)
        {
            raw = raw << 3; // 9 bit resolution default
            if (data[7] == 0x10)
            {
              // "count remain" gives full 12 bit resolution
              raw = (raw & 0xFFF0) + 12 - data[6];
            }
        } else {
            byte cfg = (data[4] & 0x60);
            // at lower res, the low bits are undefined, so let's zero them
            if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
            else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
            else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
            //// default is 12 bit resolution, 750 ms conversion time
        }

        heatsinktemp = (float)raw / 16.0;
        Serial.print("  Temperature = ");
        Serial.print(heatsinktemp);
        Serial.println(" Celsius, ");
        return;

}

void init()
{
    Serial.begin(SERIAL_BAUD_RATE); // 115200 by default
    Serial.systemDebugOutput(true); // Allow debug output to serial
    procTimer.initializeMs(2000, getTemp).start();

}
То все ОК. Но терзают меня смутные сомнения по поводу ds.begin(); вроде не место ему тут. А если его оставить в void init(), то вот эта часть срабатывает всегда, т.е. не отследить подключен ли датчик или нет.
Код:
if (!ds.search(addr))
    {
        Serial.println("No addresses found.");
        Serial.println();
        ds.reset_search();
        delay(250);
        return;
    }
Первый скриншот сделан с кодом приведенным выше. Сначала датчик подключен, потом выключен. Все корректно отображается.
1.png
Второй скриншот, когда ds.begin() внутри void init().
2.png
 

verzi

New member
И еще. Попытался объединить два примера. ScreenOLED_SSD1306 и Temperature_DS1820.
Код:
#include <user_config.h>
#include <SmingCore/SmingCore.h>
#include <Libraries/OneWire/OneWire.h>
#include <Libraries/Adafruit_SSD1306/Adafruit_SSD1306.h>

Timer lcdTimer;
Timer tempTimer;
OneWire ds(12);
float heatsinktemp;

/*
* Hardware SPI mode:
* GND      (GND)         GND
* VCC      (VCC)         3.3v
* D0       (CLK)         GPIO14
* D1       (MOSI)        GPIO13
* RES      (RESET)       GPIO16
* DC       (DC)          GPIO0
* CS       (CS)          GPIO2
*/
// For spi oled module
Adafruit_SSD1306 display(0, 16, 2);

//* For I2C mode:
// Default I2C pins 0 and 2. Pin 4 - optional reset
// Adafruit_SSD1306 display(4);

void lcdLoop(){
        display.clearDisplay();
        // text display tests
        display.setTextSize(1);
        display.setTextColor(WHITE);
        display.setCursor(0,0);
        display.println(rand());
        display.display();

}

void tempLoop()
{
    ds.begin(); // It's required for one-wire initialization!

    byte i;
    byte present = 0;
    byte type_s;
    byte data[12];
    byte addr[8];

    if (!ds.search(addr))
    {
        heatsinktemp = -1;
        debugf("No DS18B20 sensor found.");
        ds.reset_search();
        delay(250);
        return;
    }

    // the first ROM byte indicates which chip
    switch (addr[0]) {
    case 0x10:
        type_s = 1; //Chip = DS18S20 or old DS1820
    break;
    case 0x28:
        type_s = 0; //Chip = DS18B20
    break;
    case 0x22:
        type_s = 0; //Chip = DS1822
    break;
    default:
        debugf("Device is not a DS18x20 family device.");
        return;
    }

    ds.reset();
    ds.select(addr);
    ds.write(0x44, 1); // start conversion, with parasite power on at the end

    delay(750); // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.

    present = ds.reset();
    ds.select(addr);
    ds.write(0xBE); // Read Scratchpad

    for ( i = 0; i < 9; i++)
    {
        data[i] = ds.read(); // we need 9 bytes
    }

    // Convert the data to actual temperature
    // because the result is a 16 bit signed integer, it should
    // be stored to an "int16_t" type, which is always 16 bits
    // even when compiled on a 32 bit processor.
    int16_t raw = (data[1] << 8) | data[0];
    if (type_s)
    {
        raw = raw << 3; // 9 bit resolution default
        if (data[7] == 0x10)
        {
            // "count remain" gives full 12 bit resolution
            raw = (raw & 0xFFF0) + 12 - data[6];
        }
    }
    else
    {
        byte cfg = (data[4] & 0x60);
        // at lower res, the low bits are undefined, so let's zero them
        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
        // default is 12 bit resolution, 750 ms conversion time
    }

    heatsinktemp = (float)raw / 16.0;
    Serial.println(heatsinktemp);
}
void init()
{
    Serial.begin(SERIAL_BAUD_RATE); // 115200 by default
    Serial.systemDebugOutput(true); // Allow debug output to serial

    display.begin(SSD1306_SWITCHCAPVCC);

    display.display();
    delay(2000);

    // Clear the buffer.
    display.clearDisplay();

    // draw a circle, 10 pixel radius
    display.fillCircle(display.width()/2, display.height()/2, 10, WHITE);
    display.display();
    delay(2000);
    display.clearDisplay();

    // text display tests
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,0);
    display.println("Sming Framework");
    display.setTextColor(BLACK, WHITE); // 'inverted' text
    display.setCursor(104, 7);
    display.println("v1.0");
    //----
    display.setTextColor(WHITE);
    display.println("Let's do smart things");
    display.setTextSize(3);
    display.print("IoT");
    display.display();

    delay(2000);
    lcdTimer.initializeMs(2000, lcdLoop).start();
    tempTimer.initializeMs(1000, tempLoop).start();
}
По отдельности и датчик температуры и дисплей работают корректно. Прямо в этом коде. Если закомментировать одну из последних строчек которые запускают таймер дисплея или датчика. А вот вместе нет. Начальная заставка (та что про "Let's do smart things") на дисплее появляется и все на этом, дисплей не обновляется. При этом даже через последовательный порт было не подцепиться, при попытке законектиться esp вис. Только что скачал последний sming, виснуть перестал. В консоли никаких ошибок, только значения температуры. Пробовал и SPI и I2C дисплеи (разные). Sming как я уже писал последний, UDK v2.0.2. Пробовал запускать другие примеры работы с датчиком температуры (из ардуино), не работают. В общем, моих знаний явно не хватает для того что бы разобраться что тут не так.
 

JustACat

Moderator
Команда форума
verzi, а если вызвать lcdLoop прямо из tempLoop (в конце нее), без второго таймера отдельного?
Может просто они друг другу мешают, т.к. у вас у одного таймера 1 секунда, у второго 2 секунды - кратные интервалы получаются... (это догадки, я вообще без понятия, как оно внутри работает, если честно)
 

verzi

New member
Сами по себе несколько таймеров работают без проблем. Проблема в том, что после того как запускается опрос датчика температуры, дисплей перестает обновляться. Ваш совет проверил, не работает.
 

anakod

Moderator
Команда форума
Пока железа под рукой нет, но попробуйте сменить номера пинов - для I2C вызовом Wire.pins(..) или для DS18B20.
 

Def461

New member
Не получается отловить, что умудряется сбрасывать состояние GPIO

При инициализации 1wire или сбросе шины - получаю полный сброс регистров GPIO, любых.
Т.е. имеем лог."0" на GPIO, провел опрос датчиков - бац! GPIO сброшены.

В какую сторону копать?

P.S. Судя по всему у предыдущего оратора - тот же баг: после вызова 1wire отваливаются настроенные регистры у других протоколов.
 
Последнее редактирование:

Nikita

New member
При инициализации 1wire или сбросе шины - получаю полный сброс регистров GPIO, любых.
Подтверждаю, при инициализации 1wire пропадает соединение с MQTT и больше не поднимается. После исключения из проекта кода относящееся к 1wire, опрос dht22 и bmp180 и публикация их результатов через MQTT работает сутками без проблем и сбоев.
 

Nikita

New member
Еще одна проблема. Пробую использовать функцию system_get_vdd33() для чтения напряжения питания на esp, каждый вызов возвращает результат 1023. Если использую не ту функцию, пожалуйста, напишите корректную.
 

pvvx

Активный участник сообщества
Еще одна проблема. Пробую использовать функцию system_get_vdd33() для чтения напряжения питания на esp, каждый вызов возвращает результат 1023. Если использую не ту функцию, пожалуйста, напишите корректную.
2C-ESP8266__SDK__Programming Guide__EN_v1.1.2.pdf:
Function: system_get_vdd33
Measure the power voltage of VDD3P3 pin 3 and 4, unit:1/1024 V
Note:
• system_get_vdd33 can only be called when TOUT pin is suspended
• The 107th byte in esp_init_data_default.bin(0〜~127byte)is named as “vdd33_const“ , when TOUT pin is suspended vdd33_const must be set as 0xFF, that is 255.
По русски - в зависимости как установлена данная константа (107 байт в esp_init_data_default.bin), то работает или system_get_vdd33() или system_adc_read().
На сегодня, одновременно использовать в одном приложении чтение ADC и VDD можно только в моей Web свалке.
vdd_adc.gif rf_data3.gif adc_vdd.gif
Пробуйте использовать uint32 readvdd33(void) вместо system_get_vdd33() и сами пересчитывайте (калибруйте) коэффициент перевода в Вольты - он зависит от номинала резистора припаянного к ноге TOUT и от типа модуля (у ESP-01 вывод TOUT никуда не подключен)... Процесс измерения VDD в чипе происходит путем подачи на ножку TOUT тока внутренним ключом и замером полученного напряжения на ней.
 
Последнее редактирование:

Def461

New member
Таймер, установленный на 600*1000 ms интервал, срабатывает не раз в 10 минут, а раз в шесть.
Вроде ограничения для таймера быть не должно :(
Таймер на 120 секунд взводится идеально, на 600 - некорректно.
Код:
logserversTSTimer.initializeMs(600*1000, logserversTSUpdate).start();
 
Последнее редактирование:

FGX

Member
Таймер, установленный на 600*1000 ms интервал, срабатывает не раз в 10 минут, а раз в шесть.
Вроде ограничения для таймера быть не должно :(
Таймер на 120 секунд взводится идеально, на 600 - некорректно.
Код:
logserversTSTimer.initializeMs(600*1000, logserversTSUpdate).start();
Так сделайте таймер на 1 минуту, в нем заведите переменную и инкрементируйте ее при каждом вызове, как дойдет до 10 делайте что хотели и сбросьте ее в 0.. Зачем заводить кучу таймеров с разным временем, можно пару завести на 1с и 1 минуту, например, и делать все что хотели в них смотря на доп переменные.
 

Def461

New member
Так сделайте таймер на 1 минуту, в нем заведите переменную и инкрементируйте ее при каждом вызове, как дойдет до 10 делайте что хотели и сбросьте ее в 0.. Зачем заводить кучу таймеров с разным временем, можно пару завести на 1с и 1 минуту, например, и делать все что хотели в них смотря на доп переменные.
Как решать вопрос при одном таймере на всю систему - я знаю.
Не вижу смысла изобретать костыли, если framework подразумевает множественное количество таймеров штатными средствами.

Кстати, вопрос был не в нескольких таймерах, а в том, что период в 120 секунд отрабатывает корректно, а этот же таймер на 600 - нет.
 

FGX

Member
Кстати, вопрос был не в нескольких таймерах, а в том, что период в 120 секунд отрабатывает корректно, а этот же таймер на 600 - нет.
Я думаю, что таймер нельзя задавать на бесконечно большой интервал, на 1 час, например, может просто кончился его предел. Я поэтому и предложил получить 10 минут из таймера на 1 минуту, тем более проверить переменную на мой взгляд проще для системы в целом чем делать кучу таймеров.
 

Def461

New member
В примерах есть гораздо бОльшие интервалы, нежели 10 минут.
Потому я и задал вопрос, что изменилось в коде библиотек, что таймер может не работать на разумном интервале.
 

pvvx

Активный участник сообщества
@anakod не помогает это с WDT в новых SDK https://github.com/anakod/Sming/blob/master/Sming/system/flashmem.c#L100
Стирание в spiffs на 16Mбайт Flash делать в цикле нельзя. Отключается WiFi и т.д. Делал стирание flash блоками по 64к. Без остановки WDT pp_soft_wdt_stop() и рестарта pp_soft_wdt_restart() не катит. Сильно не вдавался, но и остановка не решает проблемы вылета цикла по WDT. Требуется обновление вызова pp_soft_wdt_stop() через некоторое время...
В общем spiffs не подходит к концепции оф. SDK. Надо включать второй процесс по типу RTOS, но простой - всего 2 - SDK и всё остальное :)
PS: NodeMCU это Ад. не берите от туда ничего - смотреть можно, но копировать - нет.
 
Последнее редактирование:

Def461

New member
Еcть продолжение цирка с 1wire
Библиотекой затрагивается именно GPIO14, даже если работа с далласами назначена на другой порт.

Т.е. сегодня перекомпилил работу реле с GPIO14 на GPIO16 - при опросе 18В20 GPIO16 не затрагивается
А вот I2C на "стандартных" GPIO12/14 перестает норально работать ровно после инициализации комплектной библиотеки 1Wire.

UPD: "Обошел" глюк костылём корявой работы с регистрами.
Обнаружил второй интересный глюк: если модуль рестартует после прошивки с зажатым "ресетом", то I2C библиотека не может нормально "дергать" GPIO.
 
Последнее редактирование:
Сверху Снизу