• Система автоматизации с открытым исходным кодом на базе 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 процедур и кончая самой разработкой чипа.
 
Сверху Снизу