No Frills LED Clock - 16F54 controller - Flicker free


Joined Jun 26, 2012
So you say with your much smaller program code, the display isnt flickering?
The table reads are very slow, RAM read via pointer is fast.
In addition you need to care individual sink bits, do 10 divison perhaps.
I don't know about flickering. My programmer went TU so I couldn't test the code on the F54 yet. I'll scab something together and let you know.

Thread Starter


Joined Apr 28, 2012
But that doesn't mean you are out of the woods yet.

Still buggy code, :(.
Yes. Since my laptop has many virusses and worms, they cancel out each other and the clocks synchronize. In fact, all other clocks in this world synchronize to my buggy gizmo.


Joined Jun 26, 2012
@takao21203 Well, you were right about the flickering. Despite some attention paid to streamlining the code, it flickers. I used an external pulse generator to run the F54 and disabled the arithmetic temporarily and found that the 4 digits had to be refreshed at 150Hz i.e. 6.6ms for the whole 4 digits to get a nice looking display. My quickie multiplexer wasn't getting it done with a 32KHz oscillator. A big part of the problem was the requirement for fully re-assignable IO. It turned out the XC8 in the FREE mode isn't too accommodating with masking multiple bits and things. But even with all of that, when I put a pencil to it, I wound up with pretty much the same as you did - compute the patterns as able and put them into two RAM buffers that get pushed to the ports when its time - so, good work on your part!

It is probably pointless to continue since you have a working deal. But here are a couple of things you might find useful:
Danny was right, if stingy, about never writing to TMR0 to reload because it will clear the prescaler and the overhead will likely bite you. Way back when I was tied to baseline PICs I used a construct like this for a free running TMR0:
   //------------ TIMER -------------------------
        temp = TMR0;                    // read the timer
        SysTIKS = prevSysTIKS ^ temp;   // set changes
        prevSysTIKS = temp;             // record TMR0 value for next time
If you do this at the top of your main loop, you get flag bits in SysTIKS that indicate that the bit has changed as TMR0 increments. By logging changes, you get up to 8 triggers for processes that are in the main loop - and all without writing to the timer so timing is accurate.

The second thing you might find useful is keeping time in displayable form so that you don't have to convert binary to decimal. I did this:
void bumpPackedBCD(unsigned char *t)
    if((*t & 0x0f) >= 0x0a)
        *t += 0x6;
to maintain minutes and hours in packed BCD i.e. 00h - 99h for minutes and hours., one char each. The compiler uses SWAP to select the nibbles when compiling (x >> 4) so extracting nibbles is cheap. By inspecting the value (in hex) after bumping, you can wrap at 0x59 for minutes, 0x12, 0x23 for hours etc. I tried it using globals but was surprised to find (as you did) that pointer ops are about the same load in the function code but use less to call so are faster.

Lastly, why 32KHz?? I'd consider reworking my code to reduce Tcycs but why? Using LEDs means its not low power. If the reason is that you only have an 8 bit TMR0, that's not an issue. With the construct I described, you can use any of the trigger bits to drive extended counters. For a few bytes of RAM, you can extend TMR0 to 16, 24 or more bits. That's what I did in those early designs and counted days running at 4MHz. Using a Tcyc ~= 122us (32KHz) implies challenges that are mostly academic.

And it's time for a better chip. Using the F54 with NO (current) debugging support is not a good use of anyone's time.

Anyway, it's been fun.
Well done and best regards,
Last edited:

Thread Starter


Joined Apr 28, 2012
Yes I agree a RTC chip or a better PIC is most appropiated. I have many around thats not the problem.
Sure, I could use a faster crystal as such.

But I was wondering if it is possible at all and somehow I did feel it might be possible.

One of the tables only uses 4 bits of 8 bits loaded. 32 words could be eliminated but the extra code would almost annihilate the modest saving. Its also not needed at all to proceed with this.

The display is not completely flicker free.
And using the CR2032 theres some weird Ghosting. Each digit flashes a little briefly, 2 times each.
The 10s hour digit only flashes once.
I was wondering why is this.

Pushing the set button, one segment goes out. I think never acceptable for consumer goods. Or is it?
They use epoxy blobs almost all the cheap kinds, not discrete ICs.
And have calendar- if you need to look up which day it is, you are lost anyway.
Have a stopwatch, well could be useful to be 1/100 seconds exact. The shortest I was able to push always was 80 milliseconds or so.
Have alarm but doesnt wake you up relieably.
Have a backlight some time ago, really a small bulb.

A radio even and else what.

A 100 years calendar that may still be working when you passed away.

Never saw a no frills LED clock you could just plug into a power socket. Or with lithium battery even.
The cheapest LCD watch and have some emblazoning for sure.

The Wifi speaker I show in the video has a LED watch btw., I could use that.


Joined Feb 14, 2010
Anyone interested in seeing an (untested) assembly language example program? It's in-context (16F54, 32768-Hz crystal, and four digit mux'd display) with the exception of remapped display pins (all segments on Port B). The program uses 94 words of program memory and 14 out of 25 bytes RAM, including a ten element segment pattern array. Each display is lighted in sequence at 16 cycle intervals within a 64 cycle isochronous main loop (128-Hz refresh rate). The packed-BCD RTC variables are updated once every 128 loops at precise one second (8192 cycle) intervals without disrupting the display refresh sequence and timing (no flicker). The program is probably a decent example of using partially unrolled loops and packed-BCD variables to improve performance while demonstrating a coding style for cycle accurate isochronous loops.

Cheerful regards, Mike


Last edited:

Thread Starter


Joined Apr 28, 2012
it should be noted the circuit time runs 5 minutes too fast each 24 hours.
Probably the crystal drive level is not right.

it worked 10 days or so from a lithium cell