; ------------------------------------------------------------------------ ; FILE : 8digit.asm * ; CONTENTS : Simple low-cost 8-digit counter using a PIC16F84 * ; COPYRIGHT: Peter Halicky OM3CPH * ; AUTHORS : Peter Halicky OM3CPH & Peter Halicky Jr., OM2PH * ; PCB : Tibor Madarasz OM2ATM * ;-------------------------------------------------------------------------- ; E-Mail: peter@halicky.sk ; ; Bratislava, Slovakia, July 2002 - include files modification ; ; To get include files led8t123.exe program should be run. ;-------------------------------------------------------------------------- ; This is 8-digit counter counting up to 16 777 216 Hz. The decimal point ; is after the MHz digit, but can be at any place. More dots can be set. ; ; This project is a variation on later 7-digit frequency meter. ; ; Shematics differs only by 1 transistor connected to pin No. 4 of 4051 ; (it switches anode/cathode of 8ths digit). ; ; PCB is not available....;-( ; ; Power consumption with calculator display: 2.5V/9mA, 3V/13mA, 5V/35mA. ; ; Hardware is very simple: ; ; It contains : PIC 16F84 ; 4051 (BCD -> 1 of 8 decoder) ; 8 NPN low power Si transistors, ; 8-digit calculator display (common cathode), ; some resistors, capacitors and 2 switching diodes ; ; Note: ; "Calculator display" means minimum 8 digit LED multiplexed display. ; Both common cathode and common anode can be used. Software is written ; for common cathode display. For common anode displays it requires very ; slight software and hardware modification. ; ; The counter uses internal prescaler of PIC as low byte of counter, ; TMR0 as middle byte and some register as high byte of counter. ; ; Some ideas were taken from "Simple low-cost digital frequency meter ; using a PIC 16C54" (frqmeter.asm) ; written by James Hutchby, MadLab Ltd. 1996 ; ; +++++++++ izmenjena i tabela mada mozda nije trebalo ili su zaboravili ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ------------------------------------------------------------------------ ; ; This software is free for private usage. It was created for HAM radio ; community members. Commercial exploatation is allowed only with permission ; of authors. ; ; ------------------------------------------------------------------------ list p=16f84, f=inhx8m include "P16F84.inc" BANK0 MACRO ; ovaj makro treba koristiti umesto "BCF STATUS,RP0" ERRORLEVEL +302 BCF STATUS,RP0 ENDM BANK1 MACRO ; a ovaj umesto "BSF STATUS,RP0" BSF STATUS,RP0 ERRORLEVEL -302 ENDM Index equ 0Ch ; dummy register Count equ 0Dh ; inkremental register Help equ 0Eh ; dummy register LED0 equ 0Fh LED1 equ 010h LED2 equ 011h LED3 equ 012h LED4 equ 013h LED5 equ 014h LED6 equ 015h LED7 equ 016h ; now used for last digit TimerH equ 017h ; higher byte of SW counter LowB equ 018h ; low byte of resulted frequency MidB equ 019h ; middle byte of resulted frequency HigB equ 01Ah ; high byte of resulted frequency Temp equ 01Bh ; temporary register HIndex equ 01Ch ; index register LEDIndex equ 01Dh ; LED pointer ; ------------------------------------------------------------------------ include ; ------------------------------------------------------------------------ ; ; Measuring period is 1 000 000 us. ; Procesor cycle is T = 4/fx us [MHz], fx is Xtal frequency ; ; Number of procesor cycles per measuring period: ; ; N = 1 000 000/T procesor cycles ; N = fx * 1 000 000/4 = 250 000 * fx ; ; The main steps of measuring period: ; ; 1. start measurement, ; 2. precode decimal value of digit to segments, ; 3. if it's 6th digit set decimal point, ; 4. output to PORTB, ; 5. output digit number to PORTA ; (number positions from left to right are 76543210), ; 6. test TMR0 overflow bite, if YES increase TimerH, ; 7. leave digit to light, ; 8. increase digit number, ; 9. if <8 goto 2, ; 10. else zero digit number, ; decrease counter and goto 2, ; 11. stop measurement, ; 12. shift out precounter content, ; 13. precode 3-byte value into 8 decimal numbers, ; 14. goto 1 ; ; ------------------------------------------------------------------------ ; ; Total timing formula: ; ; N = 250 000 * fx =255*[(36+3*T1+X)*8+2+3*T2+Y]+19+3*T3+Z ; ; where T1,T2,T3 are initial values of timing loops, ; X, Y, Z are additional tunig NOPs. ; let X=0, Y=0 for simplicity ; ------------------------------------------------------------------------ org 0 Start clrf Index clrf LEDIndex clrf LED0 clrf LED1 clrf LED2 clrf LED3 clrf LED4 clrf LED5 clrf LED6 clrf LED7 clrf LowB clrf MidB clrf HigB BANK1 movlw b'00010000' ; RA0..RA3 outputs movwf TRISA ; RA4 input movlw b'00000000' ; RB0..RB7 outputs movwf TRISB clrwdt ; movlw b'00100111' ; Prescaler -> TMR0, movwf OPTION_REG ; 1:256, rising edge BANK0 goto Go ;------------------------------------------------------------------------ ; 3 byte substraction of the constant from the table which sets carry if ; result is negative ;------------------------------------------------------------------------ Subc24 clrf Temp ; it will temporary save C movf Index,W ; pointer to low byte of constant movwf HIndex ; W -> HIndex call DecTable ; W returned with low byte of constant bsf STATUS,C ; set C subwf LowB,F ; LowB - W -> LowB ; if underflow -> C=0 btfsc STATUS,C goto Step1 bsf STATUS,C movlw 1 subwf MidB,F ; decrement MidB ; if underflow -> C=0 btfsc STATUS,C goto Step1 bsf STATUS,C movlw 1 subwf HigB,F ; decrement HigB btfsc STATUS,C ; if underflow -> C=0 goto Step1 bsf Temp,C ; set C Step1 decf HIndex,F movf HIndex,W ; pointer to middle byte of const call DecTable bsf STATUS,C subwf MidB,F ; MidB - W -> MidB btfsc STATUS,C ; if underflow -> C=0 goto Step2 bsf STATUS,C movlw 1 subwf HigB,1 ; decrement HigB btfsc STATUS,C ; if underflow -> C=0 goto Step2 bsf Temp,C ; set C Step2 decf HIndex,F movf HIndex,W ; pointer to middle byte of constatnt call DecTable bsf STATUS,C subwf HigB,F ; HigB - W -> HigB btfsc STATUS,C ; if underflow -> C=0 goto ClearCF bsf STATUS,C goto SubEnd ClearCF rrf Temp,C ; C -> STATUS SubEnd retlw 0 ; ------------------------------------------------------------------------ ; 3 byte addition of the constant from the table which sets carry if ; result overflows ; ------------------------------------------------------------------------ Addc24 clrf Temp ; register for temporary storage of C movf Index,W ; pointer to lower byte of const into W movwf HIndex ; save it into HIndex call DecTable ; W contains low byte of const bcf STATUS,C ; clear C addwf LowB,1 ; W + LowB -> LowB btfss STATUS,C ; test overflow goto Add2 bcf STATUS,C ; clear C movlw 1 addwf MidB,F ; increment MidB btfss STATUS,C goto Add2 bcf STATUS,C movlw 1 addwf HigB,F ; increment HigB btfss STATUS,C ; test overflow goto Add2 bsf Temp,C ; store C Add2 decf HIndex,F ; pointer to middle byte into W movf HIndex,W call DecTable bcf STATUS,C addwf MidB,1 ; W + MidB -> MidB btfss STATUS,C goto Add3 bcf STATUS,C ; clear C movlw 1 addwf HigB,1 ; increment HigB btfss STATUS,C goto Add3 bsf Temp,C Add3 decf HIndex,F ; pointer to higher byte into W movf HIndex,W call DecTable bsf STATUS,C addwf HigB,F ; W + HigB -> HigB, btfss STATUS,C goto ClarCF bsf STATUS,C goto AddEnd ClarCF rrf Temp,C ; C -> STATUS AddEnd retlw 0 ; ------------------------------------------------------------------------ ; Tables for 3 byte constants ; ------------------------------------------------------------------------ ; Table of decades ; ------------------------------------------------------------------------ DecTable addwf PCL,F ; W + PCL -> PCL retlw 0 ; 10 retlw 0 ; retlw 0Ah ; retlw 0 ; 100 retlw 0 ; retlw 064h ; retlw 0 ; 1 000 retlw 03h ; retlw 0E8h ; retlw 0 ; 10 000 retlw 027h ; retlw 010h ; retlw 01h ; 100 000 retlw 086h ; retlw 0A0h ; retlw 0Fh ; 1 000 000 retlw 042h ; retlw 040h ; retlw 098h ; 10 000 000 retlw 096h ; retlw 080h ; ; ------------------------------------------------------------------------ ; Table for conversion BCD -> 7 segments ; The view of numbers can be freely modified.... :-) ; ------------------------------------------------------------------------ ;za common ANODE LEDTable addwf PCL,F ; W + PCL -> PCL retlw b'11000000' ; ..FEDCBA = '0' retlw b'11111001' ; .....CB. = '1' retlw b'10100100' ; .G.ED.BA = '2' retlw b'10110000' ; .G..DCBA = '3' retlw b'10011001' ; .GF..CB. = '4' retlw b'10010010' ; .GF.DC.A = '5' retlw b'10000010' ; .GFEDC.A = '6' retlw b'11111000' ; .....CBA = '7' retlw b'10000000' ; .GFEDCBA = '8' retlw b'10011000' ; .GF..CBA = '9' retlw b'01111111' ; H....... = '.' ; ------------------------------------------------------------------------ ; Routine for conversion of 3 byte number into 8 digits ; ------------------------------------------------------------------------ Go BANK1 clrf TRISB BANK0 movlw 7*3-1 ; pointer to dec. table movwf Index ; 7*3-1 -> Index movlw 9 ; maximum of substractions movwf Count ; 9 -> Count clrf Help movlw 7 movwf LEDIndex Divide call Subc24 ; substract untill result is negative, btfsc STATUS,C ; if so, add last substracted number goto Add24 ; if not, next digit incf Help,F decf Count,F btfss STATUS,Z goto Divide movlw 3 subwf Index,F goto Next Add24 call Addc24 movlw 03h subwf Index,F Next movlw 9 movwf Count movlw LED1 ; LED1 -> W addwf LEDIndex,W ; LED1 + LEDIndex -> W movwf Temp decf Temp,F ; LEDIndex+LED1-1 -> TEMP movf Temp,W movwf FSR ; W -> FSR movf Help,W ; Help -> W clrf Help ; save result at LEDx movwf INDF ; W -> LED(7..1) decf LEDIndex,F movlw 1 addwf Index,W btfss STATUS,Z goto Divide movf LowB,W movwf LED0 ; the rest -> LED0 ; ------------------------------------------------------------------------- ; The registers LED0..LED7 are filled with decimal values ; ------------------------------------------------------------------------- clrf TimerH clrf TMR0 nop ; this seems to be suggested nop clrf LEDIndex movlw 0FFh ; set initial counter value movwf Index ; 255 -> Index clrf INTCON ; global INT disable, TMR0 INT disable ; clear TMR0 overflow bite ; ------------------------------------------------------------------------ ; Start measurement: RA3 + RA4 set input ; ------------------------------------------------------------------------ movlw b'00010000' ; all ports set L, RA4 set H movwf PORTA BANK1 movlw b'00011000' ; RA0..RA2 output,RA3,RA4 input movwf TRISA BANK0 ; ------------------------------------------------------------------------- ; 8-step cycle of digits ; ------------------------------------------------------------------------- LEDCycle movlw LED0 addwf LEDIndex,W ; LED1 + LEDIndex -> W movwf FSR ; W -> FSR movf INDF,W ; LED(0..7) -> W call LEDTable ; W contains segments movwf Temp ; test for decimal point movlw 6 ; can be set at any position bsf STATUS,Z ; or more than one dot can be set subwf LEDIndex,W ; or none too, of course btfss STATUS,Z ; only slight modification of this part goto NoDot ; of source code is needed... ; bsf Temp,7 bcf Temp,7 ; common anode.... NoDot movf Temp,W movwf PORTB ; segments -> PORTB movf LEDIndex,W ; LEDIndex -> W nop movwf PORTA ; digit number -> PORTA ; ------------------------------------------------------------------------ ; Test for TMR0 overflow ; ------------------------------------------------------------------------ btfss INTCON,2 goto DoNothing incf TimerH,F ; YES! Increment SW counter bcf INTCON,2 ; clear overflow bite goto O_K DoNothing nop nop nop ; ------------------------------------------------------------------------ ; The first timing loop 2+3*T1+X procesor cycles ; ------------------------------------------------------------------------ O_K movlw T1 movwf Temp Pause decfsz Temp,F goto Pause nop ;+-----------------------------------------------------------------------+ ;| The end of one digit processing | ;+-----------------------------------------------------------------------+ incf LEDIndex,F movlw 8 ; is 8th? bcf STATUS,Z subwf LEDIndex,W btfss STATUS,Z goto LEDCycle ; next digit nop ; ------------------------------------------------------------------------ ; The second timing loop 2+3*T2+Y procesor cycles ; ------------------------------------------------------------------------ movlw T2 movwf Temp Again decfsz Temp,F goto Again nop ;+-----------------------------------------------------------------------+ ;| The end of one 8-digits processing | ;+-----------------------------------------------------------------------+ clrf LEDIndex decfsz Index,F goto LEDCycle ; next 8xLED nop ; ------------------------------------------------------------------------ ; The third timing loop 2+3*T3+Z procesor cycles ; ------------------------------------------------------------------------ movlw T3 movwf Temp EndPause decfsz Temp,F goto EndPause nop include ; nop ; Z times NOP ; ------------------------------------------------------------------------ ; Final test for TMR0 overflow before stoping measurement ; ------------------------------------------------------------------------ btfss INTCON,2 goto Nothing2Do incf TimerH,F bcf INTCON,2 goto Nx Nothing2Do nop nop nop ; ------------------------------------------------------------------------ ; Stop the measurement ; ------------------------------------------------------------------------ ;Nx clrw ; For common cathode Nx movlw b'11111111' ; For common anode movwf PORTB movlw b'00010000' ; RA0..RA3 = 0 movwf PORTA ; W -> PORTA BANK1 movlw b'00010000' ; RA0..RA3 output movwf TRISA ; RA4 input BANK0 btfsc INTCON,2 ; really final check incf TimerH,F bcf INTCON,2 ; ------------------------------------------------------------------------ ; Analyse precounter and store counted value in registers ; ------------------------------------------------------------------------ movf TMR0,W movwf MidB ; TMR0 -> MidB movf TimerH,W movwf HigB ; TimerH -> HigB clrf Temp CountIt incf Temp,F bsf PORTA,3 ; _| false impulz bcf PORTA,3 ; |_ bcf INTCON,2 movf TMR0,W ; actual TMR0 -> W bcf STATUS,Z subwf MidB,W btfsc STATUS,Z goto CountIt incf Temp,F comf Temp,F incf Temp,F incf Temp,W movwf LowB goto Go ; start new cycle ; ------------------------------------------------------------------------ end