; Simple 4 1/2 digit counter for the Seimens DL2416T ASCII display. ; File: simple_rf.asm ; ; Global Assembler directives list c=132, n=80 list p=16f84a ; ; This program implements a very simple counter. It uses the external ; TMR0 input for counting. It drives an ASCII display and a bi-color ; LED. The LED is lit one way when the counter first rolls over ; and then the other way when it rolls over again and subsequently. ; This allows views of counts from 0-19999 and indication of overflow. ; ; Only 5 connections are made to the display since we only need to display ; a Blank character (0x20) or a numeric character (0x30 - 0x39). ; ; Display Data Line ; ----------------- ; 0 DATA 0 ; 1 DATA 1 ; 2 DATA 2 ; 3 DATA 3 ; 4 nBLANK ; 5 VCC ; 6 Ground ; ; ; Copyright (c) 2006 Dan Julio. Some rights reserved. ; Licensed under a Creative Commons Attribution 3.0 License ; Please see http://creativecommons.org/licenses/by/3.0/legalcode ; ; Revision History ; 09/16/06 Revision 1.0 DJJ First pass ; ; ; ------------------------------------------------------------------------ ; Processor Information: ; ; Target processor: PIC 16C84A ; Processor frequency: Any but the faster the clock, the higher the count rate ; 1 MHz ( 4 uSec instruction cycle) ; 4 MHz ( 1 uSec instruction cycle) ; 8 MHz (500 nSec instruction cycle) ; 10 MHz (400 nSec instruction cycle) ; 20 MHz (200 nSec instruction cycle) ; ; Memory Layout ; Page 0: 0x000 - 0x0FF Main code, Interrupt handler and subroutines ; Page 1: 0x100 - 0x1FF Not used ; Page 2: 0x200 - 0x2FF Not used ; Page 3: 0x300 - 0x3FF Not used ; ; Input/Output Pin Assignments (DIP package) ; ; Pin Signal Polarity I/O Default State ; ------------------------------------------------------------------------ ; 17 RA0 LED 1 Active Low Output 1 ; 18 RA1 LED 2 Active Low Output 1 ; 1 RA2 Reserved Active High Output 0 ; 2 RA3 Reserved Active High Output 0 ; 3 RA4 Clock input Active High Input 0 ; 6 RB0 Data[0] Active High Output 0 ; 7 RB1 Data[1] Active High Output 0 ; 8 RB2 Data[2] Active High Output 0 ; 9 RB3 Data[3] Active High Output 0 ; 10 RB4 nBlank Active High Output 1 ; 11 RB5 Address[0] Active High Ouptut 0 ; 12 RB6 Address[1] Active High Output 0 ; 13 RB7 nWrite Active Low Output 1 ; ; ------------------------------------------------------------------------ ; File Layout: ; ; 1. Configuration Bits ; 2. Program Constants ; 3. Macro definitions ; 4. Main code ; 5. Main code subroutines ; 6. Interrupt routines ; 7. Interrupt subroutines ; ; ; ------------------------------------------------------------------------ ; Configuration Bits _CP_ON EQU H'000F' _CP_OFF EQU H'3FFF' _PWRTE_ON EQU H'3FF7' _PWRTE_OFF EQU H'3FFF' _WDT_ON EQU H'3FFF' _WDT_OFF EQU H'3FFB' _LP_OSC EQU H'3FFC' _XT_OSC EQU H'3FFD' _HS_OSC EQU H'3FFE' _RC_OSC EQU H'3FFF' ; Set the device configuration bits __config _CP_OFF & _PWRTE_ON & _XT_OSC & _WDT_ON ; ------------------------------------------------------------------------ ; Program Constants ; ; Reset and Interrupt vector locations MAIN_VECTOR equ 0x005 INT_VECTOR equ 0x080 ; PIC Internal register equates W equ .0 F equ .1 ; Bank 0 and registers in all banks INDF equ 0x0 TMR0 equ 0x1 PCL equ 0x2 STATUS equ 0x3 FSR equ 0x4 PORT_A equ 0x5 PORT_B equ 0x6 EEDATA equ 0x8 EEADR equ 0x9 PCLATH equ 0xA INTCON equ 0xB ; Bank 1 specific OPTION_REG equ 0x1 TRISA equ 0x5 TRISB equ 0x6 EECON1 equ 0x8 EECON2 equ 0x9 ; ; PIC Internal STATUS register bits CARRY equ .0 DC equ .1 Z equ .2 PD equ .3 TO equ .4 RP0 equ .5 RP1 equ .6 IRP equ .7 ; ; Interrupt sources in the INTCON register RBIF_INT equ .0 INTF_INT equ .1 T0IF_INT equ .2 ; ; Interrupt enable bits in the INTCON register RBIE equ .3 INTE equ .4 T0IE equ .5 EEIE equ .6 GIE equ .7 ; ; EECON1 control bits RD equ .0 WR equ .1 WREN equ .2 WRERR equ .3 EEIF equ .4 ; ; External device bits (port number bits) LED_1 equ .0 ; Set low for Green (with LED_2 high) LED_2 equ .1 ; Set low for Red (with LED_1 high) CLK_IN equ .4 DATA_0 equ .0 DATA_1 equ .1 DATA_2 equ .2 DATA_3 equ .3 BLANKN equ .4 ADDR_0 equ .5 ADDR_1 equ .6 WRN equ .7 ; ; Flags variable bits (all active true) Blank_0 equ .0 ; Will never be set Blank_1 equ .1 Blank_2 equ .2 Blank_3 equ .3 ; ; Variable register equates Flags equ 0x20 Digit_1 equ 0x21 Digit_2 equ 0x22 Digit_3 equ 0x23 Temp equ 0x24 PrevTmr0 equ 0x25 ; ; Interrupt state save registers W_Temp equ 0x40 STATUS_Temp equ 0x41 PCLATH_Temp equ 0x42 ; ; PIC Initialization constants STATUS_SETUP equ B'00011000' ; 7: IRP = 0 (page 0-1) ; 6:5: RP1:0 = 00b (page 0) ; 4: TO = 1 (default state) ; 3: PD = 1 (default state) ; 2: Z = 0 ; 1: DC = 0 ; 0: C = 0 OPTION_SETUP equ B'11101100' ; 7: RBPU = 1 (disable pull-ups) ; 6: INTEDG = 1 (Int on rising edge RB0/INT) ; 5: T0CS = 1 (external TMR0 clock) ; 4: T0SE = 0 (rising TMR0 clock) ; 3: PSA = 1 (prescaler to WDT) ; 2:0: prescaler = 100b (1:16) INTCON_SETUP equ B'10100000' ; 7: GIE = 1 (interrupts enabled) ; 6: EEIE = 0 (EE Write Complete ints disabled) ; 5: T0IE = 1 (TMR0 ints enabled) ; 4: INTE = 0 (INT ints disabled) ; 3: RBIE = 0 (RB ints disabled) ; 2: T0IF = 0 ; 1: INTF = 0 ; 0: RBIF = 0 PORTA_INIT equ B'00000011' ; All to default disabled state PORTB_INIT equ B'10010000' ; All to default states PORTA_OE equ B'00010000' ; RA[3:0] outputs PORTB_OE equ B'00000000' ; All outputs ; ; Constants UPDATE_INIT equ 0x90 ; Prepare PORT_B for display update ; ------------------------------------------------------------------------ ; Macro Definitions ; ; ------------------------------------------------------------------------ ; Main Code Block ; ; The Main Code Block performs the initialization and mode selection/display ; functions. ; ; ---------------------------------------------------------------- ; Reset Vector org 0x0 goto MAIN_VECTOR ; ---------------------------------------------------------------- ; Interrupt Vector org 0x4 goto INT_VECTOR ; ---------------------------------------------------------------- ; Start of main initialization code ; org MAIN_VECTOR MAIN_VECTOR ; Initialize common PIC control registers in page 0 movlw 0xF6 ; value "0" movwf TMR0 clrf FSR clrf PCLATH movlw STATUS_SETUP movwf STATUS movlw PORTA_INIT movwf PORT_A movlw PORTB_INIT movwf PORT_B ; Initialize common PIC control registers in page 1 bsf STATUS,RP0 ; Point to page 1 registers movlw OPTION_SETUP movwf OPTION_REG movlw PORTA_OE movwf TRISA movlw PORTB_OE movwf TRISB bcf STATUS,RP0 ; Point to page 0 registers again ; Initialize common variables movlw 0x0E movwf Flags clrf Digit_1 clrf Digit_2 clrf Digit_3 call UpdateDisplay movlw 0xF6 ; value "0" movwf PrevTmr0 ; Enable interrupts before starting normal operation movlw INTCON_SETUP movwf INTCON MAIN_LOOP clrwdt ; Clear the watchdog timer ; Look for changes in TMR0, but exclude roll-over condition ; that will be handled by the interrupt routine movf TMR0,W subwf PrevTmr0,W ; W = PrevTmr0 - TMR0 btfsc STATUS,Z ; PrevTmr0 == TMR0? goto MAIN_LOOP ; Y : Do nothing ; N : Check to see if we should udpate digit 0 ; Check for roll-over movf TMR0,W movwf PrevTmr0 ; PrevTmr0 = TMR0 movlw 0x00 subwf TMR0,W ; W = TMR0 - 0 btfss STATUS,Z ; TMR0 == 0? call UpdateDigit0 ; N : Only units digit changed, update digit 0 goto MAIN_LOOP ; Y : Do nothing (udpate display handled in ISR) ; ------------------------------------------------------------------------ ; Main Code Subroutines ; UpdateDigit0 ; Digit 0 movlw UPDATE_INIT movwf PORT_B movlw .9 movwf Temp ; Temp = 9 comf TMR0,W ; W = !TMR0 (0xFF - TMR0) subwf Temp,W ; W = 9 - (0xFF - TMR0) [0-9] iorwf PORT_B,F ; Update Data[3:0] bcf PORT_B,WRN bsf PORT_B,WRN return UpdateDisplay ; Digit 0 call UpdateDigit0 ; Digit 1 movlw UPDATE_INIT movwf PORT_B bsf PORT_B,ADDR_0 btfsc Flags,Blank_1 ; Check for digit blanking bcf PORT_B,BLANKN movf Digit_1,W iorwf PORT_B,F ; Update Data[3:0] bcf PORT_B,WRN bsf PORT_B,WRN ; Digit 2 movlw UPDATE_INIT movwf PORT_B bsf PORT_B,ADDR_1 btfsc Flags,Blank_2 ; Check for digit blanking bcf PORT_B,BLANKN movf Digit_2,W iorwf PORT_B,F ; Update Data[3:0] bcf PORT_B,WRN bsf PORT_B,WRN ; Digit 3 movlw UPDATE_INIT movwf PORT_B bsf PORT_B,ADDR_0 bsf PORT_B,ADDR_1 btfsc Flags,Blank_3 ; Check for digit blanking bcf PORT_B,BLANKN movf Digit_3,W iorwf PORT_B,F ; Update Data[3:0] bcf PORT_B,WRN bsf PORT_B,WRN return ; ------------------------------------------------------------------------ ; Interrupt Code Block ; ; The Interrupt Code Block handles interrupts from the Timer when it ; rolls over from 0xFF to 0x0. ; org INT_VECTOR INT_VECTOR ; Save interrupt state movwf W_Temp swapf STATUS,W clrf STATUS movwf STATUS_Temp movf PCLATH,W movwf PCLATH_Temp clrf PCLATH ; Make sure this interrupt is really due to the T0IF Input btfsc INTCON,T0IF_INT call HandleTimer ; Restore interrupt state movf PCLATH_Temp,W movwf PCLATH swapf STATUS_Temp,W movwf STATUS swapf W_Temp,F swapf W_Temp,W ; Return from the interrupt (and re-enable interrupts) retfie ; ------------------------------------------------------------------------ ; Interrupt Code Subroutines ; HandleTimer ; Reset the timer movlw 0xF6 movwf TMR0 ; Update other digit counters movlw Digit_1 movwf FSR ; Point to first digit counter HANDLE_TIMER_1 ; Update one digit incf INDF,F ; Digit[FSR]++ movlw .10 subwf INDF,W ; W = Digit[FSR] - 10 btfss STATUS,Z ; Digit[FSR] == 10? goto HANDLE_TIMER_4 ; N : no carry out, can stop updating digits clrf INDF ; Y : wrapped around: Digit[FSR]=0, carry out ; Increment index movlw Digit_3 subwf FSR,W ; W = FSR - Digit_3 btfsc STATUS,Z ; FSR == Digit_3? goto HANDLE_TIMER_2 ; Y : Done, but carry out of digit 3 incf FSR,F ; N : increment to next digit goto HANDLE_TIMER_1 HANDLE_TIMER_2 ; Update overflow indication btfss PORT_A,LED_2 ; LED_2 = 0? (already indicating multiple overflows?) goto HANDLE_TIMER_4 ; Y : nothing more to do ; N : Then check if we're indicating 1st overflow btfss PORT_A,LED_1 ; LED_1 = 1? (no overflows indicated yet?) goto HANDLE_TIMER_3 ; N : Flip values to change from 1st to multiple bcf PORT_A,LED_1 ; Y : Set Green (1st overflow) goto HANDLE_TIMER_4 HANDLE_TIMER_3 bsf PORT_A,LED_1 ; Set multiple overflow state bcf PORT_A,LED_2 HANDLE_TIMER_4 ; Update blanked digit flags clrf Flags ; Set default value for blanking flags ; Digit 3 movf Digit_3,W ; W = Digit_3 btfss STATUS,Z ; Digit_3 == 0? goto HANDLE_TIMER_5 ; N : Done checking bsf Flags,Blank_3 ; Y : This digit blank, check next ; Digit 2 movf Digit_2,W ; W = Digit_2 btfss STATUS,Z ; Digit_2 == 0? goto HANDLE_TIMER_5 ; N : Done checking bsf Flags,Blank_2 ; Y : This digit blank, check next ; Digit 1 movf Digit_1,W ; W = Digit_1 btfsc STATUS,Z ; Digit_1 == 0? bsf Flags,Blank_1 ; Y : This digit blank, check next ; N : Done checking HANDLE_TIMER_5 ; Udpate display call UpdateDisplay ; Clear the interrupt flag bcf INTCON,T0IF_INT return end