Introduction: Home Made 7 Segment Display Clock
I built this for my girlfriend, and assembled it into a coconut shell. At the heart of it there's a PIC16F727 in TQFP package, and a common anode display. I got the display from my ex team-leader, and since these kind of displays 'shout' for being put into a circuit, I had to think of a new peoject.
Whether the project is a multimeter display, a clock,a calendar, or ampmeter, a display is a good thing to get control over. It can help you debug the project by displaying numbers on it, in order to figure out where your program is - running, or stuck - at the moment.
This project consists of a display, some button readings, timer handling and some millisecond counting, on software side. Since this is a simple project, I will give more details about how the used peripherals of the microcontroller actually work. I am giving some insight and some useful links about timers and exporting artwork to PDF file in Altium, for instance.
But first, let's draw the schematic!
Step 1: The Schematic, and a Few Words About the Components
I have been using Altium for almost a year now, I designed this project using this cool program. I started by creating a new project, and adding a schematic file to it.
What is in it:
- PIC16F727 - processor
- 7 segment display with common anode
- 13 x BCR562 logic transistors with base resistors included
- pin headers
You can see the schematic in the attachments.
PIC16F727 - microcontroller
This processor has 44 pins, and it is pretty much an overkill for this application, but I haven't had any other PIC-s hanging around at the moment. Some important features of this processor:
- Internal 16MHz oscillator
- -I²C, SPI, AUSART
- 2 X CCP (Caputure/Compare/PWM)
- 14 Channel 8b ADC
- One 8-bit Timer (TMR0)
- Two 16-bit Timer (TMR1/TMR2)
- Watchdog Timer (WDT)
- In Circuit Serial Programming™ (ICSP™)
- Built-in mTouch™ capacative sensing module
- Wide Operating Voltage (1.8V – 5.5V)
I didn't use any other perpiheral, but a single timer, the rest of the algorithm just commands the display, and keeps track of time.
If your version of the clock is going to be a battery powered version, I recommend you to do some tests with the current limit resistors for optimal current consumption/visibility. I used 1K resistors.
The same type 1K resistors were used to put as pull-ups at the button inputs.
4 digit 7 segment display
The convenient thing about these displays is, that they have their segment pins already pulled together to one single pin, you don't have to trace those when making the PCB. Just a single trace, and you have each digits 'a' segment hooked up. Same thing with the other segments.
So, a digit has the cathode of each LED put out on a pin, taking up 8 pins (there's a dot near each digit), the anode of each digit LED-s are grouped together to go out on four different pins.
That is all we need to know about our display, aside of the pin-out. The pin-out differs from display to display, I won't bother with giving details about that, you might use a different one.
BCR562 logic transistors
These have the bias resistors already mounted. They are used in saturation mode, as switches.
Step 2: How to Export the Artwork to PDF?
I used the toner transfer method to make the PCB, which was exported with Altium. Since there isn't too much that can be said about assembling the thing, I will focus more on explaining how to export the PCB artwork to a PDF, using Altium designer.
First, we need an output job file. Follow the instructions on the images to find out how you should do that. If you have that ready, you'll have to create a "Documentation output", called "PCB prints". You press that, a new line will appear, asking for a new name to be given. I don't name them anyhow, it doesn't do any harm if you just leave it that way. Click on the right side on the PDF box, then click on the little radiobutton on the right-end. A green arrow will connect the two, signaling you, that the PCB prints will be exported to PDF format.
Double click the "PCB prints" line to be able to change its properties. Double click on each layer to define which kind of object you want/don't want to show on the output file. Disable everything, leave just the top/bottom layer on, eventually the tracks on keep-out layer, to see the board edges. Press OK to dismiss the window.
Next, you'll have to tell Altium, that you want the output scaled 1:1. To do this, right click "PCB prints" and select "Page setup dialog".
When it appears, select "scaled print" in the "scale mode" dropdown list, and press OK.
Last, right click on the PDF box, and click on the "Advanced" button to see additional settings. Set the "Page size and orientation" to "Page setup dialog", as the image depicts. Then press F9 to export it to PDF, it will be opened in a few moments, if you have a PDF viewer installed. You print that to get PCB manufacturing started.
If anybody needs it, I can do an instructable for newbies about Altium designer. To my best knowledge, of course.
Step 3: An Inside Look on the PIC16F727 Tasks
I will describe the stuff I used from the PIC, to make this project happen. The one main thing you need for these kind of tasks is a timer. A timer counts the instruction cycles, which have strict relation to the crystal, or oscillator you use to clock your processor. I used the internal oscillator to keep the PCB simple. A PIC needs for clocks to execute a single instruction:
Fosc = 16000000 Hz
Finst = 4000000 Hz
Tinst = 1 / Finst = 250 ns
An instruction takes 250 nanoseconds, this is the same rate the timer counts with. If we need a timing of 1 milliseconds, we let the timer run for 4000 instructions, then signal, that 1 ms has elapsed.
To make this very precise, we will use interrupts. An interrupt to a microcontroller is like a tap on the shoulder for you. You're just minding your own business, then someone comes along, tapping your shoulder to say something. You quit doing your business, and pay attention to the 'interrupt' that just occured. After you're done listening, you react in a certain way, then go back to the stuff you've been doing before someone interrupted you. Saying this the PIC way, you just serviced an interrupt.
The PIC doesn't do what you WANT, it does, what you TELL it to do. This is a very important thing to memorize: A silicon bug is rarely the reason why your project won't start up. It's 99.9% of the times faulty programming.
What do we need to tell the PIC to do in order to achieve what we want:
We need to configure the internal oscillator to be the main clock source for this project, we do this by putting 0x30 in the OSCCON register.
First, we have to enable the interrupt system. This is done by manipulating the bits in the INTCON register.
We need to enable global interrupts, and Timer0 interrupt. Looking at the datasheet, we see bit 7 to be the global interrupt enable bit, and bit 5 to be the Timer0 interrupt enable bit. The rest of the bits are zeros, we don't need to change them. This gives a binary value of b10100000, which in hexadecimal is 0xA0. We put that in the INTCON register.
A prescaler is a counter itself, which increments on every instruction cycle. These - by default - are set to 1:1 so they don't interfere with the timer normal operation. The prescaler output is connected to the timer input, as we can see on the diagram. if we set a prescaler to 1:2, its output will go to '1' only after 2 instruction cycles have completed. This means, that the timer won't increment at every instruction cycle, but at every 2-nd. Similar to this, by setting the prescaler to divide by 4, the TMR0 is getting incremented every 4-th instruction cycle, and so on.
Configuring Timer0 to give interrupt each millisecond:
Timer0 counts the instructions by incrementing the value in the TMR0 register. that value is 8 bits wide, meaning, we can't count further, than 255. If the counter is at 255, and an increment occurs, the register will overflow, and start the counting again from 0.
This is the point, when a timer can signal an interrupt. But if this happens every 256-th cycle, how can we use it to count to 4000?Through help from the prescalers.
4000 / 256 = 15.625
So we need a division by 16 (the closest and bigger prescaler value) to make this happen.
4000 / 16 = 250;
Since the timer gives interrupt at rollover from 255 -> 0, we'll just put an offset of 256 - 250 = 6 in the TMR0 register. This value needs to be refreshed every time the interrupt is serviced. We also have to clear the flag, that was set to '1', when the Timer0 rollover occurred.
Having said that, we now have a precise interrupt, that occurs each millisecond. I usually implement a counter in the interrupt service routine, I count 1000 interrupts, building up a one second signal. Counting the seconds is to be done in the main loop, there are just simple counters that count 60 seconds, then overflow to increment the "minute" variable. Then, the same way, the "hours", "days", "months" variable is incremented.
If the project is simple enough, and has some 7 segment displays in the schematic, I never take care to locate the segment controller pins one next to the other. This project wasn't an exception, the fuzzy defines you can see at the beginning of the program are in place to simplify the ways I display the digits. If you take enough time to try to understand them, you'll see how easy this displaying part actually is.
Step 4: Finding an Enclosure
This whole clock idea came to me when i saw some coconuts on our kitchen table. I turned them into enclosure parts with a hacksaw, and my small mini drill. Even though I don't like using glue as fixing element, I had to use it this time. There was just no way to fix the board in the coconut shell with screws, without "screwing" up.
There is a glue bubble in each corner, securing it into place. The two half shells are held together by super glue in 4 or 5 points. This makes the battery change difficult, I am thinking about tuning this project up with a wall adapter.
Unfortunately, the two dots in the middle happened to be turned off when I took the pictures, but I assure you, this wasn't built in 2006 :) ! Here are some images I took while debugging, and after I assembled everything. I haven't made any pictures of the processor side, but I promise, I will, when I am changing the batteries next time!
Step 5: Final Words, Cleaning the Table
If there are any questions about this schematic, PCB, PIC, or anything in it, feel free to ask!
Have a nice day!