PIC16F877A - Object Detection and Rejection - Timer Interrupt

JohnInTX

Joined Jun 26, 2012
4,787
You need brackets { } around the code block associated with if (gotIRQ).

What sort of debugger do you have available?
Places I would start is to set a breakpoint inside the interrupt routine to see if you get an interrupt from the encoder.
Then see what happens when you set a breakpoint in the 'gotIRQ' block.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
You need brackets { } around the code block associated with if (gotIRQ).

What sort of debugger do you have available?
Places I would start is to set a breakpoint inside the interrupt routine to see if you get an interrupt from the encoder.
Then see what happens when you set a breakpoint in the 'gotIRQ' block.
now I can't test the code I am outside of conveyor place

C:
  while(1)
  {
        if (gotIRQ)
        {
           ShiftReg << 1;         // shift the integer shift register one bit left. LSbit = 0 after shift
           {
            if (SENSOR == 1)
           
            {
              ShiftReg |= 0x0001;    // bad object, put 1 in LSbit
            }
       
           if(ShiftReg & 0x0400)  // and if the #10 bit after shift is '1', kick it  
            {
              KICKER = 1;            // set output pulse high
              __delay_ms(30);    // Delay to see ouput ( inbuilt delay)
              KICKER = 0;            // set output pulse low
            }
          }
        }
        gotIRQ = 0;  // acknowledge the interrupt
  }
}
void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
     CCP1IF = 0;
     gotIRQ = 1;  // 'Signal' main that an interrupt happened
  }
}
 

djsfantasi

Joined Apr 11, 2010
9,237
@JohnInTX Back to the first topic

I have tested following code on the conveyor belt but it doesn't work as expected even it doesn't reject a single object
C:
#include <xc.h>
#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.
#define ENCODER RC0
#define SENSOR  RC1
#define KICKER  RD0
__bit gotIRQ;  // signals main that an interrupt
void main(void)
{
    unsigned int ShiftReg = 0; //  Init to 0
    INTCON = 0; // No interrupts

    TRISC = 0b00000011; // RC0 Eencoder Pin RC1 Sensor Pin

    TRISD = ob11111110; // RD0 Kicker Pin

    //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
    // 65536- 2165 = 63,371 is eual to 0xF78B
    CCPR1H = 0xF7;
    CCPR1L = 0x8B;
    CCP1IF = 0;
    INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt
    CCP1IE = 1;  //Enabled CCP1 interrupt
  while(1)
  {
        if (gotIRQ)
        ShiftReg << 1;         // shift the integer shift register one bit left. LSbit = 0 after shift
        if (SENSOR == 1)
        ShiftReg |= 0x0001;    // bad object, put 1 in LSbit
        if(ShiftReg & 0x0400)  // and if the #10 bit after shift is '1', kick it
        KICKER = 1;            // set output pulse high
        __delay_ms(30);    // Delay to see ouput ( inbuilt delay)
        KICKER = 0;            // set output pulse low
        gotIRQ = 0;  // acknowledge the interrupt
  }
}
void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
     CCP1IF = 0;
     gotIRQ = 1;  // 'Signal' main that an interrupt happened
  }
}
I checked kicker respond on 20 ms I have added 30ms short delay. I don't understand why program doesn't reject object?
Help me remember... what condition causes gotIRQ to be set?

I think that you are resetting gotIRQ in the wrong place. Once your interrupt routine sets the flag, it never gets reset until you detect the reject condition. The result is that every time through the loop, you shift the register one bit to the left. Even when you shouldn’t. And the shift register will never be 0x0400!

Take a look at this code:
Code:
while(1)
  {
        if (gotIRQ)
         
        ShiftReg << 1;         // shift the integer shift register one bit left. LSbit = 0 after shift
        if (SENSOR == 1) 
           {
            ShiftReg |= 0x0001;
            gotIRQ  = 0;
            }
        if(ShiftReg & 0x0400) 
            {
            KICKER = 1; high
             __delay_ms(30);
             KICKER = 0; 
        }
  }
Here, gotIRQ is used to perform the shift AND THEN SET TO ZERO until the next interrupt.

Secondly. I think that you want to execute those three lines of code when the 10th bit is set. Not just setting KICKER. So, I put them into a code block.

Does this make sense?
 

djsfantasi

Joined Apr 11, 2010
9,237
now I can't test the code I am outside of conveyor place

C:
  while(1)
  {
        if (gotIRQ)
        {
           ShiftReg << 1;         // shift the integer shift register one bit left. LSbit = 0 after shift
           {
            if (SENSOR == 1)
          
            {
              ShiftReg |= 0x0001;    // bad object, put 1 in LSbit
            }
      
           if(ShiftReg & 0x0400)  // and if the #10 bit after shift is '1', kick it 
            {
              KICKER = 1;            // set output pulse high
              __delay_ms(30);    // Delay to see ouput ( inbuilt delay)
              KICKER = 0;            // set output pulse low
            }
          }
        }
        gotIRQ = 0;  // acknowledge the interrupt
  }
}
void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
     CCP1IF = 0;
     gotIRQ = 1;  // 'Signal' main that an interrupt happened
  }
}
Now you have too many code blocks. Your placement of the wiggly brackets are in the wrong places.

Take a look at my code example and see it it makes sense.
 

JohnInTX

Joined Jun 26, 2012
4,787
@djsfantasi beat me to it - again - but I wonder how you know that the code had problems on the conveyor when it wouldn't even compile... Anyway, as dj said, from not enough to too many { }. This compiles and the blocks should be OK. I am out for the weekend, maybe dj will take a look at it for you.
C:
#include <xc.h>
#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.
#define ENCODER RC0
#define SENSOR  RC1
#define KICKER  RD0
#define _XTAL_FREQ 20000000  // **you need this for delays**

__bit gotIRQ;  // signals main that an interrupt

void main(void)
{
  unsigned int ShiftReg = 0; //  Init to 0
  INTCON = 0; // No interrupts

  TRISC = 0b00000011; // RC0 Eencoder Pin RC1 Sensor Pin
  TRISD = 0b11111110; // RD0 Kicker Pin ** had typo  **
  //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
  // 65536- 2165 = 63,371 is equal to 0xF78B
  CCPR1H = 0xF7;
  CCPR1L = 0x8B;
  CCP1IF = 0;
  CCP1IE = 1;  //Enabled CCP1 interrupt
  INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt

  while(1)
  {
  if (gotIRQ){
   gotIRQ = 0;  // acknowledge the interrupt ** before the delay **
   ShiftReg << 1;  // shift the integer shift register one bit left. LSbit = 0 after shift

   if (SENSOR == 1)
    ShiftReg |= 0x0001;  // bad object, put 1 in LSbit

   if(ShiftReg & 0x0400){  // and if the #10 bit after shift is '1', kick it
    KICKER = 1;  // set output pulse high
    __delay_ms(30);  // *sigh* Delay to see oupput ( inbuilt delay)
    KICKER = 0;  // set output pulse low
   }
  }//if gotIRQ
}//while
}

void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
  CCP1IF = 0;
  gotIRQ = 1;  // 'Signal' main that an interrupt happened
  }
}
Good luck!
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@djsfantasi beat me to it - again - but I wonder how you know that the code had problems on the conveyor when it wouldn't even compile... Anyway, as dj said, from not enough to too many { }. This compiles and the blocks should be OK. I am out for the weekend, maybe dj will take a look at it for you.
Good luck!
These two line missing in original code
#define _XTAL_FREQ 20000000 //Specify the XTAL crystall FREQ
TRISC = 0b00000011; // RC0 Eencoder Pin RC1 Sensor Pin

When I add this two line code would compile successfully. I made a mistake when I was editing code for posting on the forum

I am out for the weekend, maybe dj will take a look at it for you.!
@JohnInTX Wish you a nice weekend! I hope your weekend will be very much enjoyable
 

joeyd999

Joined Jun 6, 2011
6,304
Hi, again, guys.

IIRC, in standard C:

ShiftReg <<1;

does not assign the result of the shift to ShiftReg. In fact, the returned results are immediately dumped into the bit bucket on the floor.

Shouldn't this line read:

ShiftReg =<<1;

or

ShiftReg = ShiftReg <<1;

or is the original some special interpretation by embedded C?
 

Ian Rogers

Joined Dec 12, 2012
1,136
Hi, again, guys.

IIRC, in standard C:

ShiftReg <<1;

does not assign the result of the shift to ShiftReg. In fact, the returned results are immediately dumped into the bit bucket on the floor.

Shouldn't this line read:

ShiftReg =<<1;

or

ShiftReg = ShiftReg <<1;

or is the original some special interpretation by embedded C?
Quite right It is actually

ShiftReg <<= 1;
 

JohnInTX

Joined Jun 26, 2012
4,787
Agreed on the shift syntax. Good catch.
C:
  // 65536- 2165 = 63,371 is equal to 0xF78B
  CCPR1H = 0xF7;
  CCPR1L = 0x8B;
This is incorrect if you using the COMPARE mode with TIMER1 auto-reset. As discussed, in this mode the timer counts up from 0000 to the 16 value in CCPR1H and L the resets to 0000h automatically and generates the interrupt.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Agreed on the shift syntax. Good catch.
C:
  // 65536- 2165 = 63,371 is equal to 0xF78B
  CCPR1H = 0xF7;
  CCPR1L = 0x8B;
This is incorrect if you using the COMPARE mode with TIMER1 auto-reset. As discussed, in this mode the timer counts up from 0000 to the 16 value in CCPR1H and L the resets to 0000h automatically and generates the interrupt.
@JohnInTXtried this code but is not working as expected
C:
#include <xc.h>

#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.
#define ENCODER RC0
#define SENSOR  RC1
#define KICKER  RD0
#define _XTAL_FREQ 20000000  // **you need this for delays**

__bit gotIRQ;  // signals main that an interrupt

void main(void)
{
  unsigned int ShiftReg = 0; //  Init to 0

  INTCON = 0; // No interrupts

  TRISC = 0b00000011; // RC0 Eencoder Pin RC1 Sensor Pin
  TRISD = 0b00000000; // RD0 Kicker pin

  //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

  //2165 equal to 0x0875
  CCPR1H = 0x08;
  CCPR1L = 0x75;

  CCP1IF = 0;
  CCP1IE = 1;     //Enabled CCP1 interrupt

  INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt

  while(1)
  {

  if (gotIRQ){
   gotIRQ = 0;  // acknowledge the interrupt ** before the delay **

   ShiftReg = ShiftReg <<1;  // shift the integer shift register one bit left. LSbit = 0 after shift

   if (SENSOR == 1)
    ShiftReg |= 0x0001;  // bad object, put 1 in LSbit
   if(ShiftReg & 0x0400){  // and if the #10 bit after shift is '1', kick it
    KICKER = 1;  // set output pulse high
    __delay_ms(30);  // *sigh* Delay to see oupput ( inbuilt delay)
    KICKER = 0;  // set output pulse low
   }
  }
}
}

void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
  CCP1IF = 0;
  gotIRQ = 1;  // 'Signal' main that an interrupt happened
  }
}
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTXtried this code but is not working as expected
Could you be a little more specific? Exactly what are you doing to test it and exactly where is it failing to meet expectations? When it does fail, what is happening on the belt? Kick not working, kick in the wrong place, nothing??? Is 30msec really enough to actuate the kicker?
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Could you be a little more specific? Exactly what are you doing to test it and exactly where is it failing to meet expectations? When it does fail, what is happening on the belt? Kick not working, kick in the wrong place, nothing??? Is 30msec really enough to actuate the kicker?
@JohnInTX When I test program nothing happen's on the belt even it can't reject one object also

I am very sure that there is nothing wrong in encoder and kicker interfacing because when I test code #88 kicker reject the one object that proves there is no a connection problem

yes I wrote a simple program to check the capacity of a kicker It takes minimum 20ms
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
So.. problem with the sensor?
Maybe you could test the sensor by replacing it with a button temporarily. Make a mark on the belt and push the button when the mark goes by the sensor location. Then verify that the kicker kicks when the mark goes by. That would tell you a lot.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
So.. problem with the sensor?
Maybe you could test the sensor by replacing it with a button temporarily. Make a mark on the belt and push the button when the mark goes by the sensor location. Then verify that the kicker kicks when the mark goes by. That would tell you a lot.
@JohnInTX I don't think If there was a problem in the sensor then when I first tested the program #88 then it should not have worked but it worked

I think there is some problem in our program, due to which the kicker is not rejecting the object's
 

djsfantasi

Joined Apr 11, 2010
9,237
One problem that I noted earlier, but decided that it should still work, is that you only test for a reject when an object is in front of the sensor.

If the spacing is off a bit, then it’s possible that the rejected object won’t be in front of the reject mechanism exactly when there’s a new object.

The sample code I posted doesn’t have that problem. Rejecting an object is independent of when any following object is sensed.

The difference between my code and yours is how the code blocks are defined with braces. Go back and compare my program to yours.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
One problem that I noted earlier, but decided that it should still work, is that you only test for a reject when an object is in front of the sensor.

The difference between my code and yours is how the code blocks are defined with braces. Go back and compare my program to yours.
@JohnInTX @djsfantasi

I noticed that the compare mode is not working I tested following program to test on board led so LED was not toggling on the interrupt
C:
#include <xc.h>
#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.

#define _XTAL_FREQ 20000000

int main (void)

{
    TRISC = 0b00000001;
    TRISD = 0b00000000; // RD0 Kicker pin

    T1CON = 0b00001011 ;

//2165 equal to 0x0875
    CCPR1H = 0x08;
    CCPR1L = 0x75;

  CCP1IF = 0;

  while(1){

  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set
  {
     CCP1IF = 0;
 
     RD4 = ~RD4;  // toggle LED each interrupt flag

  }
}
}
Hopefully If it works then we can do for further test
 

djsfantasi

Joined Apr 11, 2010
9,237
Oops, I went back and saw that I hadn’t posted code. Since my post, you have updated your code and generally (other than my last post), I liked what you’ve done. However, my comment about separating the sensing and rejection functions still apply. I don’t believe you can condition testing for a reject upon an object being sensed. So, here’s my modified code. I didn’t write it in an IDE, so spacing might be off.

C:
  #include <xc.h>
  #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.
  #define ENCODER RC0
  #define SENSOR RC1
  #define KICKER RD0
  #define _XTAL_FREQ 20000000 // **you need this for delays**
  __bit gotIRQ; // signals main that an interrupt
  void main(void)
  {
  unsigned int ShiftReg = 0; // Init to 0
  INTCON = 0; // No interrupts
  TRISC = 0b00000011; // RC0 Eencoder Pin RC1 Sensor Pin
  TRISD = 0b00000000; // RD0 Kicker pin
  //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
  //2165 equal to 0x0875
  CCPR1H = 0x08;
  CCPR1L = 0x75;
  CCP1IF = 0;
  CCP1IE = 1; //Enabled CCP1 interrupt
  INTCON = 0xc0; //Enabled Global interrupts & Peripherals interrupt
  while(1)
  {
  if (gotIRQ){
  gotIRQ = 0; // acknowledge the interrupt ** before the delay **
  Delete this line
  ShiftReg = ShiftReg <<1; // shift the integer shift register one bit left. LSbit = 0 after shift
  } and remove this brace
  if (SENSOR == 1)
  ShiftReg |= 0x0001; // bad object, put 1 in LSbit

52a. } // move brace here

  If(ShiftReg & 0x0400){ // and if the #10 bit after shift is '1', kick it
  KICKER = 1; // set output pulse high
  __delay_ms(30); // *sigh* Delay to see oupput ( inbuilt delay)
  KICKER = 0; // set output pulse low

  }

  }
  }
  void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1) // if the CCP1 Interrupt flag is set...
  {
  CCP1IF = 0;
  gotIRQ = 1; // 'Signal' main that an interrupt happened
  }
  }
As to detecting the interrupt, JohnInTx is going to have to help. I’m not familiar with the techniques of how you’re doing that.

Mod edit: code tags - JohnInTX
 
Last edited by a moderator:

JohnInTX

Joined Jun 26, 2012
4,787
In #218 You aren’t configuring CCP1 for compare.
EDIT: Unless you are testing something simple and specific, it is usually a good idea to start with the code you are debugging if you are going to do things like LED signalling etc. When you crash together new code, you run the risk, as happened here, of missing something important then you spend all of your time debugging your debug code.

I usually just comment out the stuff I don't want interfering with the test. In some cases, I'll add a line or two to force things to happen.

FWIW: I verified in the simulator that you get an interrupt every 2166 counts of TIMER1 then it resets and begins again.
To do this, I used the 'real' code, temporarily changed TIMER1's clock source to internal, set a breakpoint at the interrupt routine then used the 'Stopwatch' to count cycles between interrupts. 2166 Tcycs. That means that if your encoder is generating valid count pulses into T1CKI, you should get the interrupt every 2166 encoder pulses.
 
Last edited:
Top