Counting Timer0 and Timer1 overflows without any interrupt handler


Closed Thread
Results 1 to 33 of 33
  1. #1
    Join Date
    Jan 2007
    Posts
    78

    Default Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi Gang,
    Today, I played around and got a couple of programs running on a 16F877A. One program monitors internal Timer1 overflows and flips a port bit every 210 counts, to produce a 1 second clock pulse. And this without an interrupt handling routine.

    (snippet)
    'setup option register for TMR0
    option_reg = %01010111 ' interrupt w/max

    mainloop:
    if TMR0 = 255 THEN
    counting = counting + 1
    if counting = 210 then
    counting = 0
    PORTD = PORTD ^ %00000001 'flip bit 0 for a clock
    endif
    endif
    goto mainloop


    The other program sets Timer1 up with pin-15 as its clock source, with prescaler=8. The main-loop starts Timer1, pauses for 1 second then turns off Timer1. Then displays the max count held within TMR1, which is offcourse <= 65535 with a max frequency input of 500khz. And this without an interrupt handling routine.

    So here is what I'm wondering:
    What I think I should be able to do is count in the main-loop, both Timer0 and Timer1 overflows. Timer0 clocking from internal source. Timer1 clocking from pin 15.
    When timer0 overflow count = 210, then exit out of the loop, turn off Timer1 and process Timer1's overflow count.

    The number of Timer1 overflows will act as a multiplier value.
    An overflow count of 2, for example would represent an clock input frequency of a little over 1mhz.

    Wondering how realistic you think my plan might be?
    I hoping to code a frequency counter that will count up to 30mhz without having to use an external ripple counter.

    Big thanks!!
    dw

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi,
    Just a couple of random notes:

    Doing IF TMR0=255 may not be the best. The reason for that is that your program may be off doing something else while TMR0 "transitions thru" 255, ie the program checks it and it's 254 next time it checks it's 0. TMR0 has overflowed but your program missed it. In THIS particular case your program is fairly "tight" so it likely runs faster than the increment rate of TMR0 but if/when you add stuff to the loop it may not work so well. Instead, check the TMR0IF, it'll get set when the timer overflows (even if you're not actually using interrupts) - just remember to clear it again.

    I'm not sure TMR1 can cope with a frequency as high as 30MHz, check the electrical specifications in the datasheet.

    /Henrik.

  3. #3
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Thank you Henrik!
    Much appreciate your knowledge of the devices!
    I just read in MicroChips DS33023A section 8 on interrupts that the interrupt flag bit gets set regardless of the corresponding enable bit setting. So yes, I can see that monitoring the flag bit allows for processing that condition while the timer is still running towards its next overflow. Just "as you mentioned" zero the flag bit until the next one.
    I'm hoping I can track both timer overflows without having to code the main loop in asm.
    I'll try it :-]
    Check Timer0 with TMR0IF status and Timer1 with PIR1.0 status.
    Thanks!!!! :-]

  4. #4
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    The following PBP3 code is my first attempt at coding for a frequency counter that can read above 500khz. The goal was to see if it could accurately capture frequency below 30mhz without using a frequency-prescaler, or ripple-counter. It does work, but its not accurate enough to be considered anything but educational or a fun project.
    Code:
    '  Code for 16F877A to count frequency
    '  Uses TMR0 and prescaler to gate 1 second counting time, internally clocked.
    '  Uses Timer1, external clock, from PIN 15  
    '  WDT, Analog, Comparitors OFF
    
    clear
    define loader_used 1
    define osc 4
    
    ' Define LCD registers and bits
    Define LCD_DREG PORTD
    Define LCD_RSREG PORTE
    Define LCD_RSBIT 0
    Define LCD_EREG PORTE
    Define LCD_EBIT 1
    define LCD_RWREG PORTE
    define LCD_RWBIT 2
    define LCD_BITS 8
    define LCD_LINES 2
    define LCD_COMMANDUS 2500
    define LCD_DATAUS 100
    
    TRISC = %11110001    'using pin 15 as input for frequency
    TRISD = 0            'PORTD all outputs
    PORTD = 0
    CMCON = 7            'disable comparators
    ADCON1 = 7           'PORTA and E digital
    
    
    'setup option register for TMR0
    option_reg.7 = 0
    option_reg.6 = 1     '1 for interrupts active
    option_reg.5 = 0
    option_reg.4 = 1     '1 for interrupts active 
    option_reg.3 = 0     'Assign prescaller to TMR0
    option_reg.2 = 1     'prescaler 0-15
    option_reg.1 = 1     'with this setting TMRO-Rate = 1:256
    option_reg.0 = 1
    
    'Prescaller settings for option_reg
    'option_reg 01011000 = 1:1 prescaler TMR0 roles over every 1mSec 
    'option_reg 01010000 = 1:2 prescaler TMR0 roles over every 152 uSec
    'option_reg 01010001 = 1:4 prescaler TMR0 roles over every 1mSec
    'option_reg 01010010 = 1:8 prescaler TMR0 roles over every 2mSec
    'option_reg 01010011 = 1:16 prescaler TMR0 roles over every 4mSec
    'option_reg 01010100 = 1:32 prescaler TMR0 roles over every 8mSec
    'option_reg 01010101 = 1:64 prescaler TMR0 roles over every 16mSec
    'option_reg 01010110 = 1:128 prescaler TMR0 roles over every 32mSec
    'option_reg 01010111 = 1:256 prescaler TMR0 roles over ever 64mSec
    
    INTCON.7 = 0   'disable interrupt routine on overflow
    INTCON.5 = 0   'disable interrupt routine on Timer0 overflow
    INTCON.4 = 0   'disable RB0 external interrupt function
    INTCON.3 = 0   'disable port change interrupt function
    INTCON.1 = 0   'not really needed, but clear possible pin change flag
    
    T1CON = %00110010 'Timer1 prescaler = 8 - osc off- sync on, external source
    
    lcdout $fe,1 'clear the display
    lcdout "Frequency Counter"
    pause 1000
    
    Tmr1flg var word
    counting var byte
    calc var byte
    mhz var byte
    khz var word
    hz var word
    
    PORTD = 0     'We will be setting PORTD.0 high through the 1 second
                  'gate-period to monitor it with Oscope
    INTCON.2 = 0  'Clear Timer0 interrupt flag
    TMR1 = 0      'Reset Timer0 counting value
    
    ' Main program loop
    mainloop:
    Tmr1flg = 0   'Clear variable which counts Timer1 overflows
    TMR1H = 0     'clear Timer1 high register 
    TMR1L = 0     'clear Timer1 low register
    PIR1.0 = 0    'clear Timer1 overflow flag bit
    INTCON.2 = 0  'Clear Timer0 interrupt flag
    TMR1 = 0      'Reset Timer0 value
    counting = 0
    
    PORTD.0 = 1       'raise the 1 second timer flag
    T1CON.0 = 1       'start Timer1
    
    while counting < 15   'Timer0 has to overflow this many times for 1 second gate period
    while INTCON.2 = 0    'watch for Timer1 overflow and count if it occurs.
    if PIR1.0 = 1 then     'if Timer1 overflow flag is up then 
    Tmr1flg = Tmr1flg + 1   'increment overflow count by 1. Each count represents value of 524280
    PIR1.0 = 0              'Now reset the Timer1 overflow flag bit
    endif
    wend                    'end of inner while loop
    INTCON.2 = 0            'Now reset the Timer0 overflow flag bit
    counting = counting + 1  'increment counting for gate time
    wend                     'end of outer while loop
    
    T1CON.0 = 0 'stop Timer1
    PORTD.0 = 0 'lower the 1 second timer flag representing the gate period
    
    
    ' calculations to get the numbers captured to the display
    ' we have to feed the number of Timer1 overflows into Mhz, Khz, hz
    ' Then we feed the Timer1 remaining count * 8 in as well
    ' and parse it out to mhz khz hz
    hz = 0
    khz = 0
    mhz = 0
    
    ' Add Timer1 overflow values into Mhz, Khz, hz
    if Tmr1flg > 0 then
    for calc = 0 to Tmr1flg
    khz = khz + 524
    hz = hz + 280
    
    while hz > 999
    khz = khz + 1
    hz = hz -1000
    wend
    while khz > 999
    mhz = mhz + 1
    khz = khz - 1000
    wend
    next
    endif
    
    ' Add remaining Timer1 count * 8 into Mhz, Khz, hz
    for calc = 0 to 7
    hz = hz + TMR1
    
    while hz > 999
    khz = khz + 1
    hz = hz -1000
    wend
    
    while khz > 999
    mhz = mhz + 1
    khz = khz - 1000
    wend
    next
    
    'Display results
    if mhz > 0 then 
    lcdout $FE,1,#mhz,".",#khz,".",#hz
    else
    lcdout $FE,1,#khz,".",#hz
    endif
    
    pause 2000
    goto mainloop   ' Go get another reading
    End
    
    Last edited by Archangel; - 4th February 2014 at 01:06.

  5. #5
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Quote Originally Posted by dw_picbasic View Post
    The following PBP3 code is my first attempt at coding for a frequency counter that can read above 500khz...
    It does work, but its not accurate enough to be considered anything but educational or a fun project.
    Since it's not a problem for the PIC chip, or for PBP ...
    Will there be a Second Attempt?

    I'd hate to interfere with the learning process.

    But I would suggest using the Timer0 input (T0CKI) for the frequency to be measured.
    The Timer0 prescaler has a minimum period of 20nS, which means it can take up to 50Mhz.
    Timer1 (T1CKI) can only take up to 1Mhz with a 4Mhz OSC, or 5Mhz with a 20Mhz OSC.

    Any frequency measurement requires an accurate "Time Base".
    And the easiest way to get that is to use a 32768 Hz crystal on the Timer1 oscillator.
    This way, Timer1 generates the 1 sec window, and Timer0 (and it's overflows) counts the frequency.

    It is a little tricky to read the Timer0 prescaler to get the lowest byte of the count though.
    The prescaler should be 1:256 (the default).

    Oh, and the PICs oscillator should be as fast as possible, so that the program can respond to the hardware flags, which have to be polled.
    The fastest oscillator for the 16F877A is 20 Mhz.

    A simulation works good up to 600Kz. Reading the exact Hz. (actual results will depend on the 32768 crystal tolerance)
    A real chip should go much higher, but the SIM crashes with the higher frequency.

    Name:  FREQy.jpg
Views: 8875
Size:  106.5 KB

    Sometimes you just need to know it can be done ... so you can figure it out on your own.
    DT

  6. #6
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Darrel,
    That's an ***AWESOME*** post!!
    It hadn't occurred to me to flip the timers around that way.
    Also, I need to go back to the data sheet and look at the electrical characteristics again for timer0 clock minimum pulse width.
    Per your info about the 20nSec I need to read through that again.
    I definitely want to try it!!
    This will be the first time, for me learning to setup Timer1 with external crystal for time base.
    Perhaps I would do well reading up on how that functionality is used for a standard 12hour clock.

    Also, what simulator are you using?
    It looks totally awesome!!
    Many thanks
    Duane :-]

  7. #7
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    The simulator is Proteus VSM from Labcenter in the UK.
    It's a bit pricey, but does an amazing job. Couldn't do my job without it.

    And I just want to point out how I have RA3 and RA4 tied together in the above schematic.
    It's a very important part of making the freq. counter work.
    DT

  8. #8
    Join Date
    Aug 2006
    Location
    Look, behind you.
    Posts
    2,818


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Thanks Darrel,
    I never could get my head around how to do that before, now I see tmr0 is a counter, tmr1 is the time base.
    If you do not believe in MAGIC, Consider how currency has value simply by printing it, and is then traded for real assets.
    .
    Gold is the money of kings, silver is the money of gentlemen, barter is the money of peasants - but debt is the money of slaves
    .
    There simply is no "Happy Spam" If you do it you will disappear from this forum.

  9. #9
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    And I just want to point out how I have RA3 and RA4 tied together in the above schematic.
    It's a very important part of making the freq. counter work.
    OK, I'll bite.... Are using RA3 to gate the signal for the T0CKI-pin, hence the seriesresistor on the input?

    /Henrik.

  10. #10
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    The two pins tied together (and the resistor) serve two purposes.

    1. You're right Henrik, since Timer0 on 16F's can't be stopped and started like all the other timers, it's used to gate the incoming signal.

    2. You can't directly read the value in Timer0's prescaler. So after counting pulses for the 1 sec. window, you have to provide additional pulses to the input until the value in TMR0 changes. The number of pulses you add tells you how many counts were already in the prescaler. This gives the low Byte of the final 32-bit value.

    The result is made up of the Timer0 overflows (HighWord), the TMR0 value (HighByte of the LowWord) and the prescaler value (LowByte of the LowWord)
    DT

  11. #11
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hmmmmm.
    I was thinking I was going to have to use a mosfet solid state relay at the input from the frequency source, so that I could pump Timer0 through the remaining clock cycles necessary to raise its flag again.
    I can see how pulling the Timer0 input pin high will disable the incoming clock from the frequency source.
    But I can't see how it could be used to pump the remaining cycles to get Timer0 to its next overflow since there is no way to dis-engage the frequency source signal. The remaining clocking and the frequency source would conflict with one another.

    Additionally, I was wondering if there is another way of pumping Timer0 to overflow, by using an internal software loop rather than doing it through an external clocking pin? I was wondering if a routine of adding 1 to TIMRL register and testing for a TMR1IF flag might work just as well.


    Unless I'm wrong that the intent is to pump Timer0 from an output pin from the PIC?

    Thanks :-]
    Last edited by dw_picbasic; - 7th February 2014 at 18:36.

  12. #12
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi,
    To enable the counter you TRISA.3=1 (pin is input). To gate the count signal OFF you set TRISA.3=0 (pin is output) and pull the pin low (or high for that matter. The resistor in series with the input will protect the DUT from the "shorted" input.

    Pulse the RA3 output in a loop until TMR0 again overflows. The pulses will override the input signal, there will be no conflicts because of the series resistor. As long as the RA3 output is LOW the input signal isn't seen by TMR0, when RA3 is high the input signal can't pull it low due to the series resistor. It'll work.

    /Henrik.

  13. #13
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Oh...that is just tooooo coool!!! :-D
    Love these toys!!!
    Thanks Henrik!!

  14. #14
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi Darrel and Hendrick,
    I'm still moving along dabbling with this project.
    Since I have the 16F887A in a LABX-1 project board, and I had a 12F683 mounted in a bread-board, I decided for convenience to see if I can make another step in this project using the 12F683. I got the 32khz crystal up and running on Timer1. By loading a preset value into Timer1's hi-byte, I can initiate the the frequency counting gate and Timer1 will interrupt right at 1Sec. (close enough on my Oscope).
    So then I moved to add using Timer0 as the counter for the external frequency.
    I'm only playing with a max input frequency of 300Khz right now, so I can utilize the PICs internal oscillator.

    The following code is my progress.
    It doesn't yet have the step of capturing the remainder value within Timer0.
    Just got the point of attempting to counting Timer0 overflows.
    But since I added the Timer0 register settings, it appears that I can't shut off the Timer1 overflow no matter what I do. Its supposed to display the timer0 overflow count and then go into a forever loop. But it keeps popping back up to "Display_Results". So I suspect timer1 is still initiating the interrupt routine.
    Code:
    ' Name        : Frequency Counter Clock in Timer0 - Gate with Timer1
    ' Compiler    : PICBASIC PRO Compiler 2.6
    ' Assembler   : PM or MPASM
    ' Target PIC  : PIC12F683
    ' Hardware    : 32.768khz crystal on OSC1-ISC2 for 1sec gate
    ' Oscillator  : 4MHz internal osc for PIC
    ' Keywords    :
    ' Language    : PICBASIC PRO
    '  
    '                     VDD --- 1|----|8--- vSS
    '    GP5/TICKI/OSC1/CLKIN --- 2|----|7--- GP0/AN0/CIN+/ICSPDAT/ULPWU
    ' GP4/AN3/T1G/OSC2/CLKOUT --- 3|----|6--- GP1/AN1/CIN-/VREF/ICSPCLK
    '            GP3/MCLR/VPP --- 4|----|5--- GP2/AN2/T0CKI/INT/COUT/CCP1
    '------------------------------------------------------------------------ 
      
    Include "modedefs.bas"  ' Include serial modes for LCD display
    define osc 4
    OSCCON = %01100100     ' internal oscillator at 4 MHZ runs the pic
    CMCON0 = 7             ' Comparators off
    ANSEL = 0              ' Set all digital
    WPU    = 0             ' Internal pull-ups = off
    GPIO   = %00000000     ' clear GPIO port
    TRISIO = %00000100     ' All outputs except gpio.2 (input to frequency)
    CCP1CON=0              ' ccpm module off
    
    LCD var GPIO.1			'use GPIO1 pin 6 to LCD display
    GATE var byte            'variable for 1 second gate flag
    TMR_CNT var word         'variable for counting timer0 overflows
    
    on interrupt goto TMR1_INT
    
    'setup Timer0 option_register
    OPTION_REG = %10100111   'bit 7 pullups disabled
                             'bit 6 don't care 
                             'bit 5 Transition on TOCKI pin
                             'bit 4 Increment on low to high TOCKI pin
                             'bit 3 Prescaller assigned to TIMER0
                             'bit 2-0 Prescaller setting 1:256
    INTCON.2 = 0		     'set Timer0 ovrflow flag zero
    TMR0 = 0                 'clear the Timer0 counter register
    
    'clear Timer1 interrupt registers
    T1CON.0 = 0    'TMR1ON disable interrupts for now
    TMR1L = 0      'clear lower 8 bits of Timer1 counter
    INTCON = 0     'clear the system interrupt control register
    PIR1 = 0       'clear the system interrup flag bits register
    PIE1 = 0       'clear perephrial interrupt enable register
    
    pause 1000
    
    'configure Timer1 interrupt settings
    T1CON.3 = 1     'T1OSC of the T1CON register enabled
    PIE1.0 = 1		'Timer1 overflow enable bit enabled
    INTCON.6 = 1	'Perephrial enable bit set to enable
    INTCON.7 = 1    'GIE Global interrupt enable bit enabled
    T1CON = 14		'T1OSCEN enable
                    'T1Sync disabled
                    'TMR1CS external source for Timer1
    TMR1H = 207     'preload hi-byte of Timer1 counter so 
                    'when interrupt occurs with 32khz crystal
                    'on OSC1 + OSC2, it will be 1 second
    T1CON.0 = 1     'T1CON.TMR1ON Timer1 enabled *NOW*
    
    GATE = 1
    
    main:
    while GATE > 0       'After 1 Second Gate interrupt this ends
    @ BTFSC INTCON,2    ;Test Timer0 overflow flag bit
    @ incf _TMR_CNT,f   ;If flag set then increment TMR_CNT by 1
    @ BTFSC INTCON,2    ;Test Timer0 overflow flag bit again
    @ BCF INTCON,2      ;If flag set then clear it
    wend
    
    Display_Results:
    serout LCD,T9600, [#TMR_CNT] 
    pause 2000
    loop_here:
    goto loop_here
    
    ' ************ TIMER1 GATE INTERRUPT ROUTINE AFTER 1 SEC **************
    disable
    TMR1_INT:
    GATE = 0
    T1CON.0 = 0    'TMR1ON disable interrupts for now
    INTCON = 0     'clear the system interrupt control register
    PIR1 = 0       'clear the system interrup flag bits register
    PIE1 = 0       'clear perephrial interrupt enable register
    INTCON.2 = 0   'set Timer0 ovrflow flag zero
    INTCON.7 = 0   'GIE OFF - Turn off all Interrupts
    resume         'goto main
    
    	 
    End
    Last edited by Darrel Taylor; - 17th February 2014 at 18:44. Reason: Fixed Archangel's code tags

  15. #15
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    For this project ... you should not be using interrupts.
    Especially not ON INTERRUPT. There's no guaranteed timing with ON INTERRUPT.

    207 isn't a good value to load in the Timer.
    Since the Timer will normally overflow in 65536 counts, you just need to set bit-7 of the high byte to make it overflow in 32768 counts.
    With a 32768 Hz crystal, it will overflow in exactly 1 second.

    Timer1 doesn't free-run. You need to stop and start it so that you can synchronize the Timer0 Gate output with Timer1's 1 second window.

    Since the PIC's changed now, the oscillator's changed and interrupts are introduced ...
    I think I'll just post my code for the 877A simulation in post #5.
    Hopefully you can convert it for your needs with a different PIC.

    Code:
    ; DT_FREQy.pbp
    ;
    ; Created     : Mon Feb 3 2014
    ; Processor   : PIC16F877A
    ; Compiler    : PicBasic Pro 3.0
    
    ;----[Device Configuration]--(See manual section 4.9)---------------------------
    #CONFIG
      __config  _HS_OSC & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF
    #ENDCONFIG
    
    ;----[DEFINEs]------------------------------------------------------------------
    DEFINE OSC 20
    
    DEFINE LCD_DREG PORTD         ; LCD data port
    DEFINE LCD_DBIT 4             ; LCD data starting bit 0 or 4
    DEFINE LCD_RSREG PORTD        ; LCD register select port
    DEFINE LCD_RSBIT 2            ; LCD register select bit
    DEFINE LCD_EREG PORTD         ; LCD enable port
    DEFINE LCD_EBIT 3             ; LCD enable bit
    DEFINE LCD_BITS 4             ; LCD bus size 4 or 8
    DEFINE LCD_LINES 2            ; LCD Number lines on LCD
    DEFINE LCD_COMMANDUS 2000     ; LCD Command delay time in us
    DEFINE LCD_DATAUS 50          ; LCD Data delay time in us
    
    ;----[Aliases]------------------------------------------------------------------
    Timer1    VAR WORD EXT : @Timer1 = TMR1L
    TMR0IF    VAR INTCON.2
    TMR0CS    VAR OPTION_REG.5
    TMR1IF    VAR PIR1.0
    TMR1CS    VAR T1CON.1         ; Timer1 Clock Source Select bit
    T1OSCEN   VAR T1CON.3         ; Timer1 Oscillator Enable Control bit
    TMR1ON    VAR T1CON.0         ; Timer1 On bit
    T1OSI     VAR PORTC.1         ; 32768 Hz input pin
    PSCLKOUT  VAR PORTA.3         ; pin to clock out the remaining prescaler
    PSA       VAR OPTION_REG.3    ; Prescaler Assignment bit
    
    ;----[Variables]----------------------------------------------------------------
    Result     VAR WORD[2]        ; Final 32-bit Frequency measurement
    T0overflow VAR Result[1]      ; Counts Timer0 overflows (HighWord of the result)
    T0value    VAR Result.BYTE1   ; Final Timer0 value
    PScount    VAR Result.BYTE0   ; Final Timer0 Prescaler value
    
    FreqHigh   VAR WORD           ; Top five digits of the decimal result
    FreqLow    VAR WORD           ; Bottom 3 digits of the decimal result
    MeasCount  VAR WORD           ; Counts number of measurements
    
    ;----[Initialize]---------------------------------------------------------------
    ADCON1 = 7                    ; All Digital
    CMCON  = 7
    T1OSCEN = 1                   ; Start Timer1 oscillator
    PAUSE 250                     ; LCD Power-Up delay 
    LCDOUT $FE,1,"DT's FREQy"
    MeasCount = 0                 ; clear the measurement count
    
    ;----[Main Program Loop]--------------------------------------------------------
    Main:
        GOSUB MeasureFreq         ; Get a Frequency Measurement
        GOSUB DisplayFreq         ; Display the Frequency
    
        MeasCount = MeasCount + 1 ; increment and display measurement count
        LCDOUT $FE,$94,"Meas = ", DEC MeasCount
    GOTO Main
    
    ;----[Measure frequency on T0CKI]-----------------------------------------------
    MeasureFreq:
        LOW PSCLKOUT          ; prevent signal from getting to Timer0
        PSA = 0               ; Prescaler is assigned to the Timer0 module
        TMR0CS = 1            ; Transition on T0CKI pin
        TMR1CS = 1            ; Timer1 Clock source = T1CKI (T1OSC)
        TMR1ON = 0            ; Stop Timer1
        TMR0IF = 0            ; Clear Timer0 overflow flag
        T0overflow = 0        ; Clear Timer0 overflow count
        TMR0 = 0              ; Clear Timer0 value
    
        Timer1 = $FFFF        ; Timer1 overflows on next cycle of 32768 Hz clock
        TMR1IF = 0            ; Clear Timer1 overflow flag
        TMR1ON = 1            ; Start Timer1 1 sec. period
        WHILE !TMR1IF : WEND  ; Synchronize to 32768 clock
        INPUT PSCLKOUT        ; Start counting freq input
        Timer1.15 = 1         ; Set Timer1 to 32768 for 1 Sec. period
        TMR1IF = 0            ; Clear Timer1 overflow flag
    
        WHILE !TMR1IF         ; while 1 sec. window is open  ---|
            IF TMR0IF THEN    ; count TMR0 overflows            | This section
                T0overflow = T0overflow + 1  ;                  | does the actual
                TMR0IF = 0                   ;                  | 1-Sec measurement
            ENDIF                            ;                  | Window
        WEND                                 ;               ---|
        LOW PSCLKOUT           ; Stop further counting
        T0value = TMR0         ; get Timer0 value
    
        PScount = 0            ; Clock out remaining prescaler
        WHILE TMR0 = T0value   ; until TMR0 value changes
            HIGH PSCLKOUT
            PAUSEUS 3
            LOW PSCLKOUT
            PAUSEUS 3
            PScount = PScount + 1
        WEND
        PScount = -PScount     ; negate to get prescaler count
    RETURN
    
    ;----[Display frequency on LCD]-------------------------------------------------
    DisplayFreq
        R2 = Result            ; Load Result into PBP's system vars for DIV32
        R0 = Result[1]
        FreqHigh = DIV32 1000  ; get left most 5 digits
        FreqLow = R2           ; remainder (R2) is right 3 digits
    
        LCDOUT $FE,$C0,"Freq = "
        IF FreqHigh > 0 THEN                        ; if any left digits
            LCDOUT DEC FreqHigh, DEC3 FreqLow,"   " ; display both left and right
        ELSE                                        ;  otherwise 
            LCDOUT DEC FreqLow,"     "              ; display only right digits
        ENDIF
    RETURN
    
    END
    Last edited by Darrel Taylor; - 17th February 2014 at 20:34.
    DT

  16. #16
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Thanks Darrel!!
    I think I'll try to figure out how to mount the 32khz crystal onto the Labx-1 board.
    I may be able to create a small pcb with headers that I can plug into the female header pins on the side of the 887a.

    I should be able to see the 32khz oscillator with an Oscope to verify its running.
    Interesting, I did play with loading different values into the high byte of Timer1s counting register and had it pull a pin high for the duration until timer1 rolled over and into the interrupt routine. 207 was what gave me a 1 sec pulse.
    So I assumed it was the right number to load.

    Thanks again for providing the code.
    It will be super fun to try it out :-]
    Duane

  17. #17
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    I had a question...but connected the dots when I posted it.
    Last edited by dw_picbasic; - 19th February 2014 at 22:12. Reason: tried to remove the question....got it :-]

  18. #18
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi Darrel,
    I'm curious about something in the code
    I see that you capture the Timer1 overflow count and load it into RESULTS.[bit16-31]
    Then load the remaining count in TMR0 into RESULTS.[bit8-15]
    But I thought that TMR0 is a 16 bit register....how is it we're loading its value into an 8 bit location in RESULTS?

    Thanks!!
    Duane :-]

  19. #19
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi Duane,
    No, the TMR0 register is only 8 bits wide, that's why you need to use the trick with getting the remaining count out of the prescaler.
    So, RESULT is a total of 4 bytes where the two most significant bytes are the number of TMR0 overflows, the next byte is the TMR0 count (where each count equals 256 transitions of the inputsignal due the 1:256 presacaler ratio) and the least significant byte is the number of transitions "stored" in the prescaler.

    /Henrik.

  20. #20
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Ah!
    Thats right!!...sorry... I forgot the Timer0 is an 8 bit register.
    I slipped on that one :-/

    Thanks!

  21. #21
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Can I pose another question:
    Lets say that the frequency that is being measured within the 1 second gate period is 301234hz
    Is it the case that the value that will be captured within T0overflow, RESULTS.[bit16-31] = (301234/256)?
    Which (in integer form) would resolve to 1176 overflows of the Timer0 8 bit register?
    And then the remainder value of 178, which remains within TMR0 will be loaded into T0value RESULTS.[bit8-15]?
    Thanks!!
    Duane

  22. #22
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    The prescaler divides by 256, and TMR0 divides by 256.
    So the overflows only happen every 65536 counts.

    With a frequency of 301234, there will only be 4 overflows, with 39090 remaining.
    That's 152 in TMR0, and 178 in the prescaler.

    Another way to look at it is to convert the Frequency to a HEX number
    #301234 = $4:98B2

    Now it's easy to see that there will be 4 overflows, TMR0 will have $98 = 152, and the prescaler has $B2 = 178.

    HTH
    DT

  23. #23
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Thanks Darrel,
    I didn't see the prescaler settings in setup code.
    I see "PSA [OPTION_REG.3] set to 0 which sets the prescaller from the WDT to Timer0
    But I don't see any settings for OPTION_REG.0, 1 and 2.
    Are they there in the code and I missed them?
    Thanks!!
    Duane

  24. #24
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    On power-up, the default value of OPTION_REG is %11111111.
    Which means the prescaler is already set to 1:256.
    There is no need to set it again in the code.

    Name:  Option_Reg_Defaults.gif
Views: 5906
Size:  14.0 KB
    DT

  25. #25
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi Duane,
    If you look up OPTION_REG in the datasheet, you'll find that it defaults to "all ones", $FF, 255 whichever way you want to look at it.
    This means that the prescaler ratio, when assigned to TMR0 defaults to 1:256 - so no need to change it.

    /Henrik.

    EDIT: Damn, you're fast today Darrel!

  26. #26
    Join Date
    Jan 2007
    Posts
    78


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Sweet!!
    Thanks!
    I had a suspicion that was the case, but I have an old habit of wanting to make sure in the code.
    This gives the old dog a new trick!! :-]

  27. #27
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Quote Originally Posted by Darrel Taylor View Post
    The prescaler divides by 256, and TMR0 divides by 256.
    So the overflows only happen every 65536 counts.

    With a frequency of 301234, there will only be 4 overflows, with 39090 remaining.
    That's 152 in TMR0, and 178 in the prescaler.

    Another way to look at it is to convert the Frequency to a HEX number
    #301234 = $4:98B2

    Now it's easy to see that there will be 4 overflows, TMR0 will have $98 = 152, and the prescaler has $B2 = 178.

    HTH
    Hello Darrel,

    found your excellent example and i would like to build the same counter based on PIC16F870. From your above post i understand, that with prescaler 256 minimum measured frequency is 65536Hz, otherwise TMR0 will not overflow, or am i wrong? To measure lower frequencies i would have to change the OPTION_REG bits 2-0 , which will set prescaler to 1:2?

    P.S. My target measurement range is 1 HZ - 1 MHz.
    Last edited by Rufinus; - 16th March 2015 at 15:53.

  28. #28
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi Rufinus,
    Sadly Darrel has passed away and is no longer with us.

    I'll try to answer your qeustion.
    It's correct that with a prescaler of 1:256 the timer will only overflow every 65536 "tick" but that doesn't prevent Darrels code from measuring frequencies lower than 65536Hz. As I wrote in a previous post the two most significant bytes of the 4 byte result will contains the number of overflows (ie "units" of 65536Hz), the next byte is the TMR0 value which is in units of 256Hz and the least significant byte is what's stored in the prescaler, in units of 1Hz. All provided your "gate time" is precisely 1Hz of course.

    So, if your input frequency is 125Hz then after the one second gate time there will be 0 overflows, 0 counts in TMR0 and 125 counts in the prescaler. The prescaler isn't readable so the code then "manually" pulses the counter input to find out how many pulses is needed before the prescaler overflows and TMR0 increases. In this example it would take 131 (125+131=256) which, when stored in a byte and negated "becomes" the value 125.

    Changing the prescaler won't help you measure the low frequencies. The only way to gain resolution at the lower end is to increase the gate time, count for 2, 5, 10 or whatever seconds instead of 1 and adjust the calculations accordingly.

    /Henrik.

  29. #29
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Holy Christ, i had no idea! So sorry about that.. R.I.P Darrel..

    Thanks for fast answer Henrik, but please let me pull my thought together before i can understand your explanation..

  30. #30
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Quote Originally Posted by HenrikOlsson View Post
    Hi Rufinus,
    Sadly Darrel has passed away and is no longer with us.

    I'll try to answer your qeustion.
    It's correct that with a prescaler of 1:256 the timer will only overflow every 65536 "tick" but that doesn't prevent Darrels code from measuring frequencies lower than 65536Hz. As I wrote in a previous post the two most significant bytes of the 4 byte result will contains the number of overflows (ie "units" of 65536Hz), the next byte is the TMR0 value which is in units of 256Hz and the least significant byte is what's stored in the prescaler, in units of 1Hz. All provided your "gate time" is precisely 1Hz of course.

    So, if your input frequency is 125Hz then after the one second gate time there will be 0 overflows, 0 counts in TMR0 and 125 counts in the prescaler. The prescaler isn't readable so the code then "manually" pulses the counter input to find out how many pulses is needed before the prescaler overflows and TMR0 increases. In this example it would take 131 (125+131=256) which, when stored in a byte and negated "becomes" the value 125.

    Changing the prescaler won't help you measure the low frequencies. The only way to gain resolution at the lower end is to increase the gate time, count for 2, 5, 10 or whatever seconds instead of 1 and adjust the calculations accordingly.

    /Henrik.
    Ok, now i think i got it. It was the last step (remainder in prescaler), which I could not understand.
    But it would mean then, that the smallest frequency, which I could measure in one second is 256 Hz.
    For lower frequencies i would have to increase sampling time.

    Lets say, it is very rare, that one needs to measure frequency below 20 Hz in normal application.
    That would mean, that in 1 second sampling time there will be 20 counts in prescaler, which in turn means we would have to provide 256-20=236 counts more to overflow it. So, 236 remaining counts divided by 20 gives us 11.8 seconds! We will need to increase sampling time to 11.8 seconds, in order to measure 20 Hz frequency, or ?!

    I think I will have to think about some other algorithm to measure frequencies below 256 Hz, maybe with COUNT command or so. Precision might suffer, but that would be a reasonable compromise. Target would be to keep the one second sampling rate over whole range.

    Thanks again Henrik, for explaining.

  31. #31
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Or "manual counting" in your example is the part of the code, which fills out the precaler by toggling PSCLKOUT for 3uS instead of using actual measured frequency to increase the count? Than it schould be significantly faster, than 11.8 seconds. In fact, it should be just very sligtly over 1 second for 20 Hz, or?

  32. #32
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Hi,
    But it would mean then, that the smallest frequency, which I could measure in one second is 256 Hz.
    For lower frequencies i would have to increase sampling time.
    Not really but it depends on the resolution you need. If the gate time is one second and the input frequency is 2Hz then the prescaler will count to 2 during each gate period - therefor you'll get a result of 2Hz. But if the frequency is 2.5Hz then the displayed result will "flicker" between 2 and 3 Hz. If the gate time is increased to 10 seconds the prescaler will accumulate 25 counts which, when divided by 10 is 2.5.

    [quote]Lets say, it is very rare, that one needs to measure frequency below 20 Hz in normal application.
    That would mean, that in 1 second sampling time there will be 20 counts in prescaler, which in turn means we would have to provide 256-20=236 counts more to overflow it.[quote]
    That's correct!

    So, 236 remaining counts divided by 20 gives us 11.8 seconds! We will need to increase sampling time to 11.8 seconds, in order to measure 20 Hz frequency, or ?!
    No, not at all.
    After the one second gate time the prescaler will hold 20 (which is the correct input frequency since the gate time was 1 second). By counting the number of additional pulses it takes for the prescaler to overflow you know what value was in the prescaler. It'll require 236 pulses which when negated is 20.

    Or "manual counting" in your example is the part of the code, which fills out the precaler by toggling PSCLKOUT for 3uS instead of using actual measured frequency to increase the count? Than it schould be significantly faster, than 11.8 seconds. In fact, it should be just very sligtly over 1 second for 20 Hz, or?
    Yes, the "gate time" needs to be exactly 1 second but the total time for the measurment, the "prescaler value extraction", calculation and display will of course be a bit more than the gate time alone.

    /Henrik.
    Last edited by HenrikOlsson; - 16th March 2015 at 22:22.

  33. #33
    Join Date
    Oct 2005
    Location
    Stuttgart, Germany
    Posts
    24


    Did you find this post helpful? Yes | No

    Default Re: Counting Timer0 and Timer1 overflows without any interrupt handler

    Great, thanks, now i do have a complete picture. Surely resolution below 1 Hz in my case is overkill. Crystals will come tomorrow and i can start testing.

    Also started reading about reciprocal counters

Similar Threads

  1. Expanding Timer1 counting range
    By sycluap in forum mel PIC BASIC Pro
    Replies: 14
    Last Post: - 3rd February 2014, 23:00
  2. PIC18 timer0 interrupt handler, still not getting it
    By ImAnEE in forum mel PIC BASIC Pro
    Replies: 4
    Last Post: - 30th April 2011, 01:25
  3. DT-INTs Interrupt handler question
    By circuitpro in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 8th January 2010, 01:06
  4. Synchronising Timer0 and Timer1
    By manxman in forum mel PIC BASIC Pro
    Replies: 8
    Last Post: - 10th April 2008, 00:12
  5. 16F690 TIMER0 and TIMER1
    By nickdaprick in forum mel PIC BASIC
    Replies: 2
    Last Post: - 18th April 2007, 15:49

Members who have read this thread : 3

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts