Driving 132 LEDs

oracacle

Senior Member
I have been asked to look into producing an analogue LED clock face.
LED for each second, minute and hour - maybe a seven segment time display too, but that something that a would like more than anything else and maybe could be added later.
I am guessing a port multiplier of some description, maybe a little multiplexing (or charlieplexing) too would be needed as that is a lot of LEDs to be driven.

I was thinking that something like some decade counters could work, but that would require around at least 12

any suggestion welcomed before I get too deep into this, I suspect I may open can of worms if I rush head long into it
 

hippy

Technical Support
Staff member
Though you have a lot of LED's there are probably only a few on at a time, possibly only three for hours, minutes and seconds.

That should lend itself well to multiplexing or charlieplexing. Possible using 4-16 line decoders to keep the number of signal lines used down.

An alternative is to find I2C/SPI display drivers which can handle 4 x 7-segment displays or more which allow individual segment selection, use those to drive individual LEDs and let them carry the work load.
 

oracacle

Senior Member
I have stumbled upon MAX7219 which can drive up to 8 seven segment displays which would give 64 LEDs per IC, one for each seconds and minutes and multiplex for the hours could do the job.
although keeping things on the I2C bus sounds like a good idea
 

BESQUEUT

Senior Member
60 APA 104 for mn and s
and 12 for hours...
For example green for s and red for mn
and many other fun effects possible...

Note that apa102 can be connected to a Picaxe, but you'll have to solder wires...
 

oracacle

Senior Member
Buzby's orrery appears to use Charlieplexing.
132 LEDs could be done with 22 pins. If I were to keep each of the LEDs for the seconds and minutes on as the time passes (original thought) I would think that there would be power issues for the picaxe. However if I were to only use the LED for the time that it is (resulting in just 3 LEDs being lit at anyone time) there should be no issue.

This could be done with one 40X2 a lot of resistors and LEDs, and a lot of charlieplexing code challenges.
 

AllyCat

Senior Member
Hi,

You might want to consider whether 12 LEDs for the hours is sufficeint. For example, at a time of 1:59 do you light the "1" or the "2" hours LED?

As a mimimum you could use 60 Red/Green LEDs and light both colours for seconds (Yellow). But the hours on a smaller radius circle (perhaps about 24 - 36 LEDs) might look more familiar and recognisable as a clock face?

Yes, Buzby's Orrery does use Charlieplexing for over 500 LEDs on a 40X2. I believe you need less than 16 pins for (say) 150 Charlieplexed LEDs, so a 20M2 or an 08M2 and two octal latches might do the job. Unless you want a really bright display, a 20M2, 15 resistors and a lot of desgn effort (and LEDs) could be all that's required. ;)

Cheers, Alan.
 

oracacle

Senior Member
Am I correct in saying the number of LEDs = Pins x (pins - 1). if that so, just 12 pins should do the trick = LEDs = 12x(12-1)=132.

also if its 1:59, its 1:59. while human will round to 2 o'clock its down to the human to do that and not the clock. imagine if clocks jumped a couple of minutes when turn 10:13 because for us that close enough to quarter past for to be quarter past. Imagine that amount of "lost" time there would be - I very much doubt employers would be very happy about the situation.

I will concede that more LEDs could be needed to be able to determine between am and PM, but again its not something that is shown on an analogue clock.

got any recommendation for latches?
 

westaust55

Moderator
Quite some time ago I posted about an 8x8 RGB display I constructed.
That equates to 192 LEDs operated in a multiplexed scheme.
That used two MCP23017 2-port (16 I/O) i2c expander chips.

Using an X1 part at the time at 8 MHz there was a little flicker but with the newer M2 parts capable of 32 MHz that should not be a problem.
With i2c even an 08M2 may suffice.
 

AllyCat

Senior Member
Hi,

At 1:59 the hour hand of an analogue clock will be pointing almost exactly at "2". But if you light the "2" LED (which is what I think a user would expect to see), then at what time did you start lighting the "2" instead of "1"? Of course the same applies with the minutes and seconsd LEDs, but that's much less important because a) the reading error is much less serious (1 minute versus 1 hour) and b) the 60 LEDs will be close together so you can light the two adjacent LEDs for the intermediate positions. *

If you're really clever you can even PWM the the brightness of the two relevant LEDs to give a "smooth movement". But to give credit for that idea: Derek Weston developed an excellent Wind Speed/Direction display about 20 years ago which used exactly that method using an 18-pin PIC. There are some links to the project and full code (PIC Assembler) on this forum.

* FWIW, my electronic "Analogue" watch (i.e. with mechanical hands) appears to use two separate stepper motors for the seconds and minutes (then a 12:1 mechanical gear for the hours hand). As expected, the seconds hand moves in 60 steps (i.e once per second) but the minutes stepper appears to have 300 "poles" so the minute hand moves almost imperceptably every 12 seconds.

Yes, I believe the maximum Charlieplex is N x (N-1). I'm not convinced that Shift-Register/Latches are necessary or desirable, but HC595 are perhaps the most commonly used now.

Cheers, Alan.
 

Buzby

Senior Member
Post #5, that's my orrery !.

It drove 528 LEDs from a 40X2, with no drivers.

132 LEDs for a clock would be no problem at all.

If you have N pins to use, then you can drive N * (N-1) LEDs, so you need 12 pins exactly to drive 132.

Charlieplexing on a Picaxe is really good for something like a clock. It only struggles when you need to light more than 20 LEDS at once, which is not what a clock needs.

If you decide to go this way just look at the listings in the blog post about the orrery, and if you need more help I'll be here.

Cheers,

Buzby
 

oracacle

Senior Member
did you pre-calculate all of the pin values for each of the possible LED permutations that you needed?
From what I can tell you set all the pins to be inputs and only switched the pins to outputs using the high low commands.

Allycat, this sort of thing goes against my nature, is some asks me what the time is I tell them "1:59", however the effect of PWM could be achieved.
If an if stated is added, with some counting variable every pass of the hour display after a certain time would add in occasional next hour display, the number of occurrences that the next hour display would increase until it was that time, the same could be done for the previous hour - as a result the first and last ten - fifteen minutes of each hour the hours would fade in and out. the down side of this could be that it makes the hour harder to read as time went by.

The other idea would be to have 60 LEDs for the hour and have a similar effect moving between 5 LEDs between each hour - this would increase mathematical load on the picaxe and increase the number of LEDs to 180.
 

Buzby

Senior Member
did you pre-calculate all of the pin values for each of the possible LED permutations that you needed?
From what I can tell you set all the pins to be inputs and only switched the pins to outputs using the high low commands.
No, I pre-calculated a table with the pin pairs for each LED, not for every permutation of LEDs. ( That would need billions of bytes ! )
I numbered the LEDs 0-527, and when the code needs to light a particular LED it looks up the relevant pins using the LED number as the index into the table.

Yes, when a pin is set to 'INPUT' it effectively is high impedance, which is what Charlieplexing depends on.

Note, increasing the number of LEDs does not increase the software 'load' on the Picaxe. The 'load' is determined by how many LEDs need to be lit at one time. So for a clock the number could be as low as 3. ( One each for H,M,S ). If you want 'between hour' trails then it might need 8 lit at once, still not too many.

Once you decide on the arrangement of the LEDs I will be quite happy to point you in the right direction with the code.

Cheers,

Buzby
 

AllyCat

Senior Member
Hi,

... if someone asks me what the time is I tell them "1:59",
If I were reading an analogue clock I would probably say "It's just before two" and even more likely "Five to Two" at the appropriate time. ;)

I have been asked to look into producing an analogue LED clock face.
In cases like this it's very wise to ask the "Customer" and also any potential "Users". There's quite an art to designing a good "User Interface" (very obvious when there's a bad one) and of course the old addage that "The Customer is always right". Unfortunately, customers often have stupid (or uninformed) ideas and you may need to steer a careful course. Possible strategies are to do exactly what was asked but make sure that you have a "Plan B", or pretend that you didn't understand what was wanted. :)

It's probably not necessary to go to as many as 60 "hours" LEDs; the diameter (and circumference) of the ring is smaller and you might use (say) 5mm LEDs (for that ring) in place of 3mm, to improve the appearance. That's why I suggested 24 - 36, with 30 perhaps a good number even though it wouldn't have LEDs exactly at the odd-numbered hours.

Much of the design may depend on how you plan to construct the "face" (PCB, hand-wiring, etc.). Personally I might be tempted to just interconnect the LEDs in the most convenient way (ensuring that each has a "unique" connection of course) and then use a lookup table to map the two required pins from each "LED number". That would be a wise precaution anyway (in case of mistakes) but the 20M2, or worse the 08M2, have rather limited table/EEPROM facilities. However, the LOOKUP command can be useful and convenient (particularly for 16-bit numbers) but beware that it can be rather slow for large arrays (because it always "looks through" the complete list of values). Also note that because the "PWM" may need to be on any pin (and switch between Hi/Low and "input") it needs to be done in software.

Cheers, Alan.
 

hippy

Technical Support
Staff member
It's probably not necessary to go to as many as 60 "hours" LEDs; the diameter (and circumference) of the ring is smaller and you might use (say) 5mm LEDs in place of 3mm to improve the appearance.
I would agree that 12 LED's for the hour may be better than 60. But whether the hours should be on the outside ring or the inside ring of a clock is a matter for debate. Hour hands are shortest, but it feels more natural and more easily readable to me for indicator rings to go hour, minutes seconds from the outside in rather than vice-versa.

Another option instead of rings is to have LED arms. That could be a lot of LED's, difficult to fit all those physically near the centre, but one could have arms only on the 5 minute marks.

Perhaps arms for the hour and minutes and a ring for the seconds.

I would say a LED analogue clock should be treated more as decorative or novel rather than being an accurate time piece so there is more flexibility in how it works and what it shows.
 

Buzby

Senior Member
The 'arms' idea would look good. ( The orrery video shows a version, but as it was never designed to be a clock it's not as good as it could be. )

Twelve arms of 10 5mm LEDs, with each LED being Red/Green, and a ring of 60 3mm white LEDs for the seconds/intermediate minutes.

That works out at 300 LEDs to be Charlieplexed. ( Each Red/Green counts as two )

This would be an easy Charlieplexing project.
 

oracacle

Senior Member
Personally I don't like the hands idea, it will remain an option though
I was thinking about producing a prototype and playing with some ideas, if they don't like the idea of the prototype I get to keep that for myself - maybe a good thing as I don't have a single wall clock in my house
One of the reasons I like the ring idea is so that something can be added to the middle - a cheesy family portrait or date display or a 7 segment display of the time.

Buzby what software did you use to get you LED circles laid out? I have been using design spark to draw circuits but it doesn't do a great job of layout and an even worse job or putting things in circles.

I am also thinking that a picaxe could be used to set all the pin values for each LED. using an EEPROM each LED has a pair of addresses (eg sec 0-119, min 120-239, hour 240-359), place a photodiode over the first LED and it start running though a sequence of pins until it detects the LED then stores the 2 pin number to the EEPROM (and reports back to the terminal for saving in case of tragedy). yes I know I would have to move the photo diode over each LED and press u button to tell it to search but that's a lot less pain full that writing it all out manually.
 

AllyCat

Senior Member
Hi,

I would say a LED analogue clock should be treated more as decorative or novel rather than being an accurate time piece
Hmm, that confirms my suggestion above that you should "Ask the Customer what they want".

To me, "A clock is a clock" (Wikipedia: A clock is an instrument to indicate, keep, and co-ordinate time) but perhaps to others it's a status symbol, ornament or a toy.

But I did think that at least we might all agree that the hours ring should be nearest to the middle ! :eek:

IMHO the difficult part is ensuring that each LED has unique pin connections. Then, writing a simple program to drive each pin combination in turn and noting which LED lights shouldn't take very long at all.

Cheers, Alan.

PS: I note the forum clock is either 12 or 48 minutes out. ;)
 
Last edited:

oracacle

Senior Member
well see allycat, if there are 3 rings, a bit of clever code could swap them about to whatever ordered was desired.
but with that said, I agree hour inner most followed by minutes and then seconds.

as it happens I am think about using a 28X2 as it will leave extra pins for push buttons to change the time if desired (handy for a standalone system). and the 64mhz if needs be, I know it would have to be dropped to read I2C clock but I don't think that will be too much of an issue
 

Buzby

Senior Member
Hi oracacle,

The orrery project was, as eclectic said, a real labour of love !.

First I couldn't find any PCB layout software that placed objects equally in a circle. ( Well, not for less than $3000 ! )
So I found a PCB layout programme with a human readable file format.

Then I wrote some Excel VB to calculate the LED positions, then cut&paste the results into an 'empty' PCB file.
When this file was opened by the PCB software, all the LEDs were in the desired positions.

Next I wrote some more VB to create the netlist. A bit more cut&paste, and now all the LEDs are connected as required.
A bit of manual work to add the Picaxe and support components, then run the autorouter. The result was the PCB you see in the blog.

I put this effort in because, apart from the initial difficulty of trying to place LEDs in circles, if there was a design or wiring error somewhere in the labyrinth it would be a nightmare to find, and maybe even worse to fix.

( The VB/Excel also drew a picture of the LEDs on-screen, so I could tweak the numbers to get just the look I was after. )

You probably don't need to go to such extremes !.

I don't know DesignSpark, but an early idea I did have was to use the VB/Excel to print the PCB co-ordinate numbers, then use the numbers to manually add each LED to the layout, with 'snap to grid' turned off.

Since building the orrery I've found that your local sheet plastic supplier can turn a sketch into a proper CAD drawing in minutes, then laser cut an acrylic sheet just as quick. This would give you the faceplate.

Poke the LEDs in, then use a wiring pen to join them up. ( This is the only bit you need to be really careful with, plan and check thoroughly. )

Regarding the LED locating idea, I don't think it's worth the effort. To wire the LEDs in the first place, either by autorouter or manually, you need a plan, and that plan has all the info you need to populate the look up table.

Cheers,

Buzby
 
Last edited:

oracacle

Senior Member
I suppose there is no reason that the circle cant be made from more than 1 board either. If each of the LEDs are routed to a header with some extra pads on the track it mean that the PCB could be made at home more easily.
If each section had 10 minutes on each, that would mean 6 sections. the other plus side of this is, if there is a fault that can not be rectified a section can be replaced at far less cost than an entire face - from what I understand charlieplex fault finding is very tricky at best. also mean I cold mock up a section to test some ideas.

I will look into the plastic sheet idea
Design spark does have a measure tool, so providing I set a datum up correctly I should be able to measure something out.
Need to pop out and pick up some drill bits and have a think about getting some prototyping done after sorting some of the chaos out (why the heck is that spelt with a ch? it makes no sense what so ever)
 

Buzby

Senior Member
... Design spark does have a measure tool, so providing I set a datum up correctly I should be able to measure something out...)
What I meant was that you should be able to position a footprint in DesignSpark using co-ords like X=15.364, Y=9.489, not just drag&drop to the nearest 0.1".
A simple Excel table will create the X,Y numbers for the LEDs, you just type them into DesignSpark to position each footprint.
 

westaust55

Moderator
as it happens I am think about using a 28X2 as it will leave extra pins for push buttons to change the time if desired (handy for a standalone system). and the 64mhz if needs be, I know it would have to be dropped to read I2C clock but I don't think that will be too much of an issue
It is not necessary to reduce the PICAXE clock speed to perform i2c comms.
If you have a "standard" = predefined clock speed you just add the _xx suffix where xx is the clock MHz.
You can also run at other speeds with an external resonator/crystal and calculate the required value to use.
I have 28x2 running at non-standard 80MHz (with 20 MHz ext resonator) as master that communicate with slave 20X2 running at 64MHz via i2c without problems by calculating the desired value for the i2c comms speed.
 

Buzby

Senior Member
No matter whether you use Charliplexing, multiplexing, or direct IO, you will still need some way to position LEDs in circles.

If you can't find a friendly CAD man, here is an Excel spreadsheet that calculates the co-ordinates for circles of LEDs.

It does not use any VB or macros, and the preview is just a standard Excel graph, but it's good for getting an overview of the results.

( Forum won't accept spreadsheets, so rename to .xls )

Cheers,

Buzby
 

Attachments

Jeremy Harris

Senior Member
I'm late to this, but did make a PCB for an LED compass years ago, using a Picaxe to drive 36 LEDs (I think..........) and decode the serial clocked data from a scrounged flux gate compass. I used it in the car, at the time an old Japanese grey import Pajero, and replaced the unneeded inclinometer instrument in the dash binnacle with the ring of LEDs compass, which was a lot more useful.

The way I did the PCB was the same way I make PCBs now, using an old 2D CAD programme from AutoDesk, AutoSketch. It's similar to AutoCad in some respects, and over the years I've built up a big library of component pads and these can be positioned anywhere. I usually use a 0.05" grid, but like most CAD software, this has the ability to automatically create circular arrays. I just created an LED pad layout, then got the software to create 36 copies of it on a 10 degree radial array, with a set radius that fitted neatly in the instrument binnacle hole. I used the same software to create a drilling template for an opaque mask that fitted over the LEDS, leaving just the tips showing through.

I've tried dedicated PCB layout programmes, and good as they are, I very often find myself reverting to laying out boards "by hand", using CAD. The combination of a good component library, many years of AutoCad experience, and some learned tricks specific to things like Picaxe programming, power supply and decoupling layouts that don't need a double sided PCB, seems to be as quick as using the dedicated PCB software, The only slight snag is that it can be a bit of a faff converting CAD files to Gerber files if I want to get multiple boards made, rather than just make a toner transfer board (although I'm soon to try using UV resist, when I've finished making the exposure unit).
 

oracacle

Senior Member
Thanks Buzby.
I will have a look what I have buried in software collection.

I have a 6x3 prototype section, more for learning than anything else. Its taken a while as I have been rather busy with my actual job.
I did learn not to switch high/low the pins for LEDs that are not connected, that causes all sorts of confusion. Also found that it will most likely be best to have the LEDs set as pairs on the PCB and a bus connected to each pin running around that jumper wired join to each LED pair.
 

oracacle

Senior Member
this worked swimmingly with the 6x3,
just need to work on the fading in an out hour, but that may have to wait until I get more of a display together.

Code:
[color=Navy]#no_data
#no_table[/color]
[color=Green]'#terminal 9600[/color]
[color=Blue]setfreq em64

symbol [/color][color=Purple]high_flag        [/color][color=DarkCyan]= [/color][color=Purple]bit0[/color]
[color=Blue]symbol [/color][color=Purple]high_pin         [/color][color=DarkCyan]= [/color][color=Purple]b4[/color]
[color=Blue]symbol [/color][color=Purple]low_pin          [/color][color=DarkCyan]= [/color][color=Purple]b5[/color]
[color=Blue]symbol [/color][color=Purple]loop_number      [/color][color=DarkCyan]= [/color][color=Purple]b6[/color]
[color=Blue]symbol [/color][color=Purple]LED              [/color][color=DarkCyan]= [/color][color=Purple]b7[/color]
[color=Blue]symbol [/color][color=Purple]temp_byte_0      [/color][color=DarkCyan]= [/color][color=Purple]b8[/color]
[color=Blue]symbol [/color][color=Purple]sec              [/color][color=DarkCyan]= [/color][color=Purple]b10[/color]
[color=Blue]symbol [/color][color=Purple]mins             [/color][color=DarkCyan]= [/color][color=Purple]b11[/color]
[color=Blue]symbol [/color][color=Purple]hour             [/color][color=DarkCyan]= [/color][color=Purple]b12[/color]

[color=Blue]symbol com              [/color][color=DarkCyan]= [/color][color=Navy]44[/color]
[color=Blue]symbol col              [/color][color=DarkCyan]= [/color][color=Navy]58[/color]
[color=Blue]symbol ret              [/color][color=DarkCyan]= [/color][color=Navy]13[/color]
[color=Blue]symbol lfeed            [/color][color=DarkCyan]= [/color][color=Navy]10

      [/color][color=Blue]pause [/color][color=Navy]1000                    [/color][color=Green]'allow terminal to open[/color]
[color=Black]init:
      [/color][color=Blue]let [/color][color=Purple]dirsb [/color][color=DarkCyan]= [/color][color=Navy]%00000000         [/color][color=Green]'set port b to input
      [/color][color=Blue]let [/color][color=Purple]LED [/color][color=DarkCyan]= [/color][color=Navy]0
      [/color][color=Blue]let [/color][color=Purple]sec [/color][color=DarkCyan]= [/color][color=Navy]0
      [/color][color=Blue]let [/color][color=Purple]mins [/color][color=DarkCyan]= [/color][color=Purple]sec [/color][color=DarkCyan]+ [/color][color=Navy]6
      [/color][color=Blue]let [/color][color=Purple]hour [/color][color=DarkCyan]= [/color][color=Purple]mins [/color][color=DarkCyan]+ [/color][color=Navy]6
      [/color]
[color=Black]main:
      [/color][color=Blue]do while [/color][color=Purple]loop_number [/color][color=DarkCyan]< [/color][color=Navy]250
            [/color][color=Blue]let [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]sec
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]display
            [/color][color=Blue]let [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]mins
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]display
            [/color][color=Blue]let [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]hour
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]display
            [/color][color=Blue]inc [/color][color=Purple]loop_number
      [/color][color=Blue]loop
      inc [/color][color=Purple]sec
      [/color][color=Blue]if [/color][color=Purple]sec [/color][color=DarkCyan]> [/color][color=Navy]5 [/color][color=Blue]then                     [/color][color=Green]'highest possible seconds LED address
            [/color][color=Blue]let [/color][color=Purple]sec [/color][color=DarkCyan]= [/color][color=Navy]0                   [/color][color=Green]'check for overflow and correct
            [/color][color=Blue]inc [/color][color=Purple]mins
            [/color][color=Blue]if [/color][color=Purple]mins [/color][color=DarkCyan]> [/color][color=Navy]11 [/color][color=Blue]then             [/color][color=Green]'highest possible minutes LED address
                  [/color][color=Blue]let [/color][color=Purple]mins [/color][color=DarkCyan]= [/color][color=Navy]6
                  [/color][color=Blue]inc [/color][color=Purple]hour
                  [/color][color=Blue]if [/color][color=Purple]hour [/color][color=DarkCyan]> [/color][color=Navy]17 [/color][color=Blue]then       [/color][color=Green]'highest possible hour LED address
                        [/color][color=Blue]goto [/color][color=Black]init
                  [/color][color=Blue]end if
            end if
      end if
      let [/color][color=Purple]loop_number [/color][color=DarkCyan]= [/color][color=Navy]0                 [/color][color=Green]'reset lopp counter
      [/color][color=Blue]goto [/color][color=Black]main
      
look_up:                                  [/color][color=Green]'lookup LED address and set high and low pins
      [/color][color=Blue]lookup [/color][color=Purple]LED[/color][color=Black], [/color][color=Blue]([/color][color=Navy]2[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]1[/color][color=Blue])[/color][color=Black],[/color][color=Purple]high_pin
      [/color][color=Blue]lookup [/color][color=Purple]LED[/color][color=Black], [/color][color=Blue]([/color][color=Navy]0[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]0[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]4[/color][color=Black],[/color][color=Navy]2[/color][color=Black],[/color][color=Navy]3[/color][color=Black],[/color][color=Navy]1[/color][color=Black],[/color][color=Navy]2[/color][color=Blue])[/color][color=Black],[/color][color=Purple]low_pin
      [/color][color=Blue]return
      [/color]
[color=Black]display:                                  [/color][color=Green]'show LED
      [/color][color=Blue]low [/color][color=Purple]low_pin
      [/color][color=Blue]high [/color][color=Purple]high_pin
      [/color][color=Blue]input [/color][color=Purple]low_pin
      [/color][color=Blue]input [/color][color=Purple]high_pin
      [/color][color=Blue]return[/color]
 

hippy

Technical Support
Staff member
Fading is just changing from one brightness level to another, brightness is simply however long a LED is on for against how long it is not on for.

It should be possible to do all that with your 6 x 3 proof of concept hardware.
 

BESQUEUT

Senior Member
Also found that it will most likely be best to have the LEDs set as pairs on the PCB and a bus connected to each pin running around that jumper wired join to each LED pair.
Fading is just changing from one brightness level to another, brightness is simply however long a LED is on for against how long it is not on for.
Sooner or later, you will consider using APA102...
 

Buzby

Senior Member
Great work !.

Put a short delay just before the first INPUT command in the Display routine.

This has the effect of keeping the LED on longer, so making it look brighter.

The maximum delay is found when the overall display starts to flicker.

10mS is a good starting point.

Cheers,

Buzby
 

oracacle

Senior Member
added this pair of sub procedures

Code:
[color=Black]hour_display:                             [/color][color=Green]'display hour with dimmed LEDs either side
      [/color][color=Blue]if [/color][color=Purple]hour_2 [/color][color=DarkCyan]= [/color][color=Navy]3 [/color][color=Blue]then                  [/color][color=Green]'2 behind of hour
            [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]hour [/color][color=DarkCyan]- [/color][color=Navy]2
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]hour_show
      [/color][color=Blue]end if
      if [/color][color=Purple]hour_1 [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Blue]then                  [/color][color=Green]'1 behind of hour
            [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]hour [/color][color=DarkCyan]- [/color][color=Navy]1
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]hour_show
      [/color][color=Blue]end if
      [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]hour
      [/color][color=Blue]gosub [/color][color=Black]look_up
      [/color][color=Blue]gosub [/color][color=Black]display
      [/color][color=Blue]if [/color][color=Purple]hour_1 [/color][color=DarkCyan]= [/color][color=Navy]1 [/color][color=Blue]then                  [/color][color=Green]'1 infront of hour
            [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]hour [/color][color=DarkCyan]+ [/color][color=Navy]1
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]hour_show
            [/color][color=Blue]let [/color][color=Purple]hour_1 [/color][color=DarkCyan]= [/color][color=Navy]0
      [/color][color=Blue]end if
      if [/color][color=Purple]hour_2 [/color][color=DarkCyan]= [/color][color=Navy]3 [/color][color=Blue]then                  [/color][color=Green]'2 infront of hour
            [/color][color=Purple]led [/color][color=DarkCyan]= [/color][color=Purple]hour [/color][color=DarkCyan]+ [/color][color=Navy]2
            [/color][color=Blue]gosub [/color][color=Black]look_up
            [/color][color=Blue]gosub [/color][color=Black]hour_show
            [/color][color=Blue]let [/color][color=Purple]hour_2 [/color][color=DarkCyan]= [/color][color=Navy]0
      [/color][color=Blue]end if
      inc [/color][color=Purple]hour_1
      [/color][color=Blue]inc [/color][color=Purple]hour_2
      [/color][color=Blue]return[/color]
[color=Black]hour_show:                                [/color][color=Green]'show hour with dimmed LEDs
      [/color][color=Blue]low [/color][color=Purple]low_pin
      [/color][color=Blue]high [/color][color=Purple]high_pin
      [/color][color=Blue]input [/color][color=Purple]low_pin
      [/color][color=Blue]input [/color][color=Purple]high_pin
      [/color][color=Blue]return[/color]
this make the 2 LEDs in front and behind come on dimly, there is flickering one the hour_2 LEDs. going to try an some quantities of loops to see if what happens. overflow and underflow needs to be added too.

I added a pause 10 as busby suggested and the LEDs are brighter, but meant I had to add a second display routine for the dimmer LEDs.
The hour position will have to be updated every 5 minutes
 

Attachments

Last edited:

oracacle

Senior Member
will need tweaking for the final thing for overflow/underflow and incrementing the hour position every 5 minutes but this does what I had imagined in a more optimised way than before and cutting back on the sub procedures

Code:
#no_data
#no_table
'#terminal 9600
setfreq em64

symbol high_flag		= bit0
symbol half_flag		= bit1
symbol third_flag		= bit2

symbol high_pin		= b4
symbol low_pin		= b5
symbol loop_number	= b6
symbol LED			= b7
symbol temp_byte_0	= b8
symbol sec			= b10
symbol mins			= b11
symbol hour			= b12
symbol pause_time	= b13
symbol hour_2		= b14

symbol com			= 44
symbol col			= 58
symbol ret			= 13
symbol lfeed		= 10

	pause 1000				'allow terminal to open
init:
	let dirsb = %00000000		'set port b to input
	let LED = 0
	let sec = 0
	let mins = 6
	let hour = 12
	let pause_time = 10
	
main:
	do while loop_number < 250
		let led = sec
		gosub look_up
		gosub display
		let led = mins
		gosub look_up
		gosub display
		led = hour
		gosub look_up
		gosub display
		gosub hour_display		'hour LED will have to increase every 5 minutes
		inc loop_number
	loop
	inc sec
	if sec > 5 then				'highest possible seconds LED address
		let sec = 0				'check for overflow and correct
		inc mins
		if mins > 11 then			'highest possible minutes LED address
			let mins = 6
			inc hour
			if hour > 17 then		'highest possible hour LED address
				goto init
			end if
		end if
	end if
	let loop_number = 0			'reset loop counter
	goto main
	
hour_display:					'display hour with dimmed LEDs either side
	let pause_time = 1     		'show 1 befor and after
	led = hour - 1
	gosub look_up
	gosub display
	led = hour + 1
	gosub look_up
	gosub display
	
	let pause_time = 0
	if hour_2 = 2 then			'2 behind of hour
		led = hour - 2
		gosub look_up
		gosub display
		led = hour + 2
		gosub look_up
		gosub display
		let hour_2 = 0
	end if
	inc hour_2
	let pause_time = 10
	return
	
look_up:						'lookup LED address and set high and low pins
	lookup LED, (2,0,4,1,3,0,3,1,2,4,1,0,4,3,3,2,2,1),high_pin
	lookup LED, (0,2,1,4,0,3,1,3,4,2,0,1,3,4,2,3,1,2),low_pin
	return
	
display:						'show LED
	low low_pin
	high high_pin
	pause pause_time
	input low_pin
	input high_pin
	return
 

Buzby

Senior Member
Hi oracacle,

I've been playing around with a LOL shield with 126 Charlieplexed LEDs.
LOL_1.png
Using LOOKUP to get the pin values is way too slow.
Even at em64 the display flickers badly with just a few LEDs lit.

So I copied the data from the LOOKUP into the scratchram.
Now it's much better.

Here is my test code.

Code:
#picaxe 28X2
#no_data
#no_table
'#terminal 76800
setfreq em64

symbol LEDpin1		= b0
symbol LEDpin2		= b1
symbol LED			= b2

symbol LEDdelay		= w10

goto Init 

' *****************************************************************************
' Subroutines
' *****************************************************************************

ShowLED:	'show LED
	low b0 : high b1
	pause LEDdelay
	input b0 : input b1
return

GetLED:	' Get LED pins from scratchpad
	ptr = LED * 2
	b0 = @ptrinc : b1 = @ptrinc
return

look_up:  'lookup LED pins into b0, b1
	lookup LED, ($205, $206, $207, $208, $209, $20A, $20D, $20C, $20B,_
			 $502, $602, $702, $802, $902, $A02, $D02, $C02, $B02,_
			 $005, $006, $007, $008, $009, $00A, $00D, $00C, $00B,_
			 $500, $600, $700, $800, $900, $A00, $D00, $C00, $B00,_
			 $105, $106, $107, $108, $109, $10A, $10D, $10C, $10B,_
			 $501, $601, $701, $801, $901, $A01, $D01, $C01, $B01,_
			 $50B, $60B, $70B, $80B, $90B, $A0B, $D0B, $C0B, $B0C,_
			 $50C, $60C, $70C, $80C, $90C, $A0C, $D0C, $C0D, $B0D,_
			 $50D, $60D, $70D, $80D, $90D, $A0D, $D0A, $C0A, $B0A,_
			 $50A, $60A, $70A, $80A, $90A, $A09, $D09, $C09, $B09,_
			 $509, $609, $709, $809, $908, $A08, $D08, $C08, $B08,_
			 $508, $608, $708, $807, $907, $A07, $D07, $C07, $B07,_
			 $507, $607, $706, $806, $906, $A06, $D06, $C06, $B06,_
			 $506, $605, $705, $805, $905, $A05, $D05, $C05, $B05 _
			 ),w0
return
' **************************************************************************
' Code starts here
' **************************************************************************
Init:

pause 1000				
let LEDdelay = 10 

' Copy LED data to scratchpad RAM
ptr = 0		
for LED = 0 to 125
	gosub look_up
	@ptrinc = b0 : @ptrinc = b1
next


MainLoop:
do
 	For LED = 117 to 125 step 3 : gosub GetLED : gosub ShowLED : next
 	For LED = 116 to 8 step-27  : gosub GetLED : gosub ShowLED : next	
 	For LED = 5 to 0 step-3 : gosub GetLED : gosub ShowLED : next	
 	For LED = 9 to 107 step 27 : gosub GetLED : gosub ShowLED : next	
loop
 
Last edited:

hippy

Technical Support
Staff member
@ Buzby

You are correct to note LOOKUP as being slow; better to put that data in EEPROM, TABLE or copy to Scratchpad as you are doing.

You can also combine your "gosub GetLED : gosub ShowLED" into a single 'gosub GetAndShowLED' which will speed things up, as will turning those calls into a #MACRO.

You should be able to gain a small speed advantage by changing "ptr=LED*2" to "ptr=LED<<1" or even "ptr=LED+LED" on an M2. I haven't actually tested that to see if it is the case.
 

oracacle

Senior Member
the lookup was a stand in for testing more than anything.
the original plan was to use an external eeprom, but if a lookup is going to be too slow, then an I2C EEPROM will be way too slow. I am little concerned about programme space having nearly 200 variables stored in code is bound to take up a lot of it

I suppose there is no reason why the values couldn't be stored on an EEPROM and read into the scratch pad at startup.
I am just about ready to start assembling the PCB ring of LEDs so testing can start and further investigation into the display print time can be done.

I will take a close look into your code, I am having difficulties reading it ATM.
 
Top