Menu

Help with Frequency Measuring will Pay you!

Help
Anonymous
2010-01-29
2013-05-30
  • Anonymous

    Anonymous - 2010-01-29

    Hi,

    Need someone to write me some code to do the following:-

    Measure frequency (about a 3-4v squarewave) of about 5hz-125hz on a PIC of your choice (needs to be 14Pin or less) and send the value out in binary via serial at about say 5hz

    Anyone interested, needs to be tested and compiled and i need the source code so i can change if needed, oh and confirmation of the circuit/components used, will pay what, $100 ?

    Have another project i am working on, need this to inerface with my existing project, and just dont have time (and probably not the skills!) to crack this one.

    Thanks

    Matthew

     
  • Nobody/Anonymous

    You want it to updated  the value 5 times each sec?
    What for baud rate?

     
  • Nobody/Anonymous

    If you are updating 5 times a sec  and the minimum freq is 5 hz  then the period has to be measured.
    Is the input signal symetrical?  so only half of it can be measured and the rest assumed?

     
  • Nobody/Anonymous

    maybe change the sample rate, so have it send out at say 2hz, when below 5hz input then change to outputting 5hz when input goes over 10hz perhaps? whatever will work, baud rate needed for output is 57600

     
  • Nobody/Anonymous

    can anyone help?

     
  • Nobody/Anonymous

    been trying to form a complete plan.
    The constraints run into each other.
    Here is what i have so far.

    First select the chip.
    Must have usart onboard to do 56.7Kbaud

    CCP capture might be helpful but it only triggers on the rising or falling edge
    so you get counting for a whole cycle

    If the signal is symmetrical then half the cycle could be counted
    using the ext interrupt to sense the begginning or end of the pulse.

    Timer 1 would be used to count the period because 10us counts are needed to tell
    125hz from 124 hz from 123 hz

    125hz = 8ms
    124hz ~ 8ms
    123hz ~ 8ms

    100hz = 10ms

    10Hz  = 100ms
    5hz   = 200ms

    Timer1 is a 16 bit counter so with 10us/cnt resolution it would fit.

    math is limited.
    so a  "word table" could be used to find the solution.

    Counting for 1 sec was sooo much easier.

     
  • Nobody/Anonymous

    ok, thanks for your help so far, input is squarewave so yes symetrical, i was assuming (probably wrongly) that you can count the period between pulses, and then calculate frequency rather than count number during a time.

    i kind of figured a microcontroller would have made short work of measing frequency, didnt realise it would be so hard!

     
  • kent_twt4

    kent_twt4 - 2010-02-05

    Well I think you are on the right track and very close to solving it.  Agree that watching rollovers of Timer1 does not apply to the time frame specified. Using the "On Interrupt CCP1 call Freq" and reading the CCP1H and CCP1L registers (copies of TMR1 registers) directly on a rising edge makes sense.  So a few ideas and code snippets might help.

    Set up the TMR1 prescale so 5Hz doesn't overflow (i.e. 200,000 us).  If the 8Mhz Osc is maintained then a prescale of 1/16 gives a 8 us tick or 25,000 counts for 5Hz.  That's good because then you could check for out of bounds, values < 5Hz, by determining if CCP1H.7 is set or not, and do something if it is.  So an init_CCP1 sub and interrupt routine might be like:

    sub initCCP1
    dim Pulse as word
    dir PortC.5 in  ;Freq input Pin RC5/CCP1/P1A
    InitTimer1 Osc, PS1_1/16    ;8 us tick with 8 Mhz Osc
    CCP1CON = b'00001001'  ;start Freq capture on rising edge
    On Interrupt CCP1 call Freq
    StartTimer 1
    end sub
    
    sub Freq
    CCP1F = 0    ;clear capture flag
    TMR1On = 0    ;stop clock
    Pulse_H = CCPR1H
    Pulse = CCPR1L
    TMR1On = 1    ;start the clock
    end sub
    

    Some ideas on a word table and reading it into an array, hope it helps.

    Table SINinverse  
    ;GCBasic inserts length of table in first bytes location
    0X00  ;bump table to even no. because 0(even) occcupied by size
    0x00  ;begin table values here SINY_H (high byte)
    0xAE  ;dec 174  1 degree SINY (low byte)
    0x01
    0x5D  ;dec 349
    0x02
    0x0B  ;dec 523
    0x02
    0xBA  ;dec 698
    0x03
    0x68  ;dec 872  5 degrees
    0x04
    0x15  ;dec 1045
    ...
    ...
    end table
    Sub ReadSINTable
    For tableNum = 2 to 51  ;i.e. 2 to 52 because of incr. 
        ReadTable SINinverse, tableNum, SINY_H
        SINarray(tableNum) = SINY_H
        tableNum += 1
        ReadTable SINinverse, tableNum, SINY
        SINarray(tableNum) = SINY
    Next
    end sub
    
     
  • mmotte

    mmotte - 2010-02-06

    Thanks Kent,
    You gave me  the structure and I filled it in.
    I only have a 16F886 to work with and timer 1  prescaler only goes to 8
    Here is  the  working  code so far.
    It prints out the  captured counts just fine!
    9-10 hz    =1382
    106-108hz = 127
    my freq counter isn't made for these low freq so it wanders

    Now  I need to program table.

    Thanks again  Mike

    #chip 16F886, 4

    #define USART_BAUD_RATE 57600 '……..or the value you want
    '#define USART_BLOCKING
    dim Pulse as word
    InitUsart
    dir PORTC.7 in
    dir PORTC.6 out
    dir PORTB.0 out
    initCCP1

    start:
    HSerPrint (Pulse)
    HSerSend(13)

    HSerSend(10)
    SET PORTB.0 OFF

    wait 10 10ms
    SET PORTB.0 ON

    wait 10 10ms

    goto start

    sub initCCP1
    dir PortC.2 in  ;Freq input Pin RC2/CCP1/P1A on the PIC16F886
    T1CON =  b'00110001'
    CCP1CON = b'00000101'  ;start Freq capture on rising edge
    On Interrupt CCP1 call Freq
    StartTimer 1
    end sub

    sub Freq
    TMR1L =0
    TMR1H =0
    Pulse_H = CCPR1H
    Pulse_L = CCPR1L
    CCP1IF = 0    ;clear capture flag
    end sub

     
  • Nobody/Anonymous

    This code is running but isn't real accurate for freq.  I don't have a good low freq source/counter at home.
    9-10hz  reads 9
    60 hz  reads 61
    106-109 reads 109
    My GCBasic compiler's  Low level usart.h file needed to be fixed.  look it up on the forum , maybe urs is ok
    I am running internal osc,  so that too is less accurate
    GL

    'up side down Freq counter for low fequencies  4-155hz
    'measures 1 cycle with the Timer 1 running  div 8 off of the system clock and tranfers
    'the length using the CCP1 of the chip to CCPR1H &L
    'Then a look down table is used to find the frequency
    'I only had three values to regress into the table equation is
    'width = 253887 * (freq ^ -0.999).  this is a rough estimate that canbe improved with more points
    '2/7/2010
    'Mike Otte
    
    #chip 16F886, 8 
    #define USART_BAUD_RATE 57600 ' the "uart.h" in low level had to be fixed  
    #define USART_BLOCKING        ' the "uart.h" in low level had to be fixed  
    dim Pulse as word
    dim Temp as word
    InitUsart
    dir PORTC.7 in
    dir PORTC.6 out
    dir PORTB.0 out
    initCCP1
    start:
    'HSerPrint (Pulse)  'uncomment to see the pulse count
    'HserSend(32)       ' send a space
    'HSerPrint (Temp)   'uncomment to see the one chosen in the table
    'HserSend(32)
    findfreq
    HSerPrint (Freqout)
    HSerSend(13)        'send a linefeed and return
    HSerSend(10)
    SET PORTB.0 OFF     ' I like "I am Alive" Leds
    wait 9 10ms
    SET PORTB.0 ON
    wait 10 10ms        'this also wastes about 190ms for the 5 hz refresh
    goto start
    sub initCCP1
    dir PortC.2 in  ;Freq input Pin RC2/CCP1/P1A on the PIC16F886
    T1CON =  b'00110001'
    CCP1CON = b'00000101'  ;start Freq capture on rising edge
    On Interrupt CCP1 call Freq    ' set up the interrupt to read the freq and reset the timer
    StartTimer 1
    end sub
    sub Freq
    TMR1L =0     ' reset timer 1
    TMR1H =0
    Pulse_H = CCPR1H  'read pulse width and store
    Pulse_L = CCPR1L
    CCP1IF = 0        'clear capture flag
    end sub
    'LOOK DOWN Search
    'find the pulse width in the table 
    'enter with 'Pulse' from above
    'exit with 'freqout'
    sub findfreq
    FOR index = 4 to 155
    ReadTable FreqTable, index, Temp
    IF  Pulse > Temp THEN goto done
    next
    done:
    freqout = index-1
    end sub
    Table FreqTable   'word table of pulse widths
    0
    0
    0
    63560
    50859
    42390
    36340
    31802
    28272
    25447
    23136
    21210
    19580
    18183
    16972
    15912
    14977
    14146
    13402
    12732
    12127
    11576
    11073
    10612
    10188
    9797
    9434
    9098
    8784
    8492
    8218
    7962
    7720
    7494
    7280
    7078
    6887
    6706
    6534
    6371
    6215
    6068
    5927
    5792
    5663
    5540
    5423
    5310
    5202
    5098
    4998
    4902
    4809
    4720
    4635
    4552
    4472
    4395
    4321
    4249
    4179
    4112
    4047
    3984
    3922
    3863
    3805
    3749
    3695
    3642
    3591
    3541
    3493
    3446
    3400
    3355
    3312
    3269
    3228
    3188
    3148
    3110
    3072
    3036
    3000
    2965
    2931
    2898
    2865
    2834
    2803
    2772
    2742
    2713
    2685
    2657
    2629
    2603
    2576
    2551
    2525
    2501
    2476
    2453
    2429
    2406
    2384
    2362
    2340
    2319
    2298
    2278
    2257
    2238
    2218
    2199
    2180
    2162
    2144
    2126
    2108
    2091
    2074
    2057
    2041
    2025
    2009
    1993
    1978
    1963
    1948
    1933
    1918
    1904
    1890
    1876
    1862
    1849
    1836
    1822
    1810
    1797
    1784
    1772
    1760
    1748
    1736
    1724
    1712
    1701
    1690
    1679
    1668
    1657
    1646
    0
    0
    End Table
    
     
  • mmotte

    mmotte - 2010-02-10

    Added some bounds checking for freq too high and freq too low

    start:
    'HSerPrint (Pulse)  'uncomment to see the pulse count
    'HserSend(32)       ' send a space
    'HSerPrint (Temp)   'uncomment to see the one chosen in the table
    'HserSend(32)
    If FreqTooLow = 0 then findfreq  'check if a CCP interrupt came thru
    HSerPrint (Freqout)
    HSerSend(13)        'send a linefeed and return
    HSerSend(10)
    SET PORTB.0 OFF     ' I like "I am Alive" Leds
    wait 9 10ms
    SET PORTB.0 ON
    wait 10 10ms        'this also wastes about 190ms for the 5 hz refresh
    goto start
    sub initCCP1
    dir PortC.2 in  ;Freq input Pin RC2/CCP1/P1A on the PIC16F886
    T1CON =  b'00110001'
    CCP1CON = b'00000101'  ;start Freq capture on rising edge
    On Interrupt CCP1 call Freq    ' set up the interrupt to read the freq and reset the timer
    StartTimer 1
    end sub
    sub Freq
    TMR1L =0     ' reset timer 1
    TMR1H =0
    Pulse_H = CCPR1H  'read pulse width and store
    Pulse_L = CCPR1L
    CCP1IF = 0        'clear capture flag
    FreqTooLow = 0
    end sub
    'LOOK DOWN Search
    'find the pulse width in the table 
    'enter with 'Pulse' from above
    'exit with 'freqout'
    sub findfreq
    ' check for overflow => freq too low
    If TMR1IF = 1 then
        TMR1L =0     ' reset timer 1
        TMR1H =0
        TMR1IF = 0  ' reset timer 1 overflow
        index = 1  'so it is 0 when subtract 1
        FreqTooLow = 1 'prevent finding freq until interrupt
        goto done
    end if
    'check for freq too high
    If Pulse < 1646 then
        index = 1  'so it is 0 when subtract 1
        goto done
    end if
    ' freq in range
    FOR index = 4 to 155
    ReadTable FreqTable, index, Temp
    IF  Pulse > Temp THEN goto done
    next
    done:
    freqout = index-1
    end sub
    
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.