I am trying to use PIC18F452 to read an optical encoder at a very low frequency (less than 100 Hz). I have tried three approaches:
-Using the CCP module to capture the rising edge and calculate the time between them to determine the period. This didn't work - The interrupt handler was never called
-Using polling: This worked in a way, but the time varied erratically and the result made no sense at all.
-Using the RBIF interrupt on port B -this works better than polling, but even then the result varies wildly.
The program also drives a seven segment display and reads an analogue input periodically.
I haven't been able to figure out what is wrong. Please help!
Thank you for reading.

With the CCP module, I set the CCP1M3:CCP1M0 to 0101 (to capture every rising edge), T3CCP2=0 (to use timer 1) and set the CCP1IE bit to enable the interrupt. However, the interrupt is never called and I cannot figure out how to make the CCP module work.
using the RBIF interrupt, I read the value of timer 1 when a rising edge occurred. I used
period = (65536-time1) + time to read the period when an overflow occurs, and period = time-time1 when it doesn't, where time1 is the previous reading, and time is the new reading.
Using this approach, the frequency reading varies through about 80 Hz.
Using polling with timer1, I get completely random readings.

With the CCP module, I set the CCP1M3:CCP1M0 to 0101 (to capture every rising edge), T3CCP2=0 (to use timer 1) and set the CCP1IE bit to enable the interrupt. However, the interrupt is never called and I cannot figure out how to make the CCP module work.
using the RBIF interrupt, I read the value of timer 1 when a rising edge occurred. I used
period = (65536-time1) + time to read the period when an overflow occurs, and period = time-time1 when it doesn't, where time1 is the previous reading, and time is the new reading.
Using this approach, the frequency reading varies through about 80 Hz.
Using polling with timer1, I get completely random readings.

Click to expand...

Why are you using a timer with an optical encoder (I assume you mean a quadrature encoder, no?)?

Perhaps if you provide us with data on the encoder itself, we may be of better help.

First, in the initialization section, you are setting the CCP interrupt enable flag, but make sure you are also setting the global IE flag(s) (perhaps you are elsewhere in the program?).

Also, if you are trying to avoid a spurious interrupt by clearing CCP1IF, you should clear it before setting CCPIE:

Code ( (Unknown Language)):

void CCP_Init()

{

//Capture mode, every rising edge

CCP1M3=0; CCP1M2=1; CCP1M1=0; CCP1M0=1;

//Select timer as timer1

T3CCP2=0

//Clear interrupt flag before enabling

CCP1IF=0;

//Enable interrupt

CCP1IE=1;

}

You should also consider initializing other variables in this section, like count and count1, but I can't figure out what they're for (more below).

In your interrupt routine:

Code ( (Unknown Language)):

if (CCPIF&&CCPIE)

{

time = CCPR1;

count1= count //no of overflows of timer1

count=0; //clear overflow counter

if (count1>0) //If overflow has occured

{

period = (65536-time1) + time;

}

else

{

period = time-time1;

}

time1=time; //set current reading as previous value

CCPIF=0; //Clear flag

}

Why do you think timer overflows need to be processed differently than if the timer did not overflow? You need to think of how things work in binary.

First off, CCPR1 is a 16 bit register. Computing (65536-time1) is the same as (0 - time1) or just -time1. So, you are telling the compiler that the time elapsed (period) is equal to the current timer value + the negative of the previous timer value. How is this different than period = time-time1?

Answer: It's not.

Secondly, you've got variables count and count1, neither of which seem to be doing anything except being set to 0. What is their purpose?

You almost certainly encountering bounce problems. As one of the slots begins to expose the detector to the LED you get a period in which it can't decide if it is seeing it or not. Similarly as you transition the other way as the slot leaves the LED. This is the whole idea behind a quadrature encoder. One way you can get the benefits of this is to mount a second LED/sensor half a slot away from the first (or aligned with any of the slot positions when the disk is positioned so that the first LED/sensor is midway between two slots).

You almost certainly encountering bounce problems. As one of the slots begins to expose the detector to the LED you get a period in which it can't decide if it is seeing it or not.

Click to expand...

I just built almost the very same idea, I just used a slot detector and used the first edge to reset T1 and read the T1 elapsed value at the second rising edge.
The results were very consistent between measurements using a servo controlled motor for the test.
Max.

I figured out what the problem was - I accidentally reset CCP1CON in the code - after initializing the CCP module.
I didn't notice that 65536-time1 + time is the same as time-time1. I corrected that.
count and count1 are for counting the overflows from timer 1 - because it overflows even with the maximum prescalar, as the minimum frequency to be measured is 1 Hz. count1 is used to capture the number of timer overflows as soon as the CCP interrupt occurs, and this is used for further calculations.
time1 is the previously measured value, and time is the current value.