ESP32-C6-Zero, i2c, SPI hoe te gebruiken?

leuk dat het werkt, als ik ellende heb kan ik hier ook eens terug lezen.

ben zo langzaam aan ook aan het overstappen van arduino naar esp.
nano is heel handig voor kleine dingen, maar als je ermee op een netwerk moet, moet je allerhande shields enzo gaan bijgebruiken. en echt snel zijn ze niet.

werk nu al een tijdje met de simpele esp8266 en die kan vele malen meer, het geheugen is groter, standaard wifi erop...
alleen jammer van die ene analoge input

ik hou van werken ..., ik kan er uren naar kijken

Leuk om te zien dat je het aan de gang hebt. Dat is dan weer het voordeel van Arduino, de tijd tot resultaat is vrij kort.

Wat betreft die chippies van espressif. Ik vind die zelf ook erg leuk inderdaad. Goedkoop en ramvol met features.

Je hebt ze trouwens ook nog in kleinere varianten, als in fysiek kleinere pcb. Ik probeer het te vinden, maar die printjes zijn ook verkrijgbaar met allerlei andere processoren.

Ah, de esp32 xiao van seeed studio. Die heb je in allerlei smaken. Inclusief varianten die ook een batterij backup ding hebben. (zelf geen ervaring mee trouwens)

PE2BAS
blackdog

Golden Member

Hi,

De post met de met de code even opgeschoond en het plaatje bijgewerkt. ;)

hardbass, even opgezocht, eigenlijk is kleiner niet mogelijk dan de esp32 xiao, wil je tenminste op een normalen manier nog iets aan kunnen sluiten.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Haha, mooie aanpassing. (niet per ongelijk vergeten te verwijderen als het straks bij een klant staat of zo.)

Die xiao lijkt me best een grappig printje, al heb ik er op het moment geen usecase voor. Wellicht dat dit nog eens veranderd.

PE2BAS
blackdog

Golden Member

Hi,

Om niet weer een nieuw topic te maken en het HF Oven topic met niet te veel experimenteer spul vol te duwen, plaats ik hier maar even mijn testen met twee displays op één controler.

Het doel hiervan is als ik de PID software in werking zet, ik de drie waarden P, I en D apart kan instellen zonder steeds de software opnieuw te moeten uploaden.

De bedoeling is dus deze waarden "Live" te kunnen aanpassen.
Hiervoor komt er dus een tweede display tijdelijk aan de controler te hangen en wat ik onder meer gisteren vandaag heb gedaan is uitzoeken hoe ik dit goed werkend kan krijgen.

Ik test dit nu even met een Arduino Nano en met het DFRobot 2x16 met RGB achtergrond dislay en het tweede 2x16 LCD display met de gele achtergrond.
Op dit tweede gele LCD komt dus de PID waarde en b.v. de "window" tijd, zeg maar de PWM frequentie.

Het geheel is nu dus werkend en dit is de code hoe ik de twee displays aan stuur.
Wat er op de displays staat is een beetje willekeur, maar daar zit ook niet de moeilijkheid, dat is gewoon de goede variabele in de lcd.print,
of voor het tweede tijdelijke display lcd2.print te zetten.

Nog niet opgeschoonde code.


#include <I2C_Rotary_003.h>
#include "DFRobot_RGBLCD1602.h"
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"

#define DHTPIN 4 
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

LiquidCrystal_I2C  lcd2(0x3F,2,1,0,4,5,6,7); // 0x3F is the I2C bus address for an unmodified backpack


// Create an instance of the DFRobot LCD  
DFRobot_RGBLCD1602 lcd(/*RGBAddr*/0x60 ,/*lcdCols*/16,/*lcdRows*/2);  //16 characters and 2 lines of show




// Declare 3 rotary objects.
// - All use the same I2C address
// - But different switch nrs 
I2C_Rotary Rotary_SW1(0xA0, 1);  // SW1
I2C_Rotary Rotary_SW2(0xA0, 2);  // SW2
I2C_Rotary Rotary_SW3(0xA0, 3);  // SW3

void setup() 
{
   Wire.begin();
   Serial.begin(38400);

  lcd2.begin (16,2); // for 16 x 2 LCD module
  lcd2.setBacklightPin(3,POSITIVE);
  lcd2.setBacklight(HIGH);


    // Setup DFRobot LCD
    lcd.init();
    lcd.setRGB(255, 255, 255);

   Serial.println();
   Serial.println( F("Turn a rotary an see what happens") );
   Serial.println();
   
   // Set parameters for Rotary_SW1
   Rotary_SW1.m_MinValue =   0;
   Rotary_SW1.m_MaxValue = 255;
   Rotary_SW1.m_StepSize =   1;
   Rotary_SW1.m_Value    =   0;
   Rotary_SW1.SetDirection(0);
   Rotary_SW1.SetAccelleration(1);

   // Set parameters for Rotary_SW2
   Rotary_SW2.m_MinValue =   0;
   Rotary_SW2.m_MaxValue = 255;
   Rotary_SW2.m_StepSize =   1;
   Rotary_SW2.m_Value    =   0;
   Rotary_SW2.SetDirection(0);
   Rotary_SW2.SetAccelleration(1);

   // Set parameters for Rotary_SW3
   Rotary_SW3.m_MinValue =    0;
   Rotary_SW3.m_MaxValue =  255;
   Rotary_SW3.m_StepSize =    1;
   Rotary_SW3.m_Value    =    0;
   Rotary_SW3.SetDirection(0);
   Rotary_SW3.SetAccelleration(1);

     dht.begin();
}


void loop() 
{
   delay(100);

  
lcd2.home (); // set cursor to 0,0
lcd2.print(dht.readHumidity(), 1); 
lcd2.setCursor (0,1);        // go to start of 2nd line
lcd2.print(dht.readTemperature(), 1);




   // Scan status of the rotary buttons:
   byte Button1 = Rotary_SW1.Button();
   byte Button2 = Rotary_SW2.Button();
   byte Button3 = Rotary_SW3.Button();

   // Scan status of the rotary clicks:
   int  Clicks1 = Rotary_SW1.Clicks();
   int  Clicks2 = Rotary_SW2.Clicks();
   int  Clicks3 = Rotary_SW3.Clicks();


    lcd.clear();
 //   lcd.setRGB(255, 255, 255);
    lcd.setCursor(2, 0);
    lcd.print("NoiseAmp ASD");

    lcd.setCursor(0, 1);
    lcd.print("R");
    lcd.print(Rotary_SW1.m_Value, 0);

    lcd.setCursor(5, 1);
    lcd.print("G");
    lcd.print(Rotary_SW2.m_Value, 0);

    lcd.setCursor(10, 1);
    lcd.print("B");
    lcd.print(Rotary_SW3.m_Value, 0);

    lcd.setRGB(Rotary_SW1.m_Value, Rotary_SW2.m_Value, Rotary_SW3.m_Value);
    

   // Just write the result to the serial port
   if(Button1)
   {  Serial.print( F("SW1 : Button = ") );
      Serial.println( Button1 );
      Serial.println();
   }
   if(Button2)
   {  Serial.print( F("SW2 : Button = ") );
      Serial.println( Button2 );
      Serial.println();
   }
   if(Button3)
   {  Serial.print( F("SW3 : Button = ") );
      Serial.println( Button3 );
      Serial.println();
   }
   
   if(Clicks1)
   {  Serial.print( F("SW1 : Clicks = ") );
      Serial.println( Clicks1 );
      Serial.print( F("SW1 : Value  = ") );
      Serial.println( Rotary_SW1.m_Value);
      Serial.println();
   }
   if(Clicks2)
   {  Serial.print( F("SW2 : Clicks = ") );
      Serial.println( Clicks2 );
      Serial.print( F("SW2 : Value  = ") );
      Serial.println( Rotary_SW2.m_Value);
      Serial.println();
   }
   if(Clicks3)
   {  Serial.print( F("SW3 : Clicks = ") );
      Serial.println( Clicks3 );
      Serial.print( F("SW3 : Value  = ") );
      Serial.println( Rotary_SW3.m_Value);
      Serial.println();
   }
}

Het DFRobot kleuren schermpje geeft nu de PID waarden weer en voor het tweede scherm staat op de eerste regel de lucht vochtigheid waarde en op de tweede regel de temperatuur.
Beide waarden komen uit een AM2302 sensor, dit is de eerste keer dat ik deze echt test, ik heb er vier op voorraad liggen, ik denk een jaar of zeven geleden gekocht en ze werken nog. :-)
Bagger traag trouwens, maar dit is verder niet zo van belang, ik wou iets "live" op het display hebben en ik kon niet even snel een andere sensor op mijn i2c bus prikken.
De AM2302 gaat verder helemaal niet gebruikt worden in dit project.

Plaatje van heden avond van de contraptie die hier voor mij op tafel ligt.
https://www.bramcam.nl/Diversen/Test-Dual-Display-01.png
.

Gisteren werd ik natuurlijk weer getergt door slechte verbindingen, doordat de displays redelijk wat stroom trekken, geeft dit aardig wat storingen en uitvallen van de verlichting
en blokkeren van de code.
Een deel heb ik maar vast gesoldeerd waar het kon, en vandaag hierdoor geen uitval meer gehad.

Nu ik steeds meer stukjes code werkend krijg moet ik nu gaan nadenken hoe ik dit met timers ga beheren en uitlezen.
Hoe vaak ga ik het hoofd display verversen.
Hoe vaak lees ik de omgeving temperatuur uit.
Hoe vaak lees ik de Luchtvochtigheid uit.
Hoe vaak lees ik de oven temperatuur uit + middeling enz.
Meting van de stroom en de spanning, berekening van het oven vermogen enz.
Misschien ga ik wat logggen, als ik dat doe dan b.v. naar een van mijn servers enz (Low Priority eis)

Ik denk dat ik op het grote Wite Board bij het bedrijf van mijn broer maar eens wat ga kledderen.
Dit heb ik altijd prettig gevonden om zaken wat duidelijker te maken voor mijn brein

Hoe doen jullie dat, ik bedoel dan een structuur maken voor code in grote lijnen, zodat je later de weg nog terug kan vinden.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Ik gebruik drawio en maak een flowchart. Daarnaast gebruik ik in de software statemachines en geen delays.

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/using-mill…

It's the rule that you live by and die for It's the one thing you can't deny Even though you don't know what the price is. It is justified.

ik maak altijd een ruwe samenvatting wat ik wil, en dit staat dan ook zo in blokken in mijn programma.
bv
display: elke seconde,
meting: elke 100mS en na 10x een gemiddelde eruit (waarde veranderd dus elke seconde wat dan weer overeenkomt met het display)

jouw loop is gigantisch groot, ik probeer altijd 10-15regels max te gebruiken, is het meer dan splits ik op/
die "lcd." regels zou ik er allemaal uitgooien en een subroutine maken met update_display();

en dan met een timer bv elke 500ms roep je dan die update display op.

dit is de loop van mijn 'dashboarddisplay' in mijn autos. hier zaten geen timers, elke seconde doet die een update van een scherm, en daartussen doet die metingen. hoefde niks anders te doen, dan maar simpel een delay

void loop(void) {
  // picture loop  
  u8g2.firstPage();  
  do {
    u8g2_prepare();
      draw_screen32w();
  } while( u8g2.nextPage() );
  
  readInput();                        // read analog inputs fuel-voltage-temp
  calculateNumbers();
  printSerial();
  litersold = liters;
  delay(1000);

}

en dit is een loop van mijn serial decoder. normaal stond ook hier een 3de if tussen voor de heartbeat, maar die heb ik gewoon in de metingenloop gezet. hier nog eens elke seconde een millis waarde bijhouden enzo, terwijl ik 10metingen doe over 100ms, en elke keer ik een gemiddelde waarde bereken, geef ik een heartbeat. als die stopt, meet die niks meer en weet ik het ook wel. als mijn waarde in html hetzelfde blijft zou ik anders nooit weten of de waarde identiek is of de boel vasthangt

void loop() {
  if (millis() < lastTime) { //arduino reset
    lastTime = millis();
    measureTime = millis();
    htmlTime = millis();
    starttestTime = millis();
  }

  if ( ((millis() - lastTime) > timerDelay) && go ) { //every 5 seconds run a html update
    getal = getal + 5;
    // getal = (millis() - starttestTime) / 1000;
    if (chargemode == 1) {
      batcharge();
    } else if (invertermode) {
      battest();
    } else  if (automode) {
      autobat();
    } else {
      normalmode();
    }
    lastTime = millis();
    measureTime = millis();
  } else   if ( (millis() - measureTime) > 100 ) {    //if no 5sec past, check to run a measurement and heartbeat
    measureTime = millis();
    measureBat();
  }
  if ( (millis() - htmlTime) > 500 ) {
    htmlTime = millis();
    if (htmlqueue.length() > 1) {
      String bericht = htmlqueue.substring(htmlqueue.indexOf("{") + 1, htmlqueue.indexOf("@"));
      String ontvanger = htmlqueue.substring(htmlqueue.indexOf("@") + 1 , htmlqueue.indexOf("}"));
      htmlqueue = htmlqueue.substring((bericht.length() + ontvanger.length() + 3) , htmlqueue.length());
      events.send(String(bericht).c_str(), ontvanger.c_str(), millis());
    }
    receiver = "";
  }

}

ik heb ooit eens met threads gewerkt, maar dit vind ik altijd moeilijk werken in 'development' mode waar ik dan continue heen en weer moet gaan scrollen.
dan liever in de loop alles definieren en daar ook de tijden wanneer die iets moet doen

ik hou van werken ..., ik kan er uren naar kijken

Je kan ook overwegen om een soort taak scheduling te doen. Dat kan handig zijn als je meerdere stukken code op een vast interval wil uitvoeren. Bijvoorbeeld de 2 pid controllers moeten op een vast interval draaien, anders kloppen de delta T berekeningen niet meer. Ik heb een klein voorbeeld voor je gemaakt van zoon scheduling.


// Arduino Task Scheduler Example
// This code defines a simple task scheduler to run tasks at specific intervals.

#include <Arduino.h>

void task1(TaskContext* context);
void task2(TaskContext* context);

// Struct to define a task's attributes and control its timing
struct TaskContext
{
    void (*taskFunction)(TaskContext* context);  // Pointer to the task function
    unsigned long intervalMs = 1000;             // Default interval in milliseconds (1 second)
    unsigned long previousExecution = 0;         // Last execution timestamp in milliseconds
    unsigned long nextExecution = 0;             // Next execution timestamp in milliseconds
};

// Define the number of tasks and initialize them in an array
#define TASK_COUNT 2
TaskContext taskList[TASK_COUNT] = 
{
    {task1, 1000},    // task1 runs every 1000 ms (1 second)
    {task2, 5000}     // task2 runs every 5000 ms (5 seconds)
};

// Task function 1 - executes every interval set in the taskList
void task1(TaskContext* context)
{
    // This task is scheduled to run based on the interval defined in taskList.
    
    // Changing 'nextExecution' affects only the next run of this task:
    // Here, we delay the next execution by setting it to 5 seconds from now,
    // meaning this task will be called again in 5 seconds, regardless of the interval.
    context->nextExecution = millis() + 5000;

    // Changing 'intervalMs' updates the task's default interval permanently:
    // This means every execution of this task after the next one
    // will occur at this new interval (2.5 seconds in this case).
    context->intervalMs = 2500;
}

// Task function 2 - placeholder for another task to run
void task2(TaskContext* context)
{
    // This is a placeholder function for the second task
    // Here you would add code to perform specific operations periodically.
}

void loop()
{
    // Iterate over the task list and check if each task needs to run
    for (int i = 0; i < TASK_COUNT; i++)
    {
        unsigned long currentTime = millis();  // Get the current time in milliseconds

        // Check if it's time to execute the task
        if (currentTime >= taskList[i].nextExecution)
        {
            // Set the next execution time according to the task's interval
            taskList[i].nextExecution = currentTime + taskList[i].intervalMs;

            // Execute the task function, passing the current task's context
            taskList[i].taskFunction(&taskList[i]);

            // Update the previous execution time to the current time
            taskList[i].previousExecution = currentTime;
        }
    }
}


PE2BAS

Trouwens, op de ESP kan je ook freertos scheduling gebruiken. Echter heeft dat behoorlijk wat dingen waar je rekening mee moet houden. Dus ik zou je afraden dat te gebruiken. Voor nu zou ik alles vanuit de main aanroepen. Die scheduling uit mijn post doet dat ook.

Er is ook nog ruimte voor verbetering / uitbreiding maar ik heb de boel wat eenvoudig proberen te houden.

PE2BAS
blackdog

Golden Member

Hi,

Dank weer voor alle info!

Even dit, het laatste stukje code dat ik hier liet zien was alleen voor de data zichtbaar te maken op de twee displays, dus hoe je dat aanpakt.
De Delay in de loop, is voor het niet zo laten knipperen van de displays, dat irriteerd als het frutsel in mijn ooghoek naast mij ligt.

Per menu pagina, wil ik de "vaste tekst" één keer plaatsen en dat de waarden alleen veranderen als nodig, hier zal ik nog mee moeten gaan experimenteren of dit zinnig is en hoe te doen.

In de laatste code staat nog een heel stuk "serial print" debug code, die is natuurlijk niet meer nodig, alles werk nu voor het aansturen van de displays.
Het ging mij er dus om, te leren hoe ik twee displays ga aansturen zonder dat deze elkaar in de weg zitten en dat werkt nu.

Dan komen we aan bij jullie adviezen. ;)
Mooi, als eerste die van Roland die een link van Adafruit stuurde, een voor mij zeer leesbaar stukje over een State Machine,
deKees heeft me daar een tijd eerder ook al eens iets over laten zien.
Daar ga ik vandaag mee aan de gang met een andere Arduino Nano, daar slingeren er hier genoeg van rond.

Ik ga voor het HF Ovenproject, het houden bij de Teensy LC, anders komt er weer meer uitzoek werk bij en dat past even niet in mijn brein, heb de laatste twee weken even genoeg last van "Aura's" gehad. ;)

Wat hardbass en fcapri laten zien, bevatten if statements met timing en counters.
Ik begrijp wat de bedoeling is, maar het lezen van deze stukjes tekst, geeft niet direct inzicht in hoe/wat/waarom er iets gebeurd.

Niet zoals je mij b.v. een voeding circuits of een versterker schema laat zien, dat ik je direct de functies van de onderdelen van de schema's kan uitleggen.
Dat is het gevolg van mijn taalprobleem, wat meespeelt bij mij is onder meer dit, dat er b.v. van rechts naar links wordt gewerkt en dan weer andersom.
Zo is nu eenmaal C, C++ enz opgebouwd, ik zal het er mee moeten doen. ;)

Als je goed wil leren zal het je meestal een keer of zeven moeten worden uitgelegd/geprobeerd en het helpt bij mij, als ik namen ga geven aan de variabelen die mij aanspreken als het kwartje echt niet wil vallen.
Voorbeeld, deKees gebruikte in een stukje code b.v. % in een regel, daar had hij een goede en galante oplossing mee bedacht, maar dat heeft aardig wat breintijd gekost voor ik het door had.
Zo'n hele regel waar % in staat,valt dan in mijn hoofd onder het kopje chaos, ik begreep wel wat de bedoeling was, maar begreep de eigenschappen van de toegepast % niet.

Mijn Dyslectie zorgt er voor, dat ik nog veel meer dan een normaal persoon, het heel veel moet doen, in die kleine voor mij hapklare brokjes code.
Voor jullie info, mensen met dyslectie raken bij het lezen van een zin, zeg als ze op 60% van de tekst zijn, het voorgaande wat ze net gelezen hebben kwijt en/of het verband rammelt hun hoofd uit.

Ik pas verschillende technieken voor het onthouden toe en je kan in mijn schema's b.v. zien, dat meestal van links naar rechts opgebouwd wordt,
met zo min mogelijk kruislijnen enz. in mijn ogen een mooie structuur.

Dit wringt dan met de code die ik probeer te begrijpen die heen en weer springt(daar kan een hele goede rede voor zijn).
Zo'n 30 jaar geleden schreef ik uitgebreide Batch code met "Go To's" en dat zag er verder mooi gestructureerd uit kan ik zeggen en werkte ook nog eens goed.
Gebouwd met de Norton Editor en daarna omgezet naar een .com bestand.
Als je tegenwoordig als je dit zo doet met Go To's, dan wordt je door de Code politie opgepakt. *grin*

Ik ga vandaag frutten met het lesje van Adafruit dat Roland liet zien en nadenken over jullie tips.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Ik snap het hoor, ben zelf ook dyslect, dus wat je schrijft, herken in wel. Krijg ook wel eens de opmerking 'heb je het überhaupt wel gelezen'. Maar goed, neem de tijd, als je deze Schedler te veel vindt voor nu, lekker laten doen.

Om je toch een indruk te geven, ik heb hier een voorbeeld waarbij ik alle code heb weg gelaten die niet relevant is. Zo zie je dat het een stuk minder ingewikkeld is om te gebruiken.


#define TASK_COUNT 2

TaskContext taskList[TASK_COUNT] = 
{
    {task1, 1000},    // task1 runs every 1000 ms (1 second)
    {task2, 5000}     // task2 runs every 5000 ms (5 seconds)
};

void task1(TaskContext* context)
{
	// Toggle led 1
	led1 = !led1;
}


int count = 0;
void task2(TaskContext* context)
{
	count++;
	lcd.printf(count);
}


@hieronder, klopt. Je kunt in de 'taken' beter geen delays gebruiken. Freertos lost dat wel weer voor je op. Tis ook allemaal een beetje afhankelijk van wat je wilt / kunt.

PE2BAS

Daarbij is het wel belangrijk in de gaten te houden dat elke taak niet langer mag duren dan de kortste interval tijd (in bovenstaand voorbeeld 1 seconde). Anders gaat de boel alsnog uit de pas lopen.

Fan van Samsung (en repareer ook TV's). :)

Wel een mooi voorbeeld van hardbass. Met zo een mechanisme kun je op eenvoudige manier een soort van multi-tasking voor elkaar krijgen. En dat is toch wel krachtig.

Maar toch, zie je vooral low-level code in het voorbeeld en dan heb je nog geen idee wat de applicatie nu eigenlijk doet.

Eigenlijk wil je op top-level geen low-level details, maar alleen de hoofdzaken van de applicatie.
Dan krijg je bijv een loop als :


void loop()
{
   UpdatePidSettings();
   ReadAmbientTemperature();
   ReadHumidity();
   ReadOvenTemperature();
   CalculateOvenPower();
   UpdateDisplay();
}

Dan kun je later die functies invullen en een stapje dieper in de implementatie duiken. Bijv:


void ReadAmbientTemperature()
{  
   static int State = 0;

   switch (State)
   {  case 0:
      {  if( StartAdc() )
         {  state += 1;
         }
         break;
      }
      case 1:
      {  if( ReadAdc() )
         {  CalculateTemperature();
            State = 0;
         }
         break;
      }  
   }
}

En weer, op dit niveau weet je wel dat je de A/D converter nodig hebt om de temperatuur te meten, maar je wilt nog geen low-level details van die ADC. Dat komt later wel als je die StartAdc() en de ReadAdc() functies gaat implementeren.

Uiteraard wil je wat lagen aanbrengen in je code. De tasks kunnen ook betere namen krijgen. Maar goed, t was maar een voorbeeldje natuurlijk. Tis maar wat je wil maken en bovendien, wat voor de programmeur te begrijpen valt.

De functies die in de loop staan van deKees, zouden zo de 'tasks' kunnen zijn in de scheduler.

@Blackdog, lekker proberen. Tis helemaal geen ramp als de code niet heel netjes is. Zolang jij het maar snapt. Als je ergens niet uitkomt of voorbeelden nodig hebt. Een AI kan je goed opweg helpen. Ook kan die goed uitleggen hoe bepaalde stukjes werken. Of als je een probleem beschrijft en de code geeft, kan die vaak ook aangeven waarom iets gebeurt. Ik weet niet of je dit al wist, maar je kan je code opsplitsen in meerdere bestanden. Als je dat doet dan staan alle ingewikkelde dingen niet meer direct in je code. Dat houd het overzichtelijker dan een hele grote file waar alle code in staat.

---

Wellicht nog even goed om aan te geven, de code van mij geplaatst hiervoor heeft wel een aantal 'issues'. Dit is grotendeels wel op te lossen, maar heb ik expres niet gedaan om het simpel te houden. Een paar punten die ik zo kan bedenken:

Korte Executietijd van Taken Vereist:
Taken moeten snel uitgevoerd worden, omdat de scheduler probeert om elke taak op vaste intervallen aan te roepen. Dit betekent dat taken worden uitgevoerd op basis van een tijdstip ("every second on the second"). Wanneer een taak te lang duurt, kan de scheduler deze timing niet langer compenseren, en andere taken kunnen vertraging oplopen.
Mogelijke oplossing: Een soort watchdog kan worden toegevoegd die waarschuwingen genereert als een taak te lang duurt.

Interval aanpassingen worden pas na de volgende iteratie doorgevoerd:
Wanneer je de interval van een taak aanpast, gaat deze wijziging pas in na de volgende geplande uitvoering. Dit kan verwarrend zijn als je verwacht dat de nieuwe interval meteen effect heeft.
Mogelijke oplossing: Je zou functies kunnen toevoegen aan de TaskContext struct om deze intervallen direct aan te passen, terwijl de tijdwaarden (nextExecution, previousExecution) private blijven en via de functies worden beheerd.

Geen rekening gehouden met millis() overflow:
De millis() functie in Arduino reset naar nul na een bepaalde tijd (ongeveer 50 dagen bij 32-bit Arduino’s). Deze overflow wordt momenteel niet opgevangen, wat de timing kan verstoren naarmate de scheduler langer draait.
Mogelijke oplossing: Je kan de overflow detecteren en compenseren.

Geen prioriteitsbeheer tussen taken:
In deze simpele scheduler worden alle taken in een vaste volgorde uitgevoerd zonder prioriteit. Dit kan problemen opleveren als sommige taken belangrijker of tijdkritischer zijn dan andere.

PE2BAS

als ik intressante code vind op internet, probeer ik altijd een basic versie ervan te maken voor in mijn sketchbook. dit is een demo code voor een programma dat 3leds die op verschillende tijd laat knipperen. zonder delays


int led1 = 9;
int led2 = 8;
int led3 = 7;

int led1State, led2State, led3State = LOW;             // ledState used to set the LED
unsigned long led1OldTime = 0;
unsigned long led2OldTime = 0;
unsigned long led3OldTime = 0;
const int led1Interval = 100;
const int led2Interval = 200;
const int led3Interval = 400;
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
}

void loop()
{
  unsigned long currentMillis = millis();
  checkled1(currentMillis);
  checkled2(currentMillis);
  checkled3(currentMillis);
}

void checkled1(unsigned long millies){
    if(millies - led1OldTime >= led1Interval) {
       led1OldTime = millies;   // save the last time you blinked the LED
       if (led1State == LOW)    // if the LED is off turn it on and vice-versa:
         led1State = HIGH;
       else
         led1State = LOW;
       digitalWrite(led1, led1State);  //change state
    }
}

void checkled2(unsigned long millies){
    if(millies - led2OldTime >= led2Interval) {
       led2OldTime = millies;   // save the last time you blinked the LED
       if (led2State == LOW)    // if the LED is off turn it on and vice-versa:
         led2State = HIGH;
       else
         led2State = LOW;
       digitalWrite(led2, led2State);  //change state
    }
}

void checkled3(unsigned long millies){
    if(millies - led3OldTime >= led3Interval) {
       led3OldTime = millies;   // save the last time you blinked the LED
       if (led3State == LOW)    // if the LED is off turn it on and vice-versa:
         led3State = HIGH;
       else
         led3State = LOW;
       digitalWrite(led3, led3State);  //change state
    }
}

dit kan je dan ook maken dat die elke 100ms je menu checked.
elke 500ms een meting doet
elke 1s je scherm update.

gewoon voor elke taak een aparte subroutine.

ik hou van werken ..., ik kan er uren naar kijken

Die is wel makkelijker te begrijpen en in essentie gebeurt er hetzelfde. Ik zou wel de globale variabelen als statics in de functie zelf plaatsen. Dan blijft het allemaal wat beter bijelkaar.

PE2BAS

Geen rekening gehouden met millis() overflow:
De millis() functie in Arduino reset naar nul na een bepaalde tijd (ongeveer 50 dagen bij 32-bit Arduino’s). Deze overflow wordt momenteel niet opgevangen, wat de timing kan verstoren naarmate de scheduler langer draait.

Klopt.

// Check if it's time to execute the task
if (millis() >= taskList[i].nextExecution)

Bovenstaande code geeft problemen na 50 dagen. Je krijgt eerst een overflow bij het zetten van nextExecution. De if geeft dan true bij elke test, zolang millis() nog geen overflow heeft gehad. Dus dan draait het systeem onder delays.

Daarom moet je altijd het verschil berekenen en dat vergelijken met de interval. Dat gaat ook goed igv overflows. Zie het voorbeeld van fcapri:

 if(millies - led1OldTime >= led1Interval) {

ik weet niet of die code dat ook gaat aanvaarden. als led1oldtime een groot getal is, en millis is gereset naar 0, dat heb je daar een negatief getal.

ik maak een thuis accu met arduino en wil ik niet dat die elke 50dagen moet gereset worden. ik probeer dat hier mee. als de millis lager is dan de laatste waardes wordt alles gereset.

 if (millis() < lastTime) { //arduino reset
    lastTime = millis();
    measureTime = millis();
    htmlTime = millis();
    starttestTime = millis();
  } 
ik hou van werken ..., ik kan er uren naar kijken

Ja, dat gaat goed. Want alle getallen zijn unsigned long en kunnen dus nooit negatief worden.

Bijv

Stel millis() = 0xFFFFFFFE en je copieert dat naar LastTime.

10 ms later staat millis() op 0x00000008.
Het verschil (millis() - Lasttime) is dan 10, precies wat je wilt.

Dus die extra controle kun je weglaten. Dat lost een probleem op dat niet bestaat.

Let wel op dat je variabelen unsigned zijn.

Edit, Oh, wat dekees net zegt

[Bericht gewijzigd door hardbass op vrijdag 1 november 2024 18:38:04 (28%)

PE2BAS
blackdog

Golden Member

Hi Heren en Dames ook! ;)

De laatste dagen duidelijk minder tijd gehad om aan de software en het oventje te werken.

Ik post hier nu even omdat ik tegen een klein probleem aan loop.
Het meeste gebruik ik na het goed opschonen i.v.m. veel problemen met de Arduino IDE 2.3.3, wat dus nu weer OK werkt nadat ik de bezem er doorheen heb gehaald.

Maar, ik test nu een Sensor en dat is de i2c BME280 en heb de IDE terminal open.
Ik wil graag de nieuwste gemeten waarden altijd in beeld hebben, maar deze scrolt nu aan de onderzijde uit beeld.

Ik heb met de "Carriage Retun" settings gespeeld maar dat is geen oplossing.
Zit dit in de gebruikte code opbouw van de door mij gebruikte test sketch,
of is is dit een functie van de Arduino IDE en hoe is dit misschien aanpasbaar?

Dank en groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

De arduino monitor is nogal erg beperkt in mogelijkheden.
Het CR charactor '\r' wordt volledig weggefilterd en heeft dus geen effect. En cursor controle is ook niet voorzien voorzover ik kan zien.

Wel heeft de monitor een autoscroll funktie, dus daarmee blijft de laatste regel wel altijd in beeld. Ik heb nog een oude IDE 1.8, en bij mij staat er een vinkje links-onder in de status balk van de Serial monitor.

Maar je hoeft niet de arduino serial monitor te gebruiken, Je kunt ook een echte monitor gebruiken zoals bijv TeraTerm of putty. Al is het dan wel iets lastiger om een sketch te downloaden.

blackdog

Golden Member

Hi deKees, :)

Puttye en Tera Term werken zoals ik het verwacht, dank je.
dan kan ik voor snelle controle van een aantal probeersels die programma's gebruiken.

Zoals de ruis die een sensor heeft bij het uitlezen en wat de aanwezige filtering er mee doet.

Nu nog in die programma's een aantal zaken als default instellen, zodat ik een leesbare font krijg, met een prettige achtergrond kleur.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Arduino IDE 2 ziet er weer heel anders uit zie ik nu. Daar heeft de serial monitor ook een auto-scroll optie, maar die kun je activeren rechts-boven in de serial monitor window, met het knopje met de 2 v-tekentjes, naast het klokje.