He is referring to the TMR1CS bit... This is the external / internal clock select bit.... He doesn't need this switched on...
I think you were referring to the pre-scaler bits and not the clock select (CS) bit! Just a misunderstanding!
TMR1CS1 = 0 and TMR1CS0 = 0 select the instruction cycle as the source..
TMR1CS1 = 0 and TMR1CS0 = 1 select the main osc as the source..
If you use the old TMR1CS = 1 then the external clock is required..
TMR1CS = 1 is the same as.. TMR1CS0 = 0 and TMR1CS1 = 1..
Also remember the instruction clock is four times slower than the system clock.
My head just exploded...And it shows that TMR1CS=2 is the external clock. not TM1CS=1.
My head just exploded...
As far as I typed out TMR1CS = 2 is the correct setting for external crystal operation....
Anything else is me being an old fart!!! Apologies for that... ( I know what I mean....I think it's called dementure! )
I would just let the timer free-run. Set it up to capture and interrupt on every rising (or falling) edge. Configure the timer so that the time between edges will fit into the 16 bits of the timer. On each interrupt, compute the number of timer tiks since the previous edge using the abs(difference) method. Guard against very slow RPM by counting timer overflows (another interrupt) between events.
EDIT: @jpanhalt beat me to it.
Good luck!
Yes, it would. But using the CCP to accurately measure the rotational period is a good approach so do that first. As discussed above on each capture, compute the elapsed time, write that time to a dedicated RPM variable and set a flag. The main routine checks the flag and when it's set, reads the RPM and clears the flag.OK I am pulling this one back off of the shelf. I am still having trouble trying to grasp what to do here.
You say "Guard against very slow RPM by counting timer overflows (another interrupt) between events."
Regardless of RPM, if the timer is running free, couldn't I possibly get an overflow between CCP events?
unsigned char RPMguardTimer; // 8 bit counter counts TMR2 tiks
unsigned char AnotherDerivedTimer; // how to do another one if you need it
bit NewRPMLoaded; // flag to indicate a new RPM value is loaded
bit HaveNewRPM; // main: indicates we have a new RPM reading..
//------------ INTERRUPTS -----------------
//Timer 2/PR2 interrupt service
if(TMR2IF){
TMR1IF=0; // clear the interrupt flag
if(RPMguardTimer)RPMguardTimer--; // decrement guard timer to 0 and stop
if(AnotherDerivedTimer)AnotherDerivedTimer--; // add a many as you need for other things
}
//CCP interrupt service (partial)
RPMguardTimer = MIN_RPM_PERIOD; // reset guard timer to ms period corresponding to min RPM
RPMperiod = Calculated_capture_difference // post the raw elapsed count, let main calculate to RPM
NewRPMLoaded = 1; // let main know that a new capture has been posted
//--------------- MAIN -------------------
if(NewRPMLoaded){ // if a new capture..
disableInterrupts(); // 16 bit values require atomic reads. Disable global or just the capture interrupt to be fancy AND you're testing for the CCPxIE flag in the service routine. Global disable for this short time is OK
temp = RPMperiod; // read the posted value
NewRPMLoaded = 0; // clear the flagto acknowledge that RPMperiod has been read..
enableInterrupts(); // turn it loose
calculateRPM(temp); // calculate RPM from the posted rotational period
HaveNewRPM = 1; // let the rest of the code know we have a new RPM value
}
else // no new RPM this poll, see if guard timer has run out
if(RPMguardTimer = 0) { // don't have to disable interrupts because it's 8 bits
RPM = 0; // guard timer ran out, RPM is below mins
HaveNewRPM = 1; // zero is a new RPM too..
}
//if neither case is true, all is OK, we're waiting for the next capture interrupt OR the guard //timer to run to 0
if (HaveNewRPM){
HaveNewRPM = 0; // ack the new RPM
processRPM();
}
// get on with the rest of it..
if (PIR4bits.CCP5IF == 1)
{
PIR4bits.CCP5IF = 0;
unsigned char thisPeriod;
thisPeriod = CCPR5H;
thisPeriod = (thisPeriod << 8) | CCPR5L;
ticksPerRev = abs(thisPeriod - prevCCPPeriod);
prevCCPPeriod = thisPeriod;
revTimeUpdated = 1;
}
Yep! Good catch.On line 9 you check for the Timer 1 interrupt flag but clear the Timer 2 interrupt flag in the ISR. Is that a typo?
Yes. Several variations of how to get to that value have been kicked around in the thread but for now just treat it as the number of TIMER1 counts between two successive rotations. EDIT: I see you added a solution.Is Calculated_capture_difference the absolute value you discussed previous?
Because the periods are 16 bit numbers. My example moves all but the minimum arithmetic outside of the interrupt routine. (You don't want a lot of processing inside the ISR for a lot of reasons.) But that means that main has to read that 16 bit number in two separate operations (it's an 8 bit machine after all). It's possible that in the middle of reading the two byte value the CCP interrupt will happen and change both bytes of the value you're reading. You get one byte of the old value and one byte of the new value - not good. There are a couple of ways to handle things like that but I prefer just disabling the interrupts for the minimum time it takes to do the read safely then reenble and continue processing from there. The 8 bit derived timers can be read directly without disabling because the compiler can move the whole value in one instruction. (Purists may disagree - with valid reasons - but that's how the compiler does it).Why do you disable then enable interrupts?
My implementation resets the guard timer each time it gets a capture so as long as the CCP interrupts keep coming, it never runs down so in turn, if you get a CCP interrupt, the wheel is turning. But my logic here may be flawed. I think the guard timer needs to be reset only after a valid RPM is read since that is what it is guarding.It looks to me you are only checking the guard timer if there is no new capture. Trying to figure why that would be.
Agreed. The little derived timers are for things that are not super time sensitive.P.S. Looking at your code, I see what you mean by derived timer. That is not going to work to fire the lights.
Hmm... yes. So when we talk RPM, what we are really after is how to know what interval to use between the columns of the characters, yes? The faster the thing is spinning, the shorted the inter-column interval and vice-versa within bounds.I think what I need to do is to poll T1 but is it is free running need to figure out how that would work.