;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