• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

OTA и прерывания

Melandr

Member
Добрый вечер!
Использую библиотеку ArduinoOTA в проекте и прерывания внешнее по входу, и по hw_timer. И прерывается обновление по WiFi. Как определить из-за чего происходит сбой обновления по воздуху?
PS: закомментировал
Код:
    hw_timer_init(NMI_SOURCE, 0);
    hw_timer_set_func(dimTimerISR);
    hw_timer_arm(tarBrightness);

    attachInterrupt(zcPin, zcDetectISR, RISING);*/
и сбои прекратились
 

Melandr

Member
Точнее закомментировал вот эту часть
Код:
    hw_timer_init(NMI_SOURCE, 0);
    hw_timer_set_func(dimTimerISR);
    hw_timer_arm(tarBrightness);
 

Melandr

Member
Доброй ночи! Хотел поинтересоваться у гуру ESP8266. Я конечно понимаю, что готовить их не умею, но все-таки непонятно почему при использовании прерывания аппаратного таймера hw_timer ломается работа с ArduinoOTA? Подключил к проекту библиотеку RemoteDebug и стало удобней смотреть, что твориться в программе. Но в связи с ограниченным количеством пинов у ESP-01 приходится использовать пин 2 для отслеживания перехода через 0, и, соответственно, пропадает возможность нормально загружать прошивку по UART, приходится выкручиваться через OTA. Пробовал загрузку по http, тоже самое, при загрузке скетча с использованием hw_timer, следующее обновление прошивки прерывается с ошибкой. Подскажите куда копать?
 

Melandr

Member
Добрый вечер!
Вот код
Код:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DNSServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include "html_pages.h"

#include "ets_sys.h"
#include "gpio.h"
#include "user_interface.h"
#include "hw_timer.h"

#include "RemoteDebug.h"

#define USE_SERIAL Serial

#define GPIO_OUT_W1TS (*(volatile uint32_t *)0x60000304)
#define GPIO_OUT_W1TC (*(volatile uint32_t *)0x60000308)

#define TIME_PULSE 60
#define MAX_DIMMING_VALUE 255
#define MIN_DIMMING_VALUE 0

#define HOST_NAME "remotedebug"
#define USE_MDNS true

// WIFI SETTINGS
const char* ssid = "ASUS";
const char* password = "gCU8YNZs";

// PIN SETTINGS
const byte zcPin = 1;
const byte outPin = 2;

byte fade = 0;            //переменная плавного затухания
byte state = 0;           //состояние объекта: 0 - выключен, 1 - включен
byte stateTriac = 0;      //состояние симистора
byte tarBrightness = 255; //требуемая яркость
byte curBrightness = 0;   //текущая яркость
byte zcState = 0;         // 0 = ready; 1 = processing;
int dimDelay = 0;

volatile uint32_t countZC_ISR = 0;
volatile uint32_t countSysTimer = 0;

// Time
uint32_t mLastTime = 0;
uint32_t mTimeSeconds = 0;

void ICACHE_RAM_ATTR zcDetectISR();
void ICACHE_RAM_ATTR dimTimerISR();

ESP8266WebServer server(80);
WiFiClient espClient;
RemoteDebug Debug;

void setup(void) {
  gpio_init();

  PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1);
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);

  // включаем соответствующие пины для использования в качестве входа и выхода
  gpio_output_set(0, 0, 0, (1 << zcPin));
  gpio_output_set(0, 0, (1 << outPin), 0);

  GPIO_OUT_W1TC = BIT(outPin);

  USE_SERIAL.begin(230400);
  USE_SERIAL.println("");

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    USE_SERIAL.print(".");
  }

  // Регистрируем host name в WiFi и mDNS
  String hostNameWifi = HOST_NAME;
  hostNameWifi.concat(".local");

  WiFi.hostname(hostNameWifi);

  initializeOTA();

#ifdef USE_MDNS  // Use the MDNS ?

  if (MDNS.begin(HOST_NAME)) {
    Serial.print("* MDNS responder started. Hostname -> ");
    Serial.println(HOST_NAME);
  }

  MDNS.addService("telnet", "tcp", 23);

#endif

  // Инициализируем RemoteDebug
  Debug.begin(HOST_NAME); // Инициализируем WiFi server

  Debug.setResetCmdEnabled(true); // Активируем команду перезапуска

  Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
  Debug.showColors(true); // Цвета

  USE_SERIAL.print("\nConnected: ");
  USE_SERIAL.println(WiFi.localIP());

  server.on("/", []() {
    // аргументы сервера для переменной состояния
    if (server.arg("s") != "") {
      if (server.arg("s") == "1" || server.arg("s") == "on" || server.arg("s") == "true") {
        updateState(1);
      }
      else if (server.arg("s") == "t") {
        updateState(!state);
      }
      else {
        updateState(0);
      }
    }

    // аргументы сервера для переменной яркости
    if (server.arg("b") != "") {
      updateBrightness((byte) server.arg("b").toInt());
    }

    // аргументы сервера для переменной плавного включения и выключения
    if (server.arg("f") != "") {
      if (server.arg("f") == "1" || server.arg("f") == "on" || server.arg("f") == "true") {
        updateFade(1);
      }
      else if (server.arg("f") == "t") {
        updateFade(!fade);
      }
      else {
        updateFade(0);
      }
    }

    // json output
    String s = "{\n   \"s\":";
    s += state;
    s += ",\n   \"b\":";
    s += tarBrightness;
    s += ",\n   \"f\":";
    s += fade;
    s += "\n}";

    server.send(200, "text/plain", s);
  });


  server.begin();

  Serial.println("HTTP server: Started");
  /*
      hw_timer_init(NMI_SOURCE, 0);
      hw_timer_set_func(dimTimerISR);
      hw_timer_arm(tarBrightness);
  */
  attachInterrupt(zcPin, zcDetectISR, RISING);
}

void loop(void)
{
  ArduinoOTA.handle();

  // Time of begin of this loop
  uint32_t timeBeginLoop = millis();

  // Каждую секунду
  if ((millis() - mLastTime) >= 1000) {

    // Time
    mLastTime = millis();
    mTimeSeconds++;

    // Debug the time (verbose level)

    //    debugV("* Time: %u seconds (VERBOSE)", mTimeSeconds);

    if (mTimeSeconds % 5 == 0) { // Каждые 5 секунд

      debugV("dimDelay = %u", dimDelay);
      debugV("curBrightness = %u", curBrightness);
      debugV("tarBrightness = %u", tarBrightness);
      debugV("state = %u", state);
      debugV("countZC_ISR = %u", countZC_ISR);
      debugV("countSysTimer = %u", countSysTimer);
    }
  }

  dimDelay = 38.9 * (MAX_DIMMING_VALUE - curBrightness);

  // handle http:
  server.handleClient();

  // RemoteDebug handle
  Debug.handle();

  // Show a debug - warning if time of these loop is over 50 (info) or 100 ms (warning)
  uint32_t time = (millis() - timeBeginLoop);

  if (time > 100) {
    debugI("* Time elapsed for the loop: %u ms.", time);
  } else if (time > 200) {
    debugW("* Time elapsed for the loop: %u ms.", time);
  }
}

void initializeOTA() {

  hw_timer_set_func(0);

  // TODO: option to authentication (password)

  ArduinoOTA.onStart([]() {
    Serial.println("* OTA: Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\n*OTA: End");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("*OTA: Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  // Begin
  ArduinoOTA.begin();

}

//функция обновления состояния
void updateState(bool newState) {
  state = newState;

}
//функция обновления плавного включения
void updateFade(bool newFade) {
  fade = newFade;

}
//функция обновления яркости
void updateBrightness(int newBrightness) {
  tarBrightness = newBrightness;

}
//обработчик прерывания системного таймера
void ICACHE_RAM_ATTR dimTimerISR() {

  if (state == 1) {
    curBrightness = tarBrightness;
  }
  else {
    curBrightness = 0;
  }

  if (curBrightness == 0) {
    state = 0;
  }
  else if (curBrightness == 255) {
    state = 1;
  }
  zcState = 0;

  if (stateTriac == 0) {
    //переводим пин в высокое состояние
    GPIO_OUT_W1TS = BIT(outPin);
    stateTriac = 1;
    hw_timer_arm(TIME_PULSE);
  }
  else if (stateTriac == 1) {
    // переводим пин в низкое состояние
    GPIO_OUT_W1TC = BIT(outPin);
    stateTriac = 0;
    //    hw_timer_set_func(0);
    //    hw_timer_arm(0);
  }
  countSysTimer++;
}
//обработчик внешнего прерывания при переходе сетевого напряжения через "0"
void ICACHE_RAM_ATTR zcDetectISR() {

  //  hw_timer_set_func(dimTimerISR);

  if (zcState == 0) {
    zcState = 1;

    if (curBrightness < 255 && curBrightness > 0) {
      GPIO_OUT_W1TC = BIT(outPin);
      stateTriac = 0;

      dimDelay = 39 * (MAX_DIMMING_VALUE - curBrightness);
      hw_timer_arm(dimDelay);
    }
  }
  countZC_ISR++;
}
Но регулировки не получается

Но в этом коде почему-то не срабатывает прерывание по переходу через "0", скорее всего неправильно инициализирую вход
 

Melandr

Member
Позже залил вот такой код
Код:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "RemoteDebug.h"

// Instance of RemoteDebug
RemoteDebug Debug;

//#define CAYENNE_PRINT Serial    // Comment this out to disable prints and save space
#include <CayenneMQTTESP8266.h>                                     // Include library file for MQTT

#define HOST_NAME "remotedebug"

#define TRIAC_PIN     2         //GPIO2         управление симистором
#define ZC_PIN        1         //GPIO1 - TXD   детектор перехода через "0"
#define BUTTON_PIN    3         //GPIO3 - RXD   кнопка

void ICACHE_RAM_ATTR zero_crosss_int();

#ifndef STASSID
#define STASSID "ASUS"
#define STAPSK  "gCU8YNZs"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

char username[] = "60267f30-21f2-11eb-8779-7d56e82df461";           // Your MQTT cayenne username
char Password[] = "a9631607be6b7979c4c117bbdadc76683b9dbf97";       // Your MQTT cayenne Password
char clientID[] = "bf444650-21fc-11eb-883c-638d8ce4c23d";           // Your MQTT cayenne clientID

volatile int DIMMING_VALUES = 0;
volatile int DIMMING_TIME = 0;
int BUTTON = 0;
int lightStatus = 0;

volatile unsigned long countZeroCross = 0;
unsigned long lastMillis = 0;

void setup() {
  Serial.begin(230400);

  //настраиваем пины ESP в зависимости от назначения
  pinMode(TRIAC_PIN, OUTPUT);                                         // Установите контакт нагрузки переменного тока как выход
  digitalWrite(TRIAC_PIN, HIGH);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(ZC_PIN, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(ZC_PIN), zero_crosss_int, RISING);   // Choose the zero cross interrupt egde selection

  Cayenne.begin(username, Password, clientID, ssid, password);               // Setup cayenne server for MQTT protocol

  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(1000);
    ESP.restart();
  }

  initializeOTA();

  // Initialize RemoteDebug
  Debug.begin(HOST_NAME); // Initialize the WiFi server
  Debug.setResetCmdEnabled(true); // Enable the reset command
  Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
  Debug.showColors(true); // Colors
}

void loop() {

  ArduinoOTA.handle();

  Cayenne.loop();

  if (millis() - lastMillis > 5000) {
    lastMillis = millis();

    debugV("DIMMING_VALUES = %u", DIMMING_VALUES);
    debugV("DIMMING_TIME = %u", DIMMING_TIME);
    debugV("countZeroCross = %u", countZeroCross);
    debugV("uptime = %u", millis());
    /*   debugV("countZC_ISR = %u", countZC_ISR);
       debugV("countSysTimer = %u", countSysTimer);*/
  }
  BUTTON = digitalRead(BUTTON_PIN);

  // RemoteDebug handle
  Debug.handle();
}

//функция инициализаци прошивки по "воздуху"
void initializeOTA() {

  ArduinoOTA.onStart([]() {
    Serial.println("* OTA: Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\n*OTA: End");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("*OTA: Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  // Begin
  ArduinoOTA.begin();

}

void ICACHE_RAM_ATTR zero_crosss_int()                   //функция, которая запускается при пересечении нуля, чтобы изменить яркость света
{
  DIMMING_TIME = (90 * DIMMING_VALUES);  // For 60Hz =>65
  delayMicroseconds(DIMMING_TIME);       // Wait till firing the TRIAC
  digitalWrite(TRIAC_PIN, HIGH);            // Fire the TRIAC
  delayMicroseconds(20);                 // triac On propogation delay
  // (for 60Hz use 8.33) Some Triacs need a longer period
  digitalWrite(TRIAC_PIN, LOW);             // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
  countZeroCross++;
}

CAYENNE_OUT_DEFAULT()
{
  // Запишите данные в Cayenne здесь. В этом примере просто отправляется текущее время безотказной работы в миллисекундах на виртуальном канале 0.
  Cayenne.virtualWrite(V0, millis());
  Cayenne.virtualWrite(V1, BUTTON);
  Cayenne.virtualWrite(V2, countZeroCross);
}

CAYENNE_IN(1)
{
  int Dimm_Val = getValue.asInt();
  DIMMING_VALUES = (100 - Dimm_Val);
}

CAYENNE_IN(2)
{
  digitalWrite(TRIAC_PIN, !getValue.asInt());  // to get the value from the website
}
 

Melandr

Member
В принципе регулировка работает, но мерцание довольно сильное.
Попробовал переделать на прямое управление gpio
Код:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "RemoteDebug.h"

#include "gpio.h"

// Instance of RemoteDebug
RemoteDebug Debug;

//#define CAYENNE_PRINT Serial    // Comment this out to disable prints and save space
#include <CayenneMQTTESP8266.h>                                     // Include library file for MQTT

#define GPIO_OUT_W1TS (*(volatile uint32_t *)0x60000304)
#define GPIO_OUT_W1TC (*(volatile uint32_t *)0x60000308)

#define HOST_NAME "remotedebug"

#define TRIAC_PIN     2         //GPIO2         управление симистором
#define ZC_PIN        1         //GPIO1 - TXD   детектор перехода через "0"
#define BUTTON_PIN    3         //GPIO3 - RXD   кнопка

void ICACHE_RAM_ATTR zero_crosss_int();

#ifndef STASSID
#define STASSID "ASUS"
#define STAPSK  "gCU8YNZs"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

char username[] = "60267f30-21f2-11eb-8779-7d56e82df461";           // Your MQTT cayenne username
char Password[] = "a9631607be6b7979c4c117bbdadc76683b9dbf97";       // Your MQTT cayenne Password
char clientID[] = "bf444650-21fc-11eb-883c-638d8ce4c23d";           // Your MQTT cayenne clientID

volatile int DIMMING_VALUES = 0;
volatile int DIMMING_TIME = 0;
int BUTTON = 0;
byte lightState = 0;

volatile unsigned long countZeroCross = 0;
unsigned long lastMillis = 0;

void setup() {
  Serial.begin(230400);

  gpio_init();

  PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1);
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3);
  // включаем соответствующие пины для использования в качестве входа и выхода
  gpio_output_set(0, 0, 0, (1 << ZC_PIN));
  gpio_output_set(0, (1 << TRIAC_PIN), (1 << TRIAC_PIN), 0);
  gpio_output_set(0, 0, 0, (1 << BUTTON_PIN));

  attachInterrupt(digitalPinToInterrupt(ZC_PIN), zero_crosss_int, RISING);   // Choose the zero cross interrupt egde selection

  Cayenne.begin(username, Password, clientID, ssid, password);               // Setup cayenne server for MQTT protocol

  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(1000);
    ESP.restart();
  }

  initializeOTA();

  // Initialize RemoteDebug
  Debug.begin(HOST_NAME); // Initialize the WiFi server
  Debug.setResetCmdEnabled(true); // Enable the reset command
  Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
  Debug.showColors(true); // Colors
}

void loop() {

  ArduinoOTA.handle();

  Cayenne.loop();

  if (millis() - lastMillis > 5000) {
    lastMillis = millis();

    debugV("DIMMING_VALUES = %u", DIMMING_VALUES);
    debugV("DIMMING_TIME = %u", DIMMING_TIME);
    debugV("countZeroCross = %u", countZeroCross);
    debugV("uptime = %u", millis());
    /*   debugV("countZC_ISR = %u", countZC_ISR);
       debugV("countSysTimer = %u", countSysTimer);*/
  }
  BUTTON = digitalRead(BUTTON_PIN);

  // RemoteDebug handle
  Debug.handle();
}

//функция инициализаци прошивки по "воздуху"
void initializeOTA() {

  ArduinoOTA.onStart([]() {
    Serial.println("* OTA: Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\n*OTA: End");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("*OTA: Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  // Begin
  ArduinoOTA.begin();

}

void ICACHE_RAM_ATTR zero_crosss_int()                   //функция, которая запускается при пересечении нуля, чтобы изменить яркость света
{
  DIMMING_TIME = (90 * DIMMING_VALUES);  // For 60Hz =>65
  delayMicroseconds(DIMMING_TIME);       // Wait till firing the TRIAC
  GPIO_OUT_W1TS = BIT(TRIAC_PIN);            // Fire the TRIAC
  delayMicroseconds(20);                 // triac On propogation delay
  // (for 60Hz use 8.33) Some Triacs need a longer period
  GPIO_OUT_W1TC = BIT(TRIAC_PIN);             // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
  countZeroCross++;
}

CAYENNE_OUT_DEFAULT()
{
  // Запишите данные в Cayenne здесь. В этом примере просто отправляется текущее время безотказной работы в миллисекундах на виртуальном канале 0.
  Cayenne.virtualWrite(V0, millis());
  Cayenne.virtualWrite(V1, BUTTON);
  Cayenne.virtualWrite(V2, countZeroCross);
}

CAYENNE_IN(1)
{
  int Dimm_Val = getValue.asInt();
  DIMMING_VALUES = (100 - Dimm_Val);
}

CAYENNE_IN(2)
{
  lightState != getValue.asInt();
  if (lightState == 1) {
    GPIO_OUT_W1TS = BIT(TRIAC_PIN);
  }
  else {
    GPIO_OUT_W1TC = BIT(TRIAC_PIN);
  }
}
 

pvvx

Активный участник сообщества
В принципе регулировка работает, но мерцание довольно сильное.
У вас Arduino. Следовательно С++.
А C++ запрещает прерывания на все запросы памяти.
Бросьте эту бяку!
Вам же давали пример с NMI прерыванием...
 

enjoynering

Well-known member
В тело самого прерывания книжки советуют много не пихать, а ограничиться только bool переменной. А уже в главном цикле по состоянию этой bool деллать все что вам надо.
 

Melandr

Member
У вас Arduino. Следовательно С++.
А C++ запрещает прерывания на все запросы памяти.
Бросьте эту бяку!
Вам же давали пример с NMI прерыванием...
pvvx, спасибо за пример, начал хоть что-то понимать с Вашим примером, но все равно вылазят новые грабли. Ваша же вэб-свалка работает. а я не собираюсь разрабатывать устройство для промышленного применения. Просто подкупает возможность управления по WiFi, чтоб не заморачиваться с интерфейсом пользователя. Да и если посмотреть, довольно много на ESP сделали, работает.
В тело самого прерывания книжки советуют много не пихать, а ограничиться только bool переменной. А уже в главном цикле по состоянию этой bool деллать все что вам надо.
Перепишу обработчики прерываний на использование флагов.
Вот код ниже, в принципе он работает, но есть мерцание. Попробую по совету pvvx сначала перевести управление gpio на регистры, а потом использовать прерывание. Но есть моменты, допустим как в обработчике прерывания от аппаратного таймера отключить его до следующего обработчика внешнего прерывания по входу отслеживания "0"
Код:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "RemoteDebug.h"

// Instance of RemoteDebug
RemoteDebug Debug;

//#define CAYENNE_PRINT Serial    // Comment this out to disable prints and save space
#include <CayenneMQTTESP8266.h>                                     // Include library file for MQTT

#define HOST_NAME "remotedebug"

#define TRIAC_PIN     2         //GPIO2         управление симистором
#define ZC_PIN        1         //GPIO1 - TXD   детектор перехода через "0"
#define BUTTON_PIN    3         //GPIO3 - RXD   кнопка

void ICACHE_RAM_ATTR zero_crosss_int();

#ifndef STASSID
#define STASSID "ASUS"
#define STAPSK  "gCU8YNZs"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

char username[] = "60267f30-21f2-11eb-8779-7d56e82df461";           // Your MQTT cayenne username
char Password[] = "a9631607be6b7979c4c117bbdadc76683b9dbf97";       // Your MQTT cayenne Password
char clientID[] = "bf444650-21fc-11eb-883c-638d8ce4c23d";           // Your MQTT cayenne clientID

volatile int DIMMING_VALUES = 0;
volatile int DIMMING_TIME = 0;
int BUTTON = 0;
int lightStatus = 0;

volatile unsigned long countZeroCross = 0;
unsigned long lastMillis = 0;

void setup() {
  Serial.begin(230400);

  //настраиваем пины ESP в зависимости от назначения
  pinMode(TRIAC_PIN, OUTPUT);                                         // Установите контакт нагрузки переменного тока как выход
  digitalWrite(TRIAC_PIN, HIGH);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(ZC_PIN, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(ZC_PIN), zero_crosss_int, RISING);   // Choose the zero cross interrupt egde selection

  Cayenne.begin(username, Password, clientID, ssid, password);               // Setup cayenne server for MQTT protocol

  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(500);
    ESP.restart();
  }

  initializeOTA();

  // Initialize RemoteDebug
  Debug.begin(HOST_NAME); // Initialize the WiFi server
  Debug.setResetCmdEnabled(true); // Enable the reset command
  Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
  Debug.showColors(true); // Colors
}

void loop() {

  ArduinoOTA.handle();

  Cayenne.loop();

  if (millis() - lastMillis > 5000) {
    lastMillis = millis();

    debugV("DIMMING_VALUES = %u", DIMMING_VALUES);
    debugV("DIMMING_TIME = %u", DIMMING_TIME);
    debugV("countZeroCross = %u", countZeroCross);
    debugV("uptime = %u", millis());
    /*   debugV("countZC_ISR = %u", countZC_ISR);
       debugV("countSysTimer = %u", countSysTimer);*/
  }
  BUTTON = digitalRead(BUTTON_PIN);

  // RemoteDebug handle
  Debug.handle();
}

//функция инициализаци прошивки по "воздуху"
void initializeOTA() {

  ArduinoOTA.onStart([]() {
    Serial.println("* OTA: Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\n*OTA: End");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("*OTA: Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  // Begin
  ArduinoOTA.begin();

}

void ICACHE_RAM_ATTR zero_crosss_int()                   //функция, которая запускается при пересечении нуля, чтобы изменить яркость света
{
  DIMMING_TIME = (90 * DIMMING_VALUES);  // For 60Hz =>65
  delayMicroseconds(DIMMING_TIME);       // Wait till firing the TRIAC
  digitalWrite(TRIAC_PIN, HIGH);            // Fire the TRIAC
  delayMicroseconds(30);                 // triac On propogation delay
  // (for 60Hz use 8.33) Some Triacs need a longer period
  digitalWrite(TRIAC_PIN, LOW);             // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
  countZeroCross++;
}

CAYENNE_OUT_DEFAULT()
{
  // Запишите данные в Cayenne здесь. В этом примере просто отправляется текущее время безотказной работы в миллисекундах на виртуальном канале 0.
  Cayenne.virtualWrite(V0, millis()/1000);
  Cayenne.virtualWrite(V1, BUTTON);
  Cayenne.virtualWrite(V2, countZeroCross);
}

CAYENNE_IN(1)
{
  int Dimm_Val = getValue.asInt();
  DIMMING_VALUES = (100 - Dimm_Val);
}

CAYENNE_IN(2)
{
  digitalWrite(TRIAC_PIN, !getValue.asInt());  // to get the value from the website
}
 

pvvx

Активный участник сообщества
но все равно вылазят новые грабли. Ваша же вэб-свалка работает. а я не собираюсь разрабатывать устройство для промышленного применения. Просто подкупает возможность управления по WiFi, чтоб не заморачиваться с интерфейсом пользователя. Да и если посмотреть, довольно много на ESP сделали, работает.
2 шт. ESP8266. Писал уже вам и это. По другому не сделать, т.к. у вас худший из всех наборов вариант - Arduino и софт диммер.
И ничего никто на ESP так и не сделал. И оно не работает, а с ним работают (играются) - как с Тамагочи. Если бы на ESP что-то работало или заработало, тогда не было бы никаких форумов, т.к. что обсуждать в рабочем устройстве?
 

Melandr

Member
Может я что-то неправильно делаю. вот есть код такой
Код:
void setup() {
  pinMode(TRIAC_PIN, OUTPUT);                                         
  digitalWrite(TRIAC_PIN, HIGH);
  ....
  }
 
  void ICACHE_RAM_ATTR zero_crosss_int()                   //функция, которая запускается при пересечении нуля, чтобы изменить яркость света
{
  DIMMING_TIME = (90 * DIMMING_VALUES);  // For 60Hz =>65
  delayMicroseconds(DIMMING_TIME);       // Wait till firing the TRIAC
  digitalWrite(TRIAC_PIN, HIGH);            // Fire the TRIAC
  delayMicroseconds(30);                 // triac On propogation delay
  // (for 60Hz use 8.33) Some Triacs need a longer period
  digitalWrite(TRIAC_PIN, LOW);             // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
  countZeroCross++;
}
Я заменяю на
Код:
void setup() {

  gpio_init();
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  gpio_output_set(0, 0, (1 << TRIAC_PIN), 0);
  GPIO_OUT_W1TC = BIT(TRIAC_PIN);
  .....
  }
 
  void ICACHE_RAM_ATTR zero_crosss_int()                   //функция, которая запускается при пересечении нуля, чтобы изменить яркость света
{
  DIMMING_TIME = (90 * DIMMING_VALUES);  // For 60Hz =>65
  delayMicroseconds(DIMMING_TIME);       // Wait till firing the TRIAC
     GPIO_OUT_W1TS = BIT(TRIAC_PIN);
  delayMicroseconds(30);                 // triac On propogation delay
  // (for 60Hz use 8.33) Some Triacs need a longer period
      GPIO_OUT_W1TC = BIT(TRIAC_PIN);
  countZeroCross++;
}
И он перестает работать
 

pvvx

Активный участник сообщества
Но есть моменты, допустим как в обработчике прерывания от аппаратного таймера отключить его до следующего обработчика внешнего прерывания по входу отслеживания "0"
В выданном вам коде все эти варианты предусмотрены несмотря на краткость.
Но есть мелкие "но" связанные с внешними процедурами, которые разрешают прерывания в прерывании :), а аппаратная платформа ESP с INT по GPIO не умеет запрещать повторное вхождение. От это при большой частоте переполнение стека. Бяка и ещё раз бяка эта ESP...
И то, что вы там пытаетесь переписать/вписать что-то в Arduino вам никак не поможет, а только усугубит ситуацию с дрожанием импульсов и т.д.
 

Melandr

Member
И ничего никто на ESP так и не сделал. И оно не работает, а с ним работают (играются) - как с Тамагочи. Если бы на ESP что-то работало или заработало, тогда не было бы никаких форумов, т.к. что обсуждать в рабочем устройстве?
Но оно же работает!!!
 

pvvx

Активный участник сообщества
А что такое delayMicroseconds()? Куда оно лезит? Случаем не запустить wifi пока типа задержка? :)
И вот вы написали Serial.printf("") - это операции со string -> с выделением памяти из кучи, а при поиске свободного куска в "heap" прерывания запрещаются и сами операции неизвестной продолжительности.
И такого там масса в Arduino и eё либах, т.к. C++.
 

pvvx

Активный участник сообщества
Но оно же работает!!!
Всё на соплях. Когда вставят в коробку - придется бегать и сбрасывать в ручную :)
И это не называется - "работает", а называется "ребенок играет". И во вторых - "Раб-ботает" от слова Раб. А рабский труд давно признан не производительным и его смели более развитые аборигены на мануфактурах, раб-ботая уже за бабло...
 

pvvx

Активный участник сообщества
В тело самого прерывания книжки советуют много не пихать, а ограничиться только bool переменной. А уже в главном цикле по состоянию этой bool деллать все что вам надо.
В главном цикле ничего не нормируется - даже кол-во этих циклов в единицу времени. Запросто может застрять даже вне Loop() на выемке данных из UART (должна быть такая фича в вызывающей loop() процедуре по Дуриновским канонам). А так-же все события и главный цикл системы с Wifi, да прерываниями всегда неопределенно сместят и раздробят время выполнения в Loop.
И решение "с флагом" без RTOS и смены приоритетов задач не имеют смысла.
 

pvvx

Активный участник сообщества
В тело самого прерывания книжки советуют много не пихать, а ограничиться только bool переменной. А уже в главном цикле по состоянию этой bool деллать все что вам надо.
Объясните этот, описываемый вами, маразм в Arduino:

В данном случае используется прерывание монопольно захваченного таймера или GPIO. Оно и данное оборудование больше никем не используется в системе. Кто вам мешает войти в данное прерывание на веки, разрешив другие (или выставив приоритет)?

Известно кто – Espressif, т.к. написал бяку и сИкретики как сменить приоритет и прочее… И туда приложили руку Дуринщики, которые вообще не шарят в программировании и тем более в аппаратной части.
А проблема там с тем, что прерывания и прочую хрень в ESP обрабатывает специальный цикл ets_run(), а вы пытаетесь из его глубин выполнить процедуры верхнего уровня, которые вызывают повторное вхождение в ту же ets_run(), которая ещё не завершила расстановку флагов в таблице прерываний и прочей фигни типа event/task и soft-timer-ов.
 

pvvx

Активный участник сообщества
И прерывания в ESP описаны аналогично - пока вы сидите в прерывании другие не будут исполняться - типа дети и программеры из Espressif не умеют писать по другому обработку таблицы прерываний. По этому исходников от ESP8266 никогда не будет - там сплошной смех и грех, начиyая с ROM процедур и кончая самой разработкой чипа.
 
Сверху Снизу