[Vraag over RTC] DayOfWeek register

Ik heb een vraag over de werking van een RTC (M41T00). Ik denk dat het zelfs een algemene vraag is over de werking van een RTC.

Er zijn registers voor seconden, minuten, uren, weekdag, maand-dag, maand en jaar. Ik vermoed dat de weekdag (DOW = Day Of Week) een losse teller is. Evengoed de dag (DD), maand (MM) en jaar-teller (YY).

Oftewel zodra de uren, minuten en seconden-registers verspringen van 23:59:59 naar 00:00:00, vinden 2 vervolgprocessen plaats :
1) Weekdag register wordt aangepast
2) Maand-dag register wordt aangepast (evt. maand en jaar-register)

In mijn geval ben ik puur geinteresseerd in de DOW-register, niet de DD MM en YY registers. Er is daardoor een grote kans dat de DOW niet in lijn is met de DD MM en YY registers. Ik probeer boven water te krijgen of de dagweek kan / mag afwijken van de datum.

Met andere woorden, klopt de beschreven werking van de RTC ?

Van elk bezoek aan CO leer ik weer meer...
Arco

Special Member

De DOW wordt door de gebruiker vastgesteld (1...7)
Dit is gedaan omdat dag 1 niet altijd hetzelfde is (kan zondag of maandag zijn), enige is dat de dag bij roll-over naar 00:00:00 wordt verhoogd.

Er wordt wel aangeraden altijd een 'legale' waarde in de datum/tijd registers te stoppen: illegale waardes kunnen tot onvoorspelbaar gedrag leiden...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

Arco : Bedankt voor je reactie ! Daar kan ik wat mee. Ik ben namelijk bezig met een timer waarbij een ESP8266 met de RTC werkt om verlichting aan te sturen. Ik programmeer voor het eerst onder Arduino IDE en probeer - voor zo ver het gaat - daarin de dingen voor elkaar te krijgen. Inmiddels kan ik rechtstreeks met de RTC communiceren (lezen/schrijven) met alleen de wire.h-library, maar ik erger me dood aan de algemene programmeerwijze. Komt grotendeels door de onbekendheid (ik ben thuis in Bascom en dat gaat een "stukje" anders).

Enfin, via een HTTP-GET komt data binnen die gecontrolleerd moet worden op validiteit. Ik ga dan strings in stukjes knippen, omzetten naar byte en vervolgens controleren of de getallen kloppen. Daar schrijf ik functies voor. Maar man wat een gepiel en geneuzel. De ene keer klopt de functie en kan ik aanroepen. Kopieer ik het naar een ander project / sketch, krijg ik allerlei foutmeldingen. Ik had zo ook iets met datum en dan omrekenen naar DOW. Ik wil daar dus van af en me beperken op de DOW. Vandaar dat ik dus erg blij ben met je antwoord (two thumbs up !) zodat ik weer verder kan stoeien. Nogmaals, bedankt !

-=[ EDIT ]=-
Zo heb ik ook nog niet helder voor de geest hoe dat zit met EEPROM en LittleFS. Ze zeggen dat een ESP8266 geen EEPROM heeft. Maar er zit wel een 4MB EEPROM op de PCB geplakt. Daarnaast dien je de EEPROM te definieeren en dat het niet zomaar werkt. Wat gebeurt er als je opnieuw code naar de ESP8266 "flashed" ? Is de EEPROM dan ook verdwenen ? Maar goed, volgens mij niet echt vragen die bij CO horen.. Ik ploeter nog wel even voort.

Van elk bezoek aan CO leer ik weer meer...

Ik werk hier met de ESP32, uit dezelfde stal. Dat zal ongeveer hetzelfde werken als jouw ESP8266.

Die heeft ook een 4Mb flash geheugen on board. Daarin kun je verschillende 'partities' definiëren en daarbij ook aangeven waar die voor gebruikt worden. De mijne heeft 3 partities voor code en 1 voor data. Nieuwe software gaat altijd naar een code partitie en daarbij blijft de data partitie ongemoeid.

Er zijn meerdere 'code' partities om 'OTA' (over the air) updates mogelijk te maken. Dan kun je dus nieuwe software laden terwijl de bestaande software blijft lopen. Dan kun je later omschakelen naar de nieuwe software als het laden volledig gelukt is, en eventueel weer terugschakelen als blijkt dat de nieuwe software toch niet naar tevredenheid functioneert. De derde code partitie is bedoeld als 'factory default'.

De 'data' partitie kun je gebruiken om data weg te schrijven (name/value pairs). Maar je kunt ook een file system aanmaken en dan data in 'files' wegschrijven en teruglezen. Dat laatste is dan de SPIFFS.

buckfast_beekeeper

Golden Member

Als RTC gebruik ik normaal de DS3231 met dit schema

De gebruikte library is RTClib. Deze heeft een functie dayOfWeek(tijd).

c code:

uint8_t weekdag = dayOfWeek(tijd);

tijd is een time_t waarde.

Zondag is standaard dag 0.

Deze library zou moeten bruikbaar zijn met M41T00. Bekijk dit voorbeeld. Belangrijk

c code:


#include <i2c_rtc_m41t00s.h>

i2c_rtc_m41t00s rtc;

uint8_t weekdag = rtc.time.dow;

Een ESP32/ESP8266 heeft inderdaad geen EEPROM. Die wordt geëmuleerd in programma geheugen. Bij upload van je code kan je kiezen dat je LittleFS en EEPROM wil leeg maken of niet.

Een externe EEPROM wordt dan niet gewist. Dit beeld is van een ESP32 project maar voor de ESP8266 is dat niet anders.

Als EEPROM gebruik ik normaal een 24LC64 met de I2C_eeprom library.

Op 1 september 2023 21:56:08 schreef deKees:
Ik werk hier met de ESP32, uit dezelfde stal. Dat zal ongeveer hetzelfde werken als jouw ESP8266.

[...]

Maar je kunt ook een file system aanmaken en dan data in 'files' wegschrijven en teruglezen. Dat laatste is dan de SPIFFS.

Er zijn toch wat verschillen tussen beide. Als je ESP8266 code wil gaan gebruiken op een ESP32 ga je toch wel wat aanpassingen moeten maken.

SPIFFS is deprecated en vervangen door LittleFS en FatFS. Tijdens het compileren ga je daar ook op gewezen worden.

[Bericht gewijzigd door buckfast_beekeeper op 1 september 2023 22:13:36 (21%)

Van Lambiek wordt goede geuze gemaakt.
Arco

Special Member

Je kunt de datasheet van de DS1340 van Dallas (nu Analog Devices) gebruiken: is equivalent en staat wat meer in...
Weekdag berekenen is simpel (voorbeeld in Mikrobasic):

pic basic code:


Const MonthVal       As Byte[12] = (0,3,3,6,1,4,6,2,5,0,3,5) 'Lookup table

Sub Procedure SetWeekDay()
  Weekday = ((Year-2000)+(((Year-2000) div 4) mod 7) + MonthVal[Month-1] + 6 + Monthday) mod 7
End Sub
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

Zo, veel info en reacties. Bedankt allemaal !

Vooruit dan maar. Dan ga ik toch even wat dieper in op waar ik mee bezig ben. Ik heb een bordje ontworpen en inmiddels voorzien van een ESP12 en kan het besturen als een NodeMCU in Arduino IDE. Omdat ik nog wat M41T00's heb, zit die er ook op gesoldeerd. Dit is omdat ik deze RTC wil gebruiken om de tijd in de gaten te houden, wanneer ik een aangesloten LED aan/uit wil schakelen.
Een M41T00 is compatible met een DS1307, qua pins en registers.

Het is de bedoeling dat er instellingen opgeslagen kunnen worden. Daarvoor heb ik HTML-bestandjes (met <forms>). Elke pagina heeft eigen functie, en komen neer op het volgende :

1) tijd / weekdag instellen
2) In/uitschakeltijden instellen
3) Netwerkgegevens (softAP / station)
4) Algemene pagina om vlot ingestelde gegevens in te kunnen zien.

Deze instellingen wou ik in eerste instantie in de EEPROM zetten. Daarvoor is een EEPROM.h beschikbaar. Dat creeert een soort virtuele EEPROM. Handig, want als het boardje spanningsloos is, kunnen de instellingen er weer uit opgelepeld worden. Ik meende ergens gelezen te hebben dat indien je iets wijzigt in deze virtuele EEPROM, de hele bups wordt verhuisd naar een andere plek. Ik kreeg vaag het beeld van hoe dat met rewritable CD-ROMs gaat.

Voor mij een reden om dan over te stappen naar LittleFS. Dan een soort JSON-file met daarin de instellingen opslaan. Ook prima. Voordeel is, dat ik dan ook meteen een plek heb om die HTML-files op te slaan.

Het magische woord is : foto. Dat maakt het meestal een stuk interessanter. Goed, ik heb net een foto gemaakt van het printje. Dan krijg je een beter beeld bij waar ik mee zit te stoeien.

-=[ EDIT ]=-
Even nog een aanvulling. Ik had eerst de meest recente Arduino IDE geinstalleerd (2 punt nogwat). Het mooie is dat er best veel info op internet gevonden kan worden, voor de ESP8266. Sterker nog, Youtube is rijkelijk voorzien van instructie-videos. Het grote nadeel is : erg veel informatie is gebaseerd op de oudere Arduino-versie. Ik heb al diverse keren mn neus gestoten tegen bijv. het installeren met libraries. Dan zit je diverse keren te verbazen en vervolgens te tieren als iets niet werkt, zoals het wordt uitgelegd. Dat heeft me al veel tijd gekost. Dus, daarom maar uit nood een oudere versie geinstalleerd...

Van elk bezoek aan CO leer ik weer meer...
buckfast_beekeeper

Golden Member

Ik gebruik nog steeds de 1.18 versie. In de 2.x versie zitten nog te veel bugs. Onderandere het verdwijnen van de ESP32 library was er 1 van. Voor 2.x is er ook nog geen lader voor LiitleFS, SPifFS of FatFS. Voor de 1.18 versie is die er wel. Dit is wel verschillend voor ESP32 en ESP8266.

HTML steek ik niet in LittleFS. Gewoon een .h bestand. Zoveel memory spaar je daar niet mee. Je mag het testen. Elke HTML pagina in een apparte .h file.

c code:

#include "htmlRoot.h"
#include "htmlLoginIndex.h"
#include "htmlServerIndex.h"

Waarna je de gegevens in deze .h file gewoon kan gebruiken.

c code:

void setupHTML() {
  server.on("/", []() {
    /*if (!server.authenticate(www_username, www_password)) {
      server.requestAuthentication();
      }*/
    htmlPage = FPSTR(rootHtmlHeader);
    htmlPage.concat(FPSTR(style));
    htmlPage.concat(FPSTR(rootBodyMain));
    server.send(200, "text/html", htmlPage);
  });
  htmlPage = FPSTR(loginIndex);
  htmlPage.concat(FPSTR(style));
  server.on("/update", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", htmlPage);
  });
  htmlPage = FPSTR(serverIndex);
  htmlPage.concat(FPSTR(style));
  server.on("/serverIndex", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", htmlPage);
  });
  /*handling uploading firmware file */

  server.on("/updater", HTTP_POST, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "ok");
    ESP.restart();
  }, []() {
    HTTPUpload& upload = server.upload();
    if (upload.status == UPLOAD_FILE_START) {
      Serial.printf("Update: %s\n", upload.filename.c_str());
      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_WRITE) {
      /* flashing firmware to ESP*/
      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_END) {
      if (Update.end(true)) { //true to set the size to the current progress
        Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
    }
  });
  server.begin();
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
}

Wel zorgen dat het in je ROM blijft en niet in RAM wordt geladen.

c code:

static const char rootBodyMain[] PROGMEM = R"=====(

Dan je HTML tekst en afsluiten met

c code:

)=====";

In een EEPROM kan je ook een JSON stream opslaan. Je kan ook writeBlock of updateBlock gebruiken.

Van Lambiek wordt goede geuze gemaakt.

Hmm,. dat is best complex wat je schrijft (voor een beginner). Wat ik als alternatief had bedacht was een functie te maken van elke html-page, als een string en deze vervolgens met "replace" te bewerken.
Zoiets als :

code:


String Func_Page() {
    String WebPage="<html>=head=<body>=Inhoud=</body></html>";
    return WebPage;
}

En in het hoofdprogramma de webpagina oproepen en delen aanpassen via :

code:


 String HtmlPage = Func_Page();
 HtmlPage = HtmlPage.replace("=head=","<head><title>HoofdPagina</title></head>");

// en zo ook voor de =Inhoud=

Ik lees ook iets over ROM. Dat is bijzonder interessant dat je dit aanstipt. Ik had al mn vraagtekens bij : [] PROGMEM = R"=====(.
Ik begreep totaal niet wat dat betekende of zou doen. Nu is het me een beetje duidelijk geworden.

Verder is dat over het ontbreken van een lader precies de druppel die me overhaalde om naar een lagere versie te gaan.

Tot slot, is dat wat ik voorstel, mogelijk (tekst aanroepen via een functie) ? Of bestaat de kans dat dat niet goed gaat of teveel geheugen gaat vreten ?

-=[ edit ]=-
Even wat foutjes weggeschraapt in code.

Van elk bezoek aan CO leer ik weer meer...
buckfast_beekeeper

Golden Member

Wil je een HTML pagina die zich ververst als er nieuwe gegevens zijn? Werk dan met websocket. Je kan dan zowel uit de ESP de pagina aanpassen als waardes versturen vanuit je client zonder dat er een refresh nodig is.

Het probleem bij PROGMEM, dat is zoveel als een constante String die niet kan gewijzigd worden. Om te wijzigen moet die in RAM.

EDIT: als de M41T00 quasi gelijk is aan de DS1307, dan kan je ook RTClib gebruiken. In de voorbeelden zit ook code voor de DS1307.

[Bericht gewijzigd door buckfast_beekeeper op 3 september 2023 10:12:35 (13%)

Van Lambiek wordt goede geuze gemaakt.

PROGMEM is een term uit de AVR hoek. Die plaatst de string in flash geheugen en dan zijn er andere instructies nodig om die te benaderen.

Op een ESP heeft dat geheel geen effect. Daar is het een dummy die niks doet.

Zie pgmspace.h voor ESP:

code:


#define PROGMEM
#define PGM_P         const char *
#define PGM_VOID_P    const void *
#define PSTR(s)       (s)
#define _SFR_BYTE(n)  (n)

Die is alleen gedefiniëerd om de code portable te houden zodat dezelfde code op verschillende processors kan draaien.

Bij deze plaats ik afbeeldingen van de webpages die ik heb gemaakt voor de ESP12. Ik denk dat daarmee best duidelijk wordt, waar ik mee bezig ben.
Ik heb dus html-pagina's waarin ik teksten met %xxx% heb staan. Deze zijn bedoeld om gegevens neer te zetten, die de ESP12 bij houdt of ingesteld worden.

  • Main
    Dit is de hoofdpagina waarin je de actuele instellingen kunt bekijken
  • Basic
    Basis-instellingen. Laat zien of de lamp is ingeschakeld, met welke PWM-waarde en verder de tijd en dag (DOW). Zoals je ziet, er is een Submit-knop. Je kunt de gegevens dus ook wijzigen.
  • Timer1
    De pagina waarop ingesteld kan worden op welke dagen (DOW) en tijden de lamp in/uitgeschakeld wordt. Net als bovenstaand puntje : de gegevens kunnen gewijzigd worden.

De werking van de overige tabs zal geen verrassing zijn. Deze werken hetzelfde als de "Basic-pagina" maar dan met andere gegevens.

P.S. Arco : Deze code is inderdaad mooi om te gebruiken. Trouwens, hoe komt een tijdstring binnen ? Testen met de HTML-pagina laat voor bijv. 10:00 zien dat er "10%3A00" verzonden wordt. Maar hoe komt het weer binnen via server.arg() binnen ? "10:00" of "10%A300" ?

Van elk bezoek aan CO leer ik weer meer...
buckfast_beekeeper

Golden Member

Met websockets en json verzend je de gegevens op de manier dat je wil.

Op mijn ESP onder andere deze verzendfunctie

c code:


void postPompNode() {
  if (flgWebSocketOpen) {
    StaticJsonDocument<400> doc;
    doc["status"] = "Pomp";
    doc["pompAdres"] = pompNode.adres;
    doc["pompAlive"] = pompNode.alive;
    doc["pompOn"] = pompNode.pompOn;
    doc["pompKlepOn"] = pompNode.klepOn;
    doc["waterIn"] = pompNode.waterIn;
    doc["waterInFlow"] = pompNode.waterInFlow;
    doc["waterInJaar"] = pompNode.waterInJaar;
    doc["waterUit"] = pompNode.waterUit;
    doc["waterUitFlow"] = pompNode.waterUitFlow;
    doc["waterUitJaar"] = pompNode.waterUitJaar;
    doc["pompRTCTemperatuur"] = pompNode.rtcTemperatuur;
    doc["versie"] = pompNode.versie;
    doc["lastScan"] = dateTimeToString(pompNode.lastScan, false, false);
    //Serial.print("post node: ");
    //Serial.println(pompNode.versie);

    char json[400];
    serializeJson(doc, json);
    webSocket.broadcastTXT(json);
  }

In de html pagina heb je dan deze html code:

code:


<table style="width: 80%" align="center">
      <tr>
        <th class="tdMid">Adres:</th>
        <th class="tdMid">Alive:</th>
        <th class="tdMid">Werking:</th>
        <th class="tdMid">Klep:</th>
        <th class="tdMid">Water in<br>in liter:</th>
        <th class="tdMid">Max water in flow<br>in liter/minuut:</th>
        <th class="tdMid">Water dit jaar in<br>in liter:</th>
        <th class="tdMid">Water uit<br>in liter:</th>
        <th class="tdMid">Max water uit flow<br>in liter/minuut:</th>
        <th class="tdMid">Water uit jaar in<br>in liter:</th>        
        <th class="tdMid">RTC temperatuur<br>°C:</th>
        <th class="tdMid">Laatste scan:</th>
        <th class="tdMid">Versie:</th>
      </tr>
      <tr>
        <td class="tdMid" id="pompAdres"></td>
        <td class="tdMid" id="pompAlive"></td>
        <td class="tdMid" id="pompAan"></td>
        <td class="tdMid" id="pompKlep"></td>
        <td class="tdMid" id="pompIn"></td>
        <td class="tdMid" id="pompInFlow"></td>
        <td class="tdMid" id="pompInJaar"></td>
        <td class="tdMid" id="pompUit"></td>
        <td class="tdMid" id="pompUitFlow"></td>
        <td class="tdMid" id="pompUitJaar"></td>
        <td class="tdMid" id="pompRTCTemperatuur"></td>
        <td class="tdMid" id="pompLastScan"></td>
        <td class="tdMid" id="pompVersie"></td>
      </tr>
    </table>    

En deze java script code

c code:


          else if(dataS["status"] == "Pomp"){
            document.getElementById("pompAdres").innerHTML = dataS["pompAdres"];
            if(dataS["pompAlive"]){
              document.getElementById("pompAlive").innerHTML = "Ja";
              // indien pomp online is verdere gegevens tonen
              if(dataS["pompOn"]){
                document.getElementById("pompAan").innerHTML = "Aan";
                document.getElementById("buttonPomp").className = "buttonOff";
                document.getElementById("buttonPomp").innerHTML = "Pomp uit";
              }     
              else{
                document.getElementById("pompAan").innerHTML = "Uit";
                document.getElementById("buttonPomp").className = "buttonOn";
                document.getElementById("buttonPomp").innerHTML = "Pomp aan";
              }      
              if(dataS["pompKlepOn"]){
                document.getElementById("pompKlep").innerHTML = "Open";
                document.getElementById("buttonPompKlep").className = "buttonOff";
                document.getElementById("buttonPompKlep").innerHTML = "Pomp klep dicht";
              }     
              else{
                document.getElementById("pompKlep").innerHTML = "Toe";
                document.getElementById("buttonPompKlep").className = "buttonOn";
                document.getElementById("buttonPompKlep").innerHTML = "Pomp klep open";
              }      
              document.getElementById("pompIn").innerHTML = dataS["waterIn"].toFixed(2);
              document.getElementById("pompInFlow").innerHTML = dataS["waterInFlow"].toFixed(2);
              document.getElementById("pompInJaar").innerHTML = dataS["waterInJaar"].toFixed(2);              
              document.getElementById("pompUit").innerHTML = dataS["waterUit"].toFixed(2);
              document.getElementById("pompUitFlow").innerHTML = dataS["waterUitFlow"].toFixed(2);
              document.getElementById("pompUitJaar").innerHTML = dataS["waterUitJaar"].toFixed(2);                            
              document.getElementById("pompRTCTemperatuur").innerHTML = dataS["pompRTCTemperatuur"].toFixed(2);
              document.getElementById("pompLastScan").innerHTML = dataS["lastScan"];
              document.getElementById("pompVersie").innerHTML = dataS["versie"];                                    
            }     

Er zit ook de code in die de respectievelijke buttons van de juiste tekst en kleur voorziet.

En dat ziet er dan zo uit;

edit: voor tijd kan je kiezen voor UTC of de npormale tijd. Maar in json kan je ook kiezen je datum en dergelijke in losse dagen, uren en minuten te verzenden. Je bent redelijk vrij als html pagina en esp de code maar op dezelfde manier begrijpen.

Van Lambiek wordt goede geuze gemaakt.

@buckfast_beekeeper :
OK,. interessant hoe je dat doet. Ik ga het bestuderen omdat ik er nog in thuis moet geraken (2 weken geleden pas echt begonnen met Arduino IDE). Ik heb wel voorzichtig een idee hoe het ongeveer werkt wat je laat zien.

@deKees :
Bedankt voor wat je schrijft over PROGMEM. Het heeft weinig zin om dat dan te gebruiken. Ik heb nog wel een vervolgvraag. Stel ik zet de html-code in een functie. En vervolgens met een andere functie vraag ik het op en voer daar wijzigingen op uit (zoals ik voorstelde). Hoe gaat dat met / in RAM ? Is het zo dat wanneer de complete html-string(webpage) verzonden is, RAM weer wordt vrijgegeven ? Ik vraag het uit voorzorg, omdat ik dingen lees over "heap" en nog wat dingen, waar ik de ballen van snap. Waar het mij om gaat, is dat de boel niet vast gaat lopen. Een andere optie die ik heb, is om de ESP om de 24 uur te resetten, terwijl de lamp / LED uit staat. Dan merkt een gebruiker er erg weinig van, maar netjes is het niet.
Daarnaast de websites vreten erg weinig geheugen, niets aan plaatjes en ik veronderstel dat je eenmalig wat gaat instellen en daarna de boel lekker op de achtergrond laat draaien. Het is een eenvoudige timer om de lamp in/uit te schakelen.

Van elk bezoek aan CO leer ik weer meer...

Oei, nu wordt het ingewikkeld... :)

Een variabele wordt aangemaakt op het moment van declaratie. En de levensduur hangt af van de 'scope'.

Een globale variabele -buiten een functie gedeclareerd- blijft altijd bestaan, zolang het programma draait.

Een lokale variabele (binnen een functie gedeclareerd) bestaat totdat het 'blok' is afgelopen. Zo een variabele wordt aangemaakt op de stack van het proces (thread) dat de variabele aanmaakt.

Bijv :

code:



int GlobalVariable = 12;   // Blijft altijd bestaan

void PrintHtml()
{
   if( ... )
   {  int LocalVariable = 10;  // Alleen binnen het if-blok
      ...
   }
}

LocalVariable kun je alleen gebruiken binnen het if-blok waar hij is gedeclareerd, en daarna is die weg (gerecycled).

De ruimte op de stack is beperkt, zeker in een klein machientje als de ESP. Hooguit een paar kilobyte, al kun je dat wel aanpassen.

De heap is een blok werk-geheugen waar je stukken uit kunt gebruiken dmv malloc(). Die blijft dan bestaan totdat je dat geheugen weer teruggeeft aan de heap dmv free(). Doorgaans gebruik je een pointer om dat geheugen te kunnen benaderen:

Bijv

code:


void PrintHtml()
{
   if( ... )
   {  char *pData = malloc(200);

      sprintf(PData, " .. " .. );
      .. 

      free(pData);
   }
}

Hier neem je een blok van 200 bytes van de heap die je via pData kunt gebruiken. De pointer pData is een lokale variable dus die is weg aan het eind van het if-blok. Voor die tijd moet je de free() aanroepen om het blok terug tegen aan de heap. Want anders wordt dat stuk nooit meer vrijgegeven, en heb je na een tijdje geen heap meer beschikbaar.

Meestal gebruik je die malloc() en free() niet direct. Maar die zitten wel vaak ingebouwd in library funkties. Bijv als je een String declareert dan wordt daar intern een pointer gebruikt en een stuk heap geheugen gereserveerd die je mbv de String funkties kunt gebruiken. De heap van een String wordt automatisch weer vrijgegeven zodra de String out-of-scope gaat, dwz aan het eind van de if-blok. Hiervoor is een 'destructor' funktie aan de String toegevoegd.

Je kunt zo een blok trouwens ook zonder if gebruiken. Dat doe ik soms wel eens om een locale scope te definiëren.

Bijv:

code:


void PrintHtml()
{
   {  int LocalVariable = 10;
      ...
   }

   {  int LocalVariable = 10;
      ...
   }

   {  int LocalVariable = 10;
      ...
   }
}

Hier wordt 3 keer een lokale variabele aangemaakt die telkens aan het eind van het blok (sluithaakje) weer verdwijnt. In het volgende blok kun je dan weer een nieuwe aanmaken, eventueel met dezelfde naam.

@deKees :
Ha, precies de informatie die ik zocht en helder uitgelegd. Top en bedankt !
De pagina's die ik heb gemaakt, komen amper boven de 3 kb uit. Dan kan dat -in mijn geval- dus binnen een functie, omdat de geheugenruimte na afronden van de functie weer vrij komt.

Trouwens, waarom wordt een string als "char" gedefinieerd ? Ik definieer -tot nu toe- bijvoorbeeld :

code:


void htmlPage () {
    String htmlContent;
 
    htmlContent = "bla die bla";
    htmlContent += "nog meer bla die bla";
    // wat bewerkingen
    // zoals htmlContent.replace("Zoek dit","Vervang door dat");
}
Van elk bezoek aan CO leer ik weer meer...

char is een basis-type van de taal. Die staat voor 1 byte.

Een string is dan in principe een array van die bytes. Dus

code:


   char Name[] = "Jan";

Er zijn een flink aantal library funkties om zulke strings te manipuleren. Bijv strcpy(), strcat(), sprintf(). Maar dat is allemaal nogal primitief (stamt uit het stenen tijdperk, +/- 1972).

De String die jij gebruikt bestaat niet in de taal. Maar die wordt dan weer wel via een String library toegevoegd (uit de arduino IDE). Zo een String is feitelijk een object met een hele reeks member funkties die het gemakkelijk maken om zo een String te gebruiken. Zoals heap geheugen management, zoeken, replace etc. In jouw voorbeeld zijn de "=()", de "+=()" en de replace() van die member funkties, en er zijn er nog veel meer.

buckfast_beekeeper

Golden Member

Op 4 september 2023 21:14:48 schreef deKees:
[...]

Een lokale variabele (binnen een functie gedeclareerd) bestaat totdat het 'blok' is afgelopen. Zo een variabele wordt aangemaakt op de stack van het proces (thread) dat de variabele aanmaakt.

[...]

Uitzondering is dan weer een variabele gedeclareerd binnen loop().

Op 4 september 2023 20:15:51 schreef oxurane:
@buckfast_beekeeper :
OK,. interessant hoe je dat doet. Ik ga het bestuderen omdat ik er nog in thuis moet geraken (2 weken geleden pas echt begonnen met Arduino IDE). Ik heb wel voorzichtig een idee hoe het ongeveer werkt wat je laat zien.

We zijn allemaal moeten beginnen. We hebben allemaal geworsteld met bepaalde zaken.

HTML in zijn oervorm is gewoon statisch. Er gebeuren pas wijzigingen als je de pagina een refresh geeft. Alles wordt dan opnieuw opgehaald. Zijn daar plaatjes bij, dan zorg je voor zeer veel webtrafiek. Bij een server zoals bij een krant kom je dan aan gigantische volumes extra.Daar is een oplossing voor gevonden in de vorm van websockets. Die gebruiken een andere poort(81 of 8081) in plaats van 80 of 8080 voor HTML. Deze websocket wordt ook gewoon open gehouden. Zodra de server nieuwe gegevens heeft voor een bepaald item, worden deze gegevens verzonden. Al de gebruikers, die dezelfde pagina geopend hebben, krijgen gelijktijdig dezelfde nieuwe info. De webpagina verwerkt deze in een fractie. Je kan dit testen door de websocket tutorial op een ESP te zetten en meerdere pc's deze laten openen. Drukt er nu 1 cliënt op de toets aa/uit dan wordt dit naar de server gezonden, deze verwerkt dit en zend de nieuwe info door. Dus alle clients hebben altijd de correcte info binnen enkele seconden.

Dit systeem wordt ook gebruikt voor news feeds en dergelijke.

Van Lambiek wordt goede geuze gemaakt.

Uitzondering is dan weer een variabele gedeclareerd binnen loop().

??? loop() (uit arduino) is een gewone functie net als alle andere functies. Daar zijn geen speciale regels voor. Dus ook daar zijn de locale variabelen weg aan het einde van de loop().

Je kunt er wel voor zorgen dat een lokale variabele blijft bestaan aan het eind van blok. Als je dat wilt moet je die 'static' declareren:

code:



void loop()
{  
   int LocalVariable = 10;   // Deze is weg aan het eind van loop()
 
   static int BlijftBestaan = 20;  // Deze blijft wel bestaan

   LocalVariabele += 1;
   BlijftBestaan  += 1;

   Serial.println(LocalVariable);  // Geeft altijd 11
   Serial.println(BlijftBestaan);  // Wordt telkens opgehoogd
} 
buckfast_beekeeper

Golden Member

De scoop van de loop blijft lopen tot je de loop stopt of de stekker er uit trekt. De loop is in principe eindeloos => dat alle variabelen binnen die loop eindeloos blijven bestaan.

Van Lambiek wordt goede geuze gemaakt.

fout. De loop() is een gewone functie. Die wordt alleen telkens opnieuw aangeroepen. Want in de arduino libraries zit een main() functie verstopt die er ongeveer zo uitziet:

code:


int main()
{  setup();
   for ( ;; )
   {  loop();
   }
}

Maar je kunt wel binnen de loop() weer een oneindige loop aanmaken. Dan blijft de scope inderdaad wel bestaan.

Bijv

code:


void loop()
{
   int LocalVariable;

   for ( ;; )   // Oneindige loop
   {  ...
   }
}        // <-- hier kom je nooit. Dus de scope blijft intact.   

[Bericht gewijzigd door deKees op 5 september 2023 11:58:10 (37%)

Voor de lamp is het een overbodige luxe om met meerder personen tegelijk de instellingen van de lamp aan te passen. Dat gebeurt niet. Ik bedoel, eenmaal ingesteld, laat je het lekker rustig draaien.

Er zijn maar enkele instellingen nodig. Die kunnen in EEPROM of via JSon in een "config.json". Ik krijg dat laatste nog niet goed voor elkaar. Dat komt enerzijds doordat ik op de site van ArduinoJson, wel voorbeelden zie, maar die gaan over het ophalen van data via een website, via een SD kaartje, maar ik heb nog geen voorbeelden gevonden voor de LittleFS. Op het moment dat ik dit schrijf, ben ik het voorbeeld van een SD-kaartje aan het overzetten naar LittleFS.
Anderszijds misschien omdat ik het te simpel zie (en benader zoals ik een Atmega programmeer onder Bascom).

Wat ik eigenlijk probeer is dat ik sequentieel data kan lezen / schrijven naar de config.json. Dus dat ik opgeef welk "sleutelwoord" ik zoek en vervolgens de waarde ophalen. En eventueel een gewijzigde waarde terug schrijven naar de config.json.

Basic : is bedoeld om de RTC in te stellen en of de lamp AAN / UIT is / moet.
Timer1 : Instellen welke dagen / tijden de lamp in/uit geschakeld moet worden
Wifi : Nodig bij opstarten als AP en/of Station.

En het andere is, dat ik met LittleFS de html-paginas wil opslaan. Zijn statische pagina's, die met een "replace()" een beetje flexibel is geworden.

De reden dat ik deze keer een ESP12 heb gepakt is, omdat ik het te idioot vond om een Atmega het werk te laten doen en erachter een ESP12 voor een beetje internet-functionaliteit. Dat kan volgens mij heel goed zonder een Atmega en alleen in de ESP12.

-=[ edit ]=-
En als ik bovenstaande eindelijk voor elkaar heb, dan kan het zijn dat ik (veel) later overweeg of er nog andere handige functionaliteiten bij kunnen. Voor nu is het een lamp met ingebouwde timers en dat het eventueel aangestuurd kan worden via een mobieltje. Eerst een beetje ervaring opdoen met Arduino en een ESP12. Dus, maak het me alsjeblieft niet te moeilijk : er is geen noodzaak voor nieuws / weerberichten of het loggen van meetgegevens :)

Van elk bezoek aan CO leer ik weer meer...
buckfast_beekeeper

Golden Member

Persoonlijk zou ik starten van het websocket voorbeeld van enkele antwoorden vroeger.

De HTML pagina's aanpassen naar wens en op dezelfde wijze verder werken.

Daarna de RTC en timer functies integreren. Er is ook een library beschikbaar die je toelaat om schakelmomenten te definiëren. De naam ontgaat me nu even.

Al wat je wil bestaat al. Het is alleen nog de puzzelstukken in elkaar passen.

Van Lambiek wordt goede geuze gemaakt.

Beetje een k-opmerking nu nog, maar is het niet veel handiger om gewoon NTP te doen ? NTP zit tegenwoordig standaard in het Espressif SDK voor zowel ESP8266 als ESP32.

Iets van:

#include <time.h> // time() ctime()

/* Configuration of NTP */
#define MY_NTP_SERVER "at.pool.ntp.org"
#define MY_TZ "CET-1CEST,M3.5.0/02,M10.5.0/03" // gmt+1 + dst

/* NTP Globals */
time_t now; // this is the epoch
struct tm tm; // the structure tm holds time information in a more convenient way

Setup:
configTime(MY_TZ, MY_NTP_SERVER); // --> Here is the IMPORTANT ONE LINER needed in your sketch!

bool NewSecond()
{
time(&now); // read the current time
if (now == before)
{
return false;
}

before = now;
localtime_r(&now, &tm); // update the structure tm with the current time

return true;
}

void loop()
{
if (NewSecond())
{
// this is a new second...

}

In de tm-struct zit dan alle info, maand, jaar dag, etc. maar ook wday.

Nooit meer bijzetten en zomertijd wordt voor je geregeld.

Overigens bak ik tegenwoordig html middels een python script in progmem en laat ik informatie via een api of websockets via javascript in de webpagina actualiseren.

Zie ook https://github.com/GerardZ/YetAnotherWeatherStation
Hier gebruik ik ook websockets...

Ja... en toen ?
buckfast_beekeeper

Golden Member

@oxurane: is het een tijdschakelaar die 's avonds het licht aan doet als het donker wordt en uit als het licht wordt?

Dat kan gewoon door gebruik te maken van de gegevens die beschikbaar zijn. Er zijn minstens 2 plaatsen waar je sunrise en sunset kan opvragen voor je locatie. Hoef je geen uren bij te stellen. Bij mijn kerst verlichting pas ik dat ook toe.

https://api.sunrise-sunset.org/json?lat=52.047688&lng=5.685682&date=to…

of openweather maar daar heb je een key nodig. Uiteraard uren in UTC. Ook in je RTC kan je best UTC tijd gebruiken.

Van Lambiek wordt goede geuze gemaakt.