post 18
oke, dit werkt nu.
kan ik dit nog verbeteren ?
Het onderstaan was geschreven voordat je bericht #22 hier plaatste.
Eerst even wat fouten proberen recht te zetten.
nextTickRed = millis() + leds[cnt].pin;
Dat zet nextTickRed op millis() plus het pin nummer; je moet leds[cnt].pinveranderen naar `leds[cnt].interval.
Volgende probleem
if (millis() > nextTickBlue ) { nextTickRed += leds[1].interval; digitalWrite(leds[1].pin, !digitalRead(leds[1].pin)); }
Als het tijd is om de blauwe LED te veranderen veranderen we ook de nextTickRed; niet logisch ![]()
Verder is het de bedoeling dat je cnt gebruikt als index in de arrays (en niet 0 en 1) in de for-loop en dat je geen nextTickxxx gebruikt maar de lastTime in de struct.
Hieronder heb ik (tegen beter weten in
) de nextTick toegevoegd aan de struct.
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// struct for LED
struct LED
{
uint8_t pin; // the pin
uint32_t lastTime; // last time that timing lapsed
uint32_t nextTick; // same approach as in original code
const uint32_t interval; // interval
};
LED leds[] = {
{ 6, 0, 0, 666 },
{ 4, 0, 0, 333 },
};
En in setup() komt dan het volgende
void setup()
{
for (uint8_t cnt = 0; cnt < NUMELEMENTS(leds); cnt++)
{
// set pin to output
pinMode(leds[cnt].pin, OUTPUT);
// set the next tick
leds[cnt].nextTick = millis() + leds[cnt].interval;
}
}
De bedoeling van de for-loop in loop() is dat je niet de indices 0, 1 etc gebruikt maar de cnt variabele; anders heb je bij 8 LEDs nog steeds een lange lap code.
void loop()
{
// for each LED
for (uint8_t cnt = 0; cnt < NUMELEMENTS(leds); cnt++)
{
// check if it's time for the LED indicated by cnt
if (millis() > leds[cnt].nextTick)
{
// update nextTick of the LED indicated by cnt
leds[cnt].nextTick += leds[cnt].interval;
// toggle the LED indicated by cnt
digitalWrite(leds[cnt].pin, !digitalRead(leds[cnt].pin));
}
}
}
Als onze elektriciteit ooit eens gerepareerd wordt (wat een tijd, paas weekend
) zal ik misschien nog een versie maken die lastTime gebruikt.
Vraag wat je niet begrijpt
Succes.
Dank je voor je geduld.
IK denk dat ik nu snap wat en hoe het werkt.
Maar snap je opmerking niet over als onze electriciteit gerepareerd wordt en wat dat te maken heeft met een versie die lastTime gebruikt.
Nu eens goed nadenken hoe ik deze lessen kan gebruiken om de teller te maken.
Maar begin wel te twijfelen of de arduino en deze weg ( geen delay) gebruiken , de goede weg is.
Leer wel veel maar merk ook meer en meer dat ik heel vast in denk patronen zit en daarom niet de oplossingen zie die jij bedenkt.
Wij zitten zonder electriciteit (aardlek). Dus kan vrij weinig doen op het moment. Laptop zal het misschien 12 uur uithouden, mobiel waarschijnlijk een dag. Het is paasweekend en om een electricien te laten komen zal moeilijk worden.
Je benadering met nextTick heeft een probleem na 49 dagen zoals eerder uitgelegd.
Voor de teller heb je deze lessen niet nodig.
Als je alleen een teller wilt die iedere seconde ophoogt kun je delay gebruiken. Als echter bv op hetzelfde moment nog iets anders wilt (bv een knop om de teller te stoppen) wordt het problematischer omdat gedurende die seconde delay de knop niet gelezen zal woeden.
Dat komt met ervaring; geduld hebben, vragen, zoeken op het web enz. en je komt er wel.
Op dit moment , denk ik eraan om een loop van 0 tot x te laten lopen en daarmee te bepalen welke led's aan moeten of welke niet.
Ik zou het met delay kunnen doen en heb dat al een keer gedaan.
Om te blijven oefenen met wat ik hier leer, wil ik proberen geen delay te gebruiken.
Voor de duidelijkheid x staat voor het eindgetal. Met 2 leds zou het dus 4 zijn en met 8 zou ik als ik het goed heb tot 255 kunnen tellen.
Hopelijk heb je geluk met de electricien en vindt je er nog een die snel kan.
Toch een prettige paasdagen gewenst.
Sta op het punt om op te geven.
Heb de code verandert zoals ik dacht dat de teller zou werken.
Maar geen van de leds gaat aan of uit.
OK, we hebben weer electriciteit en geen idee waarom het plotseling weer werkte.
Er zijn een paar dingen die fout gaan in je laatste wokwi.
Het array van structs heeft twee elementen. De indices zijn 0 en 1.
[quote]
for (uint8_t cnt = numbits; cnt > 0; cnt--)
{
...
if (millis() > leds[cnt].nextTick)
...
}
De for-loop begint met cnt 2, daarna cnt 1 en als cnt 0 wordt is de for-loop klaar.
Als je naar de if kijkt zul je de eerste keer leds[2] gebruiken en die bestaat niet. Je moet leds[cnt-1] gebruiken. Dat geldt voor alle leds[cnt] die je hebt.
Het andere probleem is dat je de teller (counter) twee keer ophoogt in die for-loop; die for-loop is allen voor het tonen van de waarde op de LEDs. Als een resultaat heb je, met twee bits, twee keer de counter verhoogt dus die counter zal alleen de waarden 0 en 2 hebben als de for-loop.
Ik denk dat de combinatie van deze twee ervoor zorgt dat de LEDs niets aangeven.
Verder is de benadering met de struct niet nodig voor de teller. Je hebt alleen een array van pinnen nodig zoals getoond in de laatste regel hieronder.
// macro to calculate number of elements in an array of any size
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// counter related
uint8_t counter;
const uint8_t numBits = 2;
// LED pins
const uint8_t ledPins[] = { 6, 4, /*other pins here*/ };
Als je naar een 3-bit teller wilt voeg je een derde pin toe, voor 4-bit ook een vierde pin enz. Alles gescheiden door commas zoals getoond, bv
const uint8_t ledPins[] = { 6, 4, 7, 5, /*other pins here*/ };
In setup() kun je nu alle pinnen uitgang maken met een for-loop.
void setup()
{
Serial.begin(115200);
for (uint8_t cnt = 0; cnt < NUMELEMENTS(ledPins); cnt++)
{
pinMode(ledPins[cnt], OUTPUT);
}
}
En in loop() kun je de waarde tonen, de teller ophogen en even wachten
void loop()
{
// show result on LEDs
for (uint8_t cnt = numBits; cnt > 0; cnt--)
{
if (counter & (1 << (cnt - 1)))
{
digitalWrite(ledPins[cnt - 1], HIGH);
Serial.print("1");
}
else
{
digitalWrite(ledPins[cnt - 1], LOW);
Serial.print("0");
}
}
Serial.println();
// increment counter and check
counter++;
if (counter == 4)
{
counter = 0;
}
// wait a bit
delay(2000);
}
Als je de bovenstaande drie stukjes in je wokwi zet heb je een werkend programma dat netjes de waardes 0..3 laat zien met een twee seconden interval.
OK, dus je wilt geen delay maar een timing gebaseerd op millis().
Voeg het volgende toe net voor setup().
// timing related
uint32_t lastTime;
const uint32_t waitTime = 1000;
En dan kun je loop() aanpassen. Het principe is dat als het tijd is, pas de tijd aan van de laatste update aan, toon het resultaat en verhoog de teller.
void loop()
{
// if it is time
if (millis() - lastTime >= interval)
{
// update de last time that de results were shown on the LEDs
lastTime = millis();
// show result on LEDs
for (uint8_t cnt = numBits; cnt > 0; cnt--)
{
if (counter & (1 << (cnt - 1)))
{
digitalWrite(ledPins[cnt - 1], HIGH);
Serial.print("1");
}
else
{
digitalWrite(ledPins[cnt - 1], LOW);
Serial.print("0");
}
}
Serial.println();
// increment counter and check
counter++;
if (counter == 4)
{
counter = 0;
}
}
}
Nu zitten er twee probleempjes in.
- De eerste keer dat de teller getoond wordt is de waarde 0, dus na het eerste interval zie je nog niets gebeuren. Je kunt dat oplossen door de teller een begin waarde van 1 te geven of door loop() wat om te gooien. Ik heb de eerste benadering gekozen
...
// counter related
uint8_t counter = 1;
...
- Als je het aantal LEDs uitbreidt moet je ook
if (counter == 4)aanpassen. Om dat op te lossen is er een variabele maxVal toegevoegd die in setup() wordt berekent aan de hand van het aantal LEDs en in loop() gebruikt wordt.
// calculate max value for number of bits
maxVal = 2;
for (uint8_t cnt = 1; cnt < numBits; cnt++)
{
maxVal *= 2;
}
Serial.print(F("max teller waarde = "));
Serial.println(maxVal - 1);
Dit is een simpele machtsverheffing (2N) door een aantal keer met twee te vermenigvuldigen
Het volledige programma hieronder
// macro to calculate number of elements in an array of any size
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// led pins
const uint8_t ledPins[] = { 6, 4, /* other pins */ };
// counter related
uint8_t counter = 1;
const uint8_t numBits = NUMELEMENTS(ledPins);
int maxVal;
// timing related
uint32_t lastTime;
const uint32_t interval = 1000;
void setup()
{
Serial.begin(115200);
// initialise pins
for (uint8_t cnt = 0; cnt < NUMELEMENTS(ledPins); cnt++)
{
pinMode(ledPins[cnt], OUTPUT);
}
// calculate max value for number of bits
maxVal = 2;
for (uint8_t cnt = 1; cnt < numBits; cnt++)
{
maxVal *= 2;
}
Serial.print(F("max teller waarde = "));
Serial.println(maxVal - 1);
}
void loop()
{
// if it is time
if (millis() - lastTime >= interval)
{
// update de last time that de results were shown on the LEDs
lastTime = millis();
// show result on LEDs
for (uint8_t cnt = numBits; cnt > 0; cnt--)
{
if (counter & (1 << (cnt - 1)))
{
digitalWrite(ledPins[cnt - 1], HIGH);
Serial.print("1");
}
else
{
digitalWrite(ledPins[cnt - 1], LOW);
Serial.print("0");
}
}
Serial.println();
// increment counter and check
counter++;
if (counter >= maxVal)
{
counter = 0;
}
}
}
Het interval is nu weer 1 seconde en er zijn wat dingen verschoven in vergelijking met de vorige versie.
Één opmerking tot slot; de seriële uitvoer heeft de bits (LEDs) omgekeerd; het is echter de normale manier waarop binaire getallen worden weergegeven.
Werk je er rustig door heen en laat maar horen.
Dank je voor echt al je geduld.
Merk keer op keer dat als zaken complex worden , ik zaken niet zie of door elkaar haal.
De code werkt alleen heb ik een ding verandert.
De volgorde heb ik omgedraaid omdat volgens mijn gevoel de blauwe led de eentallen en de rode de 2 tallen weer geeft.
IK bedoel dus dat bij 1 de blauwe moet branden en bij 10 de rode moet draaien en de blauwe niet.
In de oude code was het net andersom en ik vind dat een beetje raar uitzie.
Mooi dat de electriciteit weer werkt en ik hoop dat je een goede Pasen hebt.
Kun je me nog een keer helpen.
IK probeer het nu met 3 leds en volgens de berekening zou de teller dan tot 11 moeten werken.
Maar ik zie maar 7 getallen verschijnen voordat de teller weer naar nul gaat.
Heb jij een idee waarom dat gebeurt ?
Welke berekening? Met 3 LEDs kun je 23 slechts acht waardes (0..7) weergeven. Met 4 kun je 24 16 waardes weergeven (0..15).
Ik heb niet naar je programma gekeken omdat het me in dit geval niet nodig leek.
Deze berekening die jij hebt toegevoegd.
// calculate max value for number of bits
maxVal = 3;
for (uint8_t cnt = 1; cnt < numBits; cnt++)
{
maxVal *= 2;
}
Serial.print(F("max teller waarde = "));
Serial.println(maxVal - 1);
}
Op dit moment geeft de berekening 11 als max-value waar 7 de goede waarde heeft.
Hint: mijn berekening had daar niet 3 staan ![]()
oops, dan had ik even verkeerd begrepen wat max-value inhield,
klopt het dat met deze code:
`(counter & (1 << (cnt -1)))`
Je controleer of een bepaalde bit 0 of 1 is in de variable counter ?
Inderdaad.
Dank je.
Voor mij is dit topic klaar.
Volgende uitdaging
Maak met een push button en een led code zodat als de led uit staat , hij aan gaat en andersom.
Even wat makkelijker probleem
Die vraag staat hier
Hoe maak ik dit ook alweer werkend ?
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.