Close
0%
0%

CGA Clock

Binary clock with a bit of help from CGA colors

Similar projects worth following
(Disclaimer: This is not a novel design, just an old concept with a twist)

This binary clock displays time in 6 columns, for each digit of the 24-hour "HHmmss" format (first digit 0-2, second digit 0-9, etc...). This is BCD (Binary Coded Decimal)

The LEDs used for each 4-bit (or less) digit rolumn are chosen such that if you're color blind, it will just be a classic binary clock. If you do see color however, the Blue, Green, Red and White LEDs can be mentally added together. Refer to the color chart to see which number corresponds with which color. (White makes the RGB color 'brighter', without White, it becomes 'darker'.)

Those who have programmed or painted in DOS or Windows 3 / 98 before may remember these colors by heart, and this can speed op reading of the digits. For example, when you see this column pattern:

1 - white
1 - red
0 - green
1 - blue

You add up the colors mentally and see 'bright magenta' which you may immediately link to the number 13. (Or just use the classic way of adding 8+4+1 = 13)

The only extra thing you have to remember is that R+G+B is brighter than just White, which in itself is kinda logical if you think about it.


The LEDs are driven as a 5x4 bit matrix display (not Charlieplexing as the development board might suggest). Each second the display advances to the next time, eg. from 14:03:59 to 14:04:00. To prevent irritating flashes in the corner of your eye, the display gently fades from one time to the next using PWM with linear ramps.


It keeps time by listening to the 50Hz frequency of the mains. It won't be able to keep time on battery without an additional RTC, and for 60Hz zones it needs some reprogramming. (Porbably just change 156 to 136 in the code, but don't blame me if there are other incompatibilities, like with the fading).

  • 1 × PIC16F688
  • 1 × Transformer 8VAC
  • 6 × LED Blue (3528 package)
  • 6 × LED Green (3528 package)
  • 5 × LED Red (3528 package)

View all 18 components

  • 1
    Step 1

    Source Code

    	INCLUDE P16F688.INC
    
        ERRORLEVEL	-302	;Supress the (manual) banking message!
    
    	__CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
    
    ;===============================================================
    
    TIME_S1		EQU	0xA0
    TIME_S10	EQU	0xA1
    TIME_M1		EQU	0xA2
    TIME_M10	EQU	0xA3
    TIME_H1		EQU	0xA4
    TIME_H10	EQU	0xA5
    
    OLD_S1		EQU	0xB0
    OLD_S10		EQU	0xB1
    OLD_M1		EQU	0xB2
    OLD_M10		EQU	0xB3
    OLD_H1		EQU	0xB4
    OLD_H10		EQU	0xB5
    
    COUNT		EQU	0xC0
    
    CUR_COL		EQU	0xC1
    
    TIME_CENT	EQU	0xC2
    
    BLUR_PHASE	EQU	0xC3
    BLUR_STEP	EQU	0xC4
    
    FLAG		EQU	0x45
    
    ;===============================================================
    
    #DEFINE		DATA_PORT		PORTC
    #DEFINE		COL0_BIT		PORTA,1
    #DEFINE		COL1_BIT		PORTA,5
    #DEFINE		COL2_BIT		PORTA,4
    #DEFINE		COL3_BIT		PORTC,5
    #DEFINE		COL4_BIT		PORTC,4
    #DEFINE		BUT_BIT			PORTA,2
    
    #DEFINE		_BLUR_LENGTH	115
    
    ;===============================================================
    
    INT_OFF		MACRO
    	BCF		INTCON,GIE
    	ENDM
    
    INT_ON		MACRO
    	BSF		INTCON,GIE
    	ENDM
    
    INC_SEC		MACRO
    	INCF	TIME_S1,F
    	MOVLW	6
    	ADDWF	TIME_S1,W
    	BTFSS	STATUS,DC
    	RETURN
    	CLRF	TIME_S1
    
    	INCF	TIME_S10,F
    	MOVLW	10
    	ADDWF	TIME_S10,W
    	BTFSS	STATUS,DC
    	RETURN
    	CLRF	TIME_S10
    	ENDM
    
    INC_MIN		MACRO
    	INCF	TIME_M1,F
    	MOVLW	6
    	ADDWF	TIME_M1,W
    	BTFSS	STATUS,DC
    	RETURN
    	CLRF	TIME_M1
    
    	INCF	TIME_M10,F
    	MOVLW	10
    	ADDWF	TIME_M10,W
    	BTFSS	STATUS,DC
    	RETURN
    	CLRF	TIME_M10
    	ENDM
    
    INC_HR		MACRO
    	INCF	TIME_H1,F
    	MOVLW	6
    	BTFSC	TIME_H10,1
    	MOVLW	12
    	ADDWF	TIME_H1,W
    	BTFSS	STATUS,DC
    	RETURN
    	CLRF	TIME_H1
    
    	INCF	TIME_H10,F
    	MOVLW	6
    	ADDWF	TIME_H10,W
    	BTFSS	STATUS,DC
    	RETURN
    	CLRF	TIME_H10
    	ENDM
    
    ;===============================================================
    	ORG		0x00
    	GOTO	INIT
    
    ;===============================================================
    
    	ORG		0x04
    
    	;Read PORTA to latch the change detector
    	BANKSEL	0x00
    	MOVFW	PORTA
    	BANKSEL	0x80
    
    	CALL	INCTIME
    
    	BCF		INTCON,RAIF
    	
    	RETFIE
    
    ;===============================================================
    
    INIT
    	;CLOCK
    	BANKSEL	0x80
    	MOVLW	B'01110001'
    	MOVWF	OSCCON
    
    INIT_VARIABLES
    	BANKSEL	0x80
    	CLRF	TIME_S1
    	CLRF	TIME_S10
    	CLRF	TIME_M1
    	CLRF	TIME_M10
    	CLRF	TIME_H1
    	CLRF	TIME_H10
    	CLRF	OLD_S1
    	CLRF	OLD_S10
    	CLRF	OLD_M1
    	CLRF	OLD_M10
    	CLRF	OLD_H1
    	CLRF	OLD_H10
    	CLRF	CUR_COL
    	MOVLW	_BLUR_LENGTH
    	MOVWF	BLUR_PHASE
    	MOVWF	BLUR_STEP
    
    INIT_CMP
    ;	BANKSEL	0x80
    	CLRF	ANSEL				;Disable A/D
    	BANKSEL	0x00
    	MOVLW	B'00000111'			;Disable CMP
    	MOVWF	CMCON0
    
    INIT_IO
    ;	BANKSEL	0x00
    	MOVLW	B'00110000'
    	MOVWF	PORTC
    	MOVLW	B'00110010'
    	MOVWF	PORTA
    	BANKSEL	0x80
    
    INIT_INT
    	;INTERRUPT-ON-CHANGE (PORTA0)
    ;	BANKSEL	0x80
    ;	BSF		IOCA,0				;RA0	
    ;	BSF		INTCON,RAIE
    
    ;	BANKSEL	0x00
    
    ;===============================================================
    
    MAIN
    	INT_OFF
    
    	BANKSEL	0x00
    ;	MOVLW	B'00110000'
    ;	MOVWF	PORTC
    ;	MOVLW	B'00110010'
    ;	MOVWF	PORTA
    	BANKSEL	0x80
    
    	CALL	DISP
    	INT_ON
    
    	BANKSEL	0x00
    	MOVFW	PORTA
    	ANDLW	B'00000001'
    	XORWF	FLAG,W
    	BTFSS	STATUS,Z
    	CALL	INCTIME
    
    	BANKSEL	0x80
    	
    	BTFSC	CUR_COL,0
    	CALL	TEST_BUTTONS
    
    	BANKSEL	0x80
    
    	GOTO	MAIN
    
    ;---------------------------------------------------------------
    
    DISP
    	MOVLW	TIME_S1
    	MOVWF	FSR
    
    	MOVFW	BLUR_PHASE
    	SUBWF	BLUR_STEP,W
    	BTFSC	STATUS,C
    	GOTO	DISP_SHOW
    
    	MOVLW	0x10
    	ADDWF	FSR,F
    
    DISP_SHOW
    	MOVLW	4
    	DECF	CUR_COL,F
    	BTFSC	CUR_COL,7
    	MOVWF	CUR_COL
    
    	MOVF	CUR_COL,W
    	ADDWF	PCL,F
    	GOTO	COL0
    	GOTO	COL1
    	GOTO	COL2
    	GOTO	COL3
    ;	GOTO	COL4
    
    COL4
    	BSF		COL0_BIT
    
    	MOVLW	4
    	ADDWF	FSR,F
    	COMF	INDF,W
    	IORLW	B'11110000'
    	MOVWF	DATA_PORT
    
    	BCF		COL4_BIT
    	GOTO	DISP_BLUR
    	RETURN	
    
    COL3
    	BSF		COL4_BIT
    
    	MOVLW	3
    	ADDWF	FSR,F
    	COMF	INDF,W
    	IORLW	B'11110000'
    	MOVWF	DATA_PORT
    
    	MOVLW	2
    	ADDWF	FSR,F
    	BTFSC	INDF,1
    	BCF		DATA_PORT,3
    
    	BCF		COL3_BIT
    	GOTO	DISP_BLUR
    	RETURN
    
    COL2
    	BSF		COL3_BIT
    
    	MOVLW	2
    	ADDWF	FSR,F
    	COMF	INDF,W
    	IORLW	B'11110000'
    	MOVWF	DATA_PORT
    
    	BCF		COL2_BIT
    	GOTO	DISP_BLUR
    	RETURN
    
    COL1
    	BSF		COL2_BIT
    
    	INCF	FSR,F
    	COMF	INDF,W
    	IORLW	B'11110000'
    	MOVWF	DATA_PORT
    
    	MOVLW	4
    	ADDWF	FSR,F
    	BTFSC	INDF,0
    	BCF		DATA_PORT,3
    
    	BCF		COL1_BIT
    	GOTO	DISP_BLUR
    	RETURN
    
    COL0
    	BSF		COL1_BIT
    
    	COMF	INDF,W
    	IORLW	B'11110000'
    	MOVWF	DATA_PORT
    
    	BCF		COL0_BIT
    ;	RETURN
    
    DISP_BLUR:
    	;PREPARE BLUR
    	DECFSZ	BLUR_STEP,F
    	RETURN
    
    	MOVLW	_BLUR_LENGTH
    	MOVWF	BLUR_STEP
    
    	DECFSZ	BLUR_PHASE,F
    	RETURN
    
    	;KEEP AT 1
    	INCF	BLUR_PHASE,F
    	RETURN
    
    ;---------------------------------------------------------------
    
    TEST_BUTTONS
    	;Test if a button is pressed
    	BANKSEL	0x00
    	BTFSS	BUT_BIT
    	RETURN
    
    	BANKSEL	0x80
    
    	;Only handle buttons when millis exceeds 2<<4
    	BTFSS	TIME_CENT,4
    	RETURN
    
    
    	BTFSC	CUR_COL,1
    	GOTO	TEST_BUTTON3
    ;	GOTO	TEST_BUTTON1
    
    ;TEST_BUTTON1
    	CLRF	TIME_CENT
    	CLRF	TIME_S1
    	CLRF	TIME_S10
    	
    	INC_MIN
    	RETURN
    
    TEST_BUTTON3
    	CLRF	TIME_CENT
    	CLRF	TIME_S1
    	CLRF	TIME_S10
    
    	INC_HR
    	RETURN
    
    ;---------------------------------------------------------------
    
    INCTIME
    	XORWF	FLAG,F
    	BANKSEL	0x80
    
    	INCF	TIME_CENT,F
    	MOVLW	156
    	ADDWF	TIME_CENT,W
    	BTFSS	STATUS,C
    	RETURN
    	CLRF	TIME_CENT
    
    	;PREPARE BLUR
    	MOVFW	TIME_S1
    	MOVWF	OLD_S1
    	MOVFW	TIME_S10
    	MOVWF	OLD_S10
    	MOVFW	TIME_M1
    	MOVWF	OLD_M1
    	MOVFW	TIME_M10
    	MOVWF	OLD_M10
    	MOVFW	TIME_H1
    	MOVWF	OLD_H1
    	MOVFW	TIME_H10
    	MOVWF	OLD_H10
    
    	MOVLW	_BLUR_LENGTH
    	MOVWF	BLUR_PHASE
    	MOVWF	BLUR_STEP
    
    	INC_SEC
    
    	INC_MIN
    
    	INC_HR
    
    	RETURN
    
    ;===============================================================
    
    	END

View all instructions

Enjoy this project?

Share

Discussions

Stephen Walsh wrote 11/13/2019 at 14:15 point

My understanding of Binary Coded Decimal is that 4 bits are used to represent the digits 0 to 9 and the codes that might otherwise represent the digits 10 to 15 are not used. It is inefficient but sometimes useful and I could certainly understand a clock using it but I don't think this clock does actually use BCD at all. BCD certainly doesn't typically involve a colour code. 

What am I missing here?

  Are you sure? yes | no

Ken Yap wrote 11/13/2019 at 19:35 point

The colour code is additional to the BCD code, as the author says:

>The LEDs used for each 4-bit (or less) digit rolumn are chosen such that if you're color blind, it will just be a classic binary clock.

  Are you sure? yes | no

Mark Jeronimus wrote 09/19/2015 at 15:58 point

Some thoughts on my design choices. 

* I made it with 100% with scrap electronics (and a free sample from Microchip). This means no nicely etched PCB and such.

* I had preferred it if the PCB behind the LEDs was not visible, but I couldn't find a darker PCB. I considered making 30 holes in the front instead of just one but that severely limits viewing angle.

* I don't use RGB LEDs because that makes reading it in binary (for color blind ppl) impossible, and more importantly, the difference between bright and dark colors will quickly disappear.

* I considered using resistor color codes, but it suffers the same brightness problem between some pairs of colors.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates