; ***************************************************************************** ; N i x i e C l o c k ; Version 1.0 ; Written by Davide Bucci ; ***************************************************************************** ; Handle 4 nixies in multiplexing in a nice vintage looking clock ; License: ; -------- ; ; Copyright (C) 2007 Davide Bucci davbucciPleasenospamherE@tiscali.it ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. PROCESSOR 16F84A #include "p16f84a.inc" __CONFIG _HS_OSC & _WDT_OFF & _PWRTE_ON ; Disable watchdog, ; HS oscillator, ; Power on timer on MAX_BTN_COUNT equ 0x8F ; Maximum value of the button counter BLNKCNT equ 1D ; Display blinking counter DISP1 equ 20 ; The first display DISP2 equ 21 DISP3 equ 22 DISP4 equ 23 LASTD equ 24 ; The last display +1 ACTDISP equ 25 SET_T equ 26 ; Used to set hours, minutes, day and month TMP equ 27 STOREW equ 30 ; Store w during interrupt STORES equ 31 ; Store status during interrupt BTN1 equ 32 ; First button counter BTN2 equ 33 HOURS equ 3D MINUTES equ 3E SECONDS equ 3F ; ***************************************************************************** ; The main program ; ***************************************************************************** org 0000 goto start org 0004 goto displaymux start BANKSEL TRISA clrf TRISA ; Ports A and B as outputs clrf TRISB bsf TRISB,6 bsf TRISB,7 bcf OPTION_REG, T0CS ; The clock drives the timer bcf OPTION_REG, PSA ; We use the prescaler bcf OPTION_REG, PS2 ; 011, prescaler to 1:16 bcf OPTION_REG, 7 ; weak pull up on port B inputs ; The interrupt routine is thus called ; Fosc/4/16/256 times per second ; For a 3.2768 MHz crystal, we get 200 times per second BANKSEL PORTA movlw DISP1 ; Activate the first display movwf ACTDISP bsf INTCON, T0IE ; Interrupt on overflow active bsf INTCON, GIE clrf HOURS clrf MINUTES clrf SECONDS clrf BTN1 clrf BTN2 continue btfss PORTB,6 ; test the hour set button call hr_adjust btfss PORTB,7 ; test the minutes set button call mn_adjust call delay goto continue hr_adjust ; increment the hour counter ; An example of concurrent resource handling: we need to ; 'lock' our counters (just by disabling interrupts) bcf INTCON, GIE ; Interrupts OFF incf HOURS movfw HOURS xorlw 0x18 btfsc STATUS, Z clrf HOURS bsf INTCON, GIE ; Interrupts ON return ; increment the minutes counter mn_adjust bcf INTCON, GIE ; Interrupts OFF clrf SECONDS ; Restart second count incf MINUTES movfw MINUTES xorlw 0x3C btfsc STATUS, Z clrf MINUTES bsf INTCON, GIE ; Interrupts ON return delay decfsz BTN1 goto delay decfsz BTN2 goto delay return ; ***************************************************************************** ; Interrupt routine ; ***************************************************************************** displaymux ; Handle the multiplexing movwf STOREW ; Context save (status and w) movfw STATUS movwf STORES decf BLNKCNT, f btfsc STATUS, Z call secondenlapsed btfss BLNKCNT, 7 ; This should be once a second bsf PORTB, 4 ; Blink the seconds lamp btfsc BLNKCNT, 7 bcf PORTB, 4 call loaddisplay call activatedisplay movfw ACTDISP movwf FSR movfw INDF ; Read the nixie content call portnibble ; Send the nibble to the port disp_a incf ACTDISP, f ; Increment the nixie counter movfw ACTDISP xorlw LASTD ; If it is the last display btfsc STATUS, Z ; reset the count call resetc movfw STORES ; Context restore movwf STATUS movfw STOREW bcf INTCON, T0IF ; Clear the interrupt flag retfie ; **** end of the interrupt routine ******************************************* loaddisplay movfw MINUTES clrf TMP sub_dec_m addlw -0xA ; Substract 10(base10) incf TMP, f ; btfsc STATUS, C ; Verify if the result is negative goto sub_dec_m addlw 0x0A ; Add 10(base10) (to compensate the ; last subtraction) decf TMP movwf DISP4 ; units movfw TMP movwf DISP3 ; tenths movfw HOURS clrf TMP sub_dec_h addlw -0xA ; Substract 10(base10) incf TMP, f ; btfsc STATUS, C ; Verify if the result is negative goto sub_dec_h addlw 0x0A ; Add 10(base10) (to compensate the ; last subtraction) decf TMP movwf DISP2 ; units movfw TMP movwf DISP1 ; tenths return ; The refres frequency is 200 Hz. We need to count up to 200 to obtain 1 second secondenlapsed movlw 0xC8 ; 200 in hex movwf BLNKCNT incf SECONDS,f movfw SECONDS xorlw 0x3C btfss STATUS,Z return ; job finished clrf SECONDS incf MINUTES,f ; we need to increase minutes movfw MINUTES xorlw 0x3C btfss STATUS,Z return ; job finished clrf MINUTES incf HOURS,f ; we need to increase hours movfw HOURS xorlw 0x18 btfsc STATUS,Z clrf HOURS return ; job finished ; Restart the refresh from the first display (or nixie) resetc movlw DISP1 ; Reset the display counter movwf ACTDISP return ; Activate the current nixie activatedisplay movfw ACTDISP xorlw DISP1 btfsc STATUS,Z bcf PORTA,0 btfss STATUS,Z bsf PORTA,0 movfw ACTDISP xorlw DISP2 btfsc STATUS,Z bcf PORTA,1 btfss STATUS,Z bsf PORTA,1 movfw ACTDISP xorlw DISP3 btfsc STATUS,Z ; ************************ bcf PORTA,2 ; modify there to use RA2 btfss STATUS,Z ; or RA4 bsf PORTA,2 ; ************************ movfw ACTDISP xorlw DISP4 btfsc STATUS,Z bcf PORTA,3 btfss STATUS,Z bsf PORTA,3 return ; Put the lowest nibble of W in the B0, B1, B2 and B3 outputs portnibble andlw 0x0F ; clear the lower 4 bits of w iorwf PORTB, f ; or this with port B iorlw 0xF0 ; set lower 4 bits of w andwf PORTB, f ; and this with port B retlw 0 ; ***************************************************************************** end