;G6UYJ FREQUENCY COUNTER using PIC16F84
;
;The code is not exactly the neatest or the most compact but it works for me
;
;
; RA0 = LCD E RB0 = LCD DATA 0 / CTR RESET
; RA1 = LCD RS RB1 = LCD DATA 1 / GATE
; RA2 = PRE_MOD RB2 = LCD DATA 2 / SEL0
; RA3 = COUNT UP RB3 = LCD DATA 3 / SEL1
; RA4 = TMR0 I/P RB4 =
; RB5 =
; RB6 = MODE SW
; RB7 = GATE SW
;
;Notes for Complier
LIST P=16F84 ;set PIC for assembler
__CONFIG 0x3FF1 ;XT, no WDT, PWR-UP, NO CP
#include <P16F84.INC>
;PORT DEFINITIONS
LCD_PORT equ PORTB
LCD_CMD_PORT equ PORTA
E equ 0
RS equ 1
PRE_MOD equ 2
COUNT_UP equ 3
RESET equ 3
GATE equ 2
CH_SEL0 equ 0
CH_SEL1 equ 1
SW_MODE equ 7
SW_GATE equ 6
;MEMORY DEFINITIONS
TEMP1 equ 0x10
TEMP2 equ 0x11
TEMP3 equ 0x12
CHAR equ 0x13
DISPLAY_INFO equ 0x14 ;low nibble units, bit 7 leading zeros
COUNT equ 0x15
BCD2ASCII equ 0x16
GATE_TIME equ 0x17
MODE equ 0x18
GATE_TIME1 equ 0x19
GATE_TIME2 equ 0x1A
GATE_TIME3 equ 0x1B
DISPLAY1 equ 0x1C ;LS BYTE
DISPLAY2 equ 0x1D
DISPLAY3 equ 0x1E
DISPLAY4 equ 0x1F
DISPLAY5 equ 0x20 ;MS BYTE
FREQ1 equ 0x21 ;LS BYTE
FREQ2 equ 0x22
FREQ3 equ 0x23
FREQ4 equ 0x24 ;MS BYTE
ORG 0x00
goto INIT
ORG 0x04
goto ISR
INIT clrf STATUS
clrf PORTA
clrf PORTB
bsf STATUS,RP0 ;set PAGE1
movlw 0x18
movwf TRISA ;RA0-2 O/P RA3-4 I/P
movlw 0xF0
movwf TRISB ;RB4-7 I/P
movlw 0x37
movwf OPTION_REG ;Prescaler /256, RB PULL UP ENABLED
bcf STATUS,RP0 ;set PAGE0
clrf MODE ;set ch0 at startup
clrf GATE_TIME ;set 1 sec for startup
movlw 0x30 ;Put 0x30 into memory
movwf BCD2ASCII ;to use for LCD display
goto INIT_LCD
RETURN_INIT_LCD
bcf INTCON,RBIE ;enable interrupts
movf PORTB,W
bcf INTCON,RBIF
bsf INTCON,RBIE
bsf INTCON,GIE
START
goto COUNTER
RETURN_COUNTER
movlw 0x04
subwf MODE,W
btfss STATUS,Z
goto RETURN_OFFSET
goto IC202_OFFSET
RETURN_OFFSET
goto B2BCD
RETURN_B2BCD
goto UPDATE_DISPLAY
RETURN_UPDATE_DISPLAY
THE_END goto START
ISR
call delay ;debounce
call delay
call delay
call delay
btfss PORTB,SW_GATE ;test which key has been pressed
goto CHANGE_GATE
btfss PORTB,SW_MODE
goto CHANGE_MODE
goto START
CHANGE_MODE
movlw 0x01
addwf MODE,F
movlw 0x05
subwf MODE,W
btfsc STATUS,Z
clrf MODE
goto EXIT_ISR
CHANGE_GATE
movlw 0x01
addwf GATE_TIME,F
movlw 0x03
subwf GATE_TIME,W
btfsc STATUS,Z
clrf GATE_TIME
EXIT_ISR
movlw 0xff ;loop for about 16ms??
movwf TEMP3
key_up call delay
decfsz TEMP3,F
goto key_up
btfss PORTB,SW_MODE ;test for keys down
goto EXIT_ISR
btfss PORTB,SW_GATE
goto EXIT_ISR
bcf INTCON,RBIE ;enable interrupts
movf PORTB,W
bcf INTCON,RBIF
bsf INTCON,RBIE
bsf INTCON,GIE
goto UPDATE_MODE_GATE
lcd_send_cmd
bcf INTCON,GIE
bcf LCD_CMD_PORT,RS ;send command
goto lcd_send
lcd_send_char
bcf INTCON,GIE
bsf LCD_CMD_PORT,RS ;send char
lcd_send movwf CHAR
swapf CHAR,w
andlw 0x0f
movwf LCD_PORT
bsf LCD_CMD_PORT,E
nop
nop
bcf LCD_CMD_PORT,E
call delay
call delay
movf CHAR,w
andlw 0x0f
movwf LCD_PORT
bsf LCD_CMD_PORT,E
nop
nop
bcf LCD_CMD_PORT,E
call delay
call delay
bsf INTCON,GIE
return
delay movlw 0xff
movwf TEMP1
dloop decfsz TEMP1,F
goto dloop
return
INIT_LCD
call delay
call delay
call delay
call delay
movlw 0x32 ;init
call lcd_send_cmd
movlw 0x2C ;2 line
call lcd_send_cmd
movlw 0x08 ;disp off
call lcd_send_cmd
movlw 0x01 ;clear disp
call lcd_send_cmd
movlw 0x06 ;entry mode
call lcd_send_cmd
movlw 0x0C ;cursor
call lcd_send_cmd
movlw 0x86 ;move cursor
call lcd_send_cmd
movlw 0x47 ;G
call lcd_send_char
movlw 0x36 ;6
call lcd_send_char
movlw 0x55 ;U
call lcd_send_char
movlw 0x59 ;Y
call lcd_send_char
movlw 0x4A ;J
call lcd_send_char
goto RETURN_INIT_LCD
UPDATE_DISPLAY
movlw 0x02
call lcd_send_cmd ;goto home
bcf DISPLAY_INFO,7
digit10 swapf DISPLAY5,W
andlw 0x0f
btfss STATUS,Z
goto dig10a
movlw 0x20
call lcd_send_char
movlw 0x20
call lcd_send_char
goto digit9
dig10a addwf BCD2ASCII,W
call lcd_send_char ;display GHz units
bsf DISPLAY_INFO,7
movlw 0x2C
call lcd_send_char ;display comma
digit9 movf DISPLAY5,W
andlw 0x0f
btfss STATUS,Z
goto digit9a
btfsc DISPLAY_INFO,7
goto digit9a
movlw 0x20
call lcd_send_char
goto digit8
digit9a addwf BCD2ASCII,W
call lcd_send_char ;display MHz hundreds
bsf DISPLAY_INFO,7
digit8 swapf DISPLAY4,W
andlw 0x0f
btfss STATUS,Z
goto digit8a
btfsc DISPLAY_INFO,7
goto digit8a
movlw 0x20
call lcd_send_char
goto digit7
digit8a addwf BCD2ASCII,W
call lcd_send_char ;display MHz tens
digit7 movf DISPLAY4,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display MHz units
movlw 0x2E
call lcd_send_char ;display decimal point
swapf DISPLAY3,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display kHz hundreds
movf DISPLAY3,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display kHz tens
swapf DISPLAY2,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display kHz units
movlw 0x2C
call lcd_send_char ;display comma
movf DISPLAY2,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display Hz hundreds
swapf DISPLAY1,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display Hz tens
movf DISPLAY1,W
andlw 0x0f
addwf BCD2ASCII,W
call lcd_send_char ;display Hz units
movlw 0x4D
call lcd_send_char ;display M
movlw 0x48
call lcd_send_char ;display H
movlw 0x7a
call lcd_send_char ;display z
; goto RETURN_UPDATE_DISPLAY
UPDATE_MODE_GATE
movlw 0xC0
call lcd_send_cmd ;move to second line for MODE
movf MODE,W ;display 70MHz
btfss STATUS,Z
goto display_mode1
movlw '7'
call lcd_send_char
movlw '0'
call lcd_send_char
movlw 'M'
call lcd_send_char
movlw 'H'
call lcd_send_char
movlw 'z'
call lcd_send_char
movlw ' '
call lcd_send_char
goto display_gate
display_mode1
movlw 0x01 ;display 150MHz
subwf MODE,W
btfss STATUS,Z
goto display_mode2
movlw '1'
call lcd_send_char
movlw '5'
call lcd_send_char
movlw '0'
call lcd_send_char
movlw 'M'
call lcd_send_char
movlw 'H'
call lcd_send_char
movlw 'z'
call lcd_send_char
goto display_gate
display_mode2
movlw 0x02 ;display 2GHz
subwf MODE,W
btfss STATUS,Z
goto display_mode3
movlw '2'
call lcd_send_char
movlw 'G'
call lcd_send_char
movlw 'H'
call lcd_send_char
movlw 'z'
call lcd_send_char
movlw ' '
call lcd_send_char
movlw ' '
call lcd_send_char
goto display_gate
display_mode3
movlw 0x03 ;display 4GHz
subwf MODE,W
btfss STATUS,Z
goto display_mode4
movlw '4'
call lcd_send_char
movlw 'G'
call lcd_send_char
movlw 'H'
call lcd_send_char
movlw 'z'
call lcd_send_char
movlw ' '
call lcd_send_char
movlw ' '
call lcd_send_char
goto display_gate
display_mode4
movlw 'I' ;display IC202
call lcd_send_char
movlw 'C'
call lcd_send_char
movlw '2'
call lcd_send_char
movlw '0'
call lcd_send_char
movlw '2'
call lcd_send_char
movlw ' '
call lcd_send_char
display_gate
movlw 0xC9
call lcd_send_cmd ;move to gate time
movf GATE_TIME,W ;display 1 second gate time
btfss STATUS,Z
goto half_sec
movlw ' '
call lcd_send_char
movlw ' '
call lcd_send_char
movlw ' '
call lcd_send_char
movlw '1'
call lcd_send_char
goto display_sec
half_sec
movlw 0x01 ;display 1/2 second gate time
subwf GATE_TIME,W
btfss STATUS,Z
goto quarter_sec
movlw ' '
call lcd_send_char
movlw '0'
call lcd_send_char
movlw '.'
call lcd_send_char
movlw '5'
call lcd_send_char
goto display_sec
quarter_sec
movlw 0x02 ;display 1/2 second gate time
subwf GATE_TIME,W
btfss STATUS,Z
goto display_sec
movlw '0'
call lcd_send_char
movlw '.'
call lcd_send_char
movlw '2'
call lcd_send_char
movlw '5'
call lcd_send_char
display_sec
movlw 's'
call lcd_send_char
movlw 'e'
call lcd_send_char
movlw 'c'
call lcd_send_char
goto RETURN_UPDATE_DISPLAY
B2BCD
bcf STATUS,0
movlw .32
movwf COUNT
clrf DISPLAY5
clrf DISPLAY4
clrf DISPLAY3
clrf DISPLAY2
clrf DISPLAY1
loop32 rlf FREQ1,F
rlf FREQ2,F
rlf FREQ3,F
rlf FREQ4,F
rlf DISPLAY1,F
rlf DISPLAY2,F
rlf DISPLAY3,F
rlf DISPLAY4,F
rlf DISPLAY5,F
decfsz COUNT,F
goto ADJ_DEC
goto RETURN_B2BCD
ADJ_DEC
movlw DISPLAY1
movwf FSR
call ADJ_BCD
movlw DISPLAY2
movwf FSR
call ADJ_BCD
movlw DISPLAY3
movwf FSR
call ADJ_BCD
movlw DISPLAY4
movwf FSR
call ADJ_BCD
movlw DISPLAY5
movwf FSR
call ADJ_BCD
goto loop32
ADJ_BCD
movlw 0x03
addwf 0,w
movwf TEMP1
btfsc TEMP1,3
movwf 0
movlw 0x30
addwf 0,w
movwf TEMP1
btfsc TEMP1,7
movwf 0
retlw 0
IC202_OFFSET ;offset of 10.6985MHz
movlw 0x04
addwf FREQ1,F
btfsc STATUS,C
incf FREQ2,F
movlw 0x3F
addwf FREQ2,F
btfsc STATUS,C
incf FREQ3,F
movlw 0xA3
addwf FREQ3,F
btfsc STATUS,C
incf FREQ4,F
goto RETURN_OFFSET
COUNTER
channel_mode0 ;mode 0 = channel 0
movf MODE,W ;70MHz LF input max
btfss STATUS,Z
goto channel_mode1
bcf PORTB,CH_SEL0
bcf PORTB,CH_SEL1
goto channel_set
channel_mode1 ;mode 1 = channel 1
movlw 0x01 ;150MHz LF input max
subwf MODE,W
btfss STATUS,Z
goto channel_mode2
bsf PORTB,CH_SEL0
bcf PORTB,CH_SEL1
goto channel_set
channel_mode2 ;mode 2 = channel 2
movlw 0x02 ;2GHz HF input max
subwf MODE,W
btfss STATUS,Z
goto channel_mode3
bcf PORTB,CH_SEL0
bsf PORTB,CH_SEL1
bsf PORTA,PRE_MOD
goto channel_set
channel_mode3 ;mode 3 = channel 3
movlw 0x03 ;4GHz HF input max
subwf MODE,W
btfss STATUS,Z
goto channel_mode4
bcf PORTB,CH_SEL0
bsf PORTB,CH_SEL1
bcf PORTA,PRE_MOD
goto channel_set
channel_mode4 ;mode 4 = channel 1
movlw 0x04 ;IC202 LF input
subwf MODE,W
btfss STATUS,Z
goto channel_set
bsf PORTB,CH_SEL0
bcf PORTB,CH_SEL1
channel_set
movlw 0x01
movwf FREQ1
clrf FREQ2
clrf FREQ3
clrf FREQ4
;TIMING CONSTANTS for 4.096MHz clock
;delay = 11a + 7a(b-1) + 3ab(c-1) + 2 + (No. of NOP)
;1SEC 6 230 246
;1/2 SEC 11 130 118
;1/4 SEC 3 166 170
movf GATE_TIME,W ;set up delay constant
btfss STATUS,Z
goto half_sec_delay
movlw 0x06
movwf GATE_TIME1 ;6
movlw 0xE6
movwf GATE_TIME2 ;230
movlw 0xF6
movwf GATE_TIME3 ;246
goto gate_delay
half_sec_delay
movlw 0x01
subwf GATE_TIME,W
btfss STATUS,Z
goto quarter_sec_delay
movlw 0x0B
movwf GATE_TIME1 ;11
movlw 0x82
movwf GATE_TIME2 ;130
movlw 0x76
movwf GATE_TIME3 ;118
goto gate_delay
quarter_sec_delay
movlw 0x02 ;display 1/2 second gate time
subwf GATE_TIME,W
btfss STATUS,Z
goto display_sec
movlw 0x03
movwf GATE_TIME1 ;3
movlw 0xA6
movwf GATE_TIME2 ;166
movlw 0xAA
movwf GATE_TIME3 ;170
gate_delay
bsf PORTB,GATE ;reset gate just in case
bsf PORTB,RESET ;reset counters and s/r
nop ;
bcf PORTB,RESET ;
clrf TMR0 ;
bcf PORTB,GATE ;start gate
nop ;gate delay
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
movf GATE_TIME1,W
movwf TEMP3
loop_3 movf GATE_TIME2,W
movwf TEMP2
loop_2 movf GATE_TIME3,W
movwf TEMP1
loop_1 decfsz TEMP1,F
goto loop_1
decfsz TEMP2,F
goto loop_2
decfsz TEMP3,F
goto loop_3
bsf PORTB,GATE ;end gate
movf TMR0,W ;move RTCC to low byte
movwf FREQ4
bsf PORTB,CH_SEL0 ;set channel to +5V
bsf PORTB,CH_SEL1
CD4040_0
btfsc PORTA,COUNT_UP ;test 4060 output
goto CD4040_1 ;128 <= count <= 255
bsf PORTB,GATE ;clock 4040 once
nop
bcf PORTB,GATE
movlw 0x01 ;decrement the counter
subwf FREQ1,F
btfss STATUS,C
decf FREQ2,F
goto CD4040_0
CD4040_1
btfss PORTA,COUNT_UP ;test 4060 output
goto prescale ;it's rolled over (255 -> 0)
bsf PORTB,GATE ;clock 4040 once
nop
bcf PORTB,GATE
movlw 0x01 ;decrement the counter
subwf FREQ1,F
btfss STATUS,C
decf FREQ2,F
goto CD4040_1
prescale
movf TMR0,W ;Used to check for
movwf TEMP1 ;prescaler roll over
pres1 bsf STATUS,RP0 ;set PAGE1
bcf OPTION_REG,T0SE ;clock prescaler
nop
bsf OPTION_REG,T0SE
bcf STATUS,RP0 ;set PAGE0
decf FREQ3,F ;decrement counter
movf TMR0,W ;test TMR0 for prescale rollover
xorwf TEMP1,W ;if unchanged , XOR -> 0
btfsc STATUS,Z ;if 0 then clock again
goto pres1
decf FREQ3,F ;because we flushed 404
swapf FREQ2,F ;swap nibbles so we can move 4 places
;and get rid of unused FREQ2 nibble
movlw .4 ;shift FREQ1&2 4 places because we
movwf TEMP1 ;only have a 12bit counter
correction
bcf STATUS,C
rrf FREQ4,F
rrf FREQ3,F
rrf FREQ2,F
decfsz TEMP1,F
goto correction
multiply_data
movf GATE_TIME,W ;start off with corrction
movwf TEMP1 ;for gate time
movf MODE,W ;no multiplier for Mode 0
btfss STATUS,Z
goto count_mode1
goto data_loop
count_mode1
movlw 0x01
subwf MODE,W
btfss STATUS,Z
goto count_mode2
movlw 0x02 ; *4 for Mode 1
addwf TEMP1,F
goto data_loop
count_mode2
movlw 0x02
subwf MODE,W
btfss STATUS,Z
goto count_mode3
movlw 0x05 ; *32 for Mode 2
addwf TEMP1,F
goto data_loop
count_mode3
movlw 0x03
subwf MODE,W
btfss STATUS,Z
goto count_mode4
movlw 0x06 ; *64 for Mode 3
addwf TEMP1,F
goto data_loop
count_mode4
movlw 0x04
subwf MODE,W
btfss STATUS,Z
goto data_loop
movlw 0x02 ; *4 for Mode 4
addwf TEMP1,F
goto data_loop
data_loop
movf TEMP1,W
btfsc STATUS,Z
goto RETURN_COUNTER
rotate_data
bcf STATUS,C
rlf FREQ1,F
rlf FREQ2,F
rlf FREQ3,F
rlf FREQ4,F
decfsz TEMP1,F
goto rotate_data
goto RETURN_COUNTER
END