PIC16F877A - Object Detection and Rejection - Timer Interrupt

djsfantasi

Joined Apr 11, 2010
9,237
You seem to be having a problem understanding the concept of a bit in a shift register following a point on the conveyor. As you still seem to think in terms of 16500 pulses I will try to describe it in terms of a 16500 stage shift register. (Serial in and serial out.)Think of this shift register on the diagram above (The one in post #139) drawn below the line that says 16500 pulses. The serial in is the right hand end and the serial out is the left hand end. The serial in will be zero except when an item to be rejected is detected. The shift register is clocked with the encoder pulses. When an item to be rejected is detected the input to the shift register (Right hand end.) is set to a ONE state so the next encoder pulse will clock it into the first stage of the shift register.The shift register moves the bit one position to the left for every clock pulse (Encoder pulse.). So after 16500 pulses the ONE bit will have reached the output position (Left hand end.) This will be the same time that the item to be rejected reaches the reject point. The ONE bit at the output of the shift register can trigger the air jet to blow the faulty item off the conveyor.

Les.

A 16,500 bit shift register would be accurate to 0.07mm. I doubt he needs that much accuracy. If you could divide the counter by 100, you’d only need a 165 bit shift register and still be accurate within 0.7cm.

There’s a big savings to be had. Using 8 bit shift registers is a hell of s lot of chips. Using a 64 bit shift register and not dividing down the clock requires ~257 chips. Dividing down by 100 would require 3 chips. Of course, there are pesky details...
 

LesJones

Joined Jan 8, 2017
4,511
Hi djsfantasi,
We have been trying to convince the TS from the start that a 5000 line encoder is too much for his project from the start of the thread. At the moment John an myself are just trying to to get him to understand the concept. When we think he understands the concept we will see if we can get him to understand it when we introduce the idea of dividing the output of the encoder by 100 (We could probably go up to about 400.) The shift register could be implemented in software by shifting through 21 bytes.

Les.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Hi djsfantasi,
We have been trying to convince the TS from the start that a 5000 line encoder is too much for his project from the start of the thread.
Les.
@djsfantasi @LesJones @JohnInTX @Ian Rogers

Is it a suitable encoder for my requirements?

https://robu.in/product/incremental...MIrKuFyoyM4gIVQYmPCh312QWTEAQYASABEgK4kvD_BwE

400 PPR

Is pic18f420 suitable microcontroller for project ?

My doubt Should I change 8 bit microcontroller instead of encoder 32 Bit PIC controller may be good choice
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
A 16,500 bit shift register would be accurate to 0.07mm. I doubt he needs that much accuracy. If you could divide the counter by 100, you’d only need a 165 bit shift register and still be accurate within 0.7cm.

There’s a big savings to be had. Using 8 bit shift registers is a hell of s lot of chips. Using a 64 bit shift register and not dividing down the clock requires ~257 chips. Dividing down by 100 would require 3 chips. Of course, there are pesky details...
as understand correctly if we need 255 pulses form detection to rejection than we can use 8 bit pic microcontroller

same for 16 bit if we need 65530 pulses pulses form detection to rejection than we can use 16 bit pic microcontroller
 

Ian Rogers

Joined Dec 12, 2012
1,136
I have taken a step back as there are too many cooks on at the moment... But any pic will do this.. The pic18f4520 is a classic and will serve you well.
 

djsfantasi

Joined Apr 11, 2010
9,237
as understand correctly if we need 255 pulses form detection to rejection than we can use 8 bit pic microcontroller

same for 16 bit if we need 65530 pulses pulses form detection to rejection than we can use 16 bit pic microcontroller
Like Ian, I’m only watching the thread at this point. @LesJones & @JohnInTX are doing a great job at helping you out, so as not to create confusion, I recommend that you concentrate on their replies.
 

JohnInTX

Joined Jun 26, 2012
4,787
as understand correctly if we need 255 pulses form detection to rejection than we can use 8 bit pic microcontroller

same for 16 bit if we need 65530 pulses pulses form detection to rejection than we can use 16 bit pic microcontroller
Well, you don't understand correctly. You can make things as big as you need with an 8 bit PIC. If you are counting, an unsigned long integer is 32 bits and one of those will count to 2^32-1 (4294967295).

But your question implies that you are going to use one or more counters instead of a shift register. Is that correct? It doesn't matter to me but you need to let us know. More importantly, you need to know yourself. An approach using one or more counters is different than one using an event list or shift register.

Forgive me if I am wrong but it seems like you still don't have a clear and detailed idea of how you are going to approach this problem. You need to examine the various ideas presented here (or think of some yourself) then sketch them out on paper (NOT code) and see how its going to work. Only then can you decide things like encoder PPM etc.

Let us know which approach you have decided on.
Good luck!
 

MaxHeadRoom

Joined Jul 18, 2013
30,661
I suspect that the 5kpulse encoder may have been used because it was on hand, rather than figure out how to achieve the required result and order parts accordingly.
I know it is tempting to try and use something on hand such as an expensive encoder, but sometimes we have to bite the bullet and buy fresh!!
Max.
 

LesJones

Joined Jan 8, 2017
4,511
Just to add to John's and Max's comment (Which I agree with.) if you are using the counter method the problem is NOT the data path width it is the fact that with your 16500 counts you would have to compare up to 5 16 bit numbers every 13.7 uS. With the suggested prescaling of you encoder pulses by a factor of 100 (Which is the equivalent of using a 50 PPR encoder) you would then have 1.37 mS to do the calculations. Similar reasoning applies to the shift register approach. You would have to do a shift through 2063 bytes every 13.7 uS If you used a 50 PPR encoder you would only need to do a shift through 21 bytes every 1.3 mS. You could make a 50 PPR encoder yourself.
Just as a matter of interest I noticed line 13 of the code that djsfantast posted in post #132 which I suspected was indexing through a group of 6 counters. I wrote a very simple program in "C" (With the help of the Raspberry Pi "C" programming guide.) to see if that was what that line did and it showed my suspicion
was correct.
Les.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Just to add to John's and Max's comment (Which I agree with.) if you are using the counter method the problem is NOT the data path width it is the fact that with your 16500 counts you would have to compare up to 5 16 bit numbers every 13.7 uS. With the suggested prescaling of you encoder pulses by a factor of 100 (Which is the equivalent of using a 50 PPR encoder) you would then have 1.37 mS to do the calculations. Similar reasoning applies to the shift register approach. You would have to do a shift through 2063 bytes every 13.7 uS If you used a 50 PPR encoder you would only need to do a shift through 21 bytes every 1.3 mS. You could make a 50 PPR encoder yourself.
Just as a matter of interest I noticed line 13 of the code that djsfantast posted in post #132 which I suspected was indexing through a group of 6 counters. I wrote a very simple program in "C" (With the help of the Raspberry Pi "C" programming guide.) to see if that was what that line did and it showed my suspicion
was correct.
Les.
Hi Les. Agreed. I was typing off-line so didn't see your post earlier. I was replying to @MaxHeadRoom above and I wanted to know about the encoder.

----------------
Agreed. 5K/rev is a bit zippy for this application but if TS decides to buy another, which one? To know that, TS has to decide on how the encoder will interface to the PIC and what he will do with all of those pulses. How to figure that out? Below is the analysis for his 5000 PPR encoder. Maybe it will work. If not, where does it break down?

From earlier discussions, we assume that 5000 PPR will need to be divided into something manageable to avoid long shift registers, big counters etc. Can the PIC do it?

If we use TIMER1 and drive T1CKI with the encoder pulses we get up to a 16 bit divider. But before that, is the PIC fast enough to handle 5K PPR?
TABLE 17-6 in the 16F877A shows that the T0CKI period with no prescaler needs to be at least Tcyc+40ns (Param 42).
At 20MHz, Tcyc = 200ns so the minimum period is 240ns. That's how fast the counter can count.
At 5000 pulses/rev we can see that the max revs is 5000/240E-9 or about 833 Revs/second. That seems fast enough so far..
Lets assume that the drive rollers are 4" in diameter for roughly 12.5" circumference. So one revolution moves the belt 12.5". At a max count speed of 833 revs/second that is 833 revs/sec * 12.5"/rev
or about 10416 inches/second at max speed. That's about 591 miles/hour! So, yes, TIMER1 can count encoder pulses at T1CKI fast enough. Connect the encoder to T1CKI and configure TIMER1 as a counter and use that to prescale the encoder.

Next, how to configure TIMER1 to prescale the encoder? You don't want to reload the timer if you can avoid it, that can cause lost counts. So use the Capture/Compare with 'special event trigger'
facility. Look at FIGURE 8-2 and REGISTER 8-1 in the datasheet. You can set a value in CCPRx1H/L (the compare register) and when TIMER1 counts up to that value, it will set TMR1IF. But it gets
better. If you set CCPxM2:CCPxM0 to 1011 it does this:

1011 = Compare mode, trigger special event (CCPxIF bit is set, CCPx pin is unaffected); CCP1
resets TMR1; CCP2 resets TMR1 and starts an A/D conversion (if A/D module is
enabled)
Perfect! You can set the encoder prescale value in the capture register and it will make TIMER1 a period register that interrupts the processor every N counts. Now we have the encoder scaled to some manageable value and once set up, it works automatically.

Next:
We have said that this thing works on distance namely the distance between the sensor and the kicker. We need to know 2 things now:
1) what is the total distance between the sensor and kicker?
2) what is the resolution required over that distance?

The answer to (1) is easy. Measure it. Let's say it's 48".
The answer to (2) is a bit more involved but it determines how much memory we need to store an image of the objects on the belt. Let's say that we've looked at how objects can be arranged on the
belt and decide that a 2" resolution will be sufficient.

2" resolution over a 48" belt means 48"/2" = 24 'spaces' on the belt. That means that we need to keep track of 24 'places' on the belt, lined up between the sensor and the kicker. That's all we
need and at this point, we don't need to know what sort of software construct we need either.

We do need to know when the belt has moved that 2" resolution however, and TIMER1 will do that. We will set it up to interrupt the processor every 2" of belt travel and do a sanity check.

We decided the roller was 4" diameter and the belt moves 12.5" for each revolution of the roller. How many encoder counts is that?
(2"/INTERRUPT) / (12.5"/REV) ~= .16 REV/INTERRUPT.
(5000 PULSES/REV) * (.16 REV/INTERRUPT) ~= 795 PULSES/INTERRUPT
To interrupt every 795 pulses, set the value of the capture register to 795 (CCPR1H = 03h, CCPR1L = 1Bh).

Summary:
Encoder drives T1CKI.
TIMER1 is configured as a 16 bit counter
CAPTURE/COMPARE mode is configured to count 0->795 (2" of travel), interrupt the processor and reset TIMER1 to 0 automatically.
The value of CCP1H/L determines the length of travel between interrupts and according to the 'Lil Professor, CCP1H/L should be loaded to 795.
In dividing the 48" distance between the sensor and kicker into 2" segments, we effectively have to keep track of 24 segments on the belt. As the belt advances, we get ONE interrupt every 2" segment. At each interrupt we record whether or not to kick the object that is currently under the sensor. 24 interrupts later, that object will be at the kicker and the appropriate action is taken.

Sanity check - can we process the interrupts fast enough?
At a more reasonable 12"/sec of belt travel we will get 6 interrupts/sec. That's ~166 ms/interrupt. That's pretty often but we're not computing satellite orbits here so should be OK.. It should be
clear, though, that we're not going to have any delay loops in the interrupt service routine.

Recap:
The original question was whether a 5K PPM encoder would work. It looks it can be made to work. To determine that, we ran through the calculations that will be necessary for ANY encoder and indeed for any distance-based implementation. The only clever thing was using TIMER1 as a period counter to prescale the encoder to some manageable value. That's just from long experience with PIC peripherals. The timing values imply that the 16F877A has enough power to keep up - at least at this point.

The TS will have to decide if the described approach makes sense. Check the math. And check it again. My jabs at the calculator are no substitute for a proper analysis. You may find I've made a serious error that makes everything fall apart. At this point, I'd have it all up on an Excel spreadsheet so that I could enter real values and see if things still work.

Should TS use a more powerful uC? Sure, why not? At this point all we know is some performance criteria. Personally I don't like the midrange PICs so I'd upgrade to something better. 18F sure. 16Fxxxx, decent. PIC32, why not? If you want to stay with the '877, these calculations say it should work. If you have access to more horsepower, by all means use it if you can afford it. By the time you get it programmed, any 18F is cheaper (and better) to develop with than the midrange '877 and with a PIC32 or ARM, you have power to burn for essentially the same price. Pick one and go with it.

If the TS is on board with this method, he should then figure out how he is going to keep track of 24 segments on the belt and how each segment should show if the object in it should be left or kicked. Obviously, I think a shift register warrants some thought but the main point of THIS exercise is to see how the encoder could be made to work and if the current one will do.

Finally for the TS: note that other than a few peeks at the Timer/CCP registers, NO coding has been done. You have to have a design that you've checked out on paper before you can hope to write code for it. Once you have a functional block like this one roughed out, move on to the next part. When all parts seem to work together on paper, look at the paper. There's your coding outline.

Thinking on it, that's about all I have to say on it - this part anyway.
Have fun!
Whew!
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Hi djsfantasi,
We have been trying to convince the TS from the start that a 5000 line encoder is too much for his project from the start of the thread. At the moment John an myself are just trying to to get him to understand the concept.

Les.
Hello @LesJones @MaxHeadRoom @djsfantasi @JohnInTX @Ian Rogers

I wanted to clear some doubt myself. I have spent some time to understand what the wrong in my understanding

I want to learn how to reject a faulty object on the conveyor.I am sorry It may be my fault that I have not cleared this thing I want to learn how to reject the object of different size

I understand that if we want to reject faulty object on the accurate position then we have to use the encoder. If I am not mistaken then I think the encoder selection depends on the size of the object

I understand that I do not need the encoder of 500 PPR for the present project. As you guys told me I agree that I should use low PPR (200) encoder because the object length is 190 mm

But I do not think encoder of 200 PPR will be useful when the size of object is small for example less than 40 mm
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
More importantly, you need to know yourself. An approach using one or more counters is different than one using an event list or shift register.
You need to examine the various ideas presented here (or think of some yourself) then sketch them out on paper (NOT code) and see how its going to work. Only then can you decide things like encoder PPM etc.

Let us know which approach you have decided on.
Good luck!
Les gave me an idea of the counter which was working for me So I thought it should improve later. After that, he also cleared that shift register would be right instead counters I would prefer shift register method

Maybe you can get angry on me, because I am repeating the same thing. But I strongly feel that I have everything in hand to test my project like 500 PPR encoder, 40mm object, conveyor and microcontroller

I do not want to buy new encoder if I can use an old one 5000 PPR because it will be a waste of money. What I am doing now is an experiment. If this succeeds, I can improve it with advanced PIC 18 microcontroller running approx. 64MHz crystal.

So I think I need to test program on the machine. I know this is not an easy job but I have to start by the beginning.

Do you still think that I need to buy new encoder It is easier for me to replace an object instated of buying the new encoder
 

MaxHeadRoom

Joined Jul 18, 2013
30,661
One source of cheaper encoders is AutomationDirect.
Also decide what is the best interface for you, open collector as you have now, or RS485 etc.
Max.
 

JohnInTX

Joined Jun 26, 2012
4,787
Les gave me an idea of the counter which was working for me So I thought it should improve later. After that, he also cleared that shift register would be right instead counters I would prefer shift register method

Maybe you can get angry on me, because I am repeating the same thing. But I strongly feel that I have everything in hand to test my project like 500 PPR encoder, 40mm object, conveyor and microcontroller

I do not want to buy new encoder if I can use an old one 5000 PPR because it will be a waste of money. What I am doing now is an experiment. If this succeeds, I can improve it with advanced PIC 18 microcontroller running approx. 64MHz crystal.

So I think I need to test program on the machine. I know this is not an easy job but I have to start by the beginning.

Do you still think that I need to buy new encoder It is easier for me to replace an object instated of buying the new encoder
We're not angry, just trying to make sure that we understand how you want to proceed. Also, to be sure that you have a clear idea of each functional block in this thing. Nothing more than that. Apologies for any misunderstanding.

In #150, I made my case that I thought the current hardware (5000PPM encoder, 20MHz PIC16F877A) would work, at least as far as using the internal TIMER1/COMPARE function to divide down your encoder to something that divides the length of the belt into something you can use. I wanted also to satisfy my own curiosity. The over-long post also described one way to use the compare output interrupt to poke a bit into the shift register. If you like that, then revisit the assumptions I made (speed, distance per revolution, length of the belt segments etc.), do the math and convince yourself that you are ready to proceed with the next part of the design. If you find that it won't work because of something I overlooked or you just don't like it - that's OK too. I'm not fussy.

Good luck!
 

LesJones

Joined Jan 8, 2017
4,511
In the few lines of code I wrote for you to count a number of pulses after the fail detector and give a pulse to flash an LED I chose 100 mS for the pulse time. After you providing the speed of the conveyor I can see a problem with that pulse time if it is used to pulse the solenoid valve for the reject air jet. To see if you are now understanding the conveyor system work out what will happen with that length of air jet when you have the 190mm long objects with 50 mm spacing. (As you show in your diagrams.) Show us your calculations.

Les.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
In the few lines of code I wrote for you to count a number of pulses after the fail detector and give a pulse to flash an LED I chose 100 mS for the pulse time. After you providing the speed of the conveyor I can see a problem with that pulse time if it is used to pulse the solenoid valve for the reject air jet. To see if you are now understanding the conveyor system work out what will happen with that length of air jet when you have the 190mm long objects with 50 mm spacing. (As you show in your diagrams.) Show us your calculations.

Les.
@LesJones @JohnInTX
upload_2019-5-11_21-26-54.png


Let’s assume that the drive rollers are 50mm in diameter

Circumference = 50 * 3.14 (Pi) = 157 mm
So one revolution moves the belt 157 mm

Let’s assume object length is 50 mm and we have 5000 PPR of Encoder

Let’s assume that total distance between the sensor and kicker is 680 mm and we need 21,650 pulses to reject bad object from the sensor

4.33 rotations will generate 21,650 pulses

Note - Above are the rough calculation on the paper for better understanding
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Nice.
So 10 is the number of objects between the detection and rejection points. Any combination of those 10 can be marked by the detector for later rejection. Pulse counts and encoder scaling aside, how do you propose to keep track of the status of 10 objects at a time?
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Any combination of those 10 can be marked by the detector for later rejection. Pulse counts and encoder scaling aside, how do you propose to keep track of the status of 10 objects at a time?
@JohnInTX That is the biggest concern for me. As you suggested timer and CAPTURE/COMPARE mode. I was reading about it. I have never used capture or compare, so I also would like to know more and see specific examples.

Summary:
Encoder drives T1CKI.
TIMER1 is configured as a 16 bit counter
CAPTURE/COMPARE mode is configured to count 0->795 (2" of travel), interrupt the processor and reset TIMER1 to 0 automatically.
Capture Mode captures the 16-bit value of TMR1 into CCPR1H:CCPR1L register pair in response to an event occurring on RC2/CCP1 pin.

RC2/CCP1 pin should be configured as an input by setting TRISC (bit 2). for capture mode:

Required conditions for compare mode

1. RC2/CCP1 pin must be configured as an output by clearing TRISC<2> bit.

2. Timer-1 should be operated in timer mode (i.e., internal clock source of fosc/4) or in synchronized counter mode.

I found the following table in the datasheet

upload_2019-5-12_0-11-19.png
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
To use TIMER1 as a period counter with a settable number of counts between interrupts:
  • T1CKI (Timer 1 Clock Input) is RC0 so make that pin an input by setting TRISC:0 = 1.
  • T1CON (Timer 1 Control register) = 00000011, 1:1 prescale, OSC disabled, Input Synchronized, External clock on T1CKI(RC0), Timer ON. Connect the encoder to RC0. TIMER1 will count up from 0000h as it counts encoder pulses.
  • Set CCPR1H and CCPR1L (16 bits) to the number of encoder pulses per interrupt e.g. for 795 (031Bh) set CCPR1H= 03h and CCPR1L = 1Bh. You only have to set these values once.
  • CCP1CON = 00001011, Compare mode using CCPR1H and CCPR1L as a 16 bit value. When TIMER1 counts up to that value i.e. 0->765,
    • TIMER1 will be reset to 0 automatically
    • CCP1IF will be set to interrupt the PIC
    • CCP1 output pin (RC2) is unaffected in this mode
That is how you would use TIMER1/COMPARE1 to reduce the precision of your encoder. That's all it does. In my example above, I divided the encoder pulses to give one interrupt for every 2" of belt travel because that's as close as the objects can be together. In my example, that divided the distance between the sensor and the kicker into 24 2" segments and generate one interrupt for every 2" segment of the belt as it passed by. The result is something I thought would be a good distance-based signal usable for a 24-bit shift register as a way of 'tagging' bad objects and keeping those tags moving in the shift register as they follow the objects moving along the belt.

Regardless of what you use to tag objects for rejection (shift register, distance counter(s), etc., if you want to reduce the PPM of your encoder (so you don't have to buy another) the TIMER1/COMPARE1 setup described here should do it. Note that the number of encoder pulses per interrupt is completely programmable by changing the setting in CCPR1H/L. You can extend the range further by using the TIMER1 prescaler to further divide it down but I don't think you need to.

Note that you may want better than 2" resolution. Easy, just set CCPR1H/L to something smaller i.e. fewer encoder pulses per interrupt.

Have fun!

EDIT: changed TMR1IF to CCP1IF
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
To use TIMER1 as a period counter with a settable number of counts between interrupts:
  • T1CKI (Timer 1 Clock Input) is RC0 so make that pin an input by setting TRISC:0 = 1.
  • T1CON (Timer 1 Control register) = 00000011, 1:1 prescale, OSC disabled, Input Synchronized, External clock on T1CKI(RC0), Timer ON. Connect the encoder to RC0. TIMER1 will count up from 0000h as it counts encoder pulses.
  • Set CCPR1H and CCPR1L (16 bits) to the number of encoder pulses per interrupt e.g. for 795 (031Bh) set CCPR1H= 03h and CCPR1L = 1Bh. You only have to set these values once.
  • CCP1CON = 00001011, Compare mode using CCPR1H and CCPR1L as a 16 bit value. When TIMER1 counts up to that value i.e. 0->765,
    • TIMER1 will be reset to 0 automatically
    • TMR1IF will be set to interrupt the PIC
    • CCP1 output pin (RC2) is unaffected in this mode
Have fun!
@JohnInTX This is my attempt to write a program
C:
// PIC16F877A Configuration Bit Settings
// 'C' source line config statements
// CONFIG
#pragma config FOSC = XT  // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON  // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = OFF  // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF  // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF  // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF  // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF  // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>

void main(void)
{
  //Make all PORTD pins low
  PORTA = 0b00000000;
  PORTB = 0b00000000;
  PORTC = 0b00000000;
  PORTD = 0b00000000;
 
// Configured PORTD as Output
  TRISD4 = 0;
// Connect the encoder to RC0 &  RC1 sensor inputs
   TRISC = 3; 
  
//CCP1 MODULE INITIALIZATION

  T1CON = 0b00000011 ;    // 1:1 prescale, OSC disabled, Input Synchronized, External clock on T1CKI(RC0), Timer ON 
  CCP1CON = 0b00001011;   // Compare mode using CCPR1H and CCPR1L as a 16 bit value
 
  CCPR1H = 0x03; 
  CCPR1L = 0x1B;
  
  INTCON = 0xc0;          //Enabled Global interrupts & Peripherals interrupt
  CCP1IE = 1;             //Enabled CCP1 interrupt
  while(1);
}

void interrupt CCP1_ISP()
{
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
       RD4 = 1;            // set output pulse high
       __delay_ms(150);    // Delay to see ouput ( inbuilt delay)
       RD4 = 0;            // set output pulse low
       CCP1IF = 0;
  }
}
 
Top