LED Dawn / Sunrise Alarm Clock, Nightlight & Security Light - Arduino Compatible
by Ugifer in Circuits > Clocks
40306 Views, 123 Favorites, 0 Comments
LED Dawn / Sunrise Alarm Clock, Nightlight & Security Light - Arduino Compatible
As the nights gradually lengthened in autumn 2011, I discovered the joys of Arduino and thought that it would be a great way to implement something that I have wanted for a long while - a gentle way to wake up on a winter's morning. Sadly, it has taken me over a year to find the time and understanding to put it all together, but here, in time for some of the shortest days of this winter, are the results!
The idea is that getting up when it's pitch-black is a wrench. Equally, having a timed light that just switches on all of a sudden is a shock. What you want is a gentle ramp of light from imperceptibly dim to ragingly bright and ideally going from a nice gentle red to blazing white so that your brain thinks it's time to start that melatonin level rising. My solution is a full-function micro-controller, RTC alarm-clock with the following features, among others:
Arduino compatible ATMega328 controlled, open, hackable, reprogrammable.
Battery backed-up RTC
Brightness-controllable red LED display
Cool rotary encoder input
Up to 18W LED dawn light
8-channel PWM light control (2 x 3W RGB + 2 x 6 x 1W white)
Exponential brightness ramp on dawn light
7 independent dawn alarms stored permanently in EEPROM
Alarms setable for any day, for every day, for mon-fri or for sat-sun.
One-press "arm/disarm" with indicator (stored in battery-backed RTC RAM)
Each alarm has optional buzzer
Escalating buzzer tone
Snooze function on buzzer
Controllable "ramp" time (min to max brightness time)
Controllable "hold" time (time at max brightness)
Controllable "buzzer delay" (time between max brightness and buzzer)
Easily controlled "Night Light"
"Security Light" mode (mode stored in RTC battery-backed RAM so safe to blackouts etc).
A dawn clock aims to wake you up gently and you can buy them commercially, but they are expensive, generally just white, not very flexible, and just not much fun! We'll aim to make a full-feature dawn alarm clock and add a buzzer too, just to be sure we actually get to work on time! It's also something of a learning exercise for me so it has a whole bunch of different interface and control techniques for me (and perhaps you) to master along the way. There's about 6 separate projects in here and I'll try to put some example code in so that you can try them separately if you wish.
Although you could do this project perfectly well on a "real" Arduino, and indeed it was prototyped with a "nano" on a breadboard, I'm making the dedicated installation on a minimal Ardu' compatible so that you don't need to commit your "real" Ardu' to the clock. I have made this project both on bits of perf-board and on a dedicated PCB that I have designed & had fab'd. We'll look at both ways to do it - the result is much the same but the PCB is much less time consuming.
There are several discrete "sub-projects" that I've called "modules" in this project, any of which could be made and used individually:
The Arduino clone & RTC
The Digital time display
The Rotary encoder & switch controls with de-bounce.
The "Shift PWM" LED driver board
The lamps themselves & a trivial "buzzer" alarm.
Controlling an ATX power supply for efficient powering of the device
I've tried to make this instructable modular so just skip over any modules you can handle yourself already or use just one or two parts for your own project.
The idea is that getting up when it's pitch-black is a wrench. Equally, having a timed light that just switches on all of a sudden is a shock. What you want is a gentle ramp of light from imperceptibly dim to ragingly bright and ideally going from a nice gentle red to blazing white so that your brain thinks it's time to start that melatonin level rising. My solution is a full-function micro-controller, RTC alarm-clock with the following features, among others:
Arduino compatible ATMega328 controlled, open, hackable, reprogrammable.
Battery backed-up RTC
Brightness-controllable red LED display
Cool rotary encoder input
Up to 18W LED dawn light
8-channel PWM light control (2 x 3W RGB + 2 x 6 x 1W white)
Exponential brightness ramp on dawn light
7 independent dawn alarms stored permanently in EEPROM
Alarms setable for any day, for every day, for mon-fri or for sat-sun.
One-press "arm/disarm" with indicator (stored in battery-backed RTC RAM)
Each alarm has optional buzzer
Escalating buzzer tone
Snooze function on buzzer
Controllable "ramp" time (min to max brightness time)
Controllable "hold" time (time at max brightness)
Controllable "buzzer delay" (time between max brightness and buzzer)
Easily controlled "Night Light"
"Security Light" mode (mode stored in RTC battery-backed RAM so safe to blackouts etc).
A dawn clock aims to wake you up gently and you can buy them commercially, but they are expensive, generally just white, not very flexible, and just not much fun! We'll aim to make a full-feature dawn alarm clock and add a buzzer too, just to be sure we actually get to work on time! It's also something of a learning exercise for me so it has a whole bunch of different interface and control techniques for me (and perhaps you) to master along the way. There's about 6 separate projects in here and I'll try to put some example code in so that you can try them separately if you wish.
Although you could do this project perfectly well on a "real" Arduino, and indeed it was prototyped with a "nano" on a breadboard, I'm making the dedicated installation on a minimal Ardu' compatible so that you don't need to commit your "real" Ardu' to the clock. I have made this project both on bits of perf-board and on a dedicated PCB that I have designed & had fab'd. We'll look at both ways to do it - the result is much the same but the PCB is much less time consuming.
There are several discrete "sub-projects" that I've called "modules" in this project, any of which could be made and used individually:
The Arduino clone & RTC
The Digital time display
The Rotary encoder & switch controls with de-bounce.
The "Shift PWM" LED driver board
The lamps themselves & a trivial "buzzer" alarm.
Controlling an ATX power supply for efficient powering of the device
I've tried to make this instructable modular so just skip over any modules you can handle yourself already or use just one or two parts for your own project.
See It Working - Plus Some Shameless Groveling
This is the finished and functional clock in action - the alarm is set to come on at 14:40 (if I could get up at that time I wouldn't need this clock!) and I have set it to ramp up over 1 minute (normally you would use 10-30mins but it makes a rather dull video). You will see that every few seconds the lamp gets brighter. The ramp-up and colours aren't very good in the video but you get the idea. At the end of the ramp-up, the lamp stays on but the alarm sounds (you might normally have a delay but again, it makes a rather dull video). I press to snooze the alarm, and then again to cancel the light and reset.
Shameless Groveling:
I've entered this 'ible into the "Glow" contest so if you like it or any of its modules then please consider voting for it. I could have split it into a few entries but really it's more sensible all together and it's taken a year to get together. So if you like it, please....
Vote for me and help me get me some more fun stuff to make fun instructables with!
Cheers
Ugi
Shameless Groveling:
I've entered this 'ible into the "Glow" contest so if you like it or any of its modules then please consider voting for it. I could have split it into a few entries but really it's more sensible all together and it's taken a year to get together. So if you like it, please....
Vote for me and help me get me some more fun stuff to make fun instructables with!
Cheers
Ugi
Materials
This is the approx BoM for the clock I made. It's by no means optimised and many of the items are simply what I had to hand or could source easily from ebay. However, it does seem to work.
1 ATmega328 -DIP
1 16 MHz Crystal
1 Max7219 - DIP
1 74HC595 - DIP
8 AMC7135 - SMD 350mA
1 DS1307 - DIP
1 32.768 KHz watch crystal
2 IRF540N MOSFET*
6 BCU81 low voltage NPN
12 White 1 W LED on star
2 3W RGB LED on star
2 Heat Sink for 12W LED
1 4-digit red 7-seg display (12 pin, common cathode)
1 Rotary encoder & knob (5-pin with press-switch)
1 CR2032 3V Li Battery
1 Holder for CR2032
1 custom PCB or 4+ small perf boards
1 Heat sink glue
1 ATX power supply
1 ATX motherboard extension cable
3 Momentary/tactile switches
1 Tactile switch
1 5V Buzzer
18 100 nF ceramic capacitor
2 orange 3mm LEDS
2 green 3mm LEDs
1 red 5mm LED (flat top)
15 1K
9 10K
6 Male header pins x 7**
3 Male header pins x 6**
1 Male header pin x 3**
5 Male header pins x 2**
1 Male header pin x 1**
1 Strip of female header (useful but not essential)
1 x 40-way splittable F-F ribbon cable with individual F ends
1 Molex Socket (reclaimed or bought)
2 22 pF Ceramic cap
3 100uF Electrolytic Cap
1 470uF Electrolytic Cap
1 1000uF Electrolytic Cap
10 1N4001 (or simiar) rectifier diodes (1A, 0.8v forward voltage).
60-80cm (2-3 feet) 4-pair solid copper network cable or similar
Linkup wire (I tended to use wire from an old 3-pair telecom cable).
The relevant items are pictured by module - we'll come back to the BoM for each module as we go along.
Nearly everything was sourced from cheap Chinese suppliers on e-bay, either for this project or for others and left over. I didn't attempt to optimise it and I often bought more than I needed to have useful spares in my bits box. The last step has some additional info including what I paid. Some of the prices are more than a year old now, however. Your mileage may vary.
Tools:
Solder station
Solder
Heatshrink
Helping hands
Clippers
Pliers
File
Bench vice
Craft knife
Heat source for heatshrink (lighter)
USB to TTL converter (CP2102 based - less than £2 delivered from e-bay)
PC with Arduino IDE
Arduino for bootloading (unless your '328 is already bootloaded)
* This is massive over-kill for the current we are switching in this project but it was in-hand and I needed a low on-resistance because of the specific white LEDs I had bought.
** You may not want all of these header pins and you may want some straight and some 90' headers. Have a look at the later steps and see what they are all for.
1 ATmega328 -DIP
1 16 MHz Crystal
1 Max7219 - DIP
1 74HC595 - DIP
8 AMC7135 - SMD 350mA
1 DS1307 - DIP
1 32.768 KHz watch crystal
2 IRF540N MOSFET*
6 BCU81 low voltage NPN
12 White 1 W LED on star
2 3W RGB LED on star
2 Heat Sink for 12W LED
1 4-digit red 7-seg display (12 pin, common cathode)
1 Rotary encoder & knob (5-pin with press-switch)
1 CR2032 3V Li Battery
1 Holder for CR2032
1 custom PCB or 4+ small perf boards
1 Heat sink glue
1 ATX power supply
1 ATX motherboard extension cable
3 Momentary/tactile switches
1 Tactile switch
1 5V Buzzer
18 100 nF ceramic capacitor
2 orange 3mm LEDS
2 green 3mm LEDs
1 red 5mm LED (flat top)
15 1K
9 10K
6 Male header pins x 7**
3 Male header pins x 6**
1 Male header pin x 3**
5 Male header pins x 2**
1 Male header pin x 1**
1 Strip of female header (useful but not essential)
1 x 40-way splittable F-F ribbon cable with individual F ends
1 Molex Socket (reclaimed or bought)
2 22 pF Ceramic cap
3 100uF Electrolytic Cap
1 470uF Electrolytic Cap
1 1000uF Electrolytic Cap
10 1N4001 (or simiar) rectifier diodes (1A, 0.8v forward voltage).
60-80cm (2-3 feet) 4-pair solid copper network cable or similar
Linkup wire (I tended to use wire from an old 3-pair telecom cable).
The relevant items are pictured by module - we'll come back to the BoM for each module as we go along.
Nearly everything was sourced from cheap Chinese suppliers on e-bay, either for this project or for others and left over. I didn't attempt to optimise it and I often bought more than I needed to have useful spares in my bits box. The last step has some additional info including what I paid. Some of the prices are more than a year old now, however. Your mileage may vary.
Tools:
Solder station
Solder
Heatshrink
Helping hands
Clippers
Pliers
File
Bench vice
Craft knife
Heat source for heatshrink (lighter)
USB to TTL converter (CP2102 based - less than £2 delivered from e-bay)
PC with Arduino IDE
Arduino for bootloading (unless your '328 is already bootloaded)
* This is massive over-kill for the current we are switching in this project but it was in-hand and I needed a low on-resistance because of the specific white LEDs I had bought.
** You may not want all of these header pins and you may want some straight and some 90' headers. Have a look at the later steps and see what they are all for.
PCB - Layout & Preparation
Throughout this instructable I have described two ways in which you can construct this project - using hand-wiring on little perf-boards and also using a custom PCB. There are more photos of some of the PCB steps because the perf-board version was more or a prototype. This step describes designing the PCB. If you're not interested in that method then just skip this step.
The PCB Eagle files* (schematic and board) are attached to this step and if you have a reasonably priced way of having them fab'ed then I strongly recommend that approach. It takes a fraction of the time and the result is much neater. There were a few minor errors in the original PCBs that I had made up but those were easily sorted and are all corrected in the attached version. I am pretty sure this version is fully functional without any messing about.
The project is in several modules and so it should really have at least 4 separate PCBs. Unfortunately, that works out pretty expensive. As a result, I designed all four modules on a single 79 x 99 mm PCB. That is as large as you can design in the freeware version of Eagle and can be fab'ed for a reasonable price as one piece. It is designed to work as a single piece but where each section joins there are pairs of header pins so that the modules can be broken apart and re-joined with jumpers.
Note: The sub-boards are separated by lots of little holes. Not all fab' shops allow that - check before you buy.
I used sitopway.com, who fab'ed this board for $40 + $15 postage to UK. It came in about 10 days.
If you have the perforated PCB fab'ed then it will work as a single unit but you will probably prefer to separate it into four pieces and re-join them with jumper wires. I did this by placing the PCB in a vice at the break-point, scoring along the join (to cut the tracks that join the parts) with a craft knofe on both sides and just whacking it with the heel of my hand. It snaps cleanly without damaging the tracks.
As you see from the pictures, you first need to snap longways along the long perforation, then snap each part into two. That should give you:
A controller/RTC board (top left)
A clock display board (top right)
A switch & encoder board (bottom left)
An LED driver board (bottom right)
In the next few steps we'll populate each of these boards in turn, look at what they can do and test the functions of each.
* There were a few small errors in the version I had fab'ed - nothing that wasn't fixable. I have corrected these in the attached files and I think they are 100% correct. However, I have not tested the final version. Please check the files yourself before you pay to have them fab'ed!
The PCB Eagle files* (schematic and board) are attached to this step and if you have a reasonably priced way of having them fab'ed then I strongly recommend that approach. It takes a fraction of the time and the result is much neater. There were a few minor errors in the original PCBs that I had made up but those were easily sorted and are all corrected in the attached version. I am pretty sure this version is fully functional without any messing about.
The project is in several modules and so it should really have at least 4 separate PCBs. Unfortunately, that works out pretty expensive. As a result, I designed all four modules on a single 79 x 99 mm PCB. That is as large as you can design in the freeware version of Eagle and can be fab'ed for a reasonable price as one piece. It is designed to work as a single piece but where each section joins there are pairs of header pins so that the modules can be broken apart and re-joined with jumpers.
Note: The sub-boards are separated by lots of little holes. Not all fab' shops allow that - check before you buy.
I used sitopway.com, who fab'ed this board for $40 + $15 postage to UK. It came in about 10 days.
If you have the perforated PCB fab'ed then it will work as a single unit but you will probably prefer to separate it into four pieces and re-join them with jumper wires. I did this by placing the PCB in a vice at the break-point, scoring along the join (to cut the tracks that join the parts) with a craft knofe on both sides and just whacking it with the heel of my hand. It snaps cleanly without damaging the tracks.
As you see from the pictures, you first need to snap longways along the long perforation, then snap each part into two. That should give you:
A controller/RTC board (top left)
A clock display board (top right)
A switch & encoder board (bottom left)
An LED driver board (bottom right)
In the next few steps we'll populate each of these boards in turn, look at what they can do and test the functions of each.
* There were a few small errors in the version I had fab'ed - nothing that wasn't fixable. I have corrected these in the attached files and I think they are 100% correct. However, I have not tested the final version. Please check the files yourself before you pay to have them fab'ed!
Module 1 - the Arduino / RTC Module - Overview
The heart of this device is an Arduino compatible ATmega328. You could use a "genuine" Ardu' board and something like a prototyping shield for the RTC & connections but by making our own little board we can put all the pins we need together, include some of the pull-down resistors etc and put the 1307 RTC with its battery backup right next to the '328 on the same little PCB or perf-board. We don't need a regulator or a USB connection for this project so the part-count and cost is pretty low.
You could use this module or a variant of it for any time-based application. We break out nearly all of the useful pins to male headers and it can be re-programed by serial on the board. You will need a USB to TTL cable for programming the alarm-clock code or test code (or indeed for your own code). Mine is called "CP2102" based and was £4.75 for two including delivery (e-bay). They are even cheaper now.
To program by serial connection you need a '328 with the "Duemilanove" bootloader. You can buy these chips pre-programmed with the bootloader or use an ISP programmer. I used an existing Arduino as ISP with my new chip on a breadboard according to this tutorial:
http://arduino.cc/en/Tutorial/ArduinoToBreadboard
However, what that doesn't tell you is that you need to disable the auto-reset so look here:
http://www.arduino.cc/playground/Code/MegaISP
for the solution to that. I used a 100Ohm and 10 Ohm resistor in series from the reset pin to +5V. A 100uF capacitor between them works equally well.
If, like me, you get a '328-PU rather than a 328P (I didn't know the difference but apparently they have different power-saving modes) then you may find that the bootloader won't load because these two chips have a different device signature and the software that actually talks to the programmer (AVRdude) gets confused. The quickest fix for this is to find your avrdude.conf file and in the entry under ATmega328, edit the line:
signature = 0x1e 0x95 0x0F;
to read:
signature = 0x1e 0x95 0x14;
That makes AVRdude look for a '328-PU and all is well. Change the .conf file back after (once the bootloader is programmed). The bootloaded '328-PU will program from the IDE by serial with no problem and behaves exactly like a normal Arduino.
The ATMega328 Datasheet is at: http://www.atmel.com/Images/doc8161.pdf just in case you need 448 pages of light reading!
You will also see that I have rather gone to town on the capacitors on this board (and indeed this project). Perhaps because of the heavy PWM of several amps of LEDs, I was finding this clock was a bit unstable and would sometimes stall. Also the display went a bit mad occasionally. I have therefore taken the approach of adding a 100nf to each power connection of each chip, a 100uF on each board and a massive 470-1000uF on the Ardu' board and driver board. It's probably over-kill but it seems to work. Use your judgment as to what to leave out if you have a better understanding of these things than me.
As a final note, I have included female headers to take temporary LEDs on the power line and on pin 13. We are using pin 13 for communication and I didn't really want it flickering away all night. With a header I can pug in the LED when I want to test something and then take it out again after. If you want a permanent LED on pin 13 just solder it in place of the female headers.
BoM for Module 1:
1 PCB or Perf Board (X by Y holes)
1 28-pin DIN socket (optional but advisable)
1 bootloaded ATmega 328
1 16MHz crystal
2 22 pf ceramic capacitors
1 1307 RTC**
1 32.768 KHz, 12.5 pF watch crystal
1 2032 battery holder
1 2032 3V lithium battery (not pictured)
1 tactile switch (6x6 mm)
3 100 nf ceramic capacitors
3 10K resistors*
2 1K resistors
1 orange 3mm LED
1 green 3mm LED
optional - 2 x 2pin female header.
1 1000 uf electrolytic cap (not pictured)
2 x 7 pin male header (straight or 90')
2 x 6 pin male header (straight or 90')
1 x 2 pin straight male header
link-up wire if using perf-board (I used some old 3-pair phone cable). I will assume this in all further modules.
*according to the datasheet,** the RTC should probably have 2.5K pullups but 10K seems to work fine.
** http://www.sparkfun.com/datasheets/Components/DS1307.pdf
You could use this module or a variant of it for any time-based application. We break out nearly all of the useful pins to male headers and it can be re-programed by serial on the board. You will need a USB to TTL cable for programming the alarm-clock code or test code (or indeed for your own code). Mine is called "CP2102" based and was £4.75 for two including delivery (e-bay). They are even cheaper now.
To program by serial connection you need a '328 with the "Duemilanove" bootloader. You can buy these chips pre-programmed with the bootloader or use an ISP programmer. I used an existing Arduino as ISP with my new chip on a breadboard according to this tutorial:
http://arduino.cc/en/Tutorial/ArduinoToBreadboard
However, what that doesn't tell you is that you need to disable the auto-reset so look here:
http://www.arduino.cc/playground/Code/MegaISP
for the solution to that. I used a 100Ohm and 10 Ohm resistor in series from the reset pin to +5V. A 100uF capacitor between them works equally well.
If, like me, you get a '328-PU rather than a 328P (I didn't know the difference but apparently they have different power-saving modes) then you may find that the bootloader won't load because these two chips have a different device signature and the software that actually talks to the programmer (AVRdude) gets confused. The quickest fix for this is to find your avrdude.conf file and in the entry under ATmega328, edit the line:
signature = 0x1e 0x95 0x0F;
to read:
signature = 0x1e 0x95 0x14;
That makes AVRdude look for a '328-PU and all is well. Change the .conf file back after (once the bootloader is programmed). The bootloaded '328-PU will program from the IDE by serial with no problem and behaves exactly like a normal Arduino.
The ATMega328 Datasheet is at: http://www.atmel.com/Images/doc8161.pdf just in case you need 448 pages of light reading!
You will also see that I have rather gone to town on the capacitors on this board (and indeed this project). Perhaps because of the heavy PWM of several amps of LEDs, I was finding this clock was a bit unstable and would sometimes stall. Also the display went a bit mad occasionally. I have therefore taken the approach of adding a 100nf to each power connection of each chip, a 100uF on each board and a massive 470-1000uF on the Ardu' board and driver board. It's probably over-kill but it seems to work. Use your judgment as to what to leave out if you have a better understanding of these things than me.
As a final note, I have included female headers to take temporary LEDs on the power line and on pin 13. We are using pin 13 for communication and I didn't really want it flickering away all night. With a header I can pug in the LED when I want to test something and then take it out again after. If you want a permanent LED on pin 13 just solder it in place of the female headers.
BoM for Module 1:
1 PCB or Perf Board (X by Y holes)
1 28-pin DIN socket (optional but advisable)
1 bootloaded ATmega 328
1 16MHz crystal
2 22 pf ceramic capacitors
1 1307 RTC**
1 32.768 KHz, 12.5 pF watch crystal
1 2032 battery holder
1 2032 3V lithium battery (not pictured)
1 tactile switch (6x6 mm)
3 100 nf ceramic capacitors
3 10K resistors*
2 1K resistors
1 orange 3mm LED
1 green 3mm LED
optional - 2 x 2pin female header.
1 1000 uf electrolytic cap (not pictured)
2 x 7 pin male header (straight or 90')
2 x 6 pin male header (straight or 90')
1 x 2 pin straight male header
link-up wire if using perf-board (I used some old 3-pair phone cable). I will assume this in all further modules.
*according to the datasheet,** the RTC should probably have 2.5K pullups but 10K seems to work fine.
** http://www.sparkfun.com/datasheets/Components/DS1307.pdf
Module 1 - Arduino / RTC Module - Wiring
The first picture here is a schematic for this module. I drew that before I got the hang of any "proper" schematic drawing tools so it may not be very polished but I actually think you can see what's connected to what comparatively well. I have laid the schematic out in a similar pattern to the board so it should be fairly clear how that translates to the actual soldering work.
The Eagle schematic is the second picture. If it's too small to read you should be able to download it at the original resolution. Alternatively, the Schematic and Board files are attached.
The third picture shows the Arduino, RTC, Display and input modules all on a breadboard based around an Arduino nano. It's possible, but pretty messy!
For the PCB version:
In general it's easier to start soldering from the middle outwards. However, you need to do some of the top side components before the battery-holder because it covers the solder pads for many of these. Some of this is a little fiddly so it might not make the best first-project but nothing on this module is terribly difficult. As always, put the components through their holes, bend leads or pins out a little to hold them, turn the board over, solder and clip off.
My order was:
R6 (1K), 2-pin header for A2/A3, 1-pin header for reset.
Reset tactile switch, 10K pullup resistor on reset and neighbouring 100nf capacitors.
28-pin DIP (try to get the notch the right way around)
DS1307 RTC chip
Battery holder on the back
Crystals and 22pf caps
R2/R3 10K pullups for I2C communication (notionally these should be 2.5k)
Two x 2-pin female headers for power & D13 LEDs, plus other 1k resistor
Final 100nf cap, and remaining male headers all the way around.
1000uf cap under the board,
Cut down some 3mm LEDs to go in the female headers
Insert the bootloaded '328 (get the notch at the right end)
Add the RTC battery to the holder & off you go!
For Perf-board version:
My approach was:
1 - lay out the key components leaving some space for the large extras like the battery holder and that massive 1000 uf capacitor. The RTC uses pins 27 and 28 of the '328 so I put it up in that corner (you'll see it's upside down in comparison with the '328).
2 - solder down all of the major parts including the chips and header pins. Include as many of the key capacitors etc. as close to the chips as we can. The watch crystal I put in the same holes as pins 1 & 2 of the '1307.
3 - run the ground (blue) and power (orange) connections as far as possible. A few of these join under the board but most are visible from the top.
4 - run the signal wires (green).
5 - put in the massive 1000uf cap and the battery holder.
6 - put in the power and pin-13 LEDs with their resistors.
7 - trace the various connections and find all the things you missed (I forgot the pull-ups on the 1307). Solder these in!
8 - take a meter to your board and check no two pins of either chip are shorted. Pins 20/21 of the '328 are the only two that should be.
9 - power it up and if you have a newly bootloaded '328 then you should see the pin-13 LED flashing.
Amazingly, my board ran first time. Hopefully yours will too. Once you have the blink code running, put in the battery for the RTC and run the code to see if it's keeping time. Sketch for that is in the next step.
The Eagle schematic is the second picture. If it's too small to read you should be able to download it at the original resolution. Alternatively, the Schematic and Board files are attached.
The third picture shows the Arduino, RTC, Display and input modules all on a breadboard based around an Arduino nano. It's possible, but pretty messy!
For the PCB version:
In general it's easier to start soldering from the middle outwards. However, you need to do some of the top side components before the battery-holder because it covers the solder pads for many of these. Some of this is a little fiddly so it might not make the best first-project but nothing on this module is terribly difficult. As always, put the components through their holes, bend leads or pins out a little to hold them, turn the board over, solder and clip off.
My order was:
R6 (1K), 2-pin header for A2/A3, 1-pin header for reset.
Reset tactile switch, 10K pullup resistor on reset and neighbouring 100nf capacitors.
28-pin DIP (try to get the notch the right way around)
DS1307 RTC chip
Battery holder on the back
Crystals and 22pf caps
R2/R3 10K pullups for I2C communication (notionally these should be 2.5k)
Two x 2-pin female headers for power & D13 LEDs, plus other 1k resistor
Final 100nf cap, and remaining male headers all the way around.
1000uf cap under the board,
Cut down some 3mm LEDs to go in the female headers
Insert the bootloaded '328 (get the notch at the right end)
Add the RTC battery to the holder & off you go!
For Perf-board version:
My approach was:
1 - lay out the key components leaving some space for the large extras like the battery holder and that massive 1000 uf capacitor. The RTC uses pins 27 and 28 of the '328 so I put it up in that corner (you'll see it's upside down in comparison with the '328).
2 - solder down all of the major parts including the chips and header pins. Include as many of the key capacitors etc. as close to the chips as we can. The watch crystal I put in the same holes as pins 1 & 2 of the '1307.
3 - run the ground (blue) and power (orange) connections as far as possible. A few of these join under the board but most are visible from the top.
4 - run the signal wires (green).
5 - put in the massive 1000uf cap and the battery holder.
6 - put in the power and pin-13 LEDs with their resistors.
7 - trace the various connections and find all the things you missed (I forgot the pull-ups on the 1307). Solder these in!
8 - take a meter to your board and check no two pins of either chip are shorted. Pins 20/21 of the '328 are the only two that should be.
9 - power it up and if you have a newly bootloaded '328 then you should see the pin-13 LED flashing.
Amazingly, my board ran first time. Hopefully yours will too. Once you have the blink code running, put in the battery for the RTC and run the code to see if it's keeping time. Sketch for that is in the next step.
Module1 - Arduino/RTC - Test Code
To see if we are communicating with our '328 and '1307, we can use the attached code. This sets the time by serial input into the serial window that came with the Arduino IDE.
Please be aware that all of the code for this project was written in Arduino 0022. I have not tried 1.0 as yet.
I have not been able to upload any code as .pde files. I don't know why.
I have re-named them as .txt which you can open in WordPad and copy/paste into the IDE or you can rename them .pde when you have downloaded them.
UPLOADING:
This little Ardu' doesn't have a fancy auto-reset circuit. As a result, we need to press the reset switch at the correct moment. I have seen a number of ways suggested for timing this, but this one works well for me:
1) - connect the Tx and Rx pins from your USB converter to the headers on pins 2 and 3 of the chip (D0 and D1).
2) - power your board (from the USB if possible - if not make sure the earth connections are joined but the +5V are not!).
3) - make sure you select "Duemilanove/Tiny with '328" as your target board.
4) - click the upload button in the IDE.
5) - while your code compiles, watch the status line at the bottom of the IDE window.
6) - as soon as the little window at the bottom of the IDE tells you the size of your compiled sketch, press reset.
7) - the Tx/Rx lights on your USB converter should flash for a while.
If for whatever reason it doesn't work first time, it will time out after about 30 secs and you can try again. It's very rare for it to take more than two attempts.
The attached code will initially set the time and then display the time in the Serial Monitor window of the IDE. In the "setup" routine you can send it an "R" character for re-set of the time, so you can re-set the clock each time you reset your '328.
It will then ask you for progressively less significant aspects of the date and time and finally display the new settings for you to confirm. It's not very sophisticated, so please remember:
At every numeric input it requires two decimal digits, so for day 2 (Tuesday) enter "02" into the serial monitor.
When confirmation etc is requested, this is case specific, so to set the clock, only a "Y" will do as the final response.
Once the time is set or you "Q" out of teh setting routine then it will display the time from the RTC onto the serial monitor every second.
Obviously, once the RTC is set its battery will keep it running even when you power-down your ardu' so you can now run your own sketch and just whip a few functions from this sketch to get the time when you need it. For the finished clock we will set the time direct from the Ardu' but we need some inputs and a display for that! Time to move on to another module....
****************
// Ugi's Dawn-Light Alarm Clock Sketch.
// RTC Test Sketch
// MIT Licence
// Ugi Dec 2012
// Written for Arduino 022 running on ATmega328.
// requires Wire library
// Arduino Pin connections:
// A4 - 1307 (I2C data)
// A5 - 1307 (I2C clock)
// General clock settings:
#include <Wire.h> - // usees analogue pins A4 (SDA - pin 27) & A5 (SCL- pin 28) for 2-wire data.
const byte DS1307_Address = 0x68;
byte seconds = 45, oldseconds=0, minutes=52, hours=23, date=8, month=12, day=4, year=11, protect = 0; // defaults just to start somewhere.
byte NEWseconds = 45, NEWminutes=52, NEWhours=23, NEWdate=8, NEWmonth=12, NEWday=4, NEWyear=11 ; // These are for setting.
void setup(){
Serial.begin(9600); Serial.println(" DS1307 RTC based clock - Ugi 2012");
delay(2000); // Give RTC some time to settle.
Wire.begin(); // Need for RTC
RTCsetFromSerial(); //Chance to set time from serial each reset. Could allow for a timeout.
}
void loop() {
RTCread();
RTCprintTime(); // sends time to serial.
delay(1000);
} // End main loop
// Read time from RTC into time variables.
void RTCread(){
byte data[11]={0,0,0,0,0,0,0,0,0,0,0};
Wire.beginTransmission(DS1307_Address);
Wire.send(0); // set register to beginning
Wire.endTransmission();
Wire.requestFrom(DS1307_Address, (byte)10); // request 7 bytes from RTC into buffer.
for (byte _loop=0; _loop<10; _loop++){
data[_loop]=(Wire.receive());
}
seconds = (((data[0] & B01110000)>>4)*10)+(data[0] & B00001111);
minutes = (((data[1] & B01110000)>>4)*10)+(data[1] & B00001111);
hours = (((data[2] & B00110000)>>4)*10)+(data[2] & B00001111);
day = (data[3] & B00000111);
date = (((data[4] & B00110000)>>4)*10)+(data[4] & B00001111);
month = (((data[5] & B00010000)>>4)*10)+(data[5] & B00001111);
year = (((data[6] & B11110000)>>4)*10)+(data[6] & B00001111);
}
// Write current time to RTC
void RTCwrite(){ // writes all current data to RTC - if you only want to write one parameter then just read the clock first!
byte data[7];
data[0] = (seconds % 10) + ((seconds/10)<<4);
data[1] = (minutes % 10) + ((minutes/10)<<4);
data[2] = (hours % 10) + ((hours/10)<<4);
data[3] = day;
data[4] = (date % 10) + ((date/10)<<4);
data[5] = (month % 10)+ ((month/10)<<4);
data[6] = (year % 10) + ((year/10)<<4);
Wire.beginTransmission(DS1307_Address);
Wire.send(0); // set register to beginning
for (byte _loop=0; _loop<7; _loop++){
Wire.send(data[_loop]);
}
Wire.endTransmission();
oldseconds=seconds;
} // End RTC Write function
// Print current time to Serial...
void RTCprintTime(){
RTCread();
Serial.print("Time = "); Serial.print(hours, DEC); Serial.print(":");Serial.print(minutes, DEC);Serial.print(":"); Serial.println(seconds, DEC);
Serial.print("Date = "); Serial.print(date, DEC); Serial.print("/");Serial.print(month, DEC);Serial.print("/20"); Serial.print(year, DEC);
}
byte RTCgetSerial(byte _val, String _Str){
Serial.println(" ");
Serial.println(" *** "+_Str+" ***");
Serial.print("Current value = "); Serial.print(_val, DEC); Serial.println(" "+_Str);
Serial.println("Enter new value (two digits e.g. '01'): ");
Serial.flush();
byte NEW_val = -1;
while (Serial.available() < 2){
delay(50);}
NEW_val = ((Serial.read()-48)*10);
NEW_val = NEW_val + (Serial.read()-48);
Serial.flush();
Serial.print("New value = "); Serial.print(NEW_val, DEC); Serial.println(" "+_Str);Serial.println(" ");
if (NEW_val >=0){return NEW_val;}
else {return _val;}
}
boolean RTCconfirm(){
Serial.println(" ");
Serial.println("Currently:");
RTCprintTime();
Serial.flush();
Serial.println(" ");
Serial.println("Change to? (Y/N):");
Serial.print("time = "); Serial.print(NEWhours, DEC); Serial.print(":");Serial.print(NEWminutes, DEC);Serial.print(":"); Serial.println(NEWseconds, DEC);
Serial.print("date = "); Serial.print(NEWdate, DEC); Serial.print("/");Serial.print(NEWmonth, DEC);Serial.print("/20");Serial.print(NEWyear, DEC);
char _conf = -1;
while (Serial.available()<1){
delay(50);}
_conf = Serial.read();
Serial.flush();
Serial.print("confirm digit = "); Serial.println(_conf);
if(_conf=='Y'){return true;}
else{return false; }
}
boolean RTCsetFromSerial(){
// Get new time setting from serial port
Serial.flush(); // avoid any random data in buffer.
// See if we want to update
char _input = 'X';
while (_input != 'R' && _input !='Q'){
while (Serial.available()<1){
RTCprintTime(); // We'll keep displaying current time and see whether it needs updating.
Serial.println("Enter 'R' by serial input to re-set or Q to quit setting routine");
Serial.println(" ");
delay(1000);
}
_input = Serial.read();
Serial.flush();
}
// if(_input != 'R'){Serial.println(" "); Serial.println(" *** QUITTING ***"); Serial.println(" "); return false;}
Serial.println(" ");
Serial.println(" *** RESETTING RTC ***");
Serial.println(" ");
RTCprintTime();
NEWyear = RTCgetSerial(year, "years");
RTCprintTime();
NEWday = RTCgetSerial(day, "day of the week");
RTCprintTime();
NEWmonth = RTCgetSerial(month, "months");
RTCprintTime();
NEWdate = RTCgetSerial(date, "days of the month");
RTCprintTime();
NEWhours = RTCgetSerial(hours, "Hours");
RTCprintTime();
NEWminutes = RTCgetSerial(minutes, "Minutes");
RTCprintTime();
NEWseconds = RTCgetSerial(seconds, "Seconds");
if (RTCconfirm()){
seconds = NEWseconds;
minutes = NEWminutes;
hours = NEWhours;
date = NEWdate;
month = NEWmonth;
day = NEWday;
year = NEWyear;
RTCwrite();
Serial.println (" ");
Serial.println (" *** RTC Updated ***");
return true;
}
else {
Serial.println (" *** Update cancelled ***");
}
return false;
}
Please be aware that all of the code for this project was written in Arduino 0022. I have not tried 1.0 as yet.
I have not been able to upload any code as .pde files. I don't know why.
I have re-named them as .txt which you can open in WordPad and copy/paste into the IDE or you can rename them .pde when you have downloaded them.
UPLOADING:
This little Ardu' doesn't have a fancy auto-reset circuit. As a result, we need to press the reset switch at the correct moment. I have seen a number of ways suggested for timing this, but this one works well for me:
1) - connect the Tx and Rx pins from your USB converter to the headers on pins 2 and 3 of the chip (D0 and D1).
2) - power your board (from the USB if possible - if not make sure the earth connections are joined but the +5V are not!).
3) - make sure you select "Duemilanove/Tiny with '328" as your target board.
4) - click the upload button in the IDE.
5) - while your code compiles, watch the status line at the bottom of the IDE window.
6) - as soon as the little window at the bottom of the IDE tells you the size of your compiled sketch, press reset.
7) - the Tx/Rx lights on your USB converter should flash for a while.
If for whatever reason it doesn't work first time, it will time out after about 30 secs and you can try again. It's very rare for it to take more than two attempts.
The attached code will initially set the time and then display the time in the Serial Monitor window of the IDE. In the "setup" routine you can send it an "R" character for re-set of the time, so you can re-set the clock each time you reset your '328.
It will then ask you for progressively less significant aspects of the date and time and finally display the new settings for you to confirm. It's not very sophisticated, so please remember:
At every numeric input it requires two decimal digits, so for day 2 (Tuesday) enter "02" into the serial monitor.
When confirmation etc is requested, this is case specific, so to set the clock, only a "Y" will do as the final response.
Once the time is set or you "Q" out of teh setting routine then it will display the time from the RTC onto the serial monitor every second.
Obviously, once the RTC is set its battery will keep it running even when you power-down your ardu' so you can now run your own sketch and just whip a few functions from this sketch to get the time when you need it. For the finished clock we will set the time direct from the Ardu' but we need some inputs and a display for that! Time to move on to another module....
****************
// Ugi's Dawn-Light Alarm Clock Sketch.
// RTC Test Sketch
// MIT Licence
// Ugi Dec 2012
// Written for Arduino 022 running on ATmega328.
// requires Wire library
// Arduino Pin connections:
// A4 - 1307 (I2C data)
// A5 - 1307 (I2C clock)
// General clock settings:
#include <Wire.h> - // usees analogue pins A4 (SDA - pin 27) & A5 (SCL- pin 28) for 2-wire data.
const byte DS1307_Address = 0x68;
byte seconds = 45, oldseconds=0, minutes=52, hours=23, date=8, month=12, day=4, year=11, protect = 0; // defaults just to start somewhere.
byte NEWseconds = 45, NEWminutes=52, NEWhours=23, NEWdate=8, NEWmonth=12, NEWday=4, NEWyear=11 ; // These are for setting.
void setup(){
Serial.begin(9600); Serial.println(" DS1307 RTC based clock - Ugi 2012");
delay(2000); // Give RTC some time to settle.
Wire.begin(); // Need for RTC
RTCsetFromSerial(); //Chance to set time from serial each reset. Could allow for a timeout.
}
void loop() {
RTCread();
RTCprintTime(); // sends time to serial.
delay(1000);
} // End main loop
// Read time from RTC into time variables.
void RTCread(){
byte data[11]={0,0,0,0,0,0,0,0,0,0,0};
Wire.beginTransmission(DS1307_Address);
Wire.send(0); // set register to beginning
Wire.endTransmission();
Wire.requestFrom(DS1307_Address, (byte)10); // request 7 bytes from RTC into buffer.
for (byte _loop=0; _loop<10; _loop++){
data[_loop]=(Wire.receive());
}
seconds = (((data[0] & B01110000)>>4)*10)+(data[0] & B00001111);
minutes = (((data[1] & B01110000)>>4)*10)+(data[1] & B00001111);
hours = (((data[2] & B00110000)>>4)*10)+(data[2] & B00001111);
day = (data[3] & B00000111);
date = (((data[4] & B00110000)>>4)*10)+(data[4] & B00001111);
month = (((data[5] & B00010000)>>4)*10)+(data[5] & B00001111);
year = (((data[6] & B11110000)>>4)*10)+(data[6] & B00001111);
}
// Write current time to RTC
void RTCwrite(){ // writes all current data to RTC - if you only want to write one parameter then just read the clock first!
byte data[7];
data[0] = (seconds % 10) + ((seconds/10)<<4);
data[1] = (minutes % 10) + ((minutes/10)<<4);
data[2] = (hours % 10) + ((hours/10)<<4);
data[3] = day;
data[4] = (date % 10) + ((date/10)<<4);
data[5] = (month % 10)+ ((month/10)<<4);
data[6] = (year % 10) + ((year/10)<<4);
Wire.beginTransmission(DS1307_Address);
Wire.send(0); // set register to beginning
for (byte _loop=0; _loop<7; _loop++){
Wire.send(data[_loop]);
}
Wire.endTransmission();
oldseconds=seconds;
} // End RTC Write function
// Print current time to Serial...
void RTCprintTime(){
RTCread();
Serial.print("Time = "); Serial.print(hours, DEC); Serial.print(":");Serial.print(minutes, DEC);Serial.print(":"); Serial.println(seconds, DEC);
Serial.print("Date = "); Serial.print(date, DEC); Serial.print("/");Serial.print(month, DEC);Serial.print("/20"); Serial.print(year, DEC);
}
byte RTCgetSerial(byte _val, String _Str){
Serial.println(" ");
Serial.println(" *** "+_Str+" ***");
Serial.print("Current value = "); Serial.print(_val, DEC); Serial.println(" "+_Str);
Serial.println("Enter new value (two digits e.g. '01'): ");
Serial.flush();
byte NEW_val = -1;
while (Serial.available() < 2){
delay(50);}
NEW_val = ((Serial.read()-48)*10);
NEW_val = NEW_val + (Serial.read()-48);
Serial.flush();
Serial.print("New value = "); Serial.print(NEW_val, DEC); Serial.println(" "+_Str);Serial.println(" ");
if (NEW_val >=0){return NEW_val;}
else {return _val;}
}
boolean RTCconfirm(){
Serial.println(" ");
Serial.println("Currently:");
RTCprintTime();
Serial.flush();
Serial.println(" ");
Serial.println("Change to? (Y/N):");
Serial.print("time = "); Serial.print(NEWhours, DEC); Serial.print(":");Serial.print(NEWminutes, DEC);Serial.print(":"); Serial.println(NEWseconds, DEC);
Serial.print("date = "); Serial.print(NEWdate, DEC); Serial.print("/");Serial.print(NEWmonth, DEC);Serial.print("/20");Serial.print(NEWyear, DEC);
char _conf = -1;
while (Serial.available()<1){
delay(50);}
_conf = Serial.read();
Serial.flush();
Serial.print("confirm digit = "); Serial.println(_conf);
if(_conf=='Y'){return true;}
else{return false; }
}
boolean RTCsetFromSerial(){
// Get new time setting from serial port
Serial.flush(); // avoid any random data in buffer.
// See if we want to update
char _input = 'X';
while (_input != 'R' && _input !='Q'){
while (Serial.available()<1){
RTCprintTime(); // We'll keep displaying current time and see whether it needs updating.
Serial.println("Enter 'R' by serial input to re-set or Q to quit setting routine");
Serial.println(" ");
delay(1000);
}
_input = Serial.read();
Serial.flush();
}
// if(_input != 'R'){Serial.println(" "); Serial.println(" *** QUITTING ***"); Serial.println(" "); return false;}
Serial.println(" ");
Serial.println(" *** RESETTING RTC ***");
Serial.println(" ");
RTCprintTime();
NEWyear = RTCgetSerial(year, "years");
RTCprintTime();
NEWday = RTCgetSerial(day, "day of the week");
RTCprintTime();
NEWmonth = RTCgetSerial(month, "months");
RTCprintTime();
NEWdate = RTCgetSerial(date, "days of the month");
RTCprintTime();
NEWhours = RTCgetSerial(hours, "Hours");
RTCprintTime();
NEWminutes = RTCgetSerial(minutes, "Minutes");
RTCprintTime();
NEWseconds = RTCgetSerial(seconds, "Seconds");
if (RTCconfirm()){
seconds = NEWseconds;
minutes = NEWminutes;
hours = NEWhours;
date = NEWdate;
month = NEWmonth;
day = NEWday;
year = NEWyear;
RTCwrite();
Serial.println (" ");
Serial.println (" *** RTC Updated ***");
return true;
}
else {
Serial.println (" *** Update cancelled ***");
}
return false;
}
Downloads
Module 2 - 4-digit Display - Overview
If this is a clock, it needs to show us the time! Preferably it should do so in the dark.
To do this, I have used a cheap red (good at night) 4-digit, 7-segment LED display bought off e-bay. This has only 12 pins: 8 common anodes, one for each segment of the display, and four common cathodes, one for each digit. Obviously, you could use four separate common-cathode digits if you preferred but you would need to wire all the segment anodes together.
The colon separator is the only "segment" which lights on the eighth anode. It is associated with digit 2 (counting L to R) and uses the digit 2 cathode. No LEDs light with anode 8 and any other cathode. We also want an indication of whether the alarm is "armed" so I have put a simple red/orange LED between the anode for the colon separator and the cathode for digit 4. We could add another two indicator lights easily if we wished to on the other digits. If you make a clock that reads am/pm (mine is 24-hour clock only) then you might want a "pm" indicator, for example. Some other 4-digit LEDs may well use the decimal places on the other digits.
Because the anodes are common to each segment and the cathodes to each digit, we can address each segment individually but only one digit at a time. We could drive this directly but it would take 12 pins and we can't spare that many! That's where a dedicated driver chip comes in, and I have used the amazingly cheap-as-chips Maxim 7219. This can drive up to 8 digits by scanning each digit in turn so fast that they all appear lit to the human eye. It also has software control of the brightness, which is a nice bonus and is constant-current allowing us to avoid using a whole battery of resistors.
The '7219 communicates by a standard "shift register" type serial protocol using clock, latch and data lines - that's only 3 pins rather than 12. And if 8 digits is not enough for you then you can daisy-chain as many as you need. Four digits is plenty for us, although if you wanted to add a display of seconds too, you could do that from the same chip.
The '7219 takes a resistor between pin X and +5V to set the maximum current. A 10K gives you around 40mA which although too much for constant driving of a typical LED should be fine since we are only scanning each segment a fraction of the time (1 pass in 4 since we are driving 4 digts ). For the particular display I had, this was still crazy-bright and I have used it on the lowest software setting for a bedroom. You could put a 10K-50K trim-pot in series with the fixed 10K in order to set the brightness range in hardware then pick a specific brightness level from software.
To do this, I have used a cheap red (good at night) 4-digit, 7-segment LED display bought off e-bay. This has only 12 pins: 8 common anodes, one for each segment of the display, and four common cathodes, one for each digit. Obviously, you could use four separate common-cathode digits if you preferred but you would need to wire all the segment anodes together.
The colon separator is the only "segment" which lights on the eighth anode. It is associated with digit 2 (counting L to R) and uses the digit 2 cathode. No LEDs light with anode 8 and any other cathode. We also want an indication of whether the alarm is "armed" so I have put a simple red/orange LED between the anode for the colon separator and the cathode for digit 4. We could add another two indicator lights easily if we wished to on the other digits. If you make a clock that reads am/pm (mine is 24-hour clock only) then you might want a "pm" indicator, for example. Some other 4-digit LEDs may well use the decimal places on the other digits.
Because the anodes are common to each segment and the cathodes to each digit, we can address each segment individually but only one digit at a time. We could drive this directly but it would take 12 pins and we can't spare that many! That's where a dedicated driver chip comes in, and I have used the amazingly cheap-as-chips Maxim 7219. This can drive up to 8 digits by scanning each digit in turn so fast that they all appear lit to the human eye. It also has software control of the brightness, which is a nice bonus and is constant-current allowing us to avoid using a whole battery of resistors.
The '7219 communicates by a standard "shift register" type serial protocol using clock, latch and data lines - that's only 3 pins rather than 12. And if 8 digits is not enough for you then you can daisy-chain as many as you need. Four digits is plenty for us, although if you wanted to add a display of seconds too, you could do that from the same chip.
The '7219 takes a resistor between pin X and +5V to set the maximum current. A 10K gives you around 40mA which although too much for constant driving of a typical LED should be fine since we are only scanning each segment a fraction of the time (1 pass in 4 since we are driving 4 digts ). For the particular display I had, this was still crazy-bright and I have used it on the lowest software setting for a bedroom. You could put a 10K-50K trim-pot in series with the fixed 10K in order to set the brightness range in hardware then pick a specific brightness level from software.
Module 2 - 4-digit Display - Wiring
The BoM for this module is:
1 4-digit 7-segment red LED display with colon separator (common cathode)
1 Maxim 7219 LED digit driver
1 10K resistor
1 flat-top red LED
1 5v piezoelectric buzzer
2 100nf ceramic capacitors
1 100uf electrolytic capacitor
1 6-pin male header (90' advisable)
1 2-pin male header (90' advisable)
PCB:
The most difficult part of this module is simply getting the rather long and flexible pins of the LED display through their holes. You also need to do the pin headers before the buzzer since that mounts on the back, overlapping their solder pads. There is an optional 2-pin header if you want to mount the buzzer off the board. I soldered on everything but you don't really need the header and the buzer. I did the following:
LED display
10K resistor
7219 chip (check for the notch).
ceramic caps
LED
6-pin header (front or back)
electrolytic cap (on the back)
2-pin header (front or back)
buzzer (on the back)
Depending on how you intend to mount this module, you may want to use 90' headers or put the headers on the back. If you do that then the highest thing on the front will be the LED display so that can go right against the top of your box/case. That's one of the reasons the buzzer and big cap are also on the back.
Perfboard:
I didn't take very detailed pictures of the perf-board assembly, but it basically involved soldering the display and the chip each one row from the edge and then wiring appropriate pins together - see the schematic.
1 4-digit 7-segment red LED display with colon separator (common cathode)
1 Maxim 7219 LED digit driver
1 10K resistor
1 flat-top red LED
1 5v piezoelectric buzzer
2 100nf ceramic capacitors
1 100uf electrolytic capacitor
1 6-pin male header (90' advisable)
1 2-pin male header (90' advisable)
PCB:
The most difficult part of this module is simply getting the rather long and flexible pins of the LED display through their holes. You also need to do the pin headers before the buzzer since that mounts on the back, overlapping their solder pads. There is an optional 2-pin header if you want to mount the buzzer off the board. I soldered on everything but you don't really need the header and the buzer. I did the following:
LED display
10K resistor
7219 chip (check for the notch).
ceramic caps
LED
6-pin header (front or back)
electrolytic cap (on the back)
2-pin header (front or back)
buzzer (on the back)
Depending on how you intend to mount this module, you may want to use 90' headers or put the headers on the back. If you do that then the highest thing on the front will be the LED display so that can go right against the top of your box/case. That's one of the reasons the buzzer and big cap are also on the back.
Perfboard:
I didn't take very detailed pictures of the perf-board assembly, but it basically involved soldering the display and the chip each one row from the edge and then wiring appropriate pins together - see the schematic.
Module 2 - 4-Digit Display - Test Code
The sketch attached to this step extends the clock routine from a few steps earlier so that it displays the time on the 4-digit LED module.
Again, the sketch is attached as a .txt file - open in Worpad and paste into the IDE, or rename as .pde and open directly.
Burn the sketch to the '328 using the method from step 6. It sets the clock from serial in the "setup" part and then displays the time on the 4-digit display. You can take the "RTCsetFromSerial()" line out of the sketch once the time is set (remember the battery backup will maintain it).
Now connect the controller and display modules with a 6-way cable (I used 6 conductors stripped from a 40-way F-F jumper set - see step 19) and power it up from a 5V supply (the USB to TTL converter works fine but 3 x AA batteries would be good too).
You now have an autonomous clock - you need the serial interface to set the time and date but the RTC chip will hold the time for years on the backup battery and the time is displayed on the LED display. You could even set the code to have an alarm and use the buzzer but unfortunately there is no way to turn it off once you are awake because you have no inputs yet!
OK then - time for some inputs. On to the next module......
Again, the sketch is attached as a .txt file - open in Worpad and paste into the IDE, or rename as .pde and open directly.
Burn the sketch to the '328 using the method from step 6. It sets the clock from serial in the "setup" part and then displays the time on the 4-digit display. You can take the "RTCsetFromSerial()" line out of the sketch once the time is set (remember the battery backup will maintain it).
Now connect the controller and display modules with a 6-way cable (I used 6 conductors stripped from a 40-way F-F jumper set - see step 19) and power it up from a 5V supply (the USB to TTL converter works fine but 3 x AA batteries would be good too).
You now have an autonomous clock - you need the serial interface to set the time and date but the RTC chip will hold the time for years on the backup battery and the time is displayed on the LED display. You could even set the code to have an alarm and use the buzzer but unfortunately there is no way to turn it off once you are awake because you have no inputs yet!
OK then - time for some inputs. On to the next module......
Downloads
Module 3 - Rotary Encoder and Switches - Overview
Rotary encoders are cool!
One of the great things about this project is that when you set the time from the rotary encoder you could just as easily be a Bond villain dialing up the count-down on his stolen atom-bomb! Sure, you could do this project without the rotary encoder - an "up", a "down" and a "set" switch would do the job and take the same number of pins, but where would be the fun in that?
This module is the shortest and easiest but there are a couple of fun wrinkles and the result is great.
Firstly to encoders - I just selected on the basis of how cheaply I could source them off e-bay. There may be better criteria but that worked for me. Get one with 5 pins - they have a press-switch as well as the left/right turn encoder. You want that.
An encoder is essentially two switches. When you turn it one way the first switch is connected, followed by the second, followed by disconnection of the first, followed by disconnection of the second. In the other direction, the order is reversed so that the second switch connects, followed by the first, followed by the second disconnect, followed by the first disconnect. Using a pull-down resistor on the output and connecting the common terminal to +5V we get a "HIGH" input for a connected switch and a "LOW" for disconnected.
The sequence thus goes:
Clockwise:
A: H-H-L-L-H-H-L-L-H-H-L-L
B: L-H-H-L-L-H-H-L-L-H-H-L
Anticlockwise:
A: L-H-H-L-L-H-H-L-L-H-H-L
B: H-H-L-L-H-H-L-L-H-H-L-L
The easiest way to read these is using an interrupt set to call a routine when one of the inputs changes state. From looking at the sequence above, you will see that when it's going clockwise, A always changes to be different from B (A is leading). Going anti-clockwise, A always changes to be the same as B (A is following). A very short routine can be called when A changes and simply increase a counter if A=B and decrease the counter if A=/=B. Keeping interrupts short is always a good plan.
The only problem is that we are using a really cheap encoder. The above idea works fine but the cheap encoder "bounces" so badly that it's close to unusable.
There are plenty of debounce circuits on the internet for rotary encoders but I wanted something that was a) easy & b) using parts I had on my bench. It turns out that by connecting to the input pin through a 1K, using a 10K pull-down and adding a 100nf cap across to buffer it, we can go from unusable to near-perfect with two additional parts. It's basically a crude low-pass filter. Circuit diagram is shown in the second picture.
We could equally debounce in software and you will see that in the example code, and the full clock code, I have included commented lines that could be de-commented to implement a software debounce. If you can't spare a 100nf cap or your encoder bounces even more terribly than mine (that doesn't seem possible) then you can un-comment the software debounce.
One of the great things about this project is that when you set the time from the rotary encoder you could just as easily be a Bond villain dialing up the count-down on his stolen atom-bomb! Sure, you could do this project without the rotary encoder - an "up", a "down" and a "set" switch would do the job and take the same number of pins, but where would be the fun in that?
This module is the shortest and easiest but there are a couple of fun wrinkles and the result is great.
Firstly to encoders - I just selected on the basis of how cheaply I could source them off e-bay. There may be better criteria but that worked for me. Get one with 5 pins - they have a press-switch as well as the left/right turn encoder. You want that.
An encoder is essentially two switches. When you turn it one way the first switch is connected, followed by the second, followed by disconnection of the first, followed by disconnection of the second. In the other direction, the order is reversed so that the second switch connects, followed by the first, followed by the second disconnect, followed by the first disconnect. Using a pull-down resistor on the output and connecting the common terminal to +5V we get a "HIGH" input for a connected switch and a "LOW" for disconnected.
The sequence thus goes:
Clockwise:
A: H-H-L-L-H-H-L-L-H-H-L-L
B: L-H-H-L-L-H-H-L-L-H-H-L
Anticlockwise:
A: L-H-H-L-L-H-H-L-L-H-H-L
B: H-H-L-L-H-H-L-L-H-H-L-L
The easiest way to read these is using an interrupt set to call a routine when one of the inputs changes state. From looking at the sequence above, you will see that when it's going clockwise, A always changes to be different from B (A is leading). Going anti-clockwise, A always changes to be the same as B (A is following). A very short routine can be called when A changes and simply increase a counter if A=B and decrease the counter if A=/=B. Keeping interrupts short is always a good plan.
The only problem is that we are using a really cheap encoder. The above idea works fine but the cheap encoder "bounces" so badly that it's close to unusable.
There are plenty of debounce circuits on the internet for rotary encoders but I wanted something that was a) easy & b) using parts I had on my bench. It turns out that by connecting to the input pin through a 1K, using a 10K pull-down and adding a 100nf cap across to buffer it, we can go from unusable to near-perfect with two additional parts. It's basically a crude low-pass filter. Circuit diagram is shown in the second picture.
We could equally debounce in software and you will see that in the example code, and the full clock code, I have included commented lines that could be de-commented to implement a software debounce. If you can't spare a 100nf cap or your encoder bounces even more terribly than mine (that doesn't seem possible) then you can un-comment the software debounce.
Rotary Encoder - Wiring
BoM for this Module:
PCB/perfboard
1 x 5-pin rotarty encoder with push-switch
2 x 6x6mm tactile switches
4 x 10K resistors
2 x 1K resistors
2 x 100nf ceramic caps
1 x 7-way male header (90')
2 x 2-way male header (90')
This is a pretty easy module to wire, especially on the PCB. As before, I started from the centre outwards with:
centre 2 x 10K resistors,
100nf caps,
encoder,
tactile switches,
remaining 10K & 1K resistors,
90' Header pins (on the back)
The Perfboard version is just a case of getting the right resistors in the right places. There is a slight difference in the two versions here because I put some of the 10K pull-downs onto the controller board for the perf-board version while they are on the input board for the PCB. It makes no difference so far as I can see.
I mounted the perf-board version directly over the control board with plastic standoffs. You can do this or not as you see fit.
PCB/perfboard
1 x 5-pin rotarty encoder with push-switch
2 x 6x6mm tactile switches
4 x 10K resistors
2 x 1K resistors
2 x 100nf ceramic caps
1 x 7-way male header (90')
2 x 2-way male header (90')
This is a pretty easy module to wire, especially on the PCB. As before, I started from the centre outwards with:
centre 2 x 10K resistors,
100nf caps,
encoder,
tactile switches,
remaining 10K & 1K resistors,
90' Header pins (on the back)
The Perfboard version is just a case of getting the right resistors in the right places. There is a slight difference in the two versions here because I put some of the 10K pull-downs onto the controller board for the perf-board version while they are on the input board for the PCB. It makes no difference so far as I can see.
I mounted the perf-board version directly over the control board with plastic standoffs. You can do this or not as you see fit.
Rotary Encoder - Test Code
Now that we have some inputs, we can make a self-contained clock. We can even use the buzzer for an alarm. If you only wanted to make an alarm clock and aren't interested in the dawn-light then you could stop here & just tweak this example code.
Once again, the code is attached as a .txt - just open in WordPad and paste into the IDE or rename .pde before opening.
The code sets the time from serial in the setup() routine, but if everything is working then you can take "RTCsetFromSerial()" out of the setup() part because now you can set the time from the encoder!
The code below waits for a long-press on the rotary encoder, then sets the year, month, date, day, hour and minute from the encoder, displaying on the four-digit display. It displays the time. A short press on the encoder displays the date.
We could easily add an alarm code to this, but I didn't have the time for that in a test code - the full code at the end has loads of that type of stuff.
It's great to build your own alarm clock but basic alarm clocks are rather cheap so it's not perhaps entirely worth the effort of building one just for that. What sets us apart from a normal alarm clock is the high-power LED dawn-light. Better move on to the next module then...
Once again, the code is attached as a .txt - just open in WordPad and paste into the IDE or rename .pde before opening.
The code sets the time from serial in the setup() routine, but if everything is working then you can take "RTCsetFromSerial()" out of the setup() part because now you can set the time from the encoder!
The code below waits for a long-press on the rotary encoder, then sets the year, month, date, day, hour and minute from the encoder, displaying on the four-digit display. It displays the time. A short press on the encoder displays the date.
We could easily add an alarm code to this, but I didn't have the time for that in a test code - the full code at the end has loads of that type of stuff.
It's great to build your own alarm clock but basic alarm clocks are rather cheap so it's not perhaps entirely worth the effort of building one just for that. What sets us apart from a normal alarm clock is the high-power LED dawn-light. Better move on to the next module then...
Downloads
Module 4 - LED Driver Board - Overview
The heart of this project is an 8-channel PWM control over 6W of RGB LED and 12W of white LEDs.
Amazingly, we can control these 8 channels using a single '595 shift register and 3 pins of our Arduino compatible, using a superb library written by Elco Jacobs and called ShiftPWM (http://www.elcojacobs.com/shiftpwm/).
The idea is that six lines control 1W each of RGB from two 3W RGB LEDs and the other two lines each control 6W of white LEDs. Obviously a little shift register can't take all that current, so we use a low-side driver transistor to control the LED. We also want 350 mA through each LED, which we can get from tiny AMC7135 driver chips, which also sit to the low-side of the LEDs.
I had decided to run my clock from an ATX power supply, which has +12V and +5V lines (as well as +5V standby - see later). As a result, I put three white LEDs in series and drove them from +12V with a '7135 on each string. Each element of the RGB LED is driven from +5V and a '7135 but where there is a bit too much voltage to burn off (esp on red) I used 1-3 normal N1004 1A diodes to drop the voltage a bit. More details later.
This module can again be made on PCB or perf-board but either way it does require a little bit of surface-mount soldering of the rather small driver chips. This is the only technically challenging piece of soldering in the project and it's really not difficut using the method described in the next few steps.
Amazingly, we can control these 8 channels using a single '595 shift register and 3 pins of our Arduino compatible, using a superb library written by Elco Jacobs and called ShiftPWM (http://www.elcojacobs.com/shiftpwm/).
The idea is that six lines control 1W each of RGB from two 3W RGB LEDs and the other two lines each control 6W of white LEDs. Obviously a little shift register can't take all that current, so we use a low-side driver transistor to control the LED. We also want 350 mA through each LED, which we can get from tiny AMC7135 driver chips, which also sit to the low-side of the LEDs.
I had decided to run my clock from an ATX power supply, which has +12V and +5V lines (as well as +5V standby - see later). As a result, I put three white LEDs in series and drove them from +12V with a '7135 on each string. Each element of the RGB LED is driven from +5V and a '7135 but where there is a bit too much voltage to burn off (esp on red) I used 1-3 normal N1004 1A diodes to drop the voltage a bit. More details later.
This module can again be made on PCB or perf-board but either way it does require a little bit of surface-mount soldering of the rather small driver chips. This is the only technically challenging piece of soldering in the project and it's really not difficut using the method described in the next few steps.
Module 4 - LED Driver Board - Wiring
There's a fair few parts to this last board but only the surface-mount chips are any touble. We'll do those first.
BoM for this module:
PCB or Perfboard
1 x 74HC595 Shift Register
10 x AMC7135 Constant current LED drivers
6 x BCU81 low voltage NPNs
2 x XXX MOSFETs
8 x 1K resistors
9 x 100nf cermaic caps
2 x 100uf electrolytic caps
1 x 470uf electrolytic cap
~10 1N4001 (or similar) 1A rectifier diodes
3 x 7-way male header
1 x 3-way male header
1 x 2-way male header (optional)
1 x MOLEX socket (from e-bay or hacked off an old hard-drive)
2 x 1K resistors for LEDs (optional, not shown)
1 x 3mm orange LED (optional, not shown)
1 x 3mm green LED (optional, not shown)
For PCB or Perfboard, you will want to start with the surface-mount driver chips.
I found that the easiest method for these was:
Add a small blob of solder where each pin will go.
File the solder flat.
Place the chip on top.
Put a tiny speck of wet solder on your iron for good heat-transfer.
Touch the solder next to the central pin until it melts around the chip.
Touch the other two pins to make contact.
Once the surface-mount drivers are on, start again from the middle, with:
LEDs and resistors if you are using them
NPN transistors
Centre 6 x ceramic caps
8 x driver resistors
74HC595
470uF cap at top left (bottom)
2-way header (if used)
3-way header
7-way headers
MOSFETs
remaining ceramic caps
remaining electrolytic caps
MOLEX connector
For the Perf-board version, I put the transistors in next, close to the driver chips and bridged between them. Then the '595, which links to the transistors with 1Ks. The MOLEX connector was ripped off an old hard-drive. You have to drill the holes in the board out a bit to make it fit. Finally, link up the driver chips and power to 7-pin headers.
That gives you everything except the diodes and before they go in (last PCB picture) we really need to make up the LED lamp so that we can test what voltage drop we need.
On to the next (sub) module....
BoM for this module:
PCB or Perfboard
1 x 74HC595 Shift Register
10 x AMC7135 Constant current LED drivers
6 x BCU81 low voltage NPNs
2 x XXX MOSFETs
8 x 1K resistors
9 x 100nf cermaic caps
2 x 100uf electrolytic caps
1 x 470uf electrolytic cap
~10 1N4001 (or similar) 1A rectifier diodes
3 x 7-way male header
1 x 3-way male header
1 x 2-way male header (optional)
1 x MOLEX socket (from e-bay or hacked off an old hard-drive)
2 x 1K resistors for LEDs (optional, not shown)
1 x 3mm orange LED (optional, not shown)
1 x 3mm green LED (optional, not shown)
For PCB or Perfboard, you will want to start with the surface-mount driver chips.
I found that the easiest method for these was:
Add a small blob of solder where each pin will go.
File the solder flat.
Place the chip on top.
Put a tiny speck of wet solder on your iron for good heat-transfer.
Touch the solder next to the central pin until it melts around the chip.
Touch the other two pins to make contact.
Once the surface-mount drivers are on, start again from the middle, with:
LEDs and resistors if you are using them
NPN transistors
Centre 6 x ceramic caps
8 x driver resistors
74HC595
470uF cap at top left (bottom)
2-way header (if used)
3-way header
7-way headers
MOSFETs
remaining ceramic caps
remaining electrolytic caps
MOLEX connector
For the Perf-board version, I put the transistors in next, close to the driver chips and bridged between them. Then the '595, which links to the transistors with 1Ks. The MOLEX connector was ripped off an old hard-drive. You have to drill the holes in the board out a bit to make it fit. Finally, link up the driver chips and power to 7-pin headers.
That gives you everything except the diodes and before they go in (last PCB picture) we really need to make up the LED lamp so that we can test what voltage drop we need.
On to the next (sub) module....
Module 5 - LED Lamps - Overview
The lamps are pretty easy - each has a 3W RGB LED and 6 x 1W white LEDs on a 12W LED heatsink.
There are two chains of three white LEDs in series, each driven off +12V. The chains return to separate AMC7135 chips for constant current but are then controlled from a single MOSFET. That means all 6W of white are always the same brightness.
Each element of the RGB LED is controlled separately. That means that a low brightness we have colour control and at high brightness we have white - that's pretty much what we need to start off at a gentle dawn-red and move over to a blazing mid-day white. We'll control that in software later.
BoM for this module:
1 x aluminium heatsink for 12W of LEDs
1 x 3W RGB LED
6 - 1W white LEDs
60-80 cm (2-3 feet) solid-core network cable or other linkup wire.
There are two chains of three white LEDs in series, each driven off +12V. The chains return to separate AMC7135 chips for constant current but are then controlled from a single MOSFET. That means all 6W of white are always the same brightness.
Each element of the RGB LED is controlled separately. That means that a low brightness we have colour control and at high brightness we have white - that's pretty much what we need to start off at a gentle dawn-red and move over to a blazing mid-day white. We'll control that in software later.
BoM for this module:
1 x aluminium heatsink for 12W of LEDs
1 x 3W RGB LED
6 - 1W white LEDs
60-80 cm (2-3 feet) solid-core network cable or other linkup wire.
Module 5 - LED Lamps - Wiring
I arranged the lamps as two groups of 9W, each on a 12W heat-sink. Each group has one 3W RGB LED (3 channel control) and 6 x 1W white LEDs (1 channel control). The six white LEDs run as two strings of 3 in series off 12v, with one current driver controlling each string. To wire them up, we basically just wire the 7 lines that run from the driver board.
The +ve side of each element of the RGB LED goes to +5V and the -ve side returns to the driver board to be controlled. The white LEDs are in threes with the +ve side of each right-hand LED going to +12V and then the -ve side of the LH LED (the third in series) going back to the driver board. I used a bit of old CAT 5 solid core network cable to link them up and since I only needed 7 of the 8 cores, I doubled up on the +5v, which carries most current (3 x 350 mA).
The LEDs are secured to the heat-sink with heat-sink adhesive, which I found worked well if you put a spot on one LED and then rubbed it between that and another to spread it evenly and very thinly over two LEDs.
As you might imagine, the LEDs are a bit harder to solder once they are glued to a massive heat-sink but it's by no means impossible. I just cranked the temperature on my iron up a bit and it worked fine.
The last picture in this step gives a rough schematic of the LED layout. As you see, there are 5 current-controlled lines (both W! and W2 white lines are then PWM controlled by one MOSFET) plus +5v and +12v. That's 7 lines in total, which are nicely available from a piece of 4-pair network cable.
The +ve side of each element of the RGB LED goes to +5V and the -ve side returns to the driver board to be controlled. The white LEDs are in threes with the +ve side of each right-hand LED going to +12V and then the -ve side of the LH LED (the third in series) going back to the driver board. I used a bit of old CAT 5 solid core network cable to link them up and since I only needed 7 of the 8 cores, I doubled up on the +5v, which carries most current (3 x 350 mA).
The LEDs are secured to the heat-sink with heat-sink adhesive, which I found worked well if you put a spot on one LED and then rubbed it between that and another to spread it evenly and very thinly over two LEDs.
As you might imagine, the LEDs are a bit harder to solder once they are glued to a massive heat-sink but it's by no means impossible. I just cranked the temperature on my iron up a bit and it worked fine.
The last picture in this step gives a rough schematic of the LED layout. As you see, there are 5 current-controlled lines (both W! and W2 white lines are then PWM controlled by one MOSFET) plus +5v and +12v. That's 7 lines in total, which are nicely available from a piece of 4-pair network cable.
Joining the Lamps to the Driver
The AMC7135 constant-current driver chips are spec'ed to dissipate up to 700mA without extra heat-sinking (http://www.micro-bridge.com/data/add/amc7135.pdf). That equates to a voltage drop of 2.0V at 350 mA. They have an internal thermal cutout but we don't want to push them up to that if we can help it because replacing them is going to be a pain if we burn them out!
In practice, however, because we are not using proper reflow soldering techniques, I have aimed for a voltage drop of less than 1V over the '7135. To achieve this, there is space on the driver board for several simple 1N4001 (or 1N4007, or whatever you have) 1A rectifier diodes to burn off some of the excess voltage drop before we reach the '7135. Each diode drops the voltage by around 0.8V, so put as many in series as you need.
I have found that the red segment of the RGB LED needs 3 1N4001s (2.4V drop) to reduce the voltage over the '7135 to less than 1V. The Blue and Green segments needed 1 diode each, while 3 x white LEDs in series dropped 11.5V anyway, so no extra diodes were required on the white channels.
I would suggest populating the diode positions in the same way and then checking the current to the lamps and voltage-drop across the '7135 with your specific LEDs to be sure that this works for you. If you are not getting close to 350mA then take out a diode. If you are getting more than 1.2V voltage drop across the '7135 then put an extra one in.
In the picture you will see that the R channel has 3 diodes, G & B have one and the two white channels have a wire link because there was no excess voltage on that line. Remember that since the driver is low-side, the cathode (stripe) of the diode goes away from the header pins (stripe uppermost in the picture).
In practice, however, because we are not using proper reflow soldering techniques, I have aimed for a voltage drop of less than 1V over the '7135. To achieve this, there is space on the driver board for several simple 1N4001 (or 1N4007, or whatever you have) 1A rectifier diodes to burn off some of the excess voltage drop before we reach the '7135. Each diode drops the voltage by around 0.8V, so put as many in series as you need.
I have found that the red segment of the RGB LED needs 3 1N4001s (2.4V drop) to reduce the voltage over the '7135 to less than 1V. The Blue and Green segments needed 1 diode each, while 3 x white LEDs in series dropped 11.5V anyway, so no extra diodes were required on the white channels.
I would suggest populating the diode positions in the same way and then checking the current to the lamps and voltage-drop across the '7135 with your specific LEDs to be sure that this works for you. If you are not getting close to 350mA then take out a diode. If you are getting more than 1.2V voltage drop across the '7135 then put an extra one in.
In the picture you will see that the R channel has 3 diodes, G & B have one and the two white channels have a wire link because there was no excess voltage on that line. Remember that since the driver is low-side, the cathode (stripe) of the diode goes away from the header pins (stripe uppermost in the picture).
Module 6 - ATX Power Supply Control
This project is designed to run off a standard ATX power supply. If you like making things and have ever had an old computer, the chances are you have one of these lying around (unless of course you have used it for another project already).
ATXs are very cunning because they can supply a useful amount of current (2A in my case) at 5V on the "standby" supply and then can be switched on under firmware control to give 10s of amps at 5V and 12V when you need it. This means that the main power, the fan etc are all off and quiet until the main power is turned on.
This is, of course, just what we need because our controller runs off +5V and our lamps, which we only need occasionally, take several amps at +5V and +12V.
I have already published an instructable on how to control an ATX power supply from an Arduino, and I would refer you to that for the details of this step: https://www.instructables.com/id/Arduino-Controlled-ATX-Power-Supply/
BoM for this step:
ATX power supply
ATX motherboard extension cable
3 jumper leads (F might make more sense but I used M)
1 K resistor
heatshrink
In short, all you need to do is clip down an ATX motherboard extension cable and connect jumpers to purple and black wires, plus a 1K resistor and a jumper to the green wire (see pictures). This gives you ground and +5V standby power, which you use to power your project, plus the green control wire, which attaches to Arduino pin D6 to control the main power when required.
The lamps are powered by pulgging the standard MOLEX power connector from the ATX supply into the driver board you made a few steps ago.
If you didn't want to drive it off an ATX, you could supply +5V and +12V. You would need 2.5-3A at 5V and 1.5-2A at 12V. Obviously, you could wire all of the white LEDs separately and run everything off +5V but that would require something like 7A at +5V. Similarly, you could supply +12V and regulate some of it down to +5V but you would need a 4-5A 12V supply and 2.5-3A of 5V regulation. Overall, none of those options seems as cheap and easy as an old (or even new) ATX supply.
A short video showing the nightlight on the alarm clock and how the ATX main power is triggered when the main LED light comes on can be seen here (taken from that previous instructable):
ATXs are very cunning because they can supply a useful amount of current (2A in my case) at 5V on the "standby" supply and then can be switched on under firmware control to give 10s of amps at 5V and 12V when you need it. This means that the main power, the fan etc are all off and quiet until the main power is turned on.
This is, of course, just what we need because our controller runs off +5V and our lamps, which we only need occasionally, take several amps at +5V and +12V.
I have already published an instructable on how to control an ATX power supply from an Arduino, and I would refer you to that for the details of this step: https://www.instructables.com/id/Arduino-Controlled-ATX-Power-Supply/
BoM for this step:
ATX power supply
ATX motherboard extension cable
3 jumper leads (F might make more sense but I used M)
1 K resistor
heatshrink
In short, all you need to do is clip down an ATX motherboard extension cable and connect jumpers to purple and black wires, plus a 1K resistor and a jumper to the green wire (see pictures). This gives you ground and +5V standby power, which you use to power your project, plus the green control wire, which attaches to Arduino pin D6 to control the main power when required.
The lamps are powered by pulgging the standard MOLEX power connector from the ATX supply into the driver board you made a few steps ago.
If you didn't want to drive it off an ATX, you could supply +5V and +12V. You would need 2.5-3A at 5V and 1.5-2A at 12V. Obviously, you could wire all of the white LEDs separately and run everything off +5V but that would require something like 7A at +5V. Similarly, you could supply +12V and regulate some of it down to +5V but you would need a 4-5A 12V supply and 2.5-3A of 5V regulation. Overall, none of those options seems as cheap and easy as an old (or even new) ATX supply.
A short video showing the nightlight on the alarm clock and how the ATX main power is triggered when the main LED light comes on can be seen here (taken from that previous instructable):
Connect It All Up!
Well, if you have got this far, then you should have 4 populated boards, two big LED lamps and a modified ATX power supply. All we need now is to string them all together.
As you can see from the second picture, the sub-boards are all made so that they would function if they were still all joined. This means that we simply need to add jumpers across all of the snap-points.
I found that the easiest (& cheapest) way to do this was to get a 40-way ribbon cable with female headers on each end (a pound or so on e-bay) and peel off as many as I needed for each connection. Once the connectors are made, you can fix the separate connectors together into a block with a couple of drops of low-viscosity superglue.
All that then remains is to plug the lamps into their headers, the MOLEX from the ATX supply into the driver board and your modified ATX connector into the standby and control power connections.
Plug in and you now have a fully functioning dawn clock ready for uploading your final code.
As you can see from the second picture, the sub-boards are all made so that they would function if they were still all joined. This means that we simply need to add jumpers across all of the snap-points.
I found that the easiest (& cheapest) way to do this was to get a 40-way ribbon cable with female headers on each end (a pound or so on e-bay) and peel off as many as I needed for each connection. Once the connectors are made, you can fix the separate connectors together into a block with a couple of drops of low-viscosity superglue.
All that then remains is to plug the lamps into their headers, the MOLEX from the ATX supply into the driver board and your modified ATX connector into the standby and control power connections.
Plug in and you now have a fully functioning dawn clock ready for uploading your final code.
Final Clock Code
The Final code is LONG - 52K of text and too long to paste into this step.
As before, the code is attached as a .txt file - load in WordPad and copy/paste into the IDE or rename as .pde to load directly.
There are a lot of functions in the code but the RTC, Encoder and Display functions are the same as we have seen in the test code for the previous modules.
The sketch was written about 20 minutes at a time on my daily commute to/from work and therefore is probably not the most systematic piece of coding you will ever see. However, it does provide functions for:
Reading/Writing 1307 RTC
Writing to 4-digit display and "armed" status indicator
Scroll across 4-digit display
Reading from encoder under interrupt
Reading encoder switch and 2 momentary switches
Setting RTC from display/encoder
Display date & day
Arm/disarm alarms
Save armed status to RTC battery-backed RAM
Display current alarms
Setting up to 7 separate alarms each with on/off time, day and buzzer on/off
Save alarms to EEPROM
Set ramp time (time from min to max brightness), hold time (time of max brightness) and buzzer delay (time between reaching max brightness and starting buzzer)
Night-light mode (turn encoder)
Security light mode (random full light between 6pm and 1am with average of 45 mins between on cycles)
Buzzer alarm with escalating beep
Snooze for buzzer (7 mins or until end of lamp "hold" time).
I have had this code running for some months now and it works well for a morning dawn light. However, there may be situations that I have not yet encountered, so I cannot be certain that it's bug-free. However, it's completely open and hackable, so if you find a bug, feel free to comment with the bug nature and preferably the fix! If you can't fix it, I will do what I can.
As before, the code is attached as a .txt file - load in WordPad and copy/paste into the IDE or rename as .pde to load directly.
There are a lot of functions in the code but the RTC, Encoder and Display functions are the same as we have seen in the test code for the previous modules.
The sketch was written about 20 minutes at a time on my daily commute to/from work and therefore is probably not the most systematic piece of coding you will ever see. However, it does provide functions for:
Reading/Writing 1307 RTC
Writing to 4-digit display and "armed" status indicator
Scroll across 4-digit display
Reading from encoder under interrupt
Reading encoder switch and 2 momentary switches
Setting RTC from display/encoder
Display date & day
Arm/disarm alarms
Save armed status to RTC battery-backed RAM
Display current alarms
Setting up to 7 separate alarms each with on/off time, day and buzzer on/off
Save alarms to EEPROM
Set ramp time (time from min to max brightness), hold time (time of max brightness) and buzzer delay (time between reaching max brightness and starting buzzer)
Night-light mode (turn encoder)
Security light mode (random full light between 6pm and 1am with average of 45 mins between on cycles)
Buzzer alarm with escalating beep
Snooze for buzzer (7 mins or until end of lamp "hold" time).
I have had this code running for some months now and it works well for a morning dawn light. However, there may be situations that I have not yet encountered, so I cannot be certain that it's bug-free. However, it's completely open and hackable, so if you find a bug, feel free to comment with the bug nature and preferably the fix! If you can't fix it, I will do what I can.
Downloads
It Works!
Once you have all of the modules connected and the final firmware uploaded, you should find your clock is usable immediately. The time is probably set already from testing the RTC module and if you want to test the light then just turn the encoder. The nightlight function allows you to control the level of the lamp if you want it on in addition to the dawn alarm.
The following controls are provided by the various switches etc:
Encoder L/R: Night Light intensity, any setting.
Encoder Switch (short): Show date/day, snooze or clear alarm, clear security mode, fix any setting.
Encoder Switch (long): Set time/date
Switch 1(short): Display current alarms
Switch 1(long): Set alarms
Switch 2(short): Arm/Disarm alarms
Switch 2(long): Settings (display brightness, ramp time, hold time, buzzer delay time)
Switch 1+2 together: Security light mode.
For any setting, use the encoder L/R to set the desired value (numeric or y/n) and press encoder to fix.
Ramp time = time between lowest "dawn" light intensity and max brightness. 10-30 minutes seems appropriate.
Hold time = time that lamp remains at max brightness before switching off (max 90).
Buzzer delay = time between reaching max intensity and buzzer starting. Cannot be greater than hold time.
The alarms are held in EEPROM so a reset or power-cycle doesn't mess up your alarms. Similarly, the armed status and security light mode are held in the battery-backed up RTC RAM so they will persist after any power outage.
Good luck with the project - and enjoy your easy wake-up tomorrow!
This is the vid' again in case you missed it:
You should hear the power supply come on when the clock turns 14:40 and the main light starts up. It ramps up over 1 minute, followed by the buzzer alarm, which is snoozed and then cleared.
The following controls are provided by the various switches etc:
Encoder L/R: Night Light intensity, any setting.
Encoder Switch (short): Show date/day, snooze or clear alarm, clear security mode, fix any setting.
Encoder Switch (long): Set time/date
Switch 1(short): Display current alarms
Switch 1(long): Set alarms
Switch 2(short): Arm/Disarm alarms
Switch 2(long): Settings (display brightness, ramp time, hold time, buzzer delay time)
Switch 1+2 together: Security light mode.
For any setting, use the encoder L/R to set the desired value (numeric or y/n) and press encoder to fix.
Ramp time = time between lowest "dawn" light intensity and max brightness. 10-30 minutes seems appropriate.
Hold time = time that lamp remains at max brightness before switching off (max 90).
Buzzer delay = time between reaching max intensity and buzzer starting. Cannot be greater than hold time.
The alarms are held in EEPROM so a reset or power-cycle doesn't mess up your alarms. Similarly, the armed status and security light mode are held in the battery-backed up RTC RAM so they will persist after any power outage.
Good luck with the project - and enjoy your easy wake-up tomorrow!
This is the vid' again in case you missed it:
You should hear the power supply come on when the clock turns 14:40 and the main light starts up. It ramps up over 1 minute, followed by the buzzer alarm, which is snoozed and then cleared.
Afterword
A few pointers regarding the cost of the project. It's not all that cheap but you could probably source many of the parts more cheaply and even so it's likely to be cheaper than a commercial white-only dawn alarm clock (which seem to be about £100).
No. Item Unit Cost Total cost
1 ATmega328 -DIP* £3.75 £3.75
1 16 MHz Crystal £0.33 £0.33
1 Max7219 - DIP £0.30 £0.30
1 74HC595 - DIP £0.18 £0.18
10 AMC7135 - SMD £0.31 £3.05
1 DS1307 - DIP £0.25 £0.25
1 watch crystal £0.16 £0.16
2 IRF540N MOSFET £0.56 £1.11
6 BCU81 low voltage NPN £0.35 £2.10
12 White 1 W LED on star* £0.92 £11.08
2 3W RGB LED on star* £4.46 £8.91
2 Heat Sink for 12W LED £2.84 £5.67
1 4-digit red 7-seg display £0.64 £0.64
1 Rotary encoder & knob £1.01 £1.01
1 CR2032 3V Li Battery £0.11 £0.11
1 Holder for CR2032 £0.50 £0.50
4 Perf board** £0.50 £2.00
1 Heat sink glue £2.73 £2.73
1 ATX power supply £11.00 £11.00
2 Momentary switches £0.38 £0.75
1 Tactile switch £0.06 £0.06
1 5V Buzzer £0.99 £0.99
18 100 nF ceramic capacitor £0.02 £0.36
9 10K £0.01 £0.09
15 1K £0.01 £0.15
3 Male header pins x 40 £0.50 £1.50
40 F/F jumper leads £1.50 £1.50
1 Molex Socket (reclaimed) £0.00 £0.00
2 22 pF Ceramic cap £0.02 £0.04
3 100uF Electrolytic Cap £0.10 £0.30
1 470uF Electrolytic Cap £0.20 £0.20
1 1000uF Electrolytic Cap £0.25 £0.25
10 1N4001 rectifier diodes £0.02 £0.20
1 ATX extension lead £2.00 £2.00
Total £59.99
This isn't supposed to be an estimate of what you would pay - you may get a better or worse deal than me, you may buy in larger or smaller quantities. It's just a guide to roughly what I did pay a year or so ago when I sourced these parts.
* I'm pretty sure you can now buy these cheaper ('328s from Mouser are about 50p!).
** The custom PCB cost $55 including delivery for 10 copies.
Further Developments:
The next step in the project would be to box it up!
I would probably do this in two boxes. The modules are made so that the controller, inputs and display could go in a small box near your bed while the main light, driver board and ATX supply could be housed together further away (so you don't blind yourself finding your spec's in the morning!) . You would need a 7-core joining cable, so Cat 5 network cable, either as a soldered piece or using a patch-lead would probably be a good choice.
My next task for this project will most likely be to learn Inkscape and see if I can design a pair of laser-cut acrylic boxes for the job.
Finally:
Congratulations!
You have made it to the end of an incredibly long and involved instructable....
Your Prize? - Well, if you are still interested in this project, leave a message on the 'ible expressing an interest and the first 2 who want them can have copies of the PCB and a full set of ICs with a pre-flashed '328 (you would need to supply the other parts such as LEDs and ATX + basic components). The next 3 get a PCB and a flashed '328 only.
There are a few errors in the current PCB but they are pretty easily remedied and I'll point them out when I send the parts. I might even fix them for you if I have the time and energy. It may take me a few weeks to get them out to you, however, because I'm waiting on shipment of some of the parts. Please be patient - it's free, after all.
Please only ask for a set if you might actually use it - it would be a shame for them to go to people who have no real interest.
Ugi
No. Item Unit Cost Total cost
1 ATmega328 -DIP* £3.75 £3.75
1 16 MHz Crystal £0.33 £0.33
1 Max7219 - DIP £0.30 £0.30
1 74HC595 - DIP £0.18 £0.18
10 AMC7135 - SMD £0.31 £3.05
1 DS1307 - DIP £0.25 £0.25
1 watch crystal £0.16 £0.16
2 IRF540N MOSFET £0.56 £1.11
6 BCU81 low voltage NPN £0.35 £2.10
12 White 1 W LED on star* £0.92 £11.08
2 3W RGB LED on star* £4.46 £8.91
2 Heat Sink for 12W LED £2.84 £5.67
1 4-digit red 7-seg display £0.64 £0.64
1 Rotary encoder & knob £1.01 £1.01
1 CR2032 3V Li Battery £0.11 £0.11
1 Holder for CR2032 £0.50 £0.50
4 Perf board** £0.50 £2.00
1 Heat sink glue £2.73 £2.73
1 ATX power supply £11.00 £11.00
2 Momentary switches £0.38 £0.75
1 Tactile switch £0.06 £0.06
1 5V Buzzer £0.99 £0.99
18 100 nF ceramic capacitor £0.02 £0.36
9 10K £0.01 £0.09
15 1K £0.01 £0.15
3 Male header pins x 40 £0.50 £1.50
40 F/F jumper leads £1.50 £1.50
1 Molex Socket (reclaimed) £0.00 £0.00
2 22 pF Ceramic cap £0.02 £0.04
3 100uF Electrolytic Cap £0.10 £0.30
1 470uF Electrolytic Cap £0.20 £0.20
1 1000uF Electrolytic Cap £0.25 £0.25
10 1N4001 rectifier diodes £0.02 £0.20
1 ATX extension lead £2.00 £2.00
Total £59.99
This isn't supposed to be an estimate of what you would pay - you may get a better or worse deal than me, you may buy in larger or smaller quantities. It's just a guide to roughly what I did pay a year or so ago when I sourced these parts.
* I'm pretty sure you can now buy these cheaper ('328s from Mouser are about 50p!).
** The custom PCB cost $55 including delivery for 10 copies.
Further Developments:
The next step in the project would be to box it up!
I would probably do this in two boxes. The modules are made so that the controller, inputs and display could go in a small box near your bed while the main light, driver board and ATX supply could be housed together further away (so you don't blind yourself finding your spec's in the morning!) . You would need a 7-core joining cable, so Cat 5 network cable, either as a soldered piece or using a patch-lead would probably be a good choice.
My next task for this project will most likely be to learn Inkscape and see if I can design a pair of laser-cut acrylic boxes for the job.
Finally:
Congratulations!
You have made it to the end of an incredibly long and involved instructable....
Your Prize? - Well, if you are still interested in this project, leave a message on the 'ible expressing an interest and the first 2 who want them can have copies of the PCB and a full set of ICs with a pre-flashed '328 (you would need to supply the other parts such as LEDs and ATX + basic components). The next 3 get a PCB and a flashed '328 only.
There are a few errors in the current PCB but they are pretty easily remedied and I'll point them out when I send the parts. I might even fix them for you if I have the time and energy. It may take me a few weeks to get them out to you, however, because I'm waiting on shipment of some of the parts. Please be patient - it's free, after all.
Please only ask for a set if you might actually use it - it would be a shame for them to go to people who have no real interest.
Ugi