CSCI 381: Embedded Systems Design

Binary Clock

by Michael P.

Overview

This project is devoted to a clock with time represented in the binary system. There is some display flickering on the video, which is not noticeable in reality.

Functionality
clip
clip (AVI, ~1.6Mb)

Reading from left to right, the first 2 columns will display hours. The tens digit is in the first column and the ones will be in the next column. After that, the 3rd column, there will be a spacer column to provide a separator for the time. Next will follow minutes in the 4th and 5th column. Simular to hours, the tens digit will be in the 4th column and ones digit will be in the 5th column. The 6th column is another spacer to separate the data columns. Finally the last 2 columns will display the seconds. The 7th column will display the tens digit of the Seconds and the 8th, last, column will display the ones digit. The example above displays the time of 12:53:37.

Time encoding Example

The 2 buttons on the left side allow the time to be set. The top button will add an hour on every push while the bottom button will add one minute on every push. Currently there is no control to change the seconds.

Hardware

The heart of the project is PIC16F684 microcontroller that keeps, updates, and displays time. The PIC is running at 4 MHz from internal oscillator. The time keeping part is based on its timer TMR1 whose clock input is powered form a 32768 = 215 Hz oscillator. The timer is configured to divide this frequency into 215 times and, thus, its overflow occurs every second. The overflow event is captured and the corresponding Interrupt Service Routine (ISR) updates the clock.

Schematic PCB Front PCB Back Board

The time is displayed on a matrix LED column by column starting from hours down to minutes. To activate a column a DEMUX 74HC138 is used. The inputs A,B,C of DEMUX get a binary code of the column to activate. The causes one of the outputs get low and open the corresponding MOSFET. The column code is loaded to LED via PORTC. The resistors at its outputs provide 25mA through each dot, resulting in a very bright display even under a bright light.

The clock can be powered form a 9V DC. The board is designed for SMD components excluding buttons and LED. It is designed with Eagle software. The grid pitch on the picture is 0.05" (1.27mm) There are several wire bridges shown in a blue color. The 5-pin connector on the left photo above was used for programming and is removed from the final design.

Parts list:
PARTQTYPRICEDESCRIPTION
LTP14158 1 1.75 LED 5x8 matrix display
ECX-39 1 0.96 crystal 32,768 KHz
PIC16F684 1 1.23 microcontroller
FDC6312P 4 4x 0.34 P-Channel MOSFET
SN74HC138 1 0.50 3:8 demultiplexor

Software

The embedded software besides of configurating code consists of two parts: ISR and the main loop. The entire code is written in assembly language and formatted for compilation under MPLAB IDE. The ISR is called every second and increments the seconds counter. If needed, the minutes and hours counters are updated respectively. The new values of counters will be then used in the main loop to display time. Time values are stored in BCD representation in 6 variables, corresponding to tens and units of hours, minutes, and seconds. This way no conversion is needed for displaying them in binary.

 ORG 4						; ISR is called every second
	movwf	w_save				; save Wreg
	swapf	STATUS, w			; save stat reg without
	movwf	stat_save			; changing flags

	movlw	128				; set next timer interrupt event
	movwf	TMR1H				; 1 sec apart

	incf	s2, f				; increment units of seconds
	movlw	6
	addwf	s2, w
	btfss	STATUS, DC			; is unit(seconds) < 10 ?
	 goto	ISR_end				; YES - return from INT
	clrf	s2				; clear the lower digit of seconds	
	incf	s1, f				; increment tens of seconds
	movlw	10
	addwf	s1, w				
	btfss	STATUS, DC			; check if seconds = 60
	 goto	ISR_end				; NO - return	

	clrf	s1				; reset seconds 
	incf	m2, f				; increment units of minutes
	movlw	6
	addwf	m2, w
	btfss	STATUS, DC			; is units(minutes) < 10 ?
	 goto	ISR_end				; YES - return
	clrf	m2
	incf 	m1, f				; increment tens of minutes
	movlw	10
	addwf	m1, w				
	btfss	STATUS, DC			; check if minutes = 60
	 goto	ISR_end				; NO - return

	clrf	m1				; reset minutes
	incf	h2, f				; increment units of hours
	movlw	12
	addwf	h2, w
	btfss	STATUS, DC			; is units(minutes) = 4 ?
	 goto	not24				; NO - proceed to process
hours
	btfss	h1, 1				; is h1=2, so hours = 24 ?
	 goto	not24				; NO - proceed
	clrf	h1
	clrf	h2
	goto	ISR_end

not24
	movlw	6
	addwf	h2, w
	btfss	STATUS, DC			; if units(hours) < 10 ?
	 goto	ISR_end				; YES - return
	clrf	h2
	incf	h1, f				; increment tens of hours

ISR_end
	bcf	PIR1, TMR1IF			; clear interrupt flag
	swapf	stat_save, w			; get original flags in STATUS
	movwf	STATUS
	swapf	w_save, f			; restore Wreg		
	swapf	w_save, w
	retfie

The main loop performs two tasks. The first task is to activate column by column by updating PORTA and load the corresponding binary value to PORTC for displaying. After loading a new column value the PIC executes a 3msec delay loop. This way all 6 display columns are updated in 18msec, which corresponds to 55Hz display refresh rate. This value can be easily increased to 83Hz by loading 2 into the variable delayCnt within the colDelay routine.

The second task of the mail loop is to check the buttons stati after refreshing the display. The debouncing routine integrated into this part of code provides a reliable reading of the button stati.

loop						; column display loop
	clrf	colNo				; start with column 1

	movlw	0x1F
	iorwf	PORTC, f			; clear display column
	movf	h1, w				; pass tens of hours
	movwf	display
	call	displayColumn

	movlw	0x1F
	iorwf	PORTC, f			; clear display
	movf	h2, w				; pass units of hours
	movwf	display
	call	displayColumn

	incf	colNo, f			; skip column separator

	movlw	0x1F
	iorwf	PORTC, f			; clear display column
	movf	m1, w				; pass tens of minutes
	movwf	display
	call	displayColumn

	movlw	0x1F
	iorwf	PORTC, f			; clear display
	movf	m2, w				; pass units of minutes
	movwf	display
	call	displayColumn

	incf	colNo, f			; skip column separator

	movlw	0x1F
	iorwf	PORTC, f			; clear display column
	movf	s1, w				; pass tens of seconds
	movwf	display
	call	displayColumn

	movlw	0x1F
	iorwf	PORTC, f			; clear display
	movf	s2, w				; pass units of seconds
	movwf	display
	call	displayColumn

	; checking the button status and debouncing
	btfsc	PORTC, 5			; check the H button status
	 goto	hOff				; not pressed
	incf	debounceHon, f			; update button on state counter
	movlw	debounce
	subwf	debounceHon, w
	btfss	STATUS, C			; was H button ON for debounce times?
	 goto	checkMbut			; NO - check the other button
	clrf	debounceHon
	clrf	debounceHoff
	call	incHours			; YES - update hours
	goto	checkMbut

hOff
	incf	debounceHoff, f			; update button off state counter
	movlw	debounce
	subwf	debounceHoff, w
	btfss	STATUS, C			; was H button OFF for
debounce times ?
	 goto	checkMbut			; NO - check the other button
	clrf	debounceHon			; YES - confirm its state
	clrf	debounceHoff

checkMbut
	btfsc	PORTA, 3			; check the M button status
	 goto	mOff				; not pressed
	incf	debounceMon, f			; update button on state counter
	movlw	debounce
	subwf	debounceMon, w
	btfss	STATUS, C			; was M button ON for
debounce times?
	 goto	loop				; NO - proceed
	clrf	debounceMon
	clrf	debounceMoff
	call	incMinutes			; YES - update minutes
	goto	loop

mOff
	incf	debounceMoff, f			; update button off state counter
	movlw	debounce
	subwf	debounceMoff, w
	btfss	STATUS C			; was M button OFF for debounce times ?
	 goto	loop				; NO - proceed
	clrf	debounceMon			; YES - confirm its state
	clrf	debounceMoff
	goto	loop

Downloads


Last modified:Mon, Jan 23, 2023.

01641