Hoe krijg ik het werkend dat ik voor elke effect de snelheid grenzen kan stellen ?

Hoi,

Als laatste wil ik de snelheid grenzen kunnen stellen per effect.

Dus ik heb calcDelay verhuisd naar staart.cpp

#include "effects.h"
#include "pins.h"
#include "output.h"


static EFFECTDIRECTION direction = DIR_NONE;
static int currentLed = 0;
static byte trails[5] = { 0, 0, 0, 0, 0 };

/**
   @brief Calculates the delay interval based on the potentiometer value.

   This function adjusts the delay interval used in a timing operation (e.g., LED effect).
   It calculates the delay interval based on the input potentiometer value (`potValue`)
   by mapping it to a range. The delay interval is used to control the speed of an effect
   that moves in either a clockwise or counter-clockwise direction.

   The function returns different delay intervals depending on whether the potentiometer value
   is less than 482 (counter-clockwise), greater than 542 (clockwise), or near the middle (no delay).

   The delay intervals are mapped as follows:
   - **Counter-clockwise (potValue < 482)**: Mapped from `potValue` to a delay range between 500 ms and 75 ms.
   - **Clockwise (potValue > 542)**: Mapped from `potValue` to a delay range between 75 ms and 500 ms.
   - **Middle range (potValue between 482 and 542)**: Returns 0, which likely indicates no delay.

   @param potValue The potentiometer value (integer), which determines the delay interval.

   @return uint32_t The calculated delay in milliseconds, based on the potentiometer value.
           - A value between 75 and 500 ms for clockwise or counter-clockwise direction.
           - 0 ms if the potentiometer value is in the middle range.
*/
uint32_t calcDelay(int potValue)
{
  // 512 - 30 (middle value - offset)
  if (potValue < 482)
  {
    // calculate new interval for counterclockwise
    return map(potValue, 482, 0, 500, 75);
  }
  // 512 + 30 (middle value + offset)
  else if (potValue > 542)
  {
    // calculate new interval for clockwise
    return map(potValue, 1023, 542, 75, 500);
  }
  // somewhere in the middle
  else
  {
    return 0;
  }
}




/**
   @brief Calculates the direction based on the potentiometer value.

   This function takes an input potentiometer value and returns a direction
   based on its value relative to a middle reference point. The directions
   are defined as either counter-clockwise (DIR_CCW), clockwise (DIR_CW),
   or no direction (DIR_NONE) if the value is near the middle reference point.

   The function uses a middle reference point of 512 and applies a threshold
   of ±30 to determine the direction.

   @param potValue The potentiometer value (integer) to determine the direction.

   @return EFFECTDIRECTION The calculated direction based on the potentiometer value.
           - DIR_CCW (Counter-Clockwise) for values less than 482
           - DIR_CW (Clockwise) for values greater than 542
           - DIR_NONE for values between 482 and 542 (inclusive)
*/
static EFFECTDIRECTION calcDirection(int potValue) {
  // 512 - 30 (middle value - offset)
  if (potValue < 482) {
    // richting wordt linksom
    return DIR_CCW;
  }
  // 512 + 30 (middle value + offset)
  else if (potValue > 542) {
    return DIR_CW;
  }
  // somewhere in the middle
  else {
    return DIR_NONE;
  }
}


/**
   @brief Creates a trailing LED effect that moves in a specified direction.

   This function simulates a trailing effect where LEDs light up in a sequence,
   starting from a `currentLed` position, and the trailing LEDs dim as they move along the sequence.
   The `direction` is determined by the potentiometer value (`potValue`), which controls whether the
   effect moves clockwise (DIR_CW) or counter-clockwise (DIR_CCW). The function also ensures the LEDs
   wrap around when they reach the boundary.

   The trail is maintained in an array (`trails`), where the LEDs move according to the direction
   and their brightness fades as the trail progresses.

   @param potValue The potentiometer value (integer) used to determine the direction (clockwise or counter-clockwise).

   @return bool `true` if the LEDs were successfully set, `false` if there was an error setting the LED color.
*/
bool staart(int potValue)  {

  direction = calcDirection(potValue);

  if (direction == DIR_CW)
  {
    currentLed++;
    if (currentLed >= NUM_LEDS - 1 ) {
      currentLed = 0;
    }
  }

  if (direction == DIR_CCW)
  {
    currentLed--;
    if (currentLed <= 0) {
      currentLed = NUM_LEDS - 1;
    }
  }


  for (int i = 4; i > 0; i--) {
    trails[i] = trails[i - 1];
  }
  trails[0] = currentLed;

  int brightness[4] = { 128, 64, 32, 0} ;

  for (uint8_t cnt = 0 ; cnt < 4; cnt++) {
    if (setLedColour(trails[cnt], CRGB(0, 0, brightness[cnt])) == false) {
      return false;
    }
  } ;


  return true;
}

Maar nu zit ik vast hoe calcDelay aan te roepen omdat dit nu in runeffect wordt gedaan voordat de effecten bekend zijn.

RUNRESULT runEffect(bool (*func)(int), int potValue) {

  // Calculate the delay interval based on the potentiometer value
  uint32_t interval = calcDelay(potValue);

  // Check if the delay interval has elapsed
  if (timer(interval)) {

En pas in de if then de functie wordt aangeroepen die het effect regelen.

Dus graag een paar hints of ideeën hoe ik dit op kan lossen ?

Verwijder de timer code van runEffect en plaats het in de effecten; ieder effect heeft dan zijn eigen timer code.

oke

Daar moet ik dan even over nadenken hoe runeffect er dan uit gaat zien.

Want dat zou betekenen dat de functie heel vaak wordt opgeroepen.

/**
   @brief Runs a specified effect function and checks its status.

   This function manages the execution of an effect by calling a function pointer (`func`)
   that points to the desired effect. The function checks if the effect function is valid
   and if the time interval (calculated using the potentiometer value) has elapsed. It
   then executes the effect function and returns the status of the effect based on its
   return value.

   The status returned by the function indicates whether the effect has completed,
   is still running, or encountered an error. The delay between each execution is
   controlled by the interval, which is calculated using the potentiometer value.

   The possible statuses are:
   - **EFFECT_COMPLETE**: The effect finished successfully.
   - **EFFECT_RUNNING**: The effect is still running.
   - **EFFECT_ERROR**: An error occurred (e.g., no effect function provided).

   @param func A pointer to the effect function to run. This function must take an integer
               parameter (typically a potentiometer value) and return a boolean indicating
               if the effect is complete or still running.
   @param potValue The potentiometer value (integer) used to calculate the delay for the effect.

   @return RUNRESULT The status of the effect:
           - `EFFECT_COMPLETE` if the effect finished successfully.
           - `EFFECT_RUNNING` if the effect is still running.
           - `EFFECT_ERROR` if no valid effect function was provided.
*/
RUNRESULT runEffect(bool (*func)(int), int potValue) {

    // Check if the function pointer is null, indicating no effect function is assigned
    if (func == nullptr) {
      Serial.println("er bestaat geen effect");  // No effect function assigned
      return EFFECT_ERROR;  // Return error status if no effect function is provided
    }

    // Execute the selected effect function with the potentiometer value
    bool status = func(potValue);

    // If the effect function returns true (completed), return EFFECT_COMPLETE
    if (status) {
      return EFFECT_COMPLETE;
    }

    // If the effect function returns false (still running), return EFFECT_RUNNING
    return EFFECT_RUNNING;
  }

  // If the timer hasn't elapsed yet, return EFFECT_RUNNING
  return EFFECT_RUNNING;
}

En dat voelt niet helemaal goed

Maar is dit wel wat je bedoeld of begrijpen we elkaar even niet goed ?

Volgens mij begrijpen we elkaar prima :wink: Gewoon proberen.

Ik heb het geprobeerd met staart en het werkt.

Komende dagen eens proberen met de andere effecten

1 Like

raak weer eens gefrusteerd.

Ik heb sweep veranderd in dit :

#include "Arduino.h"
#include "output.h"
#include "pins.h"
#include "effects.h"
#include "timer.h"


/**
   @brief Calculates the delay interval based on the potentiometer value.

   This function adjusts the delay interval used in a timing operation (e.g., LED effect).
   It calculates the delay interval based on the input potentiometer value (`potValue`)
   by mapping it to a range. The delay interval is used to control the speed of an effect
   that moves in either a clockwise or counter-clockwise direction.

   The function returns different delay intervals depending on whether the potentiometer value
   is less than 482 (counter-clockwise), greater than 542 (clockwise), or near the middle (no delay).

   The delay intervals are mapped as follows:
   - **Counter-clockwise (potValue < 482)**: Mapped from `potValue` to a delay range between 500 ms and 75 ms.
   - **Clockwise (potValue > 542)**: Mapped from `potValue` to a delay range between 75 ms and 500 ms.
   - **Middle range (potValue between 482 and 542)**: Returns 0, which likely indicates no delay.

   @param potValue The potentiometer value (integer), which determines the delay interval.

   @return uint32_t The calculated delay in milliseconds, based on the potentiometer value.
           - A value between 75 and 500 ms for clockwise or counter-clockwise direction.
           - 0 ms if the potentiometer value is in the middle range.
*/
uint32_t calcDelay_sweep(int potValue)
{
  // 512 - 30 (middle value - offset)
  if (potValue < 482)
  {
    // calculate new interval for counterclockwise
    return map(potValue, 482, 0, 800, 75);
  }
  // 512 + 30 (middle value + offset)
  else if (potValue > 542)
  {
    // calculate new interval for clockwise
    return map(potValue, 1023, 542, 75, 500);
  }
  // somewhere in the middle
  else
  {
    return 0;
  }
}




/**
   @brief Creates a sweeping LED effect, moving in a back-and-forth direction.

   This function controls a series of LEDs, lighting up one LED at a time in a sweeping
   motion. The LED sweeps from one end to the other, and once it reaches either end,
   it changes direction. The sweep alternates between clockwise (DIR_CW) and counter-clockwise
   (DIR_CCW) directions each time it hits the boundary (either the first or the last LED).

   The function clears the LEDs before setting the color for the current LED and toggles
   the direction when the boundary is reached. The LED is lit with full brightness (255).

   @param potValue The potentiometer value (integer), which currently is not used but could
                   potentially influence the behavior in future versions of the function.

   @return bool `true` if the sweeping motion direction changed (i.e., when the boundary is reached),
                `false` otherwise (if no boundary is reached or the color setting fails).
*/
bool sweep(int potValue)
{
  static uint8_t idx;
  static int direction = 1;
  clearLeds();
  static int delayTime = calcDelay_sweep(potValue); 

  Serial.print("delayTime : "); 
  Serial.println(delayTime); 

  if (timer(delayTime)) {

  if (setLedColour(idx, 255) == false) {
    return false ;
  };

  idx += direction;
  if (idx == NUM_LEDS || idx == 0)
  {
    if (direction == DIR_CW)
    {
      direction = DIR_CCW;
      idx = NUM_LEDS - 2;
    }
    else
    {
      direction = DIR_CW;
      idx = 0;
    }

    return true;
  }}
  return false;
}

Maar nu als ik de potmeter verander, verandert de delaytime niet

Zet hier a.u.b een link naar je wokwi; dan zal ik deze downloaden er er (hopelijk) in de loop van de dag naar kijken.

link : https://wokwi.com/projects/438929777261353985

Er is geen reden om delayTime een static variabele te maken; het hoeft niet onthouden te worden omdat je bij iedere aanroep van sweep() de berekening opnieuw uitvoert.

calcDelay_sweep() wordt alleen de eerste keer dat sweep() wordt uitgevoerd aangeroepen als de variabele gedeclareerd wordt en daarna nooit meer; de reden is dat het een static variabele is.
Dus delayTime wordt eenmalig gezet en daarna nooit meer veranderd.

Als je delayTime als een static variabele wilt hebben moet je het volgende gebruiken

  static int delayTime;
  
  delayTime = calcDelay_sweep(potValue); 

Als *delayTime geen static variabele is kun je het volgende doen

int delayTime = calcDelay_sweep(potValue); 

Om je probleem te debuggen heb ik in eerste instantie de waarde van potVal bekeken in zowel calcDelay_sweep() als in sweep() met onderstaande codes

  static int oldPotValue = 2000;
  if(potValue != oldPotValue)
  {
    oldPotValue = potValue;
    Serial.print("calcDelay_sweep(), potValue = ");
    Serial.println(potValue);
  }

en

  static int oldPotValue = 2000;
  if(potValue != oldPotValue)
  {
    oldPotValue = potValue;
    Serial.print("sweep(), potValue = ");
    Serial.println(potValue);
  }

Dit toonde dat potVal de positie van de potentiometer volgt en er dus geen probleem in bv de bedrading was geslopen.
Het toonde ook dat calcDelay_sweep() slechts één keer aangeroepen werd (nadat het sweep effect werd gestart) hetgeen me op het juiste pad zette.

===
In staart.cpp heb je de functie calcDelay(). Ik denk dat je, om conflicten te voorkomen, in sweep.cpp de functie calcDelay_sweep() hebt genoemd. Dit is niet nodig als je de functies static maakt.

In staart.cpp

static uint32_t calcDelay(int potValue)
{
  // bereken staart interval
  ...
  ...
}

In sweep.cpp

static uint32_t calcDelay(int potValue)
{
  // bereken sweep interval
  ...
  ...
}

Beide calcDelay() functies horen dan bij hun eigen compilatie eenheid (het .cpp bestand) en er is geen naam conflict. Dit is te vergelijken met een functie in een class die je in een afgeleide class override.

class A
{
public:

  //virtual void print() = 0;
  virtual void print()
  {
    Serial.println(F("printing from class A"));
  }
};

class B : public A
{
public:

  void print() override
  {
    Serial.println(F("printing from class B"));
  }
};

Beiden hebben een print functie maar ze doen iets anders.

pff. voel me na al die tijd dat jij een "mentor" voor me bent, nog steeds een super beginner.

Maar voor 2 effecten werkt het nu.

Is het voor jou ook niet frusterend om te zien dat ik nog steeds struggle met de basics van arduino en/of c++ ?

Dingen komen met ervaring. Je had een gedeelte van de debugging zelf kunnen doen met seriële uitvoer zoals ik dat gedaan had. Dan had je alleen nog met de vraag gezeten waarom calcDelay_sweep() slechts één keer werd aangeroepen.

Het ligt aan het probleem dat je tegenkomt en hier neerzet. Soms denk ik "dat zou je nu toch moeten weten" maar dat geldt niet altijd (zoals in dit geval); maar laat dat je er niet van weerhouden om te vragen, anders kom je er nooit uit en krijg je alleen frustratie.

oke

Even iets offtopic

Ken je iemand die Koepel noemt op discord en misschien ook hier.
Ik had wat vragen over rtos uit niewsgierigheid en toen ik vertelde dat ik met arduino werk en jij me helpt dat hij jouw kende uit naam.

Ik ken hem niet persoonlijk. Er was een Koepel hier op het forum maar die heeft afscheid genomen op het forum: Leaving the forum, but still enthusiastic about Arduino.

oke

IK ga verder werken.

Hopelijk krijg ik dit project af voor mijn vakantie.
Die loopt van 1 sept tot 21 september.

Kun je eens mee kijken naar deze code

#include "effects.h"
#include <FastLED.h>
#include "pins.h"
#include "output.h"
#include "timer.h"


static bool LED0 = 0;

/**
  @brief Calculates the delay interval based on the potentiometer value.

  This function adjusts the delay interval used in a timing operation (e.g., LED effect).
  It calculates the delay interval based on the input potentiometer value (`potValue`)
  by mapping it to a range. The delay interval is used to control the speed of an effect
  that moves in either a clockwise or counter-clockwise direction.

  The function returns different delay intervals depending on whether the potentiometer value
  is less than 482 (counter-clockwise), greater than 542 (clockwise), or near the middle (no delay).

  The delay intervals are mapped as follows:
  - **Counter-clockwise (potValue < 482)**: Mapped from `potValue` to a delay range between 500 ms and 75 ms.
  - **Clockwise (potValue > 542)**: Mapped from `potValue` to a delay range between 75 ms and 500 ms.
  - **Middle range (potValue between 482 and 542)**: Returns 0, which likely indicates no delay.

  @param potValue The potentiometer value (integer), which determines the delay interval.

  @return uint32_t The calculated delay in milliseconds, based on the potentiometer value.
          - A value between 75 and 500 ms for clockwise or counter-clockwise direction.
          - 0 ms if the potentiometer value is in the middle range.
*/
static uint32_t calcDelay(int potValue)
{
 // 512 - 30 (middle value - offset)
 if (potValue < 482)
 {
   // calculate new interval for counterclockwise
   return map(potValue, 482, 0, 500, 75);
 }
 // 512 + 30 (middle value + offset)
 else if (potValue > 542)
 {
   // calculate new interval for clockwise
   return map(potValue, 1023, 542, 75, 500);
 }
 // somewhere in the middle
 else
 {
   return 0;
 }
}





/**
  @brief Toggles an LED state and alternates between two LED patterns.

  This function toggles the state of `LED0` (a boolean variable controlling
  an LED) and switches between two predefined LED patterns, setting each LED
  color in the array based on the state of `LED0`. The two patterns are stored
  in a 2D array, where the first pattern lights up LEDs in alternating blue and black
  stripes, and the second pattern switches the stripes to different positions.

  The function updates all LEDs using the appropriate pattern, based on the current
  state of `LED0`. If there is an issue with setting the LED colors, it returns `false`,
  otherwise, it returns `true`.

  @param potVal The potentiometer value (integer) which is not currently used
                in the function but could potentially be added for controlling
                the speed or intensity of the pattern in future versions.

  @return bool `true` if the LED colors were successfully updated,
               `false` if there was an error while setting the LED colors.
*/
bool tweeKeer(int potVal)
{

 LED0 = !LED0;
 CRGB leds_working[2][16] = {
   { CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black
   },
   { CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue,
     CRGB::Black,
     CRGB::Black,
     CRGB::Blue,
     CRGB::Blue
   },
 } ;

 int interval = calcDelay(potVal);

 if (timer(interval))
 {
   if (setAllLedColours(leds_working[LED0], NUM_LEDS) == false) {
     return false;
   };
 }

 return true;
};

ik heb calcDelay toevoegd maar als ik op wokiki probeer, lijkt het net of er soms op dat het effect even stopt.

Verbeeldt ik me het of zit er een probleem in de code ?

Wanneer calcDelay een waarde van de potmeter vindt die out of bounds is, dan is de return nul.
Dat zal het effect vermoedelijk stoppen, en is dan dus by design.
Uiteraard is dat alleen het geval wanneer het effect ook een stop er in heeft zitten, dat heb ik niet gecontroleerd.

Een debug is snel gemaakt zodat je weet wat je terugkrijgt van calcDelay, en dan dus ook kunt vaststellen of dit de oorzaak is van wat jij ziet.

Nee, dat verbeeld je je niet.

Hoe vaak denk je dat de regel LED0 = !LED0; uitgevoerd wordt?

Dank je

IK heb de functie veranderd naar :

bool tweeKeer(int potVal)
{

  
  CRGB leds_working[2][16] = {
    { CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black
    },
    { CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue,
      CRGB::Black,
      CRGB::Black,
      CRGB::Blue,
      CRGB::Blue
    },
  } ;

  int interval = calcDelay(potVal);

  if (timer(interval))
  {
    LED0 = !LED0;
    
    if (setAllLedColours(leds_working[LED0], NUM_LEDS) == false) {
      return false;
    };
  }

  return true;
};

en ga het vanmiddag even testen.
Nu klaar maken voor therapie :frowning:

Kun je beschrijven waarom je vorige tweeKeer() niet werkte?