Measuring change of frequency with PIC


Closed Thread
Results 1 to 6 of 6
  1. #1
    Join Date
    May 2007
    Location
    Melbourne
    Posts
    3

    Default Measuring change of frequency with PIC

    Hi boys/girls.

    I have a task to determine if the frequency on a PIC input changes more than certain %, let’s say 1%. If that occurs, I should turn on an LED and when the frequency is back, that LED should be off again.

    I am using PIC18F458 which has 4 timers, TMR0 as per manual is able to calculate pulses on RA4, i.e. able to work as a counter.

    What I decided to do is to use 2 timers TMR0 and TMR1. Initially I will reset them, after that TMR0 will count input pulses up to overflow, TMR1 will count an internal frequency within that timing interval. When TRM0 overflows, I will just stop timers and keep that value of TMR1. After that reset TMR0 and TMR1 and start counting again, etc.
    Comparing the current value and the subsequent value of TMR1 I can say whether we had a difference of more than 1%, i.e. this is like an indirect way.

    The problems.
    1. In my program the TMR0 does not work but I checked the control codes and for me they look all right.
    2. I am not sure if I use overflow of TMR0 correctly in terms of providing reset for overflow bit, etc.

    Anyway, the part of the program which calculates the subsequent values in TMR1 is below and the program does not go below


    Define OSC 10
    define HSER_TXSTA 20h
    define HSER_BAUD 9600

    ' variables defintion
    overflow var word
    OverflowValue var word
    TMR1valuelow var byte
    TMR1valuehigh var byte
    Value var word
    TMR1Overflow var bit
    TMR0Overflow var bit

    TRISA = %11111111 ' Set all PORT A to input
    TRISC = %10010000 ' Set all PORT C to output/input for RS232

    ' ports variables
    InputSignal var PORTA.4 ‘ actually TMR0 does not work if I remove this operator
    ‘ in such mode TMR0 should count pulses on PORTA.4
    TMR0Overflow = INTCON.2 ‘ just in case overflow flag reset for TMR0, not sure I
    ‘ can like that

    PIR1.0 = 0 ' clear overflow flag of TMR1 just in case
    INTCON.2 = 0 ' clear overflow flag of TMR0
    T1CON = %10000000 ' stop TMR1, internal clock, scale 1:1, 16-bit work
    T0CON = %01101000 ' stop TMR0, 8 bit, input RA4, low-high, no prescaler
    TMR1L = 0 ' clear TMR1 low
    TMR1H = 0 ' clear TMR1 high
    TMR0L = 0 ' clear TMR0 low

    main:
    T0CON = %11101000 ' start TMR0, 8 bit, input RA4, low-high, no prescaler (1:1)
    T1CON = %10000001 ' start TMR1 as 16-bit timer
    while TMR0Overflow = 0
    wend
    T1CON = %10000000 ' stop TMR1
    T0CON = %01101000 ' stop TMR0
    TMR1valuelow = TMR1L
    TMR1valuehigh = TMR1H
    OverflowValue = TMR1valuehigh * 256
    Value = TMR1valuelow + OverflowValue ' this is value of TMR1
    ‘ overflow+remaining

    Hserout [dec Value]
    ' for checking purposes when adjust the program
    ' put Value to RS232 thru hserout to see TMR1 value

    TMR1L = 0 ' clear TMR1 low
    TMR1H = 0 ' clear TMR1 high
    TMR0L = 0 ' clear TMR0 low
    PIR1.0 = 0 ' clear overflow flag of TMR1
    INTCON.2 = 0 ' clear overflow flag of TMR0


    goto main

    End

    Questions.
    1. Why TMR0 does not calculate anything?
    2. Am I right with TMR0 overflow handling?

    Thanks for comments.

  2. #2
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    1. Why TMR0 does not calculate anything?
    while TMR0Overflow = 0
    wend

    You're testing a bit variable here that's never being updated, so it's stuck in
    the loop.

    Change TMR0Overflow var bit to TMR0Overflow var INTCON.2 and it should
    work as expected.

    2. Am I right with TMR0 overflow handling?
    Testing for overflow via the overflow bit is correct.

    Also, with Timer1 configured as 16-bit, you'll want to write to TMR1H first,
    then TMR1L.

    The value being written to TMR1H is is loaded into a buffer, then transferred
    to TMR1H when a write to TMR1L occurs.

    So for writes, write to TMR1H then TMR1L. For reads, read TMR1L first, then
    TMR1H.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  3. #3
    Join Date
    May 2007
    Location
    Melbourne
    Posts
    3


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Bruce View Post
    while TMR0Overflow = 0
    wend

    You're testing a bit variable here that's never being updated, so it's stuck in
    the loop.

    Change TMR0Overflow var bit to TMR0Overflow var INTCON.2 and it should
    work as expected.


    Testing for overflow via the overflow bit is correct.

    Also, with Timer1 configured as 16-bit, you'll want to write to TMR1H first,
    then TMR1L.

    The value being written to TMR1H is is loaded into a buffer, then transferred
    to TMR1H when a write to TMR1L occurs.

    So for writes, write to TMR1H then TMR1L. For reads, read TMR1L first, then
    TMR1H.
    Thanks Bruce!
    Your idea worked fine but the issue is that it looks like at this PIC the TMR0 input signal should be synchronized with the internal phase clock which I don’t have and can’t have. My input signal is from an independent source. I found in the manual that synchronization issue.

    As a result, the timer shows basically random results.
    I gave up with TMR0 and will calculate the input pulses just using counting. I changed the program for that and noticed that it works but the problem is that the TMR1H accumulates the value and I can’t realise why. every circle TMR1 does notr have reset despite I put an operator to do that.

    The program is below.
    Do any have any suggestions? It’s some stupid error…


    Define OSC 10
    define HSER_TXSTA 20h
    define HSER_BAUD 9600

    ' variables defintion
    Counter var byte
    TMR1valuelow var byte
    TMR1valuehigh var byte

    TRISA = %11111111 ' Set all PORT A to input
    TRISB = %11111111 ' Set all port B to input
    TRISC = %10010000 ' Set all PORT C to output/input for RS232

    ' ports variables
    InputSignal var PORTB.0


    clear
    main:
    Counter = 0
    T1CON = %10000000 ' stop TMR1, internal clock, scale 1:1, 16-bit work
    TMR1L = 0 ' clear TMR1 low
    TMR1H = 0 ' clear TMR1 high
    PIR1.0 = 0 ' reset overflow flag for TMR1 just in case
    T1CON = %10000001 ' start TMR1 as 16-bits

    loop1:
    while InputSignal = 0
    wend ‘ waiting for rising edge of input signal
    Counter = Counter + 1 ' counting rising edges of input pulses
    if Counter = 250 then exit ' when 250 input pulses – look at TMR1 values
    while InputSignal = 1
    wend ‘ waiting for falling edge of input signal
    goto loop1 ‘ going back on falling edge

    exit:
    T1CON = %10000000 ' stop TMR1
    TMR1valuelow = TMR1L
    TMR1valuehigh = TMR1H

    Hserout ["TMR1low =",dec TMR1valuelow, "TMR1high =",dec TMR1valuehigh]

    goto main

    End

    So, what I noticed in here is that it looks like TMR1H does not go to zero when I reset it at each stage clearing TMR1high and accumulates the value. Why is that?
    Appreciate your comments.

  4. #4
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    With Timer1 configured for 16-bit read/write, you need to write to TRM1H
    first, then write to TMR1L.

    So change;
    TMR1L = 0 ' clear TMR1 low
    TMR1H = 0 ' clear TMR1 high

    To;
    TMR1H = 0 ' writes to TMR1H buffer
    TMR1L = 0 ' writes TMR1H 'buffer' to TMR1H register & writes to TMR1L
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  5. #5
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    If RC2 is avilable you could also use the hardware capture module.
    Code:
    ' Measuring pulse width with capture module
    ' Input signal connected to RC2/CCP1 pin
    
        DEFINE OSC 4
       
        Symbol Capture = PIR1.2 ' CCP1 capture flag
        T1 VAR WORD          ' 1st capture value
        T2 VAR WORD          ' 2nd capture value
        T3 VAR WORD          ' 3rd capture value
        LowCycle VAR WORD    ' low pulse width rsult
        HighCycle VAR WORD   ' high pulse width result
        
        TRISC.2 = 1          ' CCP1 input pin (Capture input)
        INTCON = 0           ' Interrupts off
        CCP1CON = %00000101  ' Capture mode, capture on rising edge
        T1CON = %10000001    ' TMR1 prescale=1, clock=Fosc/4, TMR1=on
     
    Main:
        WHILE !Capture      ' wait for rising edge capture
        WEND
        ' Rising edge detected so record timer1 value
        T1.HighByte = CCPR1H : T1.LowByte = CCPR1L
        
        Capture = 0         ' Clear capture flag bit
        CCP1CON.0 = 0       ' Configure capture for falling edge now
        
        While !Capture      ' While here for capture on falling edge
        Wend
        ' Falling edge detected so record timer1 value again
        T2.HighByte = CCPR1H : T2.LowByte = CCPR1L
        
        Capture = 0         ' Clear capture flag bit
        CCP1CON.0 = 1       ' Configure capture for rising edge now
        
        While !Capture      ' While here for capture on falling edge
        Wend
            
        ' Falling edge detected so record timer1 value again
        T3.HighByte = CCPR1H : T3.LowByte = CCPR1L
        
        CCP1CON = 0         ' disable capture during data processing
        
        HighCycle = T2-T1   ' High pulse width = T2 - T1
        LowCycle = T3-T2    ' Low pulse width = T3 - T2
          
        HSEROUT ["High pulse width = ",DEC HighCycle,"uS",13,10]
        HSEROUT ["Low pulse width = ",DEC LowCycle,"uS",13,10]
        HSEROUT ["Period = ",DEC LowCycle+HighCycle,"uS",13,10]
        
        Capture = 0          ' Clear capture flag bit
        CCP1CON = %00000101  ' Capture mode, capture on rising edge
        
        GOTO Main
    
        END
    If the measured frequency is too slow you can use the timer prescaler. You
    want the frequency to be high enough so the timer doesn't overflow during
    the measurement period.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  6. #6
    Join Date
    May 2007
    Location
    Melbourne
    Posts
    3


    Did you find this post helpful? Yes | No

    Smile

    Quote Originally Posted by Bruce View Post
    With Timer1 configured for 16-bit read/write, you need to write to TRM1H
    first, then write to TMR1L.

    So change;
    TMR1L = 0 ' clear TMR1 low
    TMR1H = 0 ' clear TMR1 high

    To;
    TMR1H = 0 ' writes to TMR1H buffer
    TMR1L = 0 ' writes TMR1H 'buffer' to TMR1H register & writes to TMR1L
    Thanks a lot Bruce,
    I changed only that thing in my program and it started working .
    Have never seen in the manual that such a sequence of work with the timers should be...

Similar Threads

  1. TSA5512/5511 code for PIC16F877/84
    By Marin in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 24th August 2013, 06:16
  2. newbe looking for PIC advice
    By Mad Professor in forum General
    Replies: 3
    Last Post: - 27th May 2009, 07:56
  3. Automatic VB6 to pic serial connection
    By arniepj in forum Code Examples
    Replies: 13
    Last Post: - 10th January 2008, 07:57
  4. Replies: 2
    Last Post: - 10th February 2006, 01:04
  5. Serial Pic to Pic using HSER
    By Chadhammer in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 11th March 2005, 23:14

Members who have read this thread : 1

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