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
'upsidedownFreqcounterforlowfequencies4-155hz'measures1cyclewiththeTimer1runningdiv8offofthesystemclockandtranfers'thelengthusingtheCCP1ofthechiptoCCPR1H&L'Thenalookdowntableisusedtofindthefrequency'Ionlyhadthreevaluestoregressintothetableequationis'width=253887*(freq^-0.999).thisisaroughestimatethatcanbeimprovedwithmorepoints'2/7/2010'MikeOtte#chip16F886,8#defineUSART_BAUD_RATE57600'the"uart.h"inlowlevelhadtobefixed#defineUSART_BLOCKING'the"uart.h"inlowlevelhadtobefixeddimPulseasworddimTempaswordInitUsartdirPORTC.7indirPORTC.6outdirPORTB.0outinitCCP1start:'HSerPrint(Pulse)'uncommenttoseethepulsecount'HserSend(32)'sendaspace'HSerPrint(Temp)'uncommenttoseetheonechoseninthetable'HserSend(32)findfreqHSerPrint(Freqout)HSerSend(13)'sendalinefeedandreturnHSerSend(10)SETPORTB.0OFF'Ilike"I am Alive"Ledswait910msSETPORTB.0ONwait1010ms'thisalsowastesabout190msforthe5hzrefreshgotostartsubinitCCP1dirPortC.2in;FreqinputPinRC2/CCP1/P1AonthePIC16F886T1CON=b'00110001'CCP1CON=b'00000101';startFreqcaptureonrisingedgeOnInterruptCCP1callFreq'setuptheinterrupttoreadthefreqandresetthetimerStartTimer1endsubsubFreqTMR1L=0'resettimer1TMR1H=0Pulse_H=CCPR1H'readpulsewidthandstorePulse_L=CCPR1LCCP1IF=0'clearcaptureflagendsub'LOOKDOWNSearch'findthepulsewidthinthetable'enterwith'Pulse'fromabove'exitwith'freqout'subfindfreqFORindex=4to155ReadTableFreqTable,index,TempIFPulse>TempTHENgotodonenextdone:freqout=index-1endsubTableFreqTable'wordtableofpulsewidths00063560508594239036340318022827225447231362121019580181831697215912149771414613402127321212711576110731061210188979794349098878484928218796277207494728070786887670665346371621560685927579256635540542353105202509849984902480947204635455244724395432142494179411240473984392238633805374936953642359135413493344634003355331232693228318831483110307230363000296529312898286528342803277227422713268526572629260325762551252525012476245324292406238423622340231922982278225722382218219921802162214421262108209120742057204120252009199319781963194819331918190418901876186218491836182218101797178417721760174817361724171217011690167916681657164600EndTable
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) 'uncommenttoseethepulsecount'HserSend(32) 'sendaspace'HSerPrint (Temp) 'uncommenttoseetheonechoseninthetable'HserSend(32)If FreqTooLow = 0 then findfreq 'checkifaCCPinterruptcamethruHSerPrint(Freqout)HSerSend(13)'send a linefeed and returnHSerSend(10)SET PORTB.0 OFF 'Ilike"I am Alive"Ledswait910msSETPORTB.0ONwait1010ms'this also wastes about 190ms for the 5 hz refreshgoto startsub initCCP1dir PortC.2 in ;Freq input Pin RC2/CCP1/P1A on the PIC16F886T1CON = b'00110001'CCP1CON = b'00000101' ;start Freq capture on rising edgeOn Interrupt CCP1 call Freq 'setuptheinterrupttoreadthefreqandresetthetimerStartTimer1endsubsubFreqTMR1L=0' reset timer 1TMR1H =0Pulse_H = CCPR1H 'readpulsewidthandstorePulse_L=CCPR1LCCP1IF=0'clear capture flagFreqTooLow = 0end sub'LOOKDOWNSearch'find the pulse width in the table 'enterwith'Pulse'fromabove'exit with 'freqout'sub findfreq'checkforoverflow=>freqtoolowIfTMR1IF=1thenTMR1L=0' reset timer 1 TMR1H =0 TMR1IF = 0 'resettimer1overflowindex=1'so it is 0 when subtract 1 FreqTooLow = 1 'preventfindingfrequntilinterruptgotodoneendif'check for freq too highIf Pulse < 1646 then index = 1 'soitis0whensubtract1gotodoneendif'freqinrangeFORindex=4to155ReadTableFreqTable,index,TempIFPulse>TempTHENgotodonenextdone:freqout=index-1endsub
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