ESP8266 a millis misto delay

Nedaří se vám s projektem a nenašli jste vhodné místo, kde se zeptat? Napište sem.
Pravidla fóra
Tohle subfórum je určeno pro konzultaci ucelených nápadů, popřípadě řešení komplexnějších projektů, které opravdu není možné rozdělit na menší části.
Většinu problémů jde rozdělit na menší a ptát se na ně v konkrétních subfórech.
unyhhox
Příspěvky: 41
Registrován: 19 bře 2018, 11:11
Reputation: 0

ESP8266 a millis misto delay

Příspěvek od unyhhox » 13 říj 2022, 11:24

Čest práci a rukám klid.

programuji ESP8266 D1 mini pro ovládání fotovoltaiky. Potřebuji, aby při dovršení daného napětí baterie (52.6) se barák přepl na FV. Pro přepínání mezi sítí a FV používám stykače 4NO a 4NC. Pokud baterie dosáhne 52.6V , tak stykač sepne inverter, protože trvá cca 7s než se na výstupu objeví napětí, delay 7s (čeká se na inverter), potom odepne stykač distribuční síť, delay 40ms a sepne stykač FV pro připojení FV do baraku. Toto se odehrává v sekci "void batteryvoltagerele()". Problém ale nastává s delay ve formě millis(). Při dovršení napětí 52.6V se čeká 8s a potom se sepne inverter s prvním stykačem a vzápětí druhý stykač. Potřebuji, aby po dosažení napětí sepl stykač inverteru, delay 8s, odepl stykač sítě, 40ms delay a jako poslední sepl stykač FV. Můžete mi prosím poradit, kde ve funkci millis dělám chybu?

Díky všem za rady!

Kód: Vybrat vše

#include <ESP8266WiFi.h>
float analog_voltage;   
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
char auth[] = "xxxxx";
const char *ssid     = "xxxx";
const char *password = "xxxx";
BlynkTimer timer;
long last_sensor_reading = 0;
long bojlerpower = 0;
const int numReadings = 30;
float readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
float total = 0;                  // the running total
float average = 0;                // the average
unsigned long lastExecutedMillis = 0;

void setup() {
 Serial.begin(115200);
 for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
   Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
      }
  pinMode(13,OUTPUT); //13 D7 (distribution line contactor)
  pinMode(14,OUTPUT); //14 je D5 (PV contactor)
  pinMode(12,OUTPUT); //12 je D6 (inverter)
  pinMode(16,OUTPUT); //16 je D0 (water heater)
  Blynk.begin(auth, ssid, password);
}


void batteryvoltagerele(){
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(A0)* 3.3 / 1023*18.86;
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  average = total / numReadings; // battery voltage measurement with sampling of 30
  if (average>52.6) {
  digitalWrite(12,LOW); // inverter turns on if battery voltage reaches certain point
  unsigned long currentMillis = millis();
  if (currentMillis-lastExecutedMillis>=8000){  //8s delay and then switch two contactors
    lastExecutedMillis = currentMillis;
  digitalWrite(13,LOW); // disconnect distribution line
  delay(40);
  digitalWrite(14,LOW); //connect PV system
 }}
  else if (average<51.5){ // if voltage does not need meet requirements then contactors switch from PV to Distribution line
  digitalWrite(14,HIGH);
  delay(40);
  digitalWrite(13 ,HIGH);
  digitalWrite(12 ,HIGH);
  }
  Blynk.virtualWrite(V5, average);
  Blynk.run();
}

void bojlerssr(){ //if battery is full and house does not need much power then electic water heater is turned on.
if (average>52.8) {
digitalWrite(16,HIGH);}
//if(millis() - bojlerpower >= 120000) {
else if (analog_voltage<52.5) {
digitalWrite(16,LOW);
//bojlerpower = millis();
//digitalWrite(15,LOW);
//if(millis() - bojlerpower >= 120000) {
//digitalWrite(15,HIGH);
//bojlerpower = millis(); }
}}
 
void loop() {
  batteryvoltagerele();
  bojlerssr();
   }
   

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od ondraN » 13 říj 2022, 11:58

Myslím, že je nějaký problém při měření, hned na začátku té funkce. Ty operace s měřeným napětím nějak nedávají smysl. Při použití millis problém nevidím, kromě toho, že si nekontroluješ přetečení registru millis, což nastavá sice dost zřídka, ale tahle aplikace je asi plánovaná na dlouhodobý provoz.

unyhhox
Příspěvky: 41
Registrován: 19 bře 2018, 11:11
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od unyhhox » 13 říj 2022, 12:06

ondraN píše:
13 říj 2022, 11:58
Myslím, že je nějaký problém při měření, hned na začátku té funkce. Ty operace s měřeným napětím nějak nedávají smysl. Při použití millis problém nevidím, kromě toho, že si nekontroluješ přetečení registru millis, což nastavá sice dost zřídka, ale tahle aplikace je asi plánovaná na dlouhodobý provoz.
Kód pro sampling jsem použil z examples nebo stáhnul od někoho jiného. Nejsem si teď jistý. Slouží pro eleminování špiček vlivem rušení. S tímto kódem mi ty hodnoty tak nelítají. Jak jinak by jsi to napsal?

Millis zvládne počítat 49 dní a pak se ressetne od nuly. Spínání je 1x, maximálně 2x denně. Byla by to celkem haluz, aby se tyto dvě situace potkaly. Jak to jde ošetřit?

Když jsem místo millis použil delay, tak to fungovalo. Akorát mi vadí, že s funkcí delay mi stojí celý kód. Měřením napětí by to tedy být nemělo. Dal jsem tam delay a teď s tím dva dny funguju v pohodě, ale mám tam zatim jen omezeny kód na spínání a odepínání FV od baraku a spínání bojleru. Zatím mi tu tedy ten delay nevadi, ale jakmile budu kód rozšiřovat a dělat ho komplexnější, tak bych byl nerad, aby provedl akci jednou za 10s.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od ondraN » 13 říj 2022, 13:22

A není spíš problém s tím, že se to pak chová jinak? Pokud použiješ delay, tak v podstatě 8sec neměříš. A těch 8 sekund nabíhá měnič, což musí nějak hnout s napětím baterek. K dyž použiješ milis, tak furt měříš jak o život a třeba napětí poklesne a dostaneš se zase do jiného pole a měnič se vypne. Pokud chceš stejné chování, měl bys po čas čekání na náběh měniče zakázat měření.

unyhhox
Příspěvky: 41
Registrován: 19 bře 2018, 11:11
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od unyhhox » 13 říj 2022, 13:55

ondraN píše:
13 říj 2022, 13:22
A není spíš problém s tím, že se to pak chová jinak? Pokud použiješ delay, tak v podstatě 8sec neměříš. A těch 8 sekund nabíhá měnič, což musí nějak hnout s napětím baterek. K dyž použiješ milis, tak furt měříš jak o život a třeba napětí poklesne a dostaneš se zase do jiného pole a měnič se vypne. Pokud chceš stejné chování, měl bys po čas čekání na náběh měniče zakázat měření.
Cyklování mi přijde nepravděpodobné, protože jsem to zkoušel s plnými baterkami při 53,1V a zapnutí měniče je nastaveno na 52,6. Jsou to 150Ah baterie a měnič v idle bere cca 1A při 50V, což by takový úbytek neudělalo. Jedině, že by při zapnutí byla nějaká špička.

Můžeš mě prosím nějak navést, jaký kód, pro zastavení měření v tom daném intervalu, použít?

Šlo by použít if před kód měření, takže by to vypadalo následovně?


Kód: Vybrat vše

void batteryvoltagerele(){
if (digitalWrite(12,LOW)&&digitalWrite(13,HIGH)) {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(A0)* 3.3 / 1023*18.86;
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }}
  average = total / numReadings; // battery voltage measurement with sampling of 30
  if (average>52.6) {
  digitalWrite(12,LOW); // inverter turns on if battery voltage reaches certain point
  unsigned long currentMillis = millis();
  if (currentMillis-lastExecutedMillis>=8000){  //8s delay and then switch two contactors
    lastExecutedMillis = currentMillis;
  digitalWrite(13,LOW); // disconnect distribution line
  delay(40);
  digitalWrite(14,LOW); //connect PV system
 }}
  else if (average<51.5){ // if voltage does not need meet requirements then contactors switch from PV to Distribution line
  digitalWrite(14,HIGH);
  delay(40);
  digitalWrite(13 ,HIGH);
  digitalWrite(12 ,HIGH);
  }
  Blynk.virtualWrite(V5, average);
  Blynk.run();
}
Díky moc.
Naposledy upravil(a) unyhhox dne 13 říj 2022, 14:14, celkem upraveno 1 x.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od ondraN » 13 říj 2022, 14:10

Dostanu se k tomu až večer. Možná bude někdo z kolegů tady na fóru rychlejší :P

unyhhox
Příspěvky: 41
Registrován: 19 bře 2018, 11:11
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od unyhhox » 13 říj 2022, 14:31

Upravil jsem kód viz níže. S touto úpravou by mělo docházet k měření jen pokud bude měnič zapnuty, DS odpojena nebo měnič vypnuty a DS připojena. Vynechal jsem tím těch 8s, kdy je sepnuty jak měnič, tak DS. Ale jestli to bude fungovat zjistím až doma.

Kód: Vybrat vše

void batteryvoltagerele(){
if (((digitalWrite(12,LOW))&&(digitalWrite(13,HIGH)))||((digitalWrite(12,HIGH))&&(digitalWrite(13,HIGH))) {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(A0)* 3.3 / 1023*18.86;
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }}
  average = total / numReadings; // battery voltage measurement with sampling of 30
  if (average>52.6) {
  digitalWrite(12,LOW); // inverter turns on if battery voltage reaches certain point
  unsigned long currentMillis = millis();
  if (currentMillis-lastExecutedMillis>=8000){  //8s delay and then switch two contactors
    lastExecutedMillis = currentMillis;
  digitalWrite(13,LOW); // disconnect distribution line
  delay(40);
  digitalWrite(14,LOW); //connect PV system
 }}
  else if (average<51.5){ // if voltage does not need meet requirements then contactors switch from PV to Distribution line
  digitalWrite(14,HIGH);
  delay(40);
  digitalWrite(13 ,HIGH);
  digitalWrite(12 ,HIGH);
  }
  Blynk.virtualWrite(V5, average);
  Blynk.run();
}

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od ondraN » 13 říj 2022, 19:54

Dej si pozor na to, že když máš ve funkci teď akce podle millis, tak ti proběhne celé kolečko třeba za 1ms. Takže tím posíláním dat na blynk to celé zahltíš a pak to bude váznout, je tam třeba taky použít nějaké časování. Další věc je, že v jedné funkci řešíš příliš mnoho věcí, rozděl to na měření, spínání, posílání dat. Data mohou funkce předávat pomocí globálních datových struktur jako parametry. Bude to daleko přehlednější a hlavně bezpečnější.
Nepoužívej ve funkcích globální proměnné, pokud to není nezbytné. Pokud chceš třeba udělat ve funkci proměnou, jejíž hodnota má být zachována do dalšího volání funkce, použij definici typu static. Vše ostatní předávej přes parametry hodnotou nebo odkazem.

Kód: Vybrat vše

void function()
	byte counter=0;
	.
	.
return;
V téhle funkci se při každém zavolání vytvoří proměnná counter s počáteční hodnotou 0, po skončení funkce přestane existovat a její místo se použije na něco jiného.

Kód: Vybrat vše

void function()
	static byte counter=0;
	.
	.
return;
V téhle funkci se při prvním volání vytvoří proměnná counter s počáteční hodnotou 0, ale po skončení funkce nezanikne, stále drží svou hodnotu a při dalším volání se již nedefinuje ani neinicializuje a má hodnotu s jakou opustila první volání funkce.
Tohle ti umožní udržet si privátní statické proměnné uvnitř funkcí, kde ti je nic z vnějšku nemůže změnit a celý kód bude přehlednější. Funkce se pak snadno přenášejí do jiného kódu.

unyhhox
Příspěvky: 41
Registrován: 19 bře 2018, 11:11
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od unyhhox » 13 říj 2022, 22:01

ondraN píše:
13 říj 2022, 19:54
Dej si pozor na to, že když máš ve funkci teď akce podle millis, tak ti proběhne celé kolečko třeba za 1ms. Takže tím posíláním dat na blynk to celé zahltíš a pak to bude váznout, je tam třeba taky použít nějaké časování. Další věc je, že v jedné funkci řešíš příliš mnoho věcí, rozděl to na měření, spínání, posílání dat. Data mohou funkce předávat pomocí globálních datových struktur jako parametry. Bude to daleko přehlednější a hlavně bezpečnější.
Nepoužívej ve funkcích globální proměnné, pokud to není nezbytné. Pokud chceš třeba udělat ve funkci proměnou, jejíž hodnota má být zachována do dalšího volání funkce, použij definici typu static. Vše ostatní předávej přes parametry hodnotou nebo odkazem.

Kód: Vybrat vše

void function()
	byte counter=0;
	.
	.
return;
V téhle funkci se při každém zavolání vytvoří proměnná counter s počáteční hodnotou 0, po skončení funkce přestane existovat a její místo se použije na něco jiného.

Kód: Vybrat vše

void function()
	static byte counter=0;
	.
	.
return;
V téhle funkci se při prvním volání vytvoří proměnná counter s počáteční hodnotou 0, ale po skončení funkce nezanikne, stále drží svou hodnotu a při dalším volání se již nedefinuje ani neinicializuje a má hodnotu s jakou opustila první volání funkce.
Tohle ti umožní udržet si privátní statické proměnné uvnitř funkcí, kde ti je nic z vnějšku nemůže změnit a celý kód bude přehlednější. Funkce se pak snadno přenášejí do jiného kódu.

Jsem zatím víceméně začátečník. Jsem elektrikář, který se snaží vymyslet automatizaci pomocí jednoduchého programovýní. To, co jsi zmínil, je na mě asi zatím dost složité a rád bych se to časem naučil, ale momentálně jsem v situaci, kdy potřebuju rozjet fotovoltaiku, aby mi tu nestála mimo provoz.

jsem ve fázi kódu viz níže. Sepne stykač měniče a dvě vteřiny na to odepne stykač sítě a se 40ms zpožděním sepne stykač FV. Mám tam nastaveno zpozdění 12 000 ms, ale je to max 2s. Už nevím, co s tím. Když jsem dal serial.println current millis, tak mi to tiskne millis, protože při načtení programu, připojení na wifi je tam 9s.

Kód: Vybrat vše

#include <ESP8266WiFi.h>
float analog_voltage;    
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
char auth[] = "hnn7oOuJ45oEq7hzAaz5cqJ8yFbAf-Sm";
const char *ssid     = "Kika";
const char *password = "28101993";
BlynkTimer timer;
long last_sensor_reading = 0;
long bojlerpower = 0;
const int numReadings = 30;
float readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
float total = 0;                  // the running total
float average = 0;                // the average
unsigned long lastExecutedMillis = 0;

void setup() {
 Serial.begin(115200);
 for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
   Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
      }
  pinMode(13,OUTPUT); //13 D7 (DS stykač)
  pinMode(14,OUTPUT); //14 je D5 (FV stkyač)
  pinMode(12,OUTPUT); //12 je D6 (měnič)
  pinMode(16,OUTPUT); //16 je D0 (bojler 1 a 2)
  digitalWrite(13,HIGH); //13 D7 (DS stykač)
  digitalWrite(14,HIGH); //14 je D5 (FV stkyač)
  digitalWrite(12,HIGH); //12 je D6 (měnič)
  Blynk.begin(auth, ssid, password);
}


void batteryvoltagerele(){
  if (((digitalRead(12)==LOW)&&(digitalRead(13)==HIGH))||((digitalRead(12)==HIGH)&&(digitalRead(13)==HIGH))) {
  total = total - readings[readIndex];
  readings[readIndex] = analogRead(A0)* 3.3 / 1023*18.95;
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  average = total / numReadings;
  }
    if (average>51.8) {
    digitalWrite(12,LOW);
  unsigned long currentMillis = millis();
  if (currentMillis-lastExecutedMillis>=12000){ 
    lastExecutedMillis = currentMillis;
  digitalWrite(13,LOW);
  delay(40);
  digitalWrite(14,LOW);
 }}
  else if (average<51){
  digitalWrite(14,HIGH);
  delay(40);  
  digitalWrite(13 ,HIGH);
  digitalWrite(12 ,HIGH);
  }
  Blynk.virtualWrite(V5, average);
  Blynk.run();
}

void bojlerssr(){
if (average>52.9) {
digitalWrite(16,HIGH);}
//if(millis() - bojlerpower >= 120000) {
else if (analog_voltage<52.7) {
digitalWrite(16,LOW);
//bojlerpower = millis();
//digitalWrite(15,LOW);
//if(millis() - bojlerpower >= 120000) {
//digitalWrite(15,HIGH);
//bojlerpower = millis(); }
}}
 
void loop() {
  batteryvoltagerele();
  bojlerssr();
   }

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: ESP8266 a millis misto delay

Příspěvek od ondraN » 14 říj 2022, 10:54

Jestli jsem dobře pochopil ten poslední program, tak při více než 51,8V zapínáš FV přes invertor a při méně než 51V vypínáš? O kolik poklesne napětí na bodě, kde měříš napětí při zapnutí a zatížení invertoru? Je to opravdu takhle zamýšleno?

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 12 hostů