;+------------------------------------------------------------------------ ; CONTENTS : Simple low-cost 7-digit digital scale using a PIC16F84 ; for 2m band receiver - concept with multiplied VCXO ; COPYRIGHT: Peter Halicky OM3CPH ; AUTHORS : Peter Halicky OM3CPH & Peter Halicky Jr., OM2PH ex OM2APH ; PCB : Tibor Madarasz OM2ATM ;+------------------------------------------------------------------------ ; E-Mail: peter_sr@halicky.sk ; Bratislava,Slovakia, February, 2003 ;+------------------------------------------------------------------------ ; This is 7-digit digital scale measuring frequency up to 35 MHz. The ; decimal point is after MHz digit, but can be set at any position. Two ; dots can be set too (timing formula should change!). ; Input is from tuned Xtal oscillator (VXO) which is multiplied by 8 to ; get required frequency (19.00-19.05)*8=(152-152.4)MHz. ; -8 -8 MHz IF ; ------------------ ; 144-144.4 MHz ;------------------------------------------------------------------------ ; Hardware is very simple: ; ; It contains : PIC 16F84 ; 4051 (BCD -> 1 of 8 decoder) ; 8 NPN (or PNP for common anode) low power Si trans., ; 7-digit display (common cathode or anode), ; some resistors, capacitors and 2 switching diodes ;------------------------------------------------------------------------ ; The device is derived from "Simple 7-digit digital scale". ; ; LED0 is set to display 1! All places are shifted right. The tuning reso- ; lution is 100 Hz. Only 6 digits are displaying measured frequency. ;+------------------------------------------------------------------------ ; Measuring period is 100 000 us. ; Procesor cycle is T = 4/Fx us [MHz], fx is Xtal frequency ; ; Number of procesor cycles per measuring period: ; ; N = 100 000/T procesor cycles ; N = Fx * 100 000/4 = 25 000 * Fx ; N = 60*[7*(36 + 3*T1) + 6 + 3*T2] + 12 + 3*T3 + Z ; ; The main steps of measuring period: ; ; 1. start measurement, ; 2. precode decimal value of digit to segments, ; 3. if it's 3rd digit set decimal point, ; 4. output to PortB, ; 5. output digit number to PortA ; (numbers from left to right are 6543210), ; 6. test TMR0 overflow bite, if YES increase TimerH, ; 7. leave digit to light, ; 8. increase digit number, ; 9. if <7 goto 2, ; 10. else zero digit number, decrease counter and goto 2, ; 11. stop measurement, ; 12. shift out precounter content, ; 13. substract 100MHZ + IF, ; 14. precode 3-byte value into 7 decimal numbers, ; 15. shift all numbers to right, ; 16. set LED0 = 1 ; 17. goto 1 ; ;+------------------------------------------------------------------------ ; Some ideas were taken from "Simple low-cost digital frequency meter ; using a PIC 16C54" (frqmeter.asm) ; written by James Hutchby, MadLab Ltd. 1996 ;+------------------------------------------------------------------------ ; This software is free for private usage. It was created for HAM radio ; community members. Commercial exploatation is allowed only with ; permission of authors. ;+------------------------------------------------------------------------ ; include include ;-------------------------------------------------------------------------- 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 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 ;-------------------------------------------------------------------------- ; timing loop values include ;-------------------------------------------------------------------------- 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 bsf STATUS,RP0 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 bcf STATUS,RP0 ; goto Go ; line 370 ;+------------------------------------------------------------------------- ;+ The block of subroutines and constants tables ;+------------------------------------------------------------------------- ;+------------------------------------------------------------------------- ; 3 byte substraction of the constant from the table, it sets carry ; if result is negative ;+------------------------------------------------------------------------- Subc24 clrf Temp ; it will temporary save CF 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 CF 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, it sets carry if ; result overflows ;+------------------------------------------------------------------------- Addc24 clrf Temp ; register for temporary storage of CF 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 of 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 ; ;+------------------------------------------------------------------------+ ; 100 MHz table ;+------------------------------------------------------------------------+ XTable addwf PCL,F ; W + PCL -> PCL retlw 098h ; 10.000.000 retlw 096h ; retlw 080h ; ;+-----------------------------------------------------------------------+ ; Table for conversion BCD -> 7 segments ;+-----------------------------------------------------------------------+ LEDTable addwf PCL,F ; W + PCL -> PCL ; retlw b'00111111' ; ..FEDCBA = '0' ; retlw b'00000110' ; .....CB. = '1' ; retlw b'01011011' ; .G.ED.BA = '2' ; retlw b'01001111' ; .G..DCBA = '3' ; retlw b'01100110' ; .GF..CB. = '4' ; retlw b'01101101' ; .GF.DC.A = '5' ; retlw b'01111101' ; .GFEDC.A = '6' ; retlw b'00000111' ; .....CBA = '7' ; retlw b'01111111' ; .GFEDCBA = '8' ; retlw b'01100111' ; .GF..CBA = '9' ; retlw b'10000000' ; H....... = '.' ;It follows COMMON ANODE data table 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....... = '.' ;+-----------------------------------------------------------------------+ ; Table for IF shift ;+-----------------------------------------------------------------------+ ; example: ; 108.0 MHz for 2m TRx with IF = 8 MHz ; 10 800 000 = A4 CB 80 hex ;+-----------------------------------------------------------------------+ IFTable addwf PCL,F include ;+------------------------------------------------------------------------+ ; The main cycle entry point ;+------------------------------------------------------------------------+ ; Routine forconversion of 3-byte number into 7 digits ;+------------------------------------------------------------------------+ Go bsf STATUS,RP0 movlw b'00000000' movwf TRISB bcf STATUS,RP0 movlw 6*3-1 ; pointer to dec. table movwf Index ; 6*3-1 -> Index movlw 9 ; maximum of substractions movwf Count ; 9 -> Count clrf Help movlw 6 movwf LEDIndex Divide call Subc24 ; substract untill result is negative, btfsc STATUS,C ; add last substracted number goto Add24 ; next digit incf Help,F decf Count,F btfss STATUS,Z goto Divide movlw 3 subwf Index,F goto Next Add24 call Addc24 movlw 3 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(6..1) decf LEDIndex,F movlw 1 addwf Index,W btfss STATUS,Z goto Divide movf LowB,W movwf LED0 ; the rest -> LED0 ;+-----------------------------------------------------------------------+ ; Shift to right one digit. ;+-----------------------------------------------------------------------+ movf LED1,W movwf LED0 movf LED2,W movwf LED1 movf LED3,W movwf LED2 movf LED4,W movwf LED3 movf LED5,W movwf LED4 movf LED6,W movwf LED5 movlw 1 ; set the first "1" movwf LED6 ;+-----------------------------------------------------------------------+ ; Registers LED0..LED6 are filled with values ;+-----------------------------------------------------------------------+ clrf TimerH clrf TMR0 nop nop clrf LEDIndex movlw .60 ; set initial counter value movwf Index ; 60 -> Index clrf INTCON ; global INT disable, TMR0 INT disable ; clear TMR0 overflow bite ;+---------------------------------------------------------------------+ ; Start of the measurement: RA3 + RA4 set input ;+---------------------------------------------------------------------+ movlw b'00010000' ; all ports set L, RA4 set H movwf PORTA bsf STATUS,RP0 movlw b'00011000' ; RA0..RA2 output, RA3, RA4 input movwf TRISA bcf STATUS,RP0 ;+-----------------------------------------------------------------------+ ; 7-step cycle of digits ;+-----------------------------------------------------------------------+ LEDCycle movlw LED0 ; 1 addwf LEDIndex,W ; 2 LED1 + LEDIndex -> W movwf FSR ; 3 W -> FSR movf INDF,W ; 4 LED(0..6) -> W call LEDTable ; 9 W contains segments movwf Temp ; 10 test for decimal point ; movlw 5 ; 11 movlw 3 ; 11 bsf STATUS,Z ; 12 subwf LEDIndex,W ; 13 btfss STATUS,Z ; 14 goto NoDot ; 16 ; bsf Temp,7 ; 16 common cathode.... bcf Temp,7 ; 16 common anode.... NoDot movf Temp,W ; 17 movwf PORTB ; 18 segments -> PORTB movf LEDIndex,W ; 19 LEDIndex -> W nop ; 20 movwf PORTA ; 21 digit number -> PORTA ;+------------------------------------------------------------------------ ;Test for TMR0 overflow ;+------------------------------------------------------------------------ btfss INTCON,2 ; 22 Test for TMR0 overflow goto DoNothing ; 24 incf TimerH,F ; 24 YES! Increment SW counter bcf INTCON,2 ; 25 clear overflow bite goto O_K ; 27 DoNothing nop ; 25 nop ; 26 nop ; 27 ;+----------------------------------------------------------------------- ; The first timing loop 2+3*T1 procesor cycles ;+----------------------------------------------------------------------- O_K movlw T1 ; 28 movwf Temp ; 29 Pause decfsz Temp,F goto Pause nop ; 29 + 3*T1 ;+----------------------------------------------------------------------- ; The end of one digit processing ;+----------------------------------------------------------------------- incf LEDIndex,F ; 30 movlw 7 ; 31 is 7th? bcf STATUS,Z ; 32 subwf LEDIndex,W ; 33 btfss STATUS,Z ; 34 goto LEDCycle ; 36 next digit nop ; 36 + 3*T1 ;+----------------------------------------------------------------------- ; The second timing loop 2+3*T2 procesor cycles ;+----------------------------------------------------------------------- movlw T2 ; 1 + 7 * (36 + 3*T1) movwf Temp ; 2 Again decfsz Temp,F goto Again nop ; 2 + 7 * (36 + 3*T1) + 3*T2 ;+-----------------------------------------------------------------------+ ; The end of one 7-digits processing ;+-----------------------------------------------------------------------+ clrf LEDIndex ; 3 + ... decfsz Index,F ; 4 + ... goto LEDCycle ; 6 + ... next 7 * LED nop ; 60*[7*(36 + 3*T1) + 6 + 3*T2] ;+-----------------------------------------------------------------------+ ; The third timing loop 2+3*T3+Z procesor cycles ;+-----------------------------------------------------------------------+ movlw T3 ; 1 + movwf Temp ; 2 + EndPause decfsz Temp,F goto EndPause nop include ; nop ; Z times NOP ; nop ; 60*[7*(36 + 3*T1) + 6 + 3*T2] + 2 + 3*T3 + Z ; ------------------------------------------------------------------------ ; Final test for TMR0 overflow ; ------------------------------------------------------------------------ btfss INTCON,2 ; 1 goto Nothing2Do ; 3 incf TimerH,F ; 3 bcf INTCON,2 ; 4 goto Nx ; 6 Nothing2Do nop ; 4 nop ; 5 nop ; 6 60*[7*(36 + 3*T1) + 6 + 3*T2] + 8 + 3*T3 + Z ;+---------------------------------------------------------------------+ ;+ Stop of themeasurement: RA3 set output RA4 set input + ;+---------------------------------------------------------------------+ ;Nx clrw ; 7 For common cathode Nx movlw b'11111111' ; 7 For common anode movwf PORTB ; 8 movlw b'00010000' ; 9 RA0..RA3 = 0 movwf PORTA ; 10 W -> PORTA ; 60*[7*(36 + 3*T1) + 6 + 3*T2] + 12 + 3*T3 + Z bsf STATUS,RP0 ; 11 movlw b'00010000' ; 12 RA0..RA3 output movwf TRISA ; 13 RA4 input bcf STATUS,RP0 ; 14 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 ;----------------------------------------------------------------------- ; Multiplication of all three registers by 8 to get reall frequency ;----------------------------------------------------------------------- bcf STATUS,C rlf LowB,F ; shift left through Carry = *2 rlf MidB,F rlf HigB,F bcf STATUS,C rlf LowB,F ; *2*2 rlf MidB,F rlf HigB,F bcf STATUS,C rlf LowB,F ; *2*2*2 rlf MidB,F rlf HigB,F bcf STATUS,C movlw 0 ; prepare substraction F - IF call IFTable movwf LED4 ; HighMF -> LED4 movf HigB,W movwf LED0 ; HighB -> LED0 movlw 1 call IFTable movwf LED5 ; MiddleMF -> LED5 movf MidB,W movwf LED1 ; MidB -> LED1 movlw 2 call IFTable movwf LED6 ; LowMF -> LED6 movf LowB,W movwf LED2 ; LowB -> LED2 ;+-----------------------------------------------------------------------+ ; Registers are ready, continue with substraction ;+-----------------------------------------------------------------------+ movf LED6,W bsf STATUS,C ; set C subwf LED2,F ; LED2 - LED6 -> LED2 btfsc STATUS,C goto S1 bsf STATUS,C movlw 1 subwf LED1,F btfsc STATUS,C goto S1 bsf STATUS,C movlw 1 subwf LED0,F btfsc STATUS,C goto S1 S1 movf LED5,W bsf STATUS,C subwf LED1,F ; LED1 - LED5 -> LED1 btfsc STATUS,C goto S2 bsf STATUS,C movlw 1 subwf LED0,F ; decrement LED0 btfsc STATUS,C goto S2 S2 movf LED4,W subwf LED0,F ; LED0 - LED4 -> LED0 ;+-----------------------------------------------------------------------+ ; Substraction is finished, now store result to frequency registers ;+-----------------------------------------------------------------------+ movf LED0,W movwf HigB movf LED1,W movwf MidB movf LED2,W movwf LowB movlw b'00010000' movwf PORTA ;-------------------------------------------------------------------------- goto Go ;+------------------------------------------------------------------------+ ;| The main cycle end | ;+------------------------------------------------------------------------+ end