Controlling many LEDs with an arduino; two loops at once. - Page 1
Forum section: electronics / general

author: Tim4444
author_rank: Contributor
timestamp: January 16, 2014, 12:23:16 am
content: Hello,I am trying to control 60 LEDs in one way and simultaneously 12 LEDs in another. I understand that I can run two simple programmes at once using millis() functions, but does anyone know how I can run two big functions at the same time, almost like if I had two 'for' loops running simultaneously.The idea is to make a clock where the 60 LEDs are on a loop with each LED lighting up every minute, and the other 12 (of a different colour LED) are controlled by another function causing each one to light up successively every hour.Any help on this would be very much appreciated.Tim

author: David_AVD
author_rank: Super Contributor
timestamp: January 16, 2014, 01:35:40 am
content: A microcontroller can only do one thing at once. You can however use a timer interrupt to do steps of your program at regular intervals.So, you have a timer interrupt that fires every one second. Each time it does, you update the 60 LEDs using one function.You also have one or more counters that get tested / incremented every second. One of them can count the seconds and cascade to count minutes, hours, etc.When the minute counter hits 60, you can clear it, advance the hour counter and update the 12 LEDs using another function.I've simplified it a little, but hopefully you get the general idea.

author: psycho0815
author_rank: Regular Contributor
timestamp: January 16, 2014, 01:09:56 pm
content: or you could do something like:Code:long start;setup(){start = millis();}loop(){if(((millis()-start) % 60000) == 0){doMinuteStuff();}if(((millis()-start) % (60*60000)) == 0){doHourStuff();}}However you should know that the millis() funktion on the arduino is only somewaht acurate. For a clocl you probably want an rtc.

author: dannyf
author_rank: Super Contributor
timestamp: January 16, 2014, 04:20:13 pm
content: QuoteFirst of all, unless you have a multi-core mcu, you can never truly run two "functions".2ndly, it is tough to know what exactly you meant by "big".QuoteThat's fairly easy: you need to piece of code that lights up the leds, with "time" being passed as a parameter. Anytime you call the function, it will light up the right second leds, and the right minute / hour leds.

author: Tim4444
author_rank: Contributor
timestamp: January 16, 2014, 10:30:10 pm
content: Thanks for the replies everyone.I think I will learn how to use the 'interrupt' function.Does anyone know of a good on-line source to learn this from?Tim

author: MatCat
author_rank: Frequent Contributor
timestamp: January 16, 2014, 10:37:39 pm
content: Quote from: Tim4444 on January 16, 2014, 10:30:10 pmhttp://www.arduino.cc

author: MacAttak
author_rank: Unknown
timestamp: January 17, 2014, 12:32:55 am
content: Quote from: Tim4444 on January 16, 2014, 10:30:10 pmhttp://playground.arduino.cc/Code/Interruptsedit: oops, that's what I get for walking away for dinner before posting

author: Tim4444
author_rank: Contributor
timestamp: January 20, 2014, 08:07:01 pm
content: Thanks for the replies everyone. I shall give the interrupts a go.Tim

author: daveatol
author_rank: Regular Contributor
timestamp: January 21, 2014, 12:13:29 am
content: Quote from: Tim4444 on January 16, 2014, 12:23:16 amThis doesn't require two loops, or interrupts...

author: netdudeuk
author_rank: Frequent Contributor
timestamp: January 24, 2014, 12:28:52 am
content: Quote from: daveatol on January 21, 2014, 12:13:29 amAgreed. Psycho's answer is a good starting point. There's no point in over complicating with an extra loop and interrupts.

author: dannyf
author_rank: Super Contributor
timestamp: January 24, 2014, 02:17:29 am
content: QuoteThat piece of code suffers from poor atomicity: millie() will have advanced and causing inconsistent display.A better - not yet fully atomic - approach would be like this:Code:time_now = milli(); //read the current timeshow_time(time_now); //display timeNow, millis() as well as time_now are unsigned long so the code above isn't 100% atomic. You have to institute a double read:Code:do {time_now=milli();} while ((milli() & 0xffffff00ul) ^ (time_now & 0xffffff00ul));time_now contains the correct and atomic time stamp.The best is actually use a timer + interrupt to keep time.

author: David_AVD
author_rank: Super Contributor
timestamp: January 24, 2014, 02:25:39 am
content: The interrupt method gives a stable period between "ticks". Using inline delays is just bad.

author: daveatol
author_rank: Regular Contributor
timestamp: January 24, 2014, 05:19:49 am
content: The following code should give (long-term) accurate timing. You'll have to find out what the actual value is for TICKS_PER_SECOND, as I don't know what it's called, or its value (I assume it might be 1024 though).Code:long due;setup(){due = millis();}loop(){asm("cli");long now = millis();asm("sei");if(now > due){due += TICKS_PER_SECOND * 60doMinuteStuff();static uint8_t minuteCounter = 0;if(++minuteCounter == 60){minuteCounter = 0;doHourStuff();}}}

author: psycho0815
author_rank: Regular Contributor
timestamp: January 24, 2014, 06:40:45 am
content: since timer0 that is used for millis() doesn't actually run at 1kHz your timing will always be a little of.If you want actual accuracy put a 32.768kHz crystal on TOSC und set the timer2 prescaler to 128. that'll give you an interrupt exactly every second.Or i guess you could look up what frequency timer0 actually runs at (i believe its 976Hz, but don't quote me on that) and adjust for the difference in software.Quote from: dannyf on January 24, 2014, 02:17:29 amwasn't supposed to be production code, just an idea to start with. However there are about 16000 clockcycles between increases of milli() and one milli() isn't actually one ms anyway, so i wonder how much that would really matter in terms of accuracy.

author: dannyf
author_rank: Super Contributor
timestamp: January 24, 2014, 10:57:26 am
content: Quote=1k/1024.QuoteTwo issues:1) Your code can cause display inconsistency: assume that you are 6:59.9999999 -> sufficienly close to 7:00. You pick up the time and shows the minute to be 59. Then you read milli() against to process the hour. by that time, the time has advanced to 7:00 so you show the hour to be 7 -> 6:59 being displayed as 7:59.2) millie() is 100% as accurate as the crystal. If you look at the code, the timing "errors" are accumulated so most of the time, milli() is advancing 1 per timer0 interrupt (64*256 ticks) but once in a while it will advance 2 per timer0 interrupt, in order to maintain long-term accuracy.

author: mrflibble
author_rank: Super Contributor
timestamp: January 24, 2014, 11:14:21 am
content: Quick! Someone measure the Allan deviation on those mission critical blinky leds!That said, timer + interrupt as suggested would be the way to go.

author: psycho0815
author_rank: Regular Contributor
timestamp: January 24, 2014, 11:28:23 am
content: Quote from: dannyf on January 24, 2014, 10:57:26 ami acknowledge that. As i said that code was not supposed to be used as is. Just to give him an idea of how to approach the problem. He probably would've had the problems you mentioned and tried to figure it out by diving into the innards of the arduino libraries and atmega timers. You deprived him of the learning experienceQuoteThat's my bad. i just assumed they didn't account for that. I do remember actually reading on the arduino page that the timing functions weren't that accurate. However that was quite a while back. Totally possible taht they fixed it since then or my memory is wrong to begin with.

author: Jeroen3
author_rank: Super Contributor
timestamp: January 24, 2014, 02:34:06 pm
content: Buy a Real Time Clock IC and use it. Most RTC's can also give you a interval interrupt.If you use a hardware timer for this you must use an 32 KHz oscillator, higher crystals or even the internal osc will give you seconds off every day.

author: dannyf
author_rank: Super Contributor
timestamp: January 24, 2014, 03:39:00 pm
content: QuoteI disagree, other than the internal osc part.

author: netdudeuk
author_rank: Frequent Contributor
timestamp: January 24, 2014, 04:17:01 pm
content: Quote from: dannyf on January 24, 2014, 02:17:29 amI said it was a goodstarting point. The issue you mention could be handled easily by just reading the info into a variable and then referring to that in the tests.Why doesn't he just buy a DS1307 from eBay ? Mine cost less than £2 delivered and they come with what could be a handy 32K I2E EEPROM as well.As it's just a simple clock application, he can do this with a simple loop (in loop(), funnily enough) and would still get reasonable accuracy without needing to use interrupts.

author: dannyf
author_rank: Super Contributor
timestamp: January 24, 2014, 04:58:56 pm
content: QuoteNo.QuoteSimplicity? Why buy something you don't need?QuoteHe could. But he can do better with less.

author: mrflibble
author_rank: Super Contributor
timestamp: January 24, 2014, 06:14:53 pm
content: While you guys are discussing the finer points of"how many different ways are there to blink a led in a timely fashion", the OP is probably sitting in a bar somewhere. Possibly even discussing his already working led blinky project.

author: MatCat
author_rank: Frequent Contributor
timestamp: February 03, 2014, 03:52:32 pm
content: ROFL you don't NEED an RTC to blink an LED, it's not like this project is being used by NASA to transmit data over light with sub-uS accuracy in timing... I am surprised someone didn't mention using a 555 by now!

author: David_AVD
author_rank: Super Contributor
timestamp: February 03, 2014, 09:28:06 pm
content: Ummm... well the OP is building a clock !

author: MatCat
author_rank: Frequent Contributor
timestamp: February 03, 2014, 10:49:43 pm
content: Quote from: David_AVD on February 03, 2014, 09:28:06 pmROFL I did not notice it was actually a clock, I just saw LED's, well then in that case I do recommend an RTC hehe.

author: scientist
author_rank: Frequent Contributor
timestamp: February 05, 2014, 09:33:45 am
content: Use a few shift registers and only shift out data when the clock changes?