NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Binary Clock

April 28, 2009
by mcai8sh4
mcai8sh4's Avatar

Ok, I know I'm gonna have a couple of little questions regarding my latest little project, so I thought I'd start a thread rather than hijack another one.

Basic plan - based from the real time clock demo, adapt it to initially light up leds to show the time in binary form, 4 leds for hours, six for minutes (maybe 6 for seconds), I may also add functionality to set the time as well, but initially I'm not worrying about that.

My first thought was how to get the time displayed in binary format, so I thought I'd knock up a little function to test my binary conversion. All works, but when I put this in context to my project, I dont think it's any good. First off, heres the function :

void conv_bin(int i)
{
       if (i > 0)
       {
               bin(i / 2);
               printf("%d", i % 2);
       }

}

Quite simple so far. It simply displays the binary number, but does not store it anywhere.

Now to progress, I think it would be a good idea to store the output in an array. But I'm having trouble getting it to work. My plan is then to (somehow - not thought this far ahead yet) use the array to turn the pins connected to my LEDS on.

First question, does this idea seem feasible, or is there a better way to do it? If it is feasible, how can I get this to store the result in an array? I suppose I could not do it recursively, but this just seems the easiest way.

Any thoughts/tips would be appreciated.

Thanks

April 28, 2009
by mcai8sh4
mcai8sh4's Avatar

Re-wrote the code, and it seems to work, but if I'm doing this a daft way, please let me know - thanks

Code :

#include <stdio.h>
int bin(int i, int a[])
{
        int count=0;
        while (i > 0)
        {
                a[count]=(i % 2);
                count++;
                i = (i/2);
        }
}

int main()
{
        int c, i, ary[8]={0};
        for (i=0; i<11; i++)
        {
                bin(i, ary);
                for (c=7; c>=0; c--)
                {
                        printf("%d", ary[c]);
                }
                printf("\n");
        }
}

Also, is there an easier way of posting code... adding 4 spaces could be a pain if the code snippet is of any length.

Bye

April 28, 2009
by mcai8sh4
mcai8sh4's Avatar

oops - typo in first post - the function should be called 'bin' NOT 'conv_bin'

April 28, 2009
by digiassn
digiassn's Avatar

I have something similar in the Nixie Tube clock project Im working on since the output time needs to be done in BCD for the Nixie driver.

Easiest way to do this, have a structure defined that stores the time, and have that time updated based on an interrupt. Then, you should be able to just output directly to PORTX, where X is what you initialize for your output.

I had to hack and slash the below example because the Nixie pin setting is a lot more complicated due to decimal to BCD conversion and I actually have another interupt that is sampling the input from a atomic clock radio reciever, but this "should" work since you just need turn on/off the pins on the output port. Just keep an eye out for syntax errors in the example, its untested, and just an approximation based off of working code. There are also some examples in the NErdKit code folder that show how to turn on and off individual pins using bit masks

//define type structure to keep track of time

typedef struct{

unsigned char second;   //enter the current time, date, month, and year

unsigned char minute;

unsigned char hour;

            }time;

time t;

ISR(TIMER1_COMPA_vect) {

//this isn't going to allow for an accurate clock, will lose accuracy over time

//But we will sync off the atomic clock, so thats OK

//changed, if the clock counter is 16 bit, we can compare with the correct value
//and trigger the interupt at the right interval
if (++t.second >= 60)        //keep track of time, date, month, and year
{
    t.second=0;
    if (++t.minute >= 60) 
    {
        t.minute=0;
        if (++t.hour >= 24)
        {
            t.hour=0;
        }
    }
}

}

void SetupTimer1() {

TCCR1A = 0x00;

TCCR1B = (1 << CS12) | (1 << WGM12);

OCR1A = 57652; //this should be 57600, but I changed the divider math wise to 255 instead of 256

             //and rounded up the result. The clock was slightly fast in my case, and over an 8 horu period was about half a minute

ahead of where //it should have been. (57600, 57650 and clock was too fast, 57826 and 57712, 57660, 57654 and clock was too slow.

//Timer1 Overflow Interrupt Enable

TIMSK1 = (1 << OCIE1A);

}

int main() { // LED as output

DDRB |= 0xFF;

initPins();

//general initialization for time
t.hour = 0;
t.minute = 0;
t.second = 0;

//setup the timer interupt and enable global interupt
SetupTimer1();
sei();

while(1)
{
    //whatever, output time, something like....
    //lets say PORTB is outputting the hours, this SHOULD light up the
    //hours leds
    PORTB = t.hour;
    ...
}
return 0;

}

April 28, 2009
by mcai8sh4
mcai8sh4's Avatar

Thanks digiassin, that looks good. I like the time structure - never thought of that! And it seems quite simple to set the leds to light or not.

I'm a bit confused with some bits, but I'll probably understand more when I start coding it, anything I'm not sure of, don't worry there will be questions.

I'm still thinking of how the final things going to work, but it all seems quite promising at present. I should get more time to work on this on Friday.

Thanks again, greatly appreciated.

April 29, 2009
by digiassn
digiassn's Avatar

No problem. I actually had this working as a prototype in the Nixie project running off LED's since I didn't have the driver chips in at the time, but I changed that code, but in theory it should work as long as your LED's are 0 based (bit 0 of your output is on B0, bit 1 on B1, etc). If not, you will just need to do some bit shifting, just be careful, not all the ports are 8 bits, and some of the pins are used for other things by default.

April 29, 2009
by mcai8sh4
mcai8sh4's Avatar

Thanks for the help. I only need 6 bits for minute (and seconds if I decide to implement seconds), and 4 bits for the hours (12 hr clock). I noticed that some of the ports where not 8 bits when I did the marquee project (and wired it up wrong - I really should pay more attention).

So am I right in thinking, if say it's 3 hours, and I'm using PORTC, I can simply set 'PORTC = 3;', in other words, there is no need to convert the number to binary - it will just be done [000011]. (note to staff here) This is one of the things I was wondering when first running through the nerdkits tutorial - if I could just set a number and it would turn on the bits respectively. I thought it was implied in the guide, but I wasn't sure.

I'm gonna rough it all out this weekend, once it all works I can start the design of the housing to make it look pretty in the end.

Cheers

April 29, 2009
by BobaMosfet
BobaMosfet's Avatar

Wow, I haven't seen someone working with NIXIEs for years. Last time I touched one, was for a DEC PDP8, running a nuclear fuel - handling machine in a reactor here in the USA.

BCD can be confusing until you realize it's based on hex (base 16). It's nothing more than how decimal is normally represented in binary, except that the max value a nybble can represent is 09 and the next 6 values are used for sign (10-15 aka 0xA-0xF).

NOTE: LSB is on the right

8 + 4 + 2 + 1      Bit Position
-------------
0 + 1 + 1 + 0      6 Decimal = 6 BCD = 6 hex.

If you want sign represented (like '-9' or '-324', you need to use one of the higher order BCD equivalents, A-F. You're working in hex for 0-F (base 16).

0xA = 10 dec = 1010 in Binary/BCD (not the 1-bit is actually used for sign)  0 = '+', and 1 = '-'.
0xB = 11 dec = 1011 in Binary/BCD (so this is a minus)
0xC = 12 dec = 1100 in Binary/BCD (so this is a plus)
0xD = 13 dec = 1101 in Binary/BCC (so this is a minus)
0xE = 14 dec = 1110 in Binary/BCD (so this is a plus)
0xF = 15 dec = 1111 in Binary/BCD (so this actually means *unsigned* in BCD parlance).

Using 0xC and 0xD are the preferred BCD values for displaying sign.

So '9-' (aka '-9') would be: 0x9D in hex, 10011101 in Binary/BCD.

One of the main reasons I introduce hex in this discussion is because if you use hex as your intermediary between decimal and binary, it becomes very easy and straightforward to convert between the 3 bases (2, 10, and 16). Just be thankful you're not working in octal. :P

April 30, 2009
by digiassn
digiassn's Avatar

Finally, someone who realizes how rare and cool Nixies are :) I scored mine from Russian surplus. I have the circuit working already for the clock, or at least prototyped on a breadboard, im in the process of putting it together physically with wire wrap and such. I think in the future Ill just pay the money and get the circuit etched through Sparkfun or something. I can see after doing this why these things are so expensive to buy :)

May 16, 2009
by mcai8sh4
mcai8sh4's Avatar

Alrighty - this is the first free day I've had to play around with this. So far all I've done is take thr origional clock example from the nerdkits tutorial, built the board and got the display counting up on seconds. Then I set all the pins for PORTC to be outputs via

DDRC |= (1<<PC0);
DDRC |= (1<<PC1);
...
DDRC |= (1<<PC5);

Then to get them to light up showing the binary repersentation of the seconds (I'll use minutes in the end, but seconds follow the same idea)...

PORTC = the_time / 100;

And all works.

First question, is this the correct method for setting all of PC0-PC5 as outputs - or is there a one-line way that sets all (or some) of the pins?

My next question concerns the other pins I want to use to display the hours.

I need 4 pins to display up to '12' - I'd like to use PB1-PB4 as this keeps all the output on one side (although I'm not really bothered). But I notice PB0 is used to set the chip into programming mode. So I'm not sure what to do. I could use PD0-3, but I'd like to keep these free for the programming header.

Any advise?

May 16, 2009
by mcai8sh4
mcai8sh4's Avatar

Ok - I think PB0 only goes into programming mode initially (at power on), after that I think it's safe to use for anything. So that (might) solve that.

Next... why does the sample realtime clock program initialise the serial port? I don't really get the stream things - I think I have a basic idea, but I'm probably wrong.

Since eventually I'm gona be running 'headless' (no LCD), I can remove

// init lcd
lcd_init();
FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
lcd_home();

// init serial port
uart_init();
FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
stdin = stdout = &uart_stream;

and all should still work the same?

May 16, 2009
by mcai8sh4
mcai8sh4's Avatar

Using PB0 seems to be a bad idea - it always goes into programming mode when you power on (pretty obvious really).

Is there a way around this - eg. if I have my hours number - could I just do "PORTB = hours * 2^n;" where n is the number of bits I wish to shift (in this case 1)... so to ignore PB0 I could simply do "PORTB = hours * 2;"

Is this a bad idea, should I just use PORTD?

May 16, 2009
by mcai8sh4
mcai8sh4's Avatar

Final post for the day...

All seems to be working - It has been mentioned to me that I should really push current to the chip rather than drain it - ie set the pins high for off and low for on and reverse the LEDs- is this true?

Another point I'm using an old charger 8V 200mA - all seems fine but the regulator is warm - not hot enough so you can't touch it, but warm. I never noticed it with the battery. Is this gonna cause problems, I assume they turn the excess voltage into heat to give you the nice 5V, but I want to check, don't fancy waiting another couple of week for the replacments :)

But in general all seems to be going well. The basic idea works - at the minute it counts up in seconds then increases the minutes section when it should. Im using PC0..5 for the seconds (that I'll acually use for minutes when everythings ok), and PB1..4 for the minutes (that will be hours - only need to go up to 12).

Tomorrow I'll add some buttons so I can set the time (haven't thought about this yet, but I'm sure it can't be too difficult), then get rid of the LCD and clean up the code a little. Then all thats left is to make an external housing to mount the LEDs in and look good, then that will be my first 'real' project complete (the marquee was the Nerdkits guys work, so I can't include that).

May 17, 2009
by TBNK
TBNK's Avatar

mcai8sh4, it's great watching you work through this project for yourself. I don't have answers for your questions, but it looks like you're learning lots of things as you go along. Please keep posting your progress for us.

May 17, 2009
by mcai8sh4
mcai8sh4's Avatar

Since you ask... I have progressed today :

Funny thing, I never thought my maths approach to ignore PB0 was 'bit shifting' until I'd done it!

Any way I've used that method, and it seems to work with no ill effects.

I'm still driving the LEDs from the pin to GND - still need to know if thats a good idea or not - but it seems to work.

I've not looked into the stream issue yet (I just don't quite understand it) but I've removed all that as I'm now running it 'headless'.

I've added a push switch so I can set the time.

Basically - It all seems to work, I'm still running off the battery - and the power regulator does get warm, so I guess the old charger I found will be ok, but I'll wait for clarification before I use it again.

I've not checked how accurate the time keeping is yet, but I've run it for about 15mins and it seemed ok. If the power adaptor is ok, I'll take it to work and run it all day (I'd like to keep my eye on it).

I Just need to clean up the code, but for anyone interested, it will be stored temporarily here

Once everythings done, I'll post the code somewhere more permanent.

So if the tests continue ok, and I'm happy with it, I can make the housing then I'll post a pic.

Watch this space (for my next problem with it :) )

May 17, 2009
by mcai8sh4
mcai8sh4's Avatar

As an aside, sadly, my binary reading skills aren't as good as they where 10 years ago, so it still takes me a few seconds to work out the time... so I thought I'd have something to help me.

I'm using Ubuntu Linux, and on my desktop I have conky running (to display... well, stuff) so I thought it'd be handy to have a binary representation of the time on my desktop, to 'train' my reading skills up a little - so I wrote a little bash script to display the current time in binary, then I use this script to display it on my conky setup (and it works!!! - yeah, I was surprised as well)

For anyone with Linux, who wants it here's the (very basic) script :

#!/bin/bash
#
# display the current time in binary format
# can be used with conky
let h=$(echo "ibase=10;obase=2; $(date +%I)" | bc)
let m=$(echo "ibase=10;obase=2; $(date +%M)" | bc)
echo "$h $m"

No use to most people, but someone might want it.

May 17, 2009
by digiassn
digiassn's Avatar

If your worried about the heat, just put a heat sink on it. They sell them at Rat Shack pretty cheap, just be sure to get the thermal glue also.

It will lose perfect sync over time, but almost all clocks do. Once I'm done with the Nixie clock, Ill post the schematic and the code to sync the time off the Atomic Clock module.

You should be fine driving the LED from PIN to GND. If your worried about it, you can add a small current limiting resistor in series with them, or use PWM to drive the LED at like a 75 duty cycle.

May 18, 2009
by mcai8sh4
mcai8sh4's Avatar

Thanks digiassn, I'm going to look into the PWM (try and get my head around it), as I imagine it would conserve the battery life a little.

I'm looking forward to seeing a photo of your nixie clock, I saw a picture of one this weekend, and was very jealous (I think it may be a number of years before I'm ready to even think about attempting one though).

Whilst I'm only playing around with very simple things at the minute, I must admit, I'm really enjoying it. Not sure what my next project will be, but I think I have a way to go before I will consider this one finished.

May 29, 2009
by mcai8sh4
mcai8sh4's Avatar

Right, so here's a little update on where I'm up to. It's been a busy couple of weeks, so I haven't progressed as much as I wanted to.

I've played around with the code - making slight changes here and there and, on the whole, I think the changes are improvements. These include changing the set_pins() function (simply shortened it from 1 line to set each pin to output, to 2 lines to set all the pins (the 10 that I need) to output. This was after reading waywards explanation. I've also altered the timing on the button to set the time (still not perfect - but usable). And probably a few minor other changes.

Today during my lunch I machined a quick prototype for the housings that will be my clock, and built a quick circuit to see how it looks.

I think it looks quite good - but I'm not 100% happy with it. It just doesn't seem bright enough (but looks cool now it's dark over here and I usually have the lights dim!

I've took a few pics with my phone (so the quality's not that good) but you get the idea.

Pictures and code can be found HERE

One thing I notice, one of the hour LEDs did not work, I checked the LED - fine, I checked the voltage - fine... then I got worried that I'd fried something. Turns out I'd forgot that I was ignoring PB0 and starting the hours on PB1 so I set DDRB |= 0x0F when it should be 0x1E (I think).

So basically I didn't set that pin to output, but (here's the question...) why did I still get +4.89V between the pin and the GND, when I tried to turn the pin on, but it didn't light the LED?

May 29, 2009
by wayward
wayward's Avatar

hey mcai,

if your pin was set to input mode with pull-up enabled (DDRBx 0, PORTBx 1) then you would read close to 5V on it, but the current through the pull-up resistor (typically 50k-100kΩ) would be too low to drive the LED. Or at least I think that's the reason. :)

May 30, 2009
by mcai8sh4
mcai8sh4's Avatar

I'm still not happy with the brightness of the LEDs I've got, I just bought standard cheap ones. They look great, until I put them in the housing (the light rods up - kinda total internal refraction style, but not quite). I swapped on of the ones I bought for one of the red ones that came with the Nerdkit - much better. I guess these may be ultra bright (or just not cheap nasty ones) - the quest continues

May 31, 2009
by mcai8sh4
mcai8sh4's Avatar

quick update - I've found some cheap (as in cost, hopefully not in quality) LEDs from a uk company (£0.99 delivery) - http://www.phenoptix.co.uk/

I've order some and should get them this week, hopefully they'll be bright enough for what I want.

I've looked at using a pin change interrupt for the switch to set the time. I haven't implemented this yet because everything seems to work ok. I'll give it a go, but I'll still need the if statement and probably the delay_ms() so there doesn't seem to be much benefit at present. Thanks to Humberto who helped me understand the interrupt via IRC.

If the new leds are bright enough, I'm going to try and use PWM to lower the brightness slightly and reduce the power consumption. Having tried to read the datasheet - and looked at a few example pieces of code (Valentines heart amongst others) - I still don't really get it. If anyone knows how to do this on pins PC0..5 and PB1..4, any advise would be appreciated.

Other than that, nothing else has really progressed. Once I've implemented the switch interrupt, I'll post the code snippets - it could be useful for others.

June 02, 2009
by mcai8sh4
mcai8sh4's Avatar

New LEDs have arrived - massive improvement from that last ones. I've not added any resistors yet (naughty me), but it seems to work (for the minute at least). One thing that's confused me though - when I was using the cheap nasty leds (from maplin) the power regulator was getting rather warm, but now I'm using these brighter ones it's not getting as warm (barely any heat coming off it) - is this because the LEDs are using all that power to light up and before the power was being shed by the regulator?

Since I'm a happy bunny at the minute, I'll share a picture of my prototype (still only using my phone - so the quality is poor) but things are coming on :

Binary Clock Prototype

Close up

The colours don't come out too well in the picture, they are really clear IRL, but you get the idea.

I'm going to leave it as it is for the time being, and have it run for a few hours tomorrow to see how it keeps time. I'll also be playing with the code - trying to add the switch interrupt and possibly PWM if I can.

Thats all for now! (...and I know it doesn't look that impressive - but I am really chuffed that I made that :D )

June 03, 2009
by mcai8sh4
mcai8sh4's Avatar

... added 100ohm resistors to each LED (hope thats right so stuff doesn't go bad), ran it for about 3 hours and kept perfect (as far as I could tell) time. Now I just need to figure out how to cut a bit of the power down - I'd like to be able to run it (for at least 24hrs) on a battery. Does anyone think I stand a chance? I think PWM may be the answer (lights are on for less time - so less power consumption? and longer LED life).

By putting the resistors in, excuse the stupid question here, am I making the LEDs run at the correct power, and therefore not die and short something? Here's the what I think I'm doing.... thanks to Mike's comments on the Nerdkits Unofficial IRC channel(TM) :

BLUE :
Forward Voltage (V): 3.0-3.2 
Forward Current (mA): 20-30

So... (5-3)/0.030 = 66.667 ohms - so I went bigger and used 100 ohm resistors

GREEN :
Forward Voltage (V): 2.8-3.2  
Forward Current (mA): 20-30

So... (5-2.8)/0.030 = 73.333 ohms - so again I went bigger and used 100 ohm resistors again

I don't know if I can use a software hack for PWM due to the whole loop idea (I still don't really understand it), and the hardware PWM... well the datasheet just confuses me - I'm not even sure if I can use it with the pins I'm using. This area needs a lot more study.

But on the whole - still happy, although I think this things gonna eat batteries faster than I can earn the money to buy them (and although I have used it with no issues - I'm still not satisfied with using the AC adapter I have).

And so todays little missive comes to an end :D

Post a Reply

Please log in to post a reply.

Did you know that you can connect to certain car computers via the OBD-II port with a microcontroller? Learn more...