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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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
You want it to updated the value 5 times each sec?
What for baud rate?
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?
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
can anyone help?
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.
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!
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:
Some ideas on a word table and reading it into an array, hope it helps.
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
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
Added some bounds checking for freq too high and freq too low