benleentje
Golden Member
"if millis()-starttijd > 3245)" gaat gewoon goed,
Stel starttijd is 1000.000.000
stel millis() = 0 geworden
Dan duurt het toch wel weer een tijdje voordat het groter dan 3245 is. Er loopt niet vast maar er gebeurt ook niet wat je verwacht.
buckfast_beekeeper
Van Lambiek wordt goede geuze gemaakt.
Op dinsdag 29 april 2025 13:52:03 schreef rene037:
[...]
Nooit kunnen vinden, maar de NTP library vervangen door eztime.
Had nog meer voordelen, want (Als ik me goed herinner) zit de automatische overschakeling van/naar zomertijd niet in de ntp library.
Voor de zon heeft zomertijd geen enkele meerwaarde. Gewoon in UTC het ganse jaar door. Voor al mijn log gegevens gebruik ik UTC. Heb ik nooit overlapping. Je kan dan ook gewoon sorteren op de timestamp terwijl je dat anders op ID moet gaan doen.
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Op dinsdag 29 april 2025 15:45:29 schreef benleentje:
Stel starttijd is 1000.000.000
stel millis() = 0 geworden
Dan duurt het toch wel ....
Stel even dat de wraparound op 1000 gebeurt. Makkelijk voor ons. De wraparound is dan naar -1000. Makkelijke getallen voor ons. En dat je de timeout steeds op 30 verder zet. De "range" is dus van -1000 tot +999 de fout bij een "wrap" is dan dus 2000.
op t= 990:
if ( (990 - 960) >= 30)
30 >= 30 ?
Jep! Werkt!
Je zet de starttijd nu op 990, en... even later is de millis() naar -980 ge-wrapt!.
if (-980 - 990) >= 30)
-1970 >= 30?
Die -1970 wrapt ZELF naar +30 ...
30 >= 30 ?
jep! Werkt!
Cool eh?
benleentje
Golden Member
Zeker cool had ik niet verwacht. Had het wel kunnen weten want two's complement heb ik wel geleerd maar ook wel weer vergeten.
Maar wat als het unsigned variabele is de variabele word 0?
of is 0 - 960 = ??
In 16 bit is dat dan toch 65535 - 960 = 64575 ? of 64576 ?
Maar even goed is dat ook net iets groter dan 30
Op dinsdag 29 april 2025 16:27:58 schreef buckfast_beekeeper:
[...]
Voor de zon heeft zomertijd geen enkele meerwaarde. Gewoon in UTC het ganse jaar door. Voor al mijn log gegevens gebruik ik UTC. Heb ik nooit overlapping. Je kan dan ook gewoon sorteren op de timestamp terwijl je dat anders op ID moet gaan doen.
Dat snap ik, maar het gaat om het probleem. Voor jou is DST niet belangrijk, voor anderen die het probleem ook hebben kan het een extra feature zijn.
Ik gaf je twee tips om te kijken of dat je probleem oplost.
soldeersmurf
Niet alles wat op internet staat is waar... Dat geldt ook voor CO.
Op dinsdag 29 april 2025 15:45:29 schreef benleentje:
[...]Stel starttijd is 1000.000.000
stel millis() = 0 geworden
Dan duurt het toch wel weer een tijdje voordat het groter dan 3245 is. Er loopt niet vast maar er gebeurt ook niet wat je verwacht.
Niet flauw doen! millis kan nooit groter worden dan 224 en dat is kleiner dan 100 miljoen. Je moet wel zinvolle tijden gebruiken.
Ik schreef ook dat 'als je het netjes doet' een millis overflow je niet dwars zit. "if millis() > eindtijd" mag ook natuurlijk. Aan het begin van je proces o.i.d. doe je "starttijd=millis()". Het verschil "millis() - starttijd" is dan de verstreken tijd. Is dat langer dan 3245, dan loopt de wekker af en moet je iets doen. Ook wanneer starttijd 'geklokt'is terwijl millis() op dat moment minder dan 3245 te gaan had tot overflow, werkt het. Ik had ooit starttijd als long i.p.v. unsigned long gedeclareerd. Ja, dan gaat het fout als bitje 23 geset is want dat betekent voor een long dat ie negatief is.
@rew: Leuk voorbeeldje, maar niet helemaal correct lijkt me. Ik snap wel wat je bedoelt, in je voorbeeld doe je net of het over 2-complements-getallen gaat, maar millis() kan nooit negatief worden. Echte tijd trouwens ook niet. Bitje 23 is hier geen 'sign-bit' en millis() telt gewoon vasn nul (alle bitjes laag) tot ~8,5 miljoen (alle 24 bitjes hoog). De wrap-around geeft geen ellende, tenminste als je de juiste types gebruikt, dus beide te testen waarden even groot en gelijk van type signed of unsigned. Inderdaad cool!
[Bericht gewijzigd door soldeersmurf op dinsdag 29 april 2025 23:24:50 (20%)]
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Op dinsdag 29 april 2025 17:31:02 schreef benleentje:
Zeker cool had ik niet verwacht. Had het wel kunnen weten want two's complement heb ik wel geleerd maar ook wel weer vergeten.Maar wat als het unsigned variabele is de variabele word 0?
of is 0 - 960 = ??
In 16 bit is dat dan toch 65535 - 960 = 64575 ? of 64576 ?
Maar even goed is dat ook net iets groter dan 30
Ja met signed/unsigned moet je effe opletten. Signed is makkelijker, met unsigned is er NOG een manier om het fout te doen, maar die merk je meteen omdat het dan vaak "meestal niet werkt".
Met unsigned moet je elapsed = millis() - start_time; if (elapsed > timeout) doen.
Doe je endtime = millis () + timeout; dan kan je het al niet meer goed doen als je unsigneds gebruikt. Dus beter gewoon signed gebruiken. Hierboven heb ik steeds de expressie in de if geschreven. In de praktijk doe ik het om ZEER zeker te weten dat een signed gebruikt wordt: signed int delta_t = millis() - end_time; if (delta_t >= 0) ... het woordje signed is niet nodig, maar documenteert dat ik er over nagedacht heb dat het signed moet zijn.
@soldeersmurf: Het ziet er naar uit dat millis () als unsigned 32 bit is gedefinieerd. Hoe je aan 24 bits zou komen is me een raadsel.
Dus dit betekent dat je nog steeds heel goed moet uitkijken met if ((millis () - end_time) > 0) : Je moet weten of het verschil van een unsigned en signed variabele signed of unsigned is. Ik weet dat niet. In arduino zou ik dus voor de expliciete SIGNED tussenvariabele kiezen.
[Bericht gewijzigd door rew op woensdag 30 april 2025 08:46:02 (15%)]
soldeersmurf
Niet alles wat op internet staat is waar... Dat geldt ook voor CO.
@rew
Inderdaad mijnn foutje: 32 bits moet het zijn. Het verhaal blijft hetzelfde, om zeker te weten dat het goed gaat juist géén signed gebruiken. Waarom je persé kiest voor signed is nou mijn raadsel. Ik ie niet waarom je je signed and unsignde door elkaar wilt gebruiken. Millis() is immers unsigned.
In je laatste alinea geef je het zelf al aan:
Dus dit betekent dat je nog steeds heel goed moet uitkijken met if ((millis () - end_time) > 0) : Je moet weten of het verschil van een unsigned en signed variabele signed of unsigned is. Ik weet dat niet. In arduino zou ik dus voor de expliciete SIGNED tussenvariabele kiezen.
(millis () - end_time) levert altijd een unsigned long op mits je end-time ook als unsigned hebt gedefiëerd. Als je zonder typecast expressies met verschillde types door elkaar gaat gebruikenis het ook voor mij niet duidelijk wat het resultaat wordt.
millis() - endtime is nooit goed. Want end-time ligt meestal in de toekomst en is dan groter dan millis(). En dan wordt millis() - endtime negatief wat een heel groot positief getal oplevert als je met unsigned ints werkt.
Dus altijd rekenen met millis() - starttime > timeout.
Want dat levert het aantal millis sinds starttime en dat is doorgaans een klein positief getal.
En dat gaat altijd goed, zolang millis() en starttime hetzelfde type hebben. Dat werkt voor signed net zo goed als voor unsigned.
benleentje
Golden Member
IK had wel eens ergens gelezen dat je in de if vergelijking niet elke keer een berekening wilt later doen. Dus ik doe eigenlijk de tijd waarmee ik vergelijk ophogen. Ik vind het voor mezelf ook makkelijker werken tijdens het programmeren.
IK tel dan bv steeds 1000 bij een variabele op en vergelijk dat dan met millis(). Maar dat gaat dan ook goed. Want stel mijn variabel en millis() zijn beide getallen die tot max 100.000 gaan gewoon om het even makkelijk maken voor een voorbeeld.
Als ik mijn variabele die dan bv 99.500 is met 1000 verhoog dan word die 500. En millis() doet ondertussen hetzelfde die gaat door de 100.000 heen en word weer nul en daarna 500. Dat gaat toch ook goed?
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Ik wil even die hele discussie "debunken" wat betreft die time counter.
De definitie van de time waarden behoren unsigned getallen te zijn.
Dan gebruik je (bij voorkeur) een macro die de boel cast naar een SIGNED om de time wrap goed af te handelen. En dan werkt de boel precies zoals je verwacht bij een wraparound van de tick counter. (mits de tijd niet extreem groot is, 2^31 dacht ik bij 32-bits ticker)
Linux definieerd diverse macros, bijvoorbeeld deze:
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
Die typecheck kun je in principe weglaten.
Zie deze discussie op stackoverflow: https://stackoverflow.com/questions/6234597/is-the-time-after-linux-ma…
Kortom, case closed (wat dit betreft), niet meer over beginnen.
fcapri
ik hou van werken ..., ik kan er uren naar kijken
UPDATE: boiler weer vastgelopen.
zijn clock staat op 21h42 terwijl het nu 21h35 is.
vermoedelijk hangt die dus vast van gisterenavond (douchewater koud).ik had die ook een statusveld meegegeven om te zien in welke functie die zit, en die is LEEG (meestal staat er loop in).
zit niet in loop, zit niet in solar opvragen. gewoon geenenkele loop.
na een reboot heb ik weer dat die in loop zit. ook de klok werkt weer.
elk subroutine heeft nogthans een waarde die in het veld (procedure) gezet wordt.
de tijd zat vast, de temperatuur zat vast... niks van variabele werkte nog, maar de /reboot functie deed het gewoon, de webserver werkte.
precies of die gewoon niet meer loopt (vastgelopen in het toewijzen van een nieuwe waarde aan de string 'procedure'??? en daardoor vastliep?
void loop() {
procedure="loop";
ArduinoOTA.handle();
if (updateTimer < 1) { //get internet time every hour
updateTime();
updateTimer = 3600;
runtime++;
}
if (runtime > 360){ //reboot after 15days
ESP.restart();
}
if (updateTimer % 60 == 0) { //60
calculPrintTime();
if (heatnowtime > 0) {
heatnowtime--;
if (heatnowtime == 0) {
hours[24] = 0;
}
}
if (heatnowtime < 0) {
heatnowtime++;
if (heatnowtime == 0) {
hours[24] = 0;
}
}
if (cMin < 10) {
Btime = String(cHour) + ":0" + String(cMin);
} else {
Btime = String(cHour) + ":" + String(cMin);
}
getsolardata();
if (restP == 0) { //Owatt, try again
getsolardata();
}
updateBoiler();
ws.cleanupClients();
totalTime++;
}
delay(1000);
// screenUpdate();
updateTimer--;
procedure="";
}
void updateTime() {
procedure="updateTime";
timeClient.setTimeOffset(utcOffsetInSeconds);
delay(100);
timeClient.update();
Serial.print(daysOfTheWeek[timeClient.getDay()]);
Serial.print(", ");
cHour = timeClient.getHours();
Serial.print(cHour);
Serial.print(":");
cMin = timeClient.getMinutes();
Serial.print(cMin);
Serial.print(":");
Serial.println(timeClient.getSeconds());
//Serial.println(timeClient.getFormattedTime());
totalTime = (cHour * 60) + cMin;
// Serial.println(Btime);
//summertime change
//String teststr = timeClient.getDay(à);
procedure="";
}
void calculPrintTime() {
procedure="calculPrintTime";
Serial.print("OldTime ");
Serial.print(cHour);
Serial.print(":");
Serial.print(cMin);
Serial.print("-(");
Serial.print(updateTimer);
Serial.print(")-");
cHour = int(totalTime / 60);
cMin = int(totalTime % 60);
Serial.print("CalculatedTime ");
Serial.print(cHour);
Serial.print(":");
Serial.print(r2digit(cMin));
Serial.print(" - Manual heat minutes: ");
Serial.println(heatnowtime);
Serial.print("temp ");
Serial.print(sensorValue);
Serial.print("=");
Serial.print(temperature);
Serial.println("°C");
procedure="";
}
void screenUpdate() {
procedure="screenUpdate";
digitalWrite(led2, LOW);
sensorValue = analogRead(A0); //416=15°C 246=36°C op 3,3V met 22K,, kapotte 387-226
temperature = map(sensorValue, 485, 268, 14, 55); //14°C open lucht = 485 boiler koud55°C = 268 oude waardes gaf de helft:387-226 = 18-36
cTime = String(cHour) + ":" + String(r2digit(cMin));
//if (heatnowtime == 0){
// StartEnd = "Time on " + String(StartHour) + "h->" + String(StopHour) + "h";
// screenStatus = onoff;
//} else {
// StartEnd = "Time on " + String(StartHour) + "h->" + String(StopHour) + "h";
//screenStatus = onoff;
// }
if (cHour < 13) {
StartEnd = "0-12";
for (int i = 0; i < 13; i++) {
if (hours[i] == "0") {
StartEnd = StartEnd + "_";
} else {
StartEnd = StartEnd + "#";
}
}
} else {
StartEnd = "12-0";
for (int i = 13; i <= 23; i++) {
if (hours[i] == "0") {
StartEnd = StartEnd + "_";
} else {
StartEnd = StartEnd + "#";
}
}
}
digitalWrite(led2, HIGH);
procedure="";
}
void updateBoiler() {
procedure="updateBoiler";
int power = 0;
....
het is sinds 8mei geleden dat die is vast gelopen, dat maakt 37dagen dat die werkte non stop. ook dus geen overflow van millies op 49dagen
de P1 poort ESP werkt nu ook, tijd om de hele code te herschrijven zodat die zijn tijd uit de P1 telegram datum haalt alsook het verbruik.
dan kan ik ook van heel die NTP afstappen
Wat me opvalt is dat je in subroutines een pointer naar een string toekent aan een variabele. Nu weet ik niet of het een C++ String of een char * is, maar als de routine afgelopen is, is de pointer naar die string ook niet meer valide. Op dat geheugenadres kan allang iets anders staan.
Dus dat de variabele 'procedure' leeg is of naar rommel verwijst en daarmee wel iets heel onbedoelds veroorzaakt weet ik niet. Maak procedure numeriek en zet er een getal in of bijv char[30] en gebruik strcpy om er de naam in te zetten. Dat is in ieder geval een poetntiele crash minder.
oxurane
Van elk bezoek aan CO leer ik weer meer...
Ik volg dit topic met de nodige interesse en het eerste waar ik ook aan dacht was de millis() met overflow. Maar je geeft aan dat het vastlopen ook gebeurt voordat de millis()-counter een overflow zou kunnen veroorzaken.
Ik loop ook wel eens tegen onverklaarbare situaties aan tijdens het programmeren in Arduino. Ik probeer dan de bron te achterhalen, door globaal een controle-variabele te declareren. Vervolgens laat ik binnen allerlei functies de waarde er van aanpassen, soms zelfs per uitgevoerde regel.
In jouw geval blijkt dat je niet het probleem goed kunt isoleren. Je zou dan kunnen overwegen om diverse controle-variabelen te declareren en deze in elke functie apart te laten wijzigen. Stel je hebt 5 functies in je code, dan kun je 5 controle-variabelen declareren. Telkens bij een functie-aanroep, laat je een variabele starten met de waarde 1. Deze waarde verhoog je per regel dat er iets wordt uitgevoerd.
Omdat je HTML-gedeelte wel probleemloos blijft werken, zou je een html-pagina kunnen bouwen (error.htm), die bij aanroepen de meest recente waarden laat zien. Roep je deze pagina -na vastlopen- een paar keer op, krijg je wellicht een betere indruk welke en waar een controle-variabele vastloopt.
Ook zou je -als extra- een timer-functie kunnen inbouwen ter controle. Indien bepaalde controle-variabelen niet wijzigen binnen een bepaalde tijd, dan schrijf je de waarde weg in EEPROM.
Ik weet het, het is niet ideaal, maar misschien helpt het je.
P.S. Wat voor variabele is "heatnowtime" ? Indien uint8_t of uint_16 kan deze niet negatief zijn / worden.
P.P.S. In je "updateTime()" ga je er automatisch van uit dat je altijd een verbinding hebt om de tijd op te vragen. Hoe vang je het af, indien er om een of andere reden tijdelijk geen verbinding is ? (internet-verbinding weg of geen verbinding met de server vanwege drukte of,...)
fcapri
ik hou van werken ..., ik kan er uren naar kijken
Op zondag 15 juni 2025 00:49:07 schreef rene037:
Wat me opvalt is dat je in subroutines een pointer naar een string toekent aan een variabele. Nu weet ik niet of het een C++ String of een char * is, maar als de routine afgelopen is, is de pointer naar die string ook niet meer valide. Op dat geheugenadres kan allang iets anders staan.
Dus dat de variabele 'procedure' leeg is of naar rommel verwijst en daarmee wel iets heel onbedoelds veroorzaakt weet ik niet. Maak procedure numeriek en zet er een getal in of bijv char[30] en gebruik strcpy om er de naam in te zetten. Dat is in ieder geval een poetntiele crash minder.
waar gebruik ik pointer? procedure is een string dat heel in het begin is gedeclareerd (global variabele). die word weergegeven in de html.
als ik in loop zit, wordt die procedure = "loop".
op het einde van loop zet ik procedure = "". dan is de loop afgelopen en begint die opnieuw.
is 1 van de if's true in de loop, bv als ik naar updatetime ga, dan zet ik procedure = "updatetime" enop het einde zet ik procedure = "".
als mijn updatetime zou vastlopen, dan blijft "updatetime" in procedure staan.
idem voor elke routine waar die in gaat.
echter liep die na 37dagen vast en stond er niks in procedure. hij heeft dus 'iets' doorlopen, correct procedure leeg gemaakt en vastgelopen
Op zondag 15 juni 2025 06:03:38 schreef oxurane:
Ik volg dit topic met de nodige interesse en het eerste waar ik ook aan dacht was de millis() met overflow. Maar je geeft aan dat het vastlopen ook gebeurt voordat de millis()-counter een overflow zou kunnen veroorzaken.
Je zou dan kunnen overwegen om diverse controle-variabelen te declareren en deze in elke functie apart te laten wijzigen.P.S. Wat voor variabele is "heatnowtime" ? Indien uint8_t of uint_16 kan deze niet negatief zijn / worden.
P.P.S. In je "updateTime()" ga je er automatisch van uit dat je altijd een verbinding hebt om de tijd op te vragen. Hoe vang je het af, indien er om een of andere reden tijdelijk geen verbinding is ? (internet-verbinding weg of geen verbinding met de server vanwege drukte of,...)
ik gebruik geen millis. in mijn loop zitten een delay van (1000). elke keer door de loop duurt 1 sec.
ik kan 3600keer door de loop gaan, met een updatetimer-- en dan zal die een time update doen van het internet.
elke keer het getal deelbaar door 60 doet die een andere if . niks millies nodig
heatnowtime is een int. dat is een schuifbalk waar ik kan zetten dat die 1, 2 of 3uur MOET warmen OF dat die 1,2 of 3uur NIET mag warmen.
daar zit dan een getal in tussen +180 of -180 (minuten).
staat die op nul, dan is de manuele override uitgeschakelt en werkt die volgens tijdsklok of volgens zonnepaneel injectie.
die functie wordt amper gebruikt, enkel bv gisteren omdat die koud water had, zet ik die 3uur manueel op warmen.
die timeclient blijft het goed doen, vermoed dat ze het daar wel onderscheppen. zou die uitvallen, dan is het klokje op de html pagina gewoon rommel.
bij een onderbreking en het dus ontbreken van een correct uur, zou die dan ook niet meer volgens de schakelklok kunnen warmen.
dan kan die wel nog warmen als er injectie is van de zonnepanelen, en dat deed die ook niet.
1uur later, als die opnieuw een timeupdate doet, zou die dan wel weer in lijn moeten lopen.
de hele html is ook correct in gevuld.
boiler is off: updateboiler werkt dus
56°C: het meten van temperatuur werkte dus (digitale waarde 264)
21h42: één van de laatste time updates was dus goed, en elke keer door de loop telt die een minuut op
housepower -267W: hij heeft communicatie met de zonnepanelen gehad en kreeg correcte waarde.
alle variabelen zijn correct ingevuld dus. alles draait in String, dus een foute variabele zou zichtbaar zijn hier.
het enige is dat de tijd stil stond, dat dat die niet meer door loop ging.
en aangezien die 'loop' niet in die tekst stond, ging die door geenenkel subroutine meer.
ik deed dan 192.168.1.24/reboot in de browser waardoor de ESP opstart en dus alles weer werkte. spanning is er totaal niet afgeweest
vroeger was het een grote ESP8266, nu is het een wemos D1mini. ook al verschillende hardware dus.
hij is gereset, ik ga die sourcecode ook datum geven en die in een 2de wemos laden die, zonder boiler eraan, gewoon de html blijft draaien.
er was een kans dat het met de U2G library (display) en de NTP was die in combinatie een crash veroorzaakt, maar deze versie draait zonder display
Ik zag niet of het als c++ string of als C char * gedeclareerd is.
Ik weet ok niet of C++ dit wel goed afhandelt, ik vermoed van wel. Bij een char * mag je niet doen wat je nu doet. En dat kan tot onverwachte crashes leiden, waarbij het lijkt of de string leeg is. Ik probeer ook maar dingen uit te sluiten, heb genoeg gekkigheid gezien.
fcapri
ik hou van werken ..., ik kan er uren naar kijken
ah, ok,
dacht dat ik een regel over het hoofd zag waar ik ineens een pointer bovenhaalde.
heel die rode regel op de html pagina is opgebouwde uit deel strings, die dan gecombineerd worden en weergegeven in html.
aangezien het weken goed gaat, vermoed ik niet dat het in een string zou zitten, dan zou de crash sneller voorkomen.
al van in de basis versie liep die regelmatig vast na een maand, en toen had ik die rode regel niet eens, was de zoninjectie er ook niet in. die liep enkel op die tijdsklok als een stopcontacttimer dus.
had toen wel de U2G librarie voor het display en die NTP client draaien
bij versie 11 gaan beide eruit en ga ik de tijd uit de telegram van de P1 meter halen.
die ntp client is de enige waar ik geen controle over heb
elke 15dagen voert die ook een esp.restart uit.
dat deed die dus niet, want de schuifbalkjes om 10-11 en 16h stonden uit op de vastloopfoto
Er is eerder in dit topic over gesproken, dus dit is een herhaling en allicht ten overvloede, maar het lijkt nog altijd een voor de hand liggende stap die delay(1000) te vervangen door iets non-bloking zodat de code zo vaak mogelijk door de loop() valt en daarmee vaker aandacht geeft aan wm.process();, yield();, of wat de betreffende Wifi routines die op de achtergrond lopen maar tijd geeft. Gewoonlijk time ik mijn processen op basis van millis().
Het kriebelt, en verbaasd eigenlijk meer dat het nog redelijk werkt.
Op ESP met Wifi ben ik nog niet onder de 30 Hz voor loop() gegaan, dat was een geval waar loop() gelocked was aan via I2S verzonden dmx frames.
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
Op zondag 15 juni 2025 07:51:49 schreef rene037:
Bij een char * mag je niet doen wat je nu doet. En dat kan tot onverwachte crashes leiden, waarbij het lijkt of de string leeg is. Ik probeer ook maar dingen uit te sluiten, heb genoeg gekkigheid gezien.
Nee is niet waar, de assignment is correct.
Als 'procedure' een globale pointer is (char *) werkt een assignment a la:
procedure = "leeg";
Gewoon zoals het hoort, "leeg" is namelijk een char pointer naar een const stuk geheugen en bovenstaande is gewoon een pointer assignment.
Maar een nummertje is wel wat handiger, dan weet je dat je in ieder geval nooit geen last hebt van (pointer) variablen die out of scope gaan.
Even een analyse: Je zegt dus dat de loop() gewoon blijft lopen. Anders zou die ook niet na 15 dagen rebooten?
DWZ dat je code dus niet vastgelopen is.
Waar bij mij de rode vlag omhoog gaat is de functie updateTime(). Wat is timeClient voor een class? Als dat echt de RTC van het systeem manipuleerd denk ik dat daar met zeer grote zekerheid het probleem zit. Je moet never nooit niet je systeemtijd zomaar aanpassen. Dat leid meestal tot allerlei onverwachte dingen.
Je zegt dat je NTP gebruikt dan moet je die ook de tijd aan laten aanpassen (dat gebeurd altijd monotoon) en alleen iets LEZEN uit de clock/time variablen/systeem of net waar het vandaan komt.
Als was het alleen al de timeClient.setTimeOffset(utcOffsetInSeconds); wat zeer verdacht is.
En waarom een delay(100) ? -> Ook direct een aanleiding dat daar iets niet deugt.
fcapri
ik hou van werken ..., ik kan er uren naar kijken
er is geen systeemtijd in een esp/arduino, ook geen RTC.
die haalt zijn NTP tijd binnen van het internet, die heet timeClient. dat is een constructor van het opbject.
long utcOffsetInSeconds = 3600;
char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);
daarna bepaald je hoeveel offset je hebt.
ik zit bv op UTC+1, dus dat geef je in bij die setTimeOffset (3600).
in die functie ga ik dus al die variabelen invullen van het object.
die offset verander ik in maar en oktober (zomeruur, winteruur), dan maak ik daar 7200 van.
timeclient hours wordt ingevuld (met die afwijking van utc + 1)
time client minutes wordt ingevuld,
day wordt ingevuld,
....
#######################################
# Datatypes (KEYWORD1)
#######################################
NTPClient KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
update KEYWORD2
forceUpdate KEYWORD2
isTimeSet KEYWORD2
getDay KEYWORD2
getHours KEYWORD2
getMinutes KEYWORD2
getSeconds KEYWORD2
getFormattedTime KEYWORD2
getEpochTime KEYWORD2
setTimeOffset KEYWORD2
setUpdateInterval KEYWORD2
setPoolServerName KEYWORD2
ik gebruik die functie enkel om dat de variabele cHour en cMin (current hour, current min) in te vullen in mijn eigen variabelen om die weer te geven op de html pagina.
in mijn code ga ik dan ook kijken of de cHour overeenkomt met de tabel (0-24h).
het is nu 11:34, dan zit er 11 in cHour.
als die array Hours[11] gelijk is aan 0, dan blijft de boiler uit, zit daar een 1, dan zal die warmen door de tijdklok functie.
met de rest van die tijd wordt niks meer gedaan.
ze wordt weergegeven op de html pagina zodat ik kan zien of die vastloopt.
in mijn loop wordt de tijdvariabele elke minuut met 1 verhoogd.
elk uur zal die een sync doen met de NTP zodat ik geen verloop krijg.
als de tijd vastloopt, loopt de loop dus niet meer (geen verhoging per minuut) alsook loopt de timeupdate niet meer.
100% zeker dat de loop dus vast zit.
de webserver loopt met interrupts, dus die doen het wel goed. die interrupt gaat gewoon alle variabelen in de webpagina weergeven en kan daar dus zien als de data 'oud' is
henri62
1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
De loop() loopt waarschijnlijk nog wel maar het blok:
if (updateTimer % 60 == 0)
Zal niet meer executed worden. Dat is nogal een verschil.
Haal dit er eens uit of zet het in de setup():
timeClient.setTimeOffset(utcOffsetInSeconds);
Verder inderdaad die delay(1000) oplossen dat die er niet meer zit zoals Aart zegt.
[Bericht gewijzigd door henri62 op zondag 15 juni 2025 15:38:29 (11%)]
fcapri
ik hou van werken ..., ik kan er uren naar kijken
als de loop loopt, zou er 'loop' als tekst in de variabele procedure zitten.
ergens in 1 van de subroutines als die procedure = ""; zet, loopt die vast, want komt niet in loop of een ander subroutine.
de subroutines zijn de enige die hun eigen tekst in die variabele zetten, en dan na het einde weer leegmaken.
dan loopt de loop ergens vast waardoor die niet herbegint en dus geen procedure="loop" meer zet
oxurane
Van elk bezoek aan CO leer ik weer meer...
Ik ben eigenlijk wel nieuwsgierig hoe de tijd (uren, minuten en seconden) wordt bijgehouden, nadat je via NTP de meest recente tijd hebt opgehaald. Bereken je dit zelf of gebruik je TimeLib-library ? Indien je de TimeLib-library gebruikt, kun je de delay(1000) uit je code halen.
Denk dan aan het declareren van bijv. "uint8_t prev_Second = 60;"
if (prev_Second != second()) {
/*
Code die per seconde 1x uitgevoerd moet worden
...
...
En tot slot een update voor prev_Second
*/
prev_Second = second();
}
else {
// Code die tijdens de idle-mode uitgevoerd kan worden
}
Opm : prev_Second wordt tijdens start op 60 gezet, zodat het altijd meteen wordt aangepast.
fcapri
ik hou van werken ..., ik kan er uren naar kijken
ntp wordt binnengehaald en in cMin en cHour gezet (current minut, current hour)
daarna zet ik:
updateTimer = 3600;
in mijn loop staat op het einde
delay(1000);
updateTimer--;
dus de loop draait elke seconde en haalt eentje van die 3600 af.
is die 3600 voorbij, doet die een NTP controle en zet de tijd correct. elk uur dus syncroniseert die
ik doe bij elke loop ook telkens deze controle:
if (updateTimer % 60 == 0) { //60
is bij een deling door 60 de rest 0 (exact 1 minuut voorbij), voert die een screen update uit, haal het verbruik of de injectie op, doet wat handelingen.
en in die code ergens wordt er 1 bijgeteld bij de minuut.
ik doe cHour x 60 + minuut. 4h58 wordt dan 298.
ik tel er één bij, komt op 299.
cHour = 298 / 60 (is een int, dus krijgt 4)
cMin = 298 % 60 (rest na een deling van 60, dus krijgt 59).
zo hoef ik dus ook niet te gaan tellen met uren, en wanneer die van 59 naar 60 ga dat ik een uur update doe
elke minuut wordt er wat gedaan, en elk uur gebeurt er een ntp update
oxurane
Van elk bezoek aan CO leer ik weer meer...
Helder. Je houdt zelf bij wanneer een seconde voorbij is via "delay(1000)".
1) via NTP haal je de tijd op.
Je gebruikt dan de uren en minuten om cHour en cMin in te stellen. Ik kan het niet goed zien, maar krijg de indruk dat je de seconden achterwege laat. Dus als het 10:34:01 of 10:34:31 is, maakt niet uit.
2) Seconden-tracker.
Hoe nauwkeurig werkt het bijhouden van de seconden, indien een webpage-request wordt uitgevoerd ? Wordt die delay(1000) dan onderbroken op de achtergrond ?
Als ik eerlijk mag zijn, ben ik -net als anderen- niet gecharmeerd van die "delay(1000)" als seconden-tracker. Je gebruikt bijvoorbeeld de "if (updateTimer % 60 == 0) {".
Stel dat er ergens in deze constructie een aanroep is naar een functie die veel tijd opslurpt, dan is je "delay(1000)" geen betrouwbare seconden-tracker meer.
Ik hintte dus met een reden naar de "TimeLib" en de constructie met prev_Second.
Mijn advies : probeer die library eens, samen met de prev_Second.
-=[EDIT]=-
if (prev_Second != second()) {
/*
Code die per seconde 1x uitgevoerd moet worden
...
...
En tot slot een update voor prev_Second
*/
prev_Second = second();
}
else {
// Code die tijdens de idle-mode uitgevoerd kan worden
}
In het "if"-gedeelte kun je dan iets uitvoeren dat 1x per seconde uitgevoerd moet worden. In het "else"-gedeelte heb je bijvoorbeeld de mogelijkheid om allerlei sensoren of drukknopjes te scannen of andere dingen die leuk of interessant zijn. Indien iets per minuut moet worden uitgevoerd, kun je ook een prev_Minute erbij definieeren als variabele.
En om verwarring te voorkomen : prev_Second en prev_Minute zijn zelf gedeclareerde variabelen. Het had evengoed "oldSec" en "oldMin" kunnen heten.
Je kunt dan denken aan "iets" dat per 5 minuten op 15 seconden uitgevoerd wordt :
if (prev_Second != second()) {
prev_Second = second(); // Update seconden-tracker
doe_Iets(); // Elke volle seconde iets doen
if (prev_Second % 10 == 0) {chk_Temp();} // Check temp per 10 seconden
if (minute() % 5 == 0) { // 1x per 5 minuten
if (prev_Second == 0) { doe_IetsAnders();} // Tijd is bij seconde "0"
if (prev_Second == 15) { doe_NogIets();} // Tijd is bij seconde "15"
}
}
else {
// Code die tijdens de idle-mode uitgevoerd kan worden
scan_Buttons(); // functie die druktoetsen uitleest
}
Edit klein foutje weggehaald (prev_Minute).
En verder gebruik ik prev_Second om mee te vergelijken. Want stel dat "doe_Iets();" meer dan 1 seconde tijd vreet, dan wordt de rest ook nog steeds doorlopen, zoals "chk_Temp();" of "doe_IetsAnders();"