Vol. 09: Digital Clock
Programming PIC microcontrollers, part 3.
By Sparkle Labs
Digital Edition
SUBSCRIBERS:Read this article now in your digital edition!
Get Make:
Subscribe to MAKE and get the best rate!
+ Downloads & Extras:
Extras
Up to now most of the parts we have been using with our microcontroller have been discreet components like resistors and potentiometers. Peripheral devices are integrated circuits (ICs) like our microcontroller that pack all of the discreet components into a small chip to perform particular function. These chips come in a variety of package styles. We are going to prototype on a breadboard so we ordered our chips in a PDIP package.
Looking at the Pin Description for this chip we see that pins 1,12 and 13 are used for data and will connect to I/O pins on the PIC. Pins 4 and 9 go to ground. Pin 18 is a resistor to set the peak segment current for the LEDs which is calculated based on the forward voltage of the LEDs you choose. This resistor can also be used to limit the brightness of the LEDs. Pin 19 connects to +5volts. Pin 24 is dataout which we are not using. The remaining pins connect to the LED display. This chip is for use with common-cathode type 7-segment displays or common-cathode-row 8x8 or smaller LED matrix displays. Pins labeled DIG 0-7 sink current from each digit's cathodes while pins labeled SEG A-G, and DP source current to the individual LEDs in the digit. So the SEG A pin on the 7221 connects to the SEG A pin of every digit. That is a lot of wires on your breadboard! Fortunately we are only using 5 digits in our display. Now that we have our PIC, the 7221 and the display wired up and powered we can write some code to see if it works.
From the MAX7219/MAX7221 datasheet:Table 1. Serial-Data Format (16 Bits) D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 X | X | X | X | ADDRESS | DATA |
The 7221
Table 1 of the data sheet shows us the serial data format for the 7221. From this table we learn that communication takes place in 16 bit chunks and that the first 4 bits do not matter. The next 4 bits say which register we want to send the data to and the last 8 bits are the data to send. All of the information the chip needs to operate are stored in its registers. We control the chip by changing the data stored in the registers. Table 2 shows the register address map. Take for instance the Shutdown Mode register. According to the datasheet the 7221 begins in Shutdown Mode. We need to Set this to off in order for our chip to run. We will initialize our display registers when our program first runs by first making the 7221's latch pin low, sending the 16 bits on the data line and then setting the latch pin high. The code looks like this:
low s7221 'make the latch pin low
shiftout dout, dclock, 1, [%00001100,%00000001 ]
'the first byte selects the shutdown mode register. the next sets it to normal operation.
high s7221 'make the latch pin high
Other registers we set in the top of our code are:Intensity register - set to maximum. Scan Limit - we only use 5 digits. Decode mode - set to on for the first 4 digits. Test mode - set "on" then "off" 3 times with a pause so we see that the communication is working.
After initializing the 7221, writing information to the display is a simple matter. Each digit or row of LEDs has its own register. So to write to the first digit, we first send the address for that digit and then the binary version of the number we want to display. %00000001 for the first digit and %00000010 to show the number "2". This would have a different effect on the fifth digit for which we are not using the decode mode. This digit is treated as a row of 8 LEDs so sending %00000101 and %00000010 would light the 2nd LED in that row of LEDs. This is how you would use a matrix of LEDs. Already we have a clock that is correct twice a day. Next we need to add a way to keep track of time.
Drawing a picture to an 8x8 matrix of LEDs:
row7 = %01111110
row6 = %10000001
row5 = %10100101
row4 = %10000001
row3 = %10100101
row2 = %10111101
row1 = %10000001
row0 = %01111110
The graphical equivalent of "Hello, World!"
Watch Crytal
The DS1305 Real Time Clock will keep track of the year, date, day of the week, hour and seconds. All we need to make it run is a 32.768kHz watch crystal. We can access the registers to read and write the time. We can set two alarms and even keep information on the chip.
First we connect the chip to our circuit. Running through the pin description in the datasheet:
Pin 1: ground as we have no rechargeable battery.
Pin 2: to connects to a +9volt battery
Pin 3 & 4: the two leads of our watch crystal.
Pin 5-7: we will not use
Pin 8: ground
Pin 9: connects to power to tell the chip to use SPI for communication.
Pin 10: the latch pin
Pin 11: the data communication clock
Pin 12: data in from the microcontroller
Pin 13: data out to the microcontroller
Pin 14: connects to power
Pin 15: not used
Pin 16: Power
Communicating with the DS1305 is similar to with the 7221. Send the address you want to talk too and then send the data. First we must initialize the chip by first sending $8F which is the hex value of the control register. $8F is the same as %10001111 which is the same as 143. The datasheet lists the values in hex format so we will use those too. Immediately after sending the address we send the data which is %00000111. It is important to set the first two bits to 0. The rest do not matter now. Later I may want to use alarms with the clock so I set the last three bits to 1.
Development Environment
- Write the code in a plain text editor or an integrated development environment (IDC). An IDC puts all the software you need for programming in one package. We used Microcode Studio available here. MPLAB is another IDC which is available from www.microchip.com.
- Compile the code with the PicBasicPro (PBP) compiler from www.melabs.com. After installing PBP and telling the IDC where to find it we have only to press Compile in the IDC. Compiling creates a hex file from the code we wrote.
- Program the microcontroller by loading the hex file created by the compiler into the software for your programmer. We used the PICkit 1 programmer available from Microchip. The PICkit 1 has been replaced by the PICkit 2. This programmer can only program PICs with up to 14 pins. There are many PIC programmers on the market. www.melabs.com makes a variety of programmers capable of programming larger pics.
The PIC we are using is the 16F675 that came with the programmer. PICs are manufactured by www.microchip.com. They can be ordered from them or from another electronic components store such as digikey.com or jameco.com.
» MAKE: NOISE — Discuss this article
You must be logged in to post a talkback.[ Display main threads only] [ Oldest First]
Showing messages 1 through 12 of 12.
- Picaxe version of Digital Clock
You must be logged in to reply.
Hello, I have read this article at least 15 times, and I know that others want to do this project. I devoted my spare time to figure this out, and I have a working solution. I have a full schematic, basic program, and Bill of Materials ready for download.
Visit http://tech-tut.com/?p=15 for all of this. Make is a great magazine, and I look forward to more cool projects like this one.
Posted by tech-tut on July 22, 2008 at 08:32:16 Pacific Time
- Picaxe version of Digital Clock
You must be logged in to reply.
Good Work!Posted by kakekoko on July 22, 2008 at 13:20:38 Pacific Time
- half ass
You must be logged in to reply.
this article is pretty half ass. as the poster before me states no real schematic available. i don't see any code other than the snippets in the article. I was more interested in making the actual clock case (i guess is what you would call it) and theres no info on that. Am i missing something or is this really that crappy an article?Posted by chupa0@gmail.com on March 10, 2007 at 17:19:16 Pacific Time
- casing
You must be logged in to reply.
How is the case for the clock made, or where can it be purchased?
Posted by modestyprevails on March 06, 2007 at 20:36:32 Pacific Time
- casing
You must be logged in to reply.
That is for a different article.
It is just pieces of plexiglass glued together with a solvent/glue for acrylic. You can cut the plexi yourself or order it cut to size. Some places will even laser cut shapes like holes for buttons. The glue is very easy to use. You just put the two pieces of plastic together and run the needle applicator along the join. Be careful as edges that were cut by laser will not glue well.Posted by kakekoko on March 10, 2007 at 21:33:38 Pacific Time
- Schematic? BOM? Source code?
You must be logged in to reply.
Is there a schematic that uses standard symbols, such as would be created with CadSoft's Eagle Light[1]?
Is there a Parts list or Bill of Materials?
Is the PicBasic source code available?
[1] http://www.cadsoftusa.com/freeware.htm
Posted by mctaylor on March 03, 2007 at 14:15:17 Pacific Time
- Schematic? BOM? Source code?
You must be logged in to reply.
Posted by giantskou on July 13, 2008 at 16:42:16 Pacific Time
- Schematic? BOM? Source code?
You must be logged in to reply.
Here is the PBP source code. It should have been posted above for you. No schematic was created for this circuit. All of the major parts are listed in the article.Posted by kakekoko on March 10, 2007 at 21:00:46 Pacific Time
- Schematic? BOM? Source code?
You must be logged in to reply.
yay, thank youPosted by chupa0@gmail.com on March 17, 2007 at 19:03:32 Pacific Time
- Schematic? BOM? Source code?
You must be logged in to reply.
Thank you for posting the PBasic source code.Posted by mctaylor on March 17, 2007 at 12:02:53 Pacific Time
- Source code?
You must be logged in to reply.
REM target device: PIC165876
REM peripherels: MAX1305 RTC and MAX7221 Display driver
Include "modedefs.bas"
pause 100
temp0 var byte
temp1 var byte
i var byte
'pin assignments###########################
'PGD var portb.7 'in circuit programming pins
'PGC var portb.6 'do not need to declare these
'PGM var portb.3 'so i just note them here.
'data communication
dout var portc.5 'data out
din var portc.4 'data in to
dclock var portc.3 'clock for data
s7221 var portc.0 'chip select LED driver
s1305 var portc.1 : low s1305 'chip select RTC
alarm_int var portb.0 'interrupt pin for alarm
button0 var portb.1 : input button0 'setup 3 buttons
button1 var portb.2 : input button1
button1Var var byte : button1Var = 0 'variable for autorepeat
button2 var portb.3 : input button2
button2Var var byte : button2Var = 0 'variable for autorepeat
debugLED var portc.7 'i can blink this led to check code
'RTC chip#################################
clockmin var byte : clockmin = %00000000 'default hours are 12
clockhour var byte : clockhour = %01010010 'in packed binary coded decimel
setmin var byte : setmin = %00000000
sethour var byte : sethour = %01010010
'setup addresses
rmin var byte
rmin = $01
wmin var byte
wmin = $81
rhour var byte : whour var byte
rhour = $02 : whour = $82
wdate var byte : wdate = $84
wmonth var byte : wmonth = $85
ralarmmin var byte : walarmmin var byte 'alarm vars to functions later
ralarmmin = $08 : walarmmin = $88
ralarmhour var byte : walarmhour var byte
ralarmhour = $09 : walarmhour = $89
'set control register
high s1305
shiftout dout, dclock,1, [$8F,%00000011 ]
low s1305
pause 50
high s1305 'set clock to default time
shiftout dout, dclock,1, [wmin]
shiftout dout, dclock,1, [setmin]
low s1305
high s1305
shiftout dout, dclock,1, [whour]
shiftout dout, dclock,1, [sethour]
low s1305
'LED driver#############################
digit0 var byte : digit0 = 1
digit1 var byte : digit1 = 2
digit2 var byte : digit2 = 3
digit3 var byte : digit3 = 4
row4 var byte : row4 = %00000001
dots var row4.0
PMlight var row4.1
alarmlight var row4.2
'set decode to decode numbers or set LEDs individually
low s7221
shiftout dout, dclock, 1, [%00001001,%00001111 ]
high s7221
'set intensity of LEDs
low s7221
shiftout dout, dclock, 1, [%00001010, %00001111]
high s7221
'set scan limit - how many digits
low s7221
shiftout dout, dclock, 1, [%00001011, %00000100]
high s7221
'turn driver on (shutdown mode = off)
low s7221
shiftout dout, dclock, 1, [%00001100, %00000001]
high s7221
'test LEDS
for i = 1 to 3
low s7221
shiftout dout, dclock, 1, [%00001111, %00000001]
high s7221
high debugLED
pause 100
low s7221
shiftout dout, dclock, 1, [%00001111, %00000000]
high s7221
low debugLED
pause 50
next
gosub display
pause 500
'###############################################
'the main loop###################################
main:
gosub display
gosub readclock
gosub converttime
if button0 = 1 then
setmin = (digit1 * 10) + digit0
sethour = (digit3 * 10) + digit2
gosub settime
gosub writeclock
endif
goto main
'subroutines####################################
converttime:
digit0 = clockmin & $0F
digit1 = (clockmin & $F0) >> 4
digit2 = clockhour & $0F
digit3 = (clockhour & $10) >> 4
PMlight = clockhour.5
return
settime:
button button1,1,100,20,button1var,0,skipmin
setmin = setmin + 1
if setmin > 59 then
setmin = 0
endif
skipmin:
button button2,1,100,45,button2var,0,skiphour
sethour = sethour + 1
if sethour > 12 then
sethour = 1
endif
if sethour > 11 then
toggle PMlight
endif
skiphour:
digit0 = setmin DIG 0
digit1 = setmin DIG 1
digit2 = sethour DIG 0
digit3 = sethour DIG 1
gosub display
if button0 = 1 then
goto settime
endif
return
writeclock:
setmin = (digit1 << 4) + digit0
sethour = (digit3 << 4) + digit2
sethour.5 = PMlight
sethour.6 = 1 'set clock for 12hour time
high s1305
shiftout dout, dclock,1, [wmin]
shiftout dout, dclock,1, [setmin]
low s1305
high s1305
shiftout dout, dclock,1, [whour]
shiftout dout, dclock,1, [sethour]
low s1305
return
readclock:
high s1305
shiftout dout, dclock,1, [rmin]
shiftin din, dclock,2, [clockmin]
low s1305
high s1305
shiftout dout, dclock,1, [rhour]
shiftin din, dclock,2, [clockhour]
low s1305
return
display:
if digit3 = 0 then
digit3 = 15
endif
for i = 0 to 4 'output each digit one at a time
lookup i, [%00000001,%00000010,%00000011,%00000100,%00000101],temp0
lookup2 i, [digit0,digit1,digit2,digit3,row4],temp1
low s7221
shiftout dout, dclock, 1, [temp0,temp1]
high s7221
next
if digit3 = 15 then
digit3 = 0
endif
return
Posted by kakekoko on March 10, 2007 at 20:51:03 Pacific Time
- Source code question?
You must be logged in to reply.
What does the colon (:) mean in variable declaration statements?
Example
button0 var portb.1 : input button0
Is it further appending something to the button0 variable? Please advise. Thanks for your help and I look forward to hearing from you soon.
Posted by jcastino on May 29, 2007 at 10:45:24 Pacific Time
|
Showing messages 1 through 12 of 12. |
Join the conversation -- every MAKE article has an online page that includes a place for discussion. We've made these RSS and Atom feeds to help you watch the discussions: subscribe.










