Flashing Multiple LEDs at the Same Time

Advert

Flashing Multiple LEDs at the Same Time

Home Forums Electronics in the Workshop Flashing Multiple LEDs at the Same Time

Viewing 25 posts - 1 through 25 (of 25 total)
  • Author
    Posts
  • #776658
    James Alford
    Participant
      @jamesalford67616

      I though that it would be sensible to start a fresh thread for this, following on from my last one on missing libraries.

      The code posted in this post Sample Code has been a great help and has reminded me how I succeeded in flashing several LEDs at the same time in my old, corrupted, code. I used the same principle, but added variables that were initiated when the correct time was set on the RTC. These variables ensured the the LEDs flashed at the start of each minute, hour and so forth. My current iteration of the code has them flashing once a minute and hour, but not at the start of the period.

      I shall post my progress here.

      James.

      Advert
      #776661
      John Haine
      Participant
        @johnhaine32865

        I’m not sure how the code you linked to does it but one way would be to wire all the LED anodes together and feed them from Vcc via a series switch (transistor).  Then the cathodes would be fed from individual outputs, active low.  You set the appropriate combination of outputs for the pattern you want then pulse the switch on/off to flash.

        #776664
        James Alford
        Participant
          @jamesalford67616
          On John Haine Said:

          I’m not sure how the code you linked to does it but one way would be to wire all the LED anodes together and feed them from Vcc via a series switch (transistor).  Then the cathodes would be fed from individual outputs, active low.  You set the appropriate combination of outputs for the pattern you want then pulse the switch on/off to flash.

          Thank you for the suggestion which I shall have a look at.

          For clarity, I am trying to achieve is flashing one LED one the second, each second, another at the start of the minute and another at the start of the hour. On the hour, I want all three to flash at the same time (all bar the few milliseconds that the code needs to run), rather than one after the other.

          James.

          #776672
          duncan webster 1
          Participant
            @duncanwebster1

            If you drive them all off the same port you can make them all react at exactly the same time by changing the port output. It’s a bit mind blowing to start with, but once the penny has dropped it’s easier than multiple digitalWrite statements. I used it for driving a stepper motor in half step mode

            #776691
            SillyOldDuffer
            Moderator
              @sillyoldduffer
              On duncan webster 1 Said:

              If you drive them all off the same port you can make them all react at exactly the same time by changing the port output. It’s a bit mind blowing to start with, but once the penny has dropped it’s easier than multiple digitalWrite statements. I used it for driving a stepper motor in half step mode

              Good idea, but I’d put it on the back burner for the time being.   Not only is it ‘a bit mind blowing to start with’, but the programmer has to get port code absolutely right, and, unlike digitalWrite(), there is no error checking.  The computer will silently do as it’s told even if that completely screws up other internal functions!  digitalWrite()  checks for such nightmears, and, though the program won’t work as expected, digitalWrite() doesn’t cause any weird hard to debug side effects.

              Here’s the ATmega328P’s block diagram:

              at328block

              Bottom left is a box labelled ‘Port D (8)’, meaning ‘I am an 8 bit register connected to 8 pins, that do digital Input-Output’.  The pins it services are listed on the arrow below – PD0 to PD7.   Next diagram shows how they relate to physical pins on an Arduino Nano, not always logically – PB5 is D13:

              Arduino-Nano-Pinout-Diagram-Image

               

              The advantage of writing directly to PortD is that eight pins will be switched together simultaneously on the next clock tick. Super-fast and synchronised, wonderful, and the code is simple.

              DDRD = B11111111;  // Set all pins controlled by PORT D to HIGH

              DDRD = B0000000;  // All pins set LOW

              The problem with my DDRD example is that PortD is also connected to Timer/Counter 0, and USART0. (Universal Synchronous/Asynchronous Receiver/Transmitter)   As Arduino Nano Pins PD0 and PD1 are dedicated by Arduino to Serial Transmit and Receive, my DDRD code example collides with a system function.  Eek – don’t do it by accident!   The chip’s other Ports are also shared with other system functions, so proceed with care, and watch out for weird bugs – probably indicate a collision under the bonnet!

              Good explanation of how to read and write ports directly here.

              Excellent technique, but I was James, I’d save it for later.  In his application, I doubt it matters if the second, minute and hour pulses are staggered by a few tens of microseconds.

              Also, when speed matters, the DirectIO library is a good compromise. digitalWrite() wastes a lot of time by checking for conflicts every time it’s called. DirectIO checks at compile time, and doesn’t worry thereafter.    On the downside, DirectIO isn’t quite as bomb-proof, and it uses a C++ template, which is a step harder to understand in the first place than a function.   But easier than writing directly to a port register.

              Dave

              #776714
              peter1972
              Participant
                @peter1972

                Perhaps I am missing something but this seems to have become unbelievably complicated. The code below flashes the seconds LED for 0.5s on every second, starting when millis() =0, ignoring processing time. The minutes LED will flash for 0.5s on at the start of each minute and the hours LED will flash for 0.5s on at the start of every hour. So all three LEDs will flash at the same time at the start of every hour.

                void setup() {
                pinMode(12, OUTPUT);   //seconds pin
                pinMode(11, OUTPUT);   //minutes pin
                pinMode(10, OUTPUT);   //hours pin
                }

                void loop() {
                digitalWrite(12, (millis() % 1000 / 500 ) == 0);
                digitalWrite(11, (millis() % 60000 / 500) == 0);
                digitalWrite(10, (millis() % 3600000 / 500) == 0);
                }

                You will need to add a long-integer variable to be set when the correct time is set on the RTC.

                 

                #777379
                James Alford
                Participant
                  @jamesalford67616

                  I am making progress. I now have LEDs flashing:

                  1 each second. This is simply on for 100ms and off for 900ms in a loop.

                  1 each minute. This is triggered by the RTC and flashes at the start of the minute.

                  1 each hour. This is triggered by the RTC and flashes at the start of the hour.

                  1 at midnight. This is triggered by the RTC and flashes at the start of the hour.

                  At midnight, they all flash at the same time, as required. The seconds, minute and hour LED stay on for the same duration, but for some reason, the midnight LED stays on for longer.

                  I had a variable that was set to 100ms and was used by all of the LEDs, but as the midnight LED misbehaved, I gave it its own variable. However, no matter what value I put in this variable, it still stays on for a longer time than the others. It was only when I set it to zero that it changed, flashing then briefly.

                  I have posted the code below and should welcome any suggestions as to the reason for this behaviour. I can only assume that I am missing something obvious.

                  void Seconds_Flasher() {
                  // Flash the first LED every second
                  unsigned long Present_Time = millis();

                  Elapsed_Time = Present_Time – Previous_Millis;
                  if (Elapsed_Time <= Period_On) {
                  State_of_LED = HIGH;
                  }
                  if (Elapsed_Time > Period_On) {
                  State_of_LED = LOW;
                  }
                  if (Elapsed_Time >= Period_On + Period_Off) {
                  Previous_Millis = Present_Time;
                  }
                  // set the LED with the ledState of the variable:
                  digitalWrite(ledPin1, State_of_LED);
                  }

                  void Minutes_Flasher() {
                  // Flash the second LED at the start of every minute without using delay
                  static unsigned long previousMillisMinutes = 0;
                  const long intervalMinutes = 100;

                  DateTime now = rtc.now();
                  This_is_the_Current_Minute = now.minute();

                  if (This_is_the_Current_Minute != This_is_the_Previous_Minute) {
                  This_is_the_Previous_Minute = This_is_the_Current_Minute;
                  previousMillisMinutes = millis();
                  digitalWrite(ledPin2, HIGH);
                  }

                  if (millis() – previousMillisMinutes >= intervalMinutes) {
                  digitalWrite(ledPin2, LOW);
                  }
                  }

                  void Hours_Flasher() {
                  // Flash the third LED at the start of every hour without using delay
                  static unsigned long previousMillisHours = 0;
                  const long intervalHours = 100;

                  DateTime now = rtc.now();
                  This_is_the_Current_Hour = now.hour();

                  if (This_is_the_Current_Hour != This_is_the_Previous_Hour) {
                  This_is_the_Previous_Hour = This_is_the_Current_Hour;
                  previousMillisHours = millis();
                  digitalWrite(ledPin3, HIGH);
                  }

                  if (millis() – previousMillisHours >= intervalHours) {
                  digitalWrite(ledPin3, LOW);
                  }
                  }

                  void Midnight_Flasher() {
                  // Flash the fourth LED at midnight to trigger the change of day without using delay
                  static unsigned long previousMillisMidnight = 0;
                  const long intervalMidnight = 100;

                  DateTime now = rtc.now();

                  if (now.hour() == 0 && now.minute() == 0 && now.second() == 0) {
                  previousMillisMidnight = millis();
                  digitalWrite(ledPin4, HIGH);
                  }

                  if (millis() – previousMillisMidnight >= intervalMidnight) {
                  digitalWrite(ledPin4, LOW);
                  }
                  }

                   

                   

                  #777394
                  James Alford
                  Participant
                    @jamesalford67616

                    Note: I put each event in its own void so that I could isolate errors and follow the code more easily.  Each event is named in the void loop.

                    James

                    #777396
                    John Haine
                    Participant
                      @johnhaine32865

                      Pedant alert.  “Void” is not a noun, it qualifies the name of the function that follows it such as Midnight_Flasher in your example. In arduino it means that the function returns no information to the function that calls it, at least through the parameter list.

                      https://docs.arduino.cc/language-reference/en/variables/data-types/void/

                      #777440
                      SillyOldDuffer
                      Moderator
                        @sillyoldduffer
                        On peter1972 Said:

                        Perhaps I am missing something but this seems to have become unbelievably complicated. The code below flashes the seconds LED for 0.5s on every second, starting when millis() =0, ignoring processing time. The minutes LED will flash for 0.5s on at the start of each minute and the hours LED will flash for 0.5s on at the start of every hour. So all three LEDs will flash at the same time at the start of every hour.

                        void setup() {
                        pinMode(12, OUTPUT);   //seconds pin
                        pinMode(11, OUTPUT);   //minutes pin
                        pinMode(10, OUTPUT);   //hours pin
                        }

                        void loop() {
                        digitalWrite(12, (millis() % 1000 / 500 ) == 0);
                        digitalWrite(11, (millis() % 60000 / 500) == 0);
                        digitalWrite(10, (millis() % 3600000 / 500) == 0);
                        }

                        You will need to add a long-integer variable to be set when the correct time is set on the RTC.

                         

                        Neat!  Like it.  Produces 1/2 second pulses at s, m and h.  Very good, and simple code that works is always the best answer.

                        Accuracy 1 or 2 Arduino milliseconds. The worst case is if millis() clocks over a s,m,h boundary during a digitalWrite(), in which case the flash might be 1 millisecond late.   Doesn’t matter if the LEDs are for humans, would if the code is timing anything electronic!

                        Chief objection is the code uses millis().   millis() depends on the Arduino’s oscillator, which is often a ceramic resonator.  Not good timekeepers!  They drift with temperature, and I was able to show they also wobble several hundreds of hertz around nominal even when warmed up.  Arduinos fitted with crystals such as the Leonardo do better, but they aren’t temperature compensated or cut for accuracy.  They’re poor compared with the crystal in an RTC.

                        My original example uses millis() to generate seconds inside a function called fakeClock()   I called it ‘fakeClock()’ to emphasise it was imitating an RTC seconds source and wasn’t a good timekeeper.   James is using an RTC, and these usually have a hardware seconds pulse output.   This, connected to an interrupt pin, makes an RTC quality second counter available, hence the rest of my example.

                        James has taken a different route, using millis() for seconds, and changes in HH:MM:SS to flash the LEDs, which is a bit complicated.

                        If I feel better later I’ll dig out an RTC and combine it with Peter’s code: my mission, to achieve RTC precision with Peter’s level of simplicity.

                        Dave

                         

                         

                         

                        #777447
                        James Alford
                        Participant
                          @jamesalford67616

                          Thank you, Dave.

                          I tried Peter’s approach, which I liked, but I struggled to get it to work with my requirements and the RTC. The method that I used is a combination of my original method,  which worked until it corrupted, and amendments by Copilot. I realise that it is not especially efficient, but it does work, mostly. Any suggestions to refine it would be appreciated.

                          James

                          #777479
                          peter1972
                          Participant
                            @peter1972

                            I suggest you read the RTC and from that work out the miliseconds since midnight. Then use that instead of millis().

                            A question is whether you will want to do that within every Arduino loop or only, say, every hour.

                            After hurriedly posting, I realised my code can be reduced a little further! Here for 100ms flashes:

                            void setup() {
                            pinMode(12, OUTPUT);   //seconds pin
                            pinMode(11, OUTPUT);   //minutes pin
                            pinMode(10, OUTPUT);   //hours pin
                            }

                            void loop() {
                            digitalWrite(12, millis() % 1000 < 100);
                            digitalWrite(11, millis() % 60000 < 100);
                            digitalWrite(10, millis() % 3600000 < 100);
                            }

                            #777483
                            SillyOldDuffer
                            Moderator
                              @sillyoldduffer
                              On peter1972 Said:

                              I suggest you read the RTC and from that work out the miliseconds since midnight. Then use that instead of millis().

                              A question is whether you will want to do that within every Arduino loop or only, say, every hour.

                              After hurriedly posting, I realised my code can be reduced a little further! Here for 100ms flashes:

                              void setup() {
                              pinMode(12, OUTPUT);   //seconds pin
                              pinMode(11, OUTPUT);   //minutes pin
                              pinMode(10, OUTPUT);   //hours pin
                              }

                              void loop() {
                              digitalWrite(12, millis() % 1000 < 100);
                              digitalWrite(11, millis() % 60000 < 100);
                              digitalWrite(10, millis() % 3600000 < 100);
                              }

                              Excellent!

                              Translation of Peter’s genius if anyone is interested:

                              • digitalWrite(pinnumber, n) sets the output pin HIGH or LOW, depending on the value in n
                              • if n is zero, the pin is set LOW (i.e zero volts), any other numbers sets it  HIGH (either 3.3 or 5V depending on the chip.)  The pin is connected to a LED via a dropper resistor.
                              • millis() returns a count of the number of milliseconds elapsed since the Arduino powered up
                              • the % operator is the remainder after division, so millis() % 3600000 goes zero once every 3600000
                              • in a conditional test, TRUE is any value other than zero, and FALSE is zero.  There’s a correspondance between HIGH, LOW, TRUE, FALSE, and integer arithmetic.
                              • Peter tests for remainders less than 100mS, so that’s how long the LED flashes.

                              I find this sort of logic strangely attractive, beautiful even!

                              Apart from feeling sorry for myself I’ve done nothing.  Might risk a boiled egg later…

                              🙁

                              Dave

                              #777518
                              duncan webster 1
                              Participant
                                @duncanwebster1

                                The RTC outputs a 1 second pulse, so instead of counting millis() you could connect that to an interrupt and in the ISR check whether rtcTime.minute() has changed, if it has set a flag and check whether the hour has changed, and set another flag, then flash one, two or three leds as appropriate.

                                Now independant of iffy Arduino clock apart from the duration of the flash. The code is nothing like as fast as Peter’s, but it only executes once per second.

                                #777589
                                peter1972
                                Participant
                                  @peter1972
                                  On peter1972 Said:

                                  I suggest you read the RTC and from that work out the miliseconds since midnight. Then use that instead of millis().

                                   

                                  A question is whether you will want to do that within every Arduino loop or only, say, every hour.

                                  I should have explained that more fully. If you want to read the RTC only say every hour to synchronise to the RTC, you would still need to use millis() to increment the time in the Arduino loop. You would also need to read the RTC on power-up of the Arduino.

                                  I like Duncan’s suggestion of using the RTC’s 1Hz square wave to interrupt the Arduino once per second.

                                  #777686
                                  James Alford
                                  Participant
                                    @jamesalford67616

                                    Dave.

                                    Thank you for the explanation of Peter’s code, which I had not fully understood. I was trying to adapt it for my requirements and could not work out why I could not get it to work. I have now incorporated it into my programme. I still have more to do,  though.

                                    James

                                    #777740
                                    SillyOldDuffer
                                    Moderator
                                      @sillyoldduffer

                                      No success here yet, so I’m going to ask for Peter’s help!

                                      I wrote the code needed to set a DS3231 Real Time Clock and for it to output 1 second pulses.   These show millis() is inaccurate, at least for accurate time-keeping.

                                      The Arduino catches the seconds with this Interrupt Service Routine, which as can be seen is very simple.  It lags the RTC by however long it takes the microcontroller to save what it’s doing when a second event is detected, to jump to the ISR, increment the counter, and then restart whatever it was doing before.  Microseconds or less.

                                      jaisr

                                      loop() detects seconds events by comparison, so again quick.  But this breaks Peter’s original code: this doesn’t work:

                                      jaloop

                                      The reason is that working in RTC seconds means millis() inside the ‘if’ counts in close to round seconds so the less than 100 test is never true!

                                      So what’s needed is code that satisfies James’ original question, flashing LEDs when the seconds, minutes and hours roll over.

                                      Latest version here if anyone wants to play.  Note the code that sets the RTC’s start time is a temporary bodge.  I’ll update it later so sets time properly.

                                      Dave

                                       

                                      #777742
                                      duncan webster 1
                                      Participant
                                        @duncanwebster1

                                        As I said before, set the interrupt to react to change

                                        If (digital Read (intPin) ==High

                                        {

                                        read minutes and hours

                                        if minutes! = old minutes

                                        {minChange =true

                                        OldMinutes =minutes}

                                        If (hours! =oldhours

                                        {etc as minutes}

                                        DigitalWrite(secPin, high)

                                        digitalWrite(min Pin, minChange)

                                        Ditto hourPin

                                        }

                                        else

                                        {write all 3 pins low

                                        Set flags back to false}

                                        As stated in other post my PC has died, so I’m doing this on a phone. Capitals are all wrong, and no ; at end of lines, but I think the logic should work. I think it turns the appropriate leds on for 1/2 second

                                        #777744
                                        duncan webster 1
                                        Participant
                                          @duncanwebster1

                                          Once I get PC back I’ll give it a whirl

                                          #777943
                                          SillyOldDuffer
                                          Moderator
                                            @sillyoldduffer

                                            This is the best I can do for the moment.

                                            jaledflash

                                            Full code here:

                                            • Optionally sets the RTC with a unix timestamp typed in by the user.   (If pin 4 is grounded at boot. Otherwise assumes the RTC was set correctly earlier.)
                                            • Uses Duncan Webster’s interrupt to count the accurate second pulses emitted by the RTC SQW pin.
                                            • Uses James’ compare technique in loop() to detect second events.
                                            • Uses Peter’s modulus arithmetic to switch the LEDs on.   But I had to use the compare technique again with millis() to turn them off 100mS later.  May not be the simplest possible solution.
                                            • Contains most of the code needed to get a DS3231 RTC module to work, including how to extract human readable date-time info.

                                            Many improvements possible!  For example, setting the RTC involves the user getting the latest time off the web, which might be a few tenths of seconds out, plus however long it takes a slow-mo human to cut and paste it.   Better to write a program on the PC that removes the need for a web search and human delays; then the RTC would be set to better than 0.1s*.   Also the way I set time may not suit James, who mentioned buttons.  His method is extremely common; no need to connect a kitchen cooker to a PC to set the clock!

                                            The seconds are considerably more accurate than the 0.1s pulses measured out by millis().   The seconds come from a good temperature compensated crystal oscillator in a competent Real Time Clock module.  millis() is based on a wobbly ceramic resonator – fine for most purposes, but not a precision time source.

                                            Probably mistakes too…

                                            Dave

                                            * Note for time-nuts!  By default UNIX machines frequently correct their clocks by polling NTP time servers on the web, so bog standard Linux is unlikely to be more than 100mS off Atomic Time.   Windows, by default, is less fussy, and can drift further off, especially if running on older hardware.   When accurate time is important look up how Windows is tweaked to poll time more often.

                                             

                                             

                                            #778249
                                            peter1972
                                            Participant
                                              @peter1972

                                              In the code below I attempt to demonstrate how my original code could be synchronised to a real time clock (RTC).

                                              The variable msSync becomes the time of the most recent synchronisation since the start of program run (in milliseconds).

                                              (millis() – msSync) is therefore the milliseconds since the most recent synchronisation.

                                              The variable msRTC represents the most recent read of the RTC in milliseconds since midnight.

                                              (msRTC + millis() – msSync) therefore becomes the RTC synchronisation time incremented by the milliseconds since synchronisation.

                                              When the program starts, msRTC and msSync are set to zero which causes all LEDs to flash simultaneously as with my previous code. (There is a sneaky reason to do this).

                                              For the purpose of demonstration, I am synchronising after each flash of the ‘minutes’ LED on pin 11. This could be extended so synchronisation happens only each hour or even each midnight. As flashes are set to 100ms duration, synchronisation should first happen 100ms after program run start.

                                              I am simulating a RTC starting on program run start at 58.9 minutes past midnight (3534000ms since midnight).

                                              It probably makes more sense to read the RTC every second as recommended by Duncan.

                                              void setup() {
                                              pinMode(12, OUTPUT);   // seconds pin
                                              pinMode(11, OUTPUT);   // minutes pin
                                              pinMode(10, OUTPUT);   // hours pin
                                              }

                                               

                                              bool oldPin11;
                                              unsigned long msRTC = 0, msSync = 0;   // miliseconds

                                               

                                              void loop() {
                                              oldPin11 = digitalRead(11);
                                              digitalWrite(12, (msRTC + millis() – msSync) % 1000 < 100);
                                              digitalWrite(11, (msRTC + millis() – msSync) % 60000 < 100);
                                              digitalWrite(10, (msRTC + millis() – msSync) % 3600000 < 100);
                                              if( oldPin11 && !digitalRead(11) ) {   //sync to RTC after flash of minutes LED
                                              msRTC = 3534000 + millis();        // simulated read of RTC in milliseconds
                                              msSync = millis();                        // time of sync since program start
                                              }
                                              }

                                              It’s annoying this forum deletes initial space characters in each line within block quotes.

                                              #778287
                                              duncan webster 1
                                              Participant
                                                @duncanwebster1

                                                lots of references on web to routines which set the date/time when you load the code onto the Arduino, no user intervention

                                                Even in examples provided with IDE https://www.instructables.com/Simple-Guide-to-Setting-Time-on-a-DS3231DS3107DS13/

                                                 

                                                #778354
                                                James Alford
                                                Participant
                                                  @jamesalford67616

                                                  Thank you for the additional examples and suggestions for the code and for the explanations of how they work. I shall have a good look at these over the next couple of days.

                                                  Currently, I have a programme that sets the time on the RTC to defined hour when loaded, but allows the use of buttons to advance or retard the times as desired. I also have code that reads the current minute or hour from the RTC and uses that to trigger flashing the LEDS. These all flash at the same time, all bar few milliseconds. My code for these is not efficient or consistent and I do plan to improve it.

                                                  I have LEDs that flash:

                                                  • once per second – this is just an unsynchronised on – off routine
                                                  • once per minute – synchronised to the RTC
                                                  • once per hour – synchronised to the RTC
                                                  • once at midnight – synchronised to the RTC (to mark the change of day)
                                                  • once at 15 minutes past the hour, twice at half-past the hour and so forth

                                                  I also plan to add code to flash another LED once, twice, thrice per hour and so on until 12:00.

                                                  The aim, in time, is to use the outputs to trigger solenoids which will then drive an electro-mechanical clock. I started this project long ago and have recently been inspired to resurrect it.

                                                  Regards,

                                                  James.

                                                  #778366
                                                  SillyOldDuffer
                                                  Moderator
                                                    @sillyoldduffer

                                                    Well done James, and thanks for the feedback.   Now you’ve got the LEDs working, adding a quarters flash shouldn’t be difficult, it’s just a slightly more complicated ‘if’ on the same principle.   Please report progress as your clock develops – I love clocks!

                                                    Duncan made another good point by mentioning examples.  Arduino libraries usually come with example programs showing how to exploit the library.   No need to search the web for guidance – like as not one of the examples in the IDE will be a good start.

                                                    Dave

                                                    #779496
                                                    James Alford
                                                    Participant
                                                      @jamesalford67616

                                                      All being well, this my final update on this thread. I now have the code working in the way that I want. I have added code to flash another LED on the hour, once at one, twice at two and so on. It only flashes between 8:00 and 23:00 and waits until the flashes that precede it have finished. I just need to tidy up the code.

                                                      Thank you all for you help with this.

                                                      James.

                                                    Viewing 25 posts - 1 through 25 (of 25 total)
                                                    • Please log in to reply to this topic. Registering is free and easy using the links on the menu at the top of this page.

                                                    Advert

                                                    Latest Replies

                                                    Viewing 25 topics - 1 through 25 (of 25 total)
                                                    Viewing 25 topics - 1 through 25 (of 25 total)

                                                    View full reply list.

                                                    Advert

                                                    Newsletter Sign-up