Connect with us

16f628 - Problem counting clock frequency

Discussion in '8bit Microcontrollers' started by Sambo, Feb 25, 2006.

  1. Sambo

    Sambo Guest

    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)
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-