Maker Pro
Maker Pro

16f628 - Problem counting clock frequency

S

Sambo

Jan 1, 1970
0
I have added some code to my IR sampler so the chip/board can double as unknown/salvaged
crystal identifier. For internal and external clocking of 4Mhz I am getting counts of about 55%.
I used single comparator mode to catch pulses from a full rectifier through 1M/270K divider (with the current 9.2 Vac US Robatics wall adapter.)
I have been wrestling with this program for a few days , ironing out some other problems, and my brain is a mush. I would appreciate some help with this.

;**********************************************************************
; This file is a basic code template for object module code *
; generation on the PICmicro PIC16F628A. This file contains the *
; basic code building blocks to build upon. As a project minimum *
; the 16F628A.lkr file will also be required for this file to *
; correctly build. The .lkr files are located in the MPLAB *
; directory. *
; *
; If interrupts are not used all code presented between the *
; code section "INT_VECTOR and code section "MAIN" can be removed. *
; In addition the variable assignments for 'w_temp' and *
; 'status_temp' can be removed. *
; *
; If interrupts are used, as in this template file, the 16F628A.lkr *
; file will need to be modified as follows: Remove the lines *
; CODEPAGE NAME=vectors START=0x0 END=0x4 PROTECTED *
; and *
; SECTION NAME=STARTUP ROM=vectors *
; and change the start address of the page0 section from 0x5 to 0x0 *
; *
; Refer to the MPASM User's Guide for additional information on *
; features of the assembler and linker (Document DS33014). *
; *
; Refer to the respective PICmicro data sheet for additional *
; information on the instruction set. *
; *
;**********************************************************************
; *
; Filename: irs_osc_cntr.asm *
; Date: *
; File Version: *
; *
; Author: *
; Company: *
; *
; *
;**********************************************************************
; *
; Files required: *
; 16F628A.lkr *
; *
; *
;**********************************************************************
; *
; Notes: modified IR_sampler (unfinished, unresolved TX_max_char_count *
; outs all possible values ) *
; besides sampling ir signals, use of the comparators and *
; AC supply to count/measure the oscilator frequency *
; *
;**********************************************************************

list p=16F628A ; list directive to define processor
#include <p16F628A.inc> ; processor specific variable definitions

errorlevel -302 ; suppress message 302 from list file


; __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT
__CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.



;***** VARIABLE DEFINITIONS (examples)

; example of using Shared Uninitialized Data Section
INT_VAR UDATA 0x20

DD_PA equ 0xa6
DD_PB equ 0xf2

timer1_prescaler res 1 ; /start
PB5_old_val res 1
PB5_new_val res 1
timer_lo res 1
timer_hi res 1
timer1_timeouts res 1 ; number of timeouts at 20, decrement the
; TX_max_char_count so that we can periodicaly
; check the degree of activity in the output buffer
; ( when external commands are implemented )
; for now transfer the TX_max_char_count at first timeout.
ResultsA res 1 ; port A outputs
; 0 - output
; 1 - comp-
; 2 - comp+ / ref out 120/60 Hz input
; 3 -
; 4 -
; 5 - VPP/!MCLR always input
; 6 -
; 7 - baud rate input HI/LO (BRGH bit)

ResultsB res 1 ; port B outputs
; 0 - timer read hickup indicator
; 1 - Async RX
; 2 - Async Tx
; 3 - ?IR output? not yet implemented
; 4 - measure AC low / PGM
; 5 - IR input
; 6 - PGC
; 7 - PGD
comp_flags res 1
AC_present equ 0 ; 0 - ac detected
start_measurement equ 1 ; 1 - start measurement ( next zero cross)
measuring equ 2 ; 2 - measurement in progress
long equ 3 ; 3 - short(.1sec)/ long (1sec)
comparator_old_state equ 4 ; 4 - comp old state
; 5 -
; 6 - comp new state
; 7 -
reference_adjust res 1 ; incremented by Timer1
; timeouts ( when marker is
; transmited ) when 4 or 8 and no AC
; reduce the reference
reference_adjust_done equ 6 ;
AC_found equ 7 ; flag indicating ac
; was just detected and reference
; should be reduced one more notch



zero_cross_count res 1
tmr0_temp res 1
t0_ovf1 res 1
t0_ovf2 res 1
t0_ovf3 res 1


;###################################################################################
; Commands from the serial port precceded by 00 AA sync chars
; Read or write registers
; 101 00001 read register specified in following byte
; 101 00010 write register specified in following byte with data in next additional byte

;
sync_OK res 1 ; set to 0 when 0 received incremented when AA received
Last_command res 1 ; if sync is 1 store bytes
Command_data1 res 1 ; usualy address
Command_data2 res 1 ; usualy data value

Free_ram:

INT_VAR_SHR UDATA_SHR 0x71
w_temp res 1 ; variable used for context saving
status_temp res 1 ; variable used for context saving

temp1 res 1 ; used by place_byte_in_output_buffer
temp2 res 1 ; used by place_byte_in_output_buffer
temp3 res 1
buff_head res 1 ; points to where new data is stored
buff_tail res 1 ; points to which byte is next to be transmited ( read advance )
buff_start res 1 ;
buff_end res 1
new_buff_head res 1
TX_char_count res 1
TX_max_char_count res 1
;**********************************************************************
RESET_VECTOR CODE 0x000 ; processor reset vector
goto main ; go to beginning of program


INT_VECTOR CODE 0x004 ; interrupt vector location
movwf w_temp ; save off current W register contents
swapf STATUS, w ; move status register into W register
movwf status_temp ; save off contents of STATUS register

bcf STATUS, RP0
bcf STATUS, RP1

; check for comparator state change
movfw TMR0
movwf tmr0_temp

btfss PIR1, CMIF
goto comparator_done
bsf PORTA, 3
btfsc CMCON, C2OUT
goto wrap_up_comp_int
bsf comp_flags, AC_present
bsf ResultsA, 0
bsf PORTA, 0
btfss comp_flags, start_measurement
goto wrap_up_comp_int
btfss comp_flags, measuring
goto setup_measurement
incf zero_cross_count, f
; movfw zero_cross_count
; call place_byte_in_output_buffer

btfsc comp_flags, long
goto check_long
movlw .12
subwf zero_cross_count, w
btfss STATUS, Z
goto measurement_incomplete
goto transnit_count
check_long:
movlw .120
subwf zero_cross_count, w
btfss STATUS, Z
goto measurement_incomplete
transnit_count:
movfw t0_ovf3
call place_byte_in_output_buffer
movfw t0_ovf2
call place_byte_in_output_buffer
movfw t0_ovf1
call place_byte_in_output_buffer
movfw tmr0_temp
call place_byte_in_output_buffer
; movlw A'/'
; call place_byte_in_output_buffer
; movlw A'.'
; call place_byte_in_output_buffer
; movlw A'1'
; call place_byte_in_output_buffer
btfsc comp_flags, long
goto wrap_up_measurements
bsf comp_flags, long
bcf comp_flags, measuring
goto wrap_up_comp_int

wrap_up_measurements:
bcf PORTA, 0
bcf comp_flags, measuring
bcf comp_flags, start_measurement
bcf comp_flags, long
bsf T1CON, TMR1ON
goto wrap_up_comp_int

setup_measurement:
; 17 instruction cycles to get here
movlw 0x13 ; start with 19 (19 instructions since
; ZERO crossing
movwf TMR0
clrf zero_cross_count
; clrf TMR0
clrf t0_ovf1
clrf t0_ovf2
clrf t0_ovf3
bcf T1CON, TMR1ON
bsf comp_flags, measuring

measurement_incomplete:
wrap_up_comp_int:
bcf PIR1, CMIF
comparator_done:
; check timer0 overflow
do_timer0:
btfss INTCON, T0IF
goto timer0_done
incf t0_ovf1, f
btfss STATUS, Z
goto timer0_wrap_up
incf t0_ovf2, f
btfss STATUS, Z
goto timer0_wrap_up
incf t0_ovf3, f
btfss STATUS, Z
; goto timer0_wrap_up

timer0_wrap_up:
bcf INTCON, T0IF
timer0_done:

; isr code can go here or be located as a call subroutine elsewhere
test_PB_change:
bcf STATUS, RP0 ; RAM PAGE 0
btfss INTCON, RBIF
goto timer_overflow
movfw PORTB
andlw 0x20
movwf PB5_new_val
subwf PB5_old_val, w
btfsc STATUS, Z
goto PB_change_wrap_up1
movfw TMR1H
movwf timer_hi
movfw TMR1L
movwf timer_lo
movf TMR1H, w ; Read high byte
SUBWF timer_hi, W ; Sub 1st read with
; 2nd read
BTFSC STATUS, Z ; Is result = 0
GOTO done_reading_timer ; Good 16-bit read
bsf ResultsB, 0
decf timer_hi, f
done_reading_timer:
clrf TMR1H
clrf TMR1L
clrf timer1_timeouts
; output the data to the Async output buffer
; test if change is L/H or H/L

btfsc PB5_new_val, 5
goto bit_end ; on account of IR receiver being normaly high
; invert logic
bsf timer_hi, 7 ; slap the bit start indicator into the highest bit
movfw timer_hi
call place_byte_in_output_buffer
movfw timer_lo
call place_byte_in_output_buffer
goto PB_change_wrap_up
bit_end:
bcf timer_hi, 7 ; slap the bit end indicator into the highest bit
movfw timer_hi
call place_byte_in_output_buffer
movfw timer_lo
call place_byte_in_output_buffer
PB_change_wrap_up:
movwf PB5_new_val
movfw PB5_old_val
PB_change_wrap_up1:
bcf INTCON, RBIF

portB_no_change:
timer_overflow;
btfss PIR1, TMR1IF ; did timer 1 overflow?
goto timer1_service_done
bcf PIR1, TMR1IF
; clear a byte somewhere?

; handle first time out: send '#' followed by the maximun number of bytes
; in transmit buffer
incf timer1_timeouts, f
movlw 1
subwf timer1_timeouts, w
btfss STATUS, Z
goto handle_buff_treshold_counter
movlw 23
call place_byte_in_output_buffer
movfw TX_max_char_count
call place_byte_in_output_buffer

;every 20 timeouts ( aprox 1 sec, 0.5 with 8MHz clock ) send '*'
handle_buff_treshold_counter:
movlw 14
subwf timer1_timeouts, w
btfss STATUS, C
goto timer1_service_done
clrf timer1_timeouts
incf timer1_timeouts, f
movlw 2a
call place_byte_in_output_buffer
bcf STATUS, RP0 ; RAM PAGE 0

movlw 1
subwf TX_max_char_count, w
btfss STATUS, Z
decf TX_max_char_count, f

; btfsc reference_adjust, AC_found
; goto timer1_service_done
; clrf comp_flags
btfss reference_adjust, 1
incf reference_adjust, f

; bsf comp_flags, start_measurement


timer1_service_done:

int_done:
swapf status_temp, w ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp, f
swapf w_temp, w ; restore pre-isr W register contents
retfie ; return from interrupt

place_byte_in_output_buffer:
; pointers - test write/read advance

movwf temp1
; test if head + 1 is equal tail , if so buffer is full!!!
; first test if it hits end of buffer
movfw buff_head
addlw 1
movwf new_buff_head
; movwf temp2
subwf buff_end, w
btfsc STATUS, Z
goto head_hit_end
; now test it against the tail pointer
movfw new_buff_head
subwf buff_tail, w
btfsc STATUS, Z
goto buffer_full
goto place_character

head_hit_end:
; head will be pointing to beginning - is tail currently pointing to the beginning?
movfw buff_tail
subwf buff_start, w
btfsc STATUS, Z
goto buffer_full
movfw buff_start
movwf new_buff_head
place_character:
movfw buff_head
movwf FSR
movfw temp1
movwf INDF
movfw new_buff_head
movwf buff_head

character_qued_for_output:
bcf STATUS, C
return

buffer_full:
bsf STATUS, C
return

main
; remaining code goes here
bcf STATUS, RP0 ; RAM PAGE 0
bcf STATUS, RP1 ; RAM PAGE 0

clrf PORTA
movlw 0x04
movwf PORTB

banksel OPTION_REG
bcf OPTION_REG, NOT_RBPU
bsf STATUS, RP0 ; RAM PAGE 1
movlw 0x0f ; high speed int osc, POR and BOR
movwf PCON
movlw DD_PA
movwf TRISA ; PA5, PA7 inputs

movlw DD_PB ; RB7-RB4 and RB1(RX)=input, others output
movwf TRISB
banksel PORTB
movlw 0x04
movwf PORTB
movwf ResultsB
movlw 0x00
movwf PORTA
movwf ResultsA
; setup voltage reference
banksel VRCON
; bsf TRISA, 2
movlw 0xff ; low range max (3.593V) the length below this treshold could be measured
; and the reference adjusted depending on the voltage applied
movwf VRCON

bcf STATUS, RP0 ; PAGE 0
movlw 5 ; comparator 2 only
movwf CMCON

BCF PIR1,CMIF ; Clear pending interrupts
comp_old_state
; setup timer 0
bsf STATUS, RP0 ; PAGE 0
bcf OPTION_REG, T0CS

clrf temp1
settle decfsz temp1,F
goto settle



banksel T1CON
movlw 0x20 ; prescale /8, enable timer
movwf T1CON
; clrf T1CON
movwf timer1_prescaler
movlw 0x30
andwf timer1_prescaler, f
movlw 0xc8 ; enable global interrupts, peripheral interrupts, interrupt on change of port B
movwf INTCON
bsf STATUS, RP0 ; RAM PAGE 1
; bsf PIE1, TMR1IE ; enable timer 1 interrupts, timeout clears any in-progrees IR character reception??
; postpone enabling the timer ints untill after the test messages have been sent
; to avoid the possibility that we are in place_byte_in_output_buffer() which is otherwise
; used by the interrupt routine
movlw 1 ; set time outs to 1 to indicate we are not
movwf timer1_timeouts ; in the middle of receiving IR code/char

; ------------------------------------
; SET BAUD RATE TO COMMUNICATE WITH PC
; ------------------------------------
; Boot Baud Rate = 9600, No Parity, 1 Stop Bit
;
banksel SPBRG
movlw 0x19 ; 0x19=9600 bps (0x0C=19200 bps)
movwf SPBRG
movlw b'00100110' ; brgh(2) = high
movwf TXSTA ; enable Async Transmission, set brgh

bcf STATUS, RP0 ; RAM PAGE 0
movlw b'10010000' ; enable Async Reception and continuous receive
movwf RCSTA
bsf PIR1, TXIF ; set tx reg empty interrupt flag for simulator

bcf STATUS, RP0 ; RAM PAGE 0
; call check_baud_rate_input


; setup the circular buffers
movlw Free_ram
addlw 10
andlw 0f0
movwf buff_start
movwf buff_head
movwf buff_tail
movlw 70
movwf buff_end

bcf STATUS, RP0 ; bank 0
movlw 0x23
movwf TXREG
bsf STATUS, RP0 ; bank 1
clrf EEADR
get_next_char

bsf STATUS, RP0 ; Bank1
bsf EECON1, RD ; EE Read
movfw EEDATA
wait_trans_complete:
bcf STATUS, RP0 ; bank 0
btfss PIR1, TXIF ; (1) transmission is complete if hi
goto wait_trans_complete
movwf TXREG ; send data in W
sublw 0
btfsc STATUS, Z
goto ready_mess_done
bsf STATUS, RP0 ; Bank1
incf EEADR, f
goto get_next_char
ready_mess_done:
bcf STATUS, RP0


;************************** DEBUG CODE ************************
; setup buffer pointers to point near the end of buffer
movlw -5
addwf buff_end, w
movwf buff_head
movwf buff_tail
send_test_message: ; if baudrate changed, main loop starts here send 9-0 digits
movlw 0x39 ; prepare ASCII of '9'
movwf temp3
send_next_byte:
movfw temp3
call place_byte_in_output_buffer
movlw 0x30
subwf temp3, w
btfsc STATUS, Z
goto mess2_done
decf temp3, f
goto send_next_byte

mess2_done:

clrf temp3
bsf STATUS, RP0 ; Bank1
bsf PIE1, TMR1IE ; enable timer 1 interrupts, timeout clears any in-progrees IR character reception??
bcf STATUS, RP0 ; Bank0
bsf T1CON, TMR1ON

; set up vars and interrupts for comp and timer int ( related to measuring the clock )
clrf comp_flags
clrf reference_adjust
; clrf zero_cross_count
; clrf t0_ovf1
; clrf t0_ovf2
; clrf t0_ovf3

bcf INTCON, T0IF
bsf INTCON, T0IE

bcf PIR1, CMIF
bsf STATUS, RP0 ; Bank1
bsf PIE1, CMIE
bcf STATUS, RP0 ; Bank0

;************************ END DEBUG CODE **********************
main_loop:
; first see if there is any data in the transmit buffer
; and calculate the number of bytes in there for performance monitoring
; otherwise it can be all dumped and transmit_data called blindly.


movfw buff_tail
subwf buff_head, w
btfsc STATUS, Z
goto adjust_reference
btfsc STATUS, C
goto was_positive
movwf TX_char_count
movfw buff_end
addwf TX_char_count
movfw buff_start
subwf TX_char_count
goto calc_count_done
was_positive:
movwf TX_char_count
calc_count_done:
movfw TX_max_char_count
subwf TX_char_count, w
btfss STATUS, C
goto new_char_count_max_done
movfw TX_char_count
movwf TX_max_char_count
new_char_count_max_done:
;************************ DEBUG CODE: generate inter character spacing
; incf temp3
; btfss STATUS, Z
; goto check_for_incoming_data
; movlw 0x80
;************************ END DEBUG CODE **********************

call transmit_data


; poll async receive for commands
adjust_reference:
btfsc reference_adjust, reference_adjust_done
goto adjust_reference_end
btfss reference_adjust, 1
goto adjust_reference_end
btfsc reference_adjust, AC_found
goto ac_just_started
btfss comp_flags, AC_present
goto still_no_AC
bsf reference_adjust, AC_found

ac_just_started:
bsf STATUS, RP0 ; Bank1
movfw VRCON
movwf temp3
movlw 0f
andwf temp3, f
movlw 0
subwf temp3
btfsc STATUS, Z
decf VRCON, f
bsf reference_adjust, reference_adjust_done
goto adjust_reference_wrap_up

still_no_AC:
bsf STATUS, RP0 ; Bank1
movfw VRCON
movwf temp3
movlw 0f
andwf temp3, f
movlw 0
subwf temp3
btfsc STATUS, Z
goto vref_at_minimum
decf VRCON, f
goto adjust_reference_wrap_up


vref_at_minimum:
movlw 0f
iorwf VRCON, f

adjust_reference_wrap_up:
bcf STATUS, RP0
movlw 0c0
andwf reference_adjust, f
adjust_reference_end:

decide_if_to_do_freq_measurement:
btfss comp_flags, AC_present
goto done_deciding
movlw 01
andwf t0_ovf3, w
btfsc STATUS, Z
bsf comp_flags, start_measurement
done_deciding:

check_for_incoming_data:

check_for_commands:


; if OK to change baudrate ie UART shift reg empty, timer 1 timed out ( at least once )
; command not being received (sync received)
; !!! CURRENTLY just DOIT !!!
; disabled since I decided to use a crystal could be moved to RB4 but....
; call check_baud_rate_input


movfw ResultsB
movwf PORTB

goto main_loop ; loop forever, remove this instruction, for test only

transmit_data:
;********************************************************************
; Transfer byte from cyrcular output buffer into transmit register
; if transmit register flag ( TXIF in PIR1 )indicates it is empty
; inputs: no direct input
; outputs: flag Z= 0 indicates byte was transfered
; 1 uart full/busy or no bytes in output buffer
;********************************************************************
; see if we can transmit
bcf STATUS, RP0 ; RAM PAGE 0
btfss PIR1, TXIF ; is transmit reg empty
goto tramsmiter_busy ; check UART for data?

; is there anything in the buffer?
movfw buff_head
subwf buff_tail, w
btfsc STATUS, Z
goto no_data_to_transmit

place_in_TX_REG:
movfw buff_tail
incf buff_tail, f
movwf FSR
movfw INDF
movwf TXREG

bcf STATUS, RP0 ; bank 0
movfw buff_end
subwf buff_tail, w
btfss STATUS, Z
goto tail_pointer_OK
movfw buff_start
movwf buff_tail
tail_pointer_OK:

bcf STATUS, Z
return
no_data_to_transmit: ; or chanel not yet free
; bsf ResultsA, 4
; bsf PORTA, 4

bsf STATUS, Z
return

tramsmiter_busy:
bsf STATUS, Z
return

check_baud_rate_input:
;*****************************************************
; read external input and reflect it in TXSTA, BRGH
;*****************************************************

bcf STATUS, RP0 ; RAM PAGE 0
btfss PORTA, 7
goto set_low_BRGH
bsf STATUS, RP0 ; RAM PAGE 1
bsf TXSTA, BRGH
goto check_baud_rate_input_done
set_low_BRGH:
bsf STATUS, RP0 ; RAM PAGE 1
bcf TXSTA, BRGH

check_baud_rate_input_done:
bcf STATUS, RP0 ; RAM PAGE 0
return

; initialize eeprom locations
EE CODE 0x2100
DE ">>>READY."
DE 0


END ; directive 'end of program'

Not sure how following captured binary data (freq.log) will come out but here it is.
Alternating 1/10 and 1sec. counts (4bytes)
 
Top