PIC16F877A - Object Detection and Rejection - Timer Interrupt

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTX This is my attempt to write a program
Well, you are coding before you have decided on the design (shift register, counter, etc.) How can that possibly work? If you are to be successful with this thing, you need to step back, add to what you have shown in #156 to indicate how you will track bad objects as they move along the belt. The code you show here only implements the encoder divider. What then?

But you probably want to see something -anything!- work at this point so here we go.
First, your code doesn't compile. If you have C syntax errors, hit the books. Fix that stuff first. That includes compiler warnings too. Warnings are errors that don't happen until run-time.
Initialize ALL of your I/O pins, not just the ones you are using. Set any unconnected pins to output 0. Leaving uninitialized pins leaves you open to all kinds of problems.
Next, you have a delay inside your interrupt routine. That can't work. While you are merrily burning CPU cycles to show your LED, you will miss all of the encoder counts during that time. Interrupt routines in a PIC must be kept short and avoid doing I/O inside an interrupt routine. I show one way to beat that below.
You don't say what the code is supposed to do. How are we to know when it does or doesn't do it?

The code below actually compiles (XC8 Ver 2.00) and toggles the LED on each interrupt. Says me, I haven't tested it. Of interest is how I used a flag - gotIRQ - to indicate when an interrupt happens. The 'while' loop in main waits for this signal then complements the LED to flash it at 1/2 the interrupt rate. That's enough to prove out the timer/compare stuff. You also can experiment with different settings for the compare registers.

A final concern. I see that you have BOTH encoder inputs connected in this one. That's different. If what you really need is quadrature encoding (both directions of the belt) then this implementation won't work.

Good luck!
C:
// Daljeet: always describe what a program is supposed to do.  That way,
// when it doesn't, you at least know what to look at

// This program uses TIMER1/CCP1 as a period counter that counts
// encoder pulses on T1CKI.  When the count is equal to the value in CCP1RH/L,
// it toggles the LED on RD4

// 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>
__bit gotIRQ;  // signals main that an interrupt

void main(void)
{
  //Make all PORTD pins low  <- No, it doesn't
  PORTA = 0b00000000;
  PORTB = 0b00000000;
  PORTC = 0b00000000;
  PORTD = 0b00000000;
// Configured PORTD as Output
  TRISD4 = 0;
// Connect the encoder to RC0 &  RC1 sensor inputs
  TRISC = 3;
   
// How about the REST of the IO pins??????   
   
  RD4 = 0;  // init LED
//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;
  CCP1IF = 0;
 
  INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt
  CCP1IE = 1;  //Enabled CCP1 interrupt
  while(1){
  if (gotIRQ)
  RD4 = ~RD4;  // toggle LED each interrupt
  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
  // NEVER delay inside an interrupt routine   
  }
}
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Well, you are coding before you have decided on the design (shift register, counter, etc.)
@JohnInTX so we are doing rejection based on the distance. This diagram shows the 10 slot's with pulses and distance.
upload_2019-5-13_15-40-11.png

I want to know how rejection will done with shift register logic.

Manually I have everything pulses distance, and 10 slot's But still I don't understand how to implement logic into the program?
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTX so we are doing rejection based on the distance. This diagram shows the 10 slot's with pulses and distance.
View attachment 177271

I want to know how rejection will done with shift register logic.

Manually I have everything pulses distance, and 10 slot's But still I don't understand how to implement logic into the program?
All of that has been pretty thoroughly covered already.

The PLC example demonstrates the concept. In #102, I show another way to think about the shift register solution and show how to use a C integer to implement the shift register itself and how to add bits at the sensor and detect ‘1’ bits at the kicker.

Just above I show how to divide your encoder down to generate one interrupt per segment on the belt to control when you sample the sensor and look at the output of the shift register to control the kicker.

What, specifically, are you having trouble with?

EDIT:
You really have all of the pieces:
  • A belt divided into segments, one object per segment
  • An interrupt that indicates when the belt has traveled one segment length and that it is time to make some decisions.
  • A 'signal' from interrupt to main to let main know when each segment has passed
  • A shift register that assigns one bit to each belt segment. That bit indicates whether or not the object in that segment is GOOD or BAD.
  • A sensor at the beginning that indicates GOOD/BAD i.e. whether the current segment under the belt should actuate the kicker when that segment has moved to the end.
  • A kicker at the end that can remove an object when it is actuated.
Now it's time to put them together.

If you haven't yet done it, make a simple sketch on paper of everything and run it in your head. Write some pseudo-code (simplified C that doesn't care about syntax):
C:
unsigned long int ShiftRegister;  // a 32 bit integer will handle up to 32 belt segments.  Should be enough.

interrupt(){
signal_one_segment_has_passed();
}

main()
{
  initialize();

  while(1){
  wait_for_interrupt_signal();
  clear_interrupt_signal();  // acknowledge signal for next time

// sample object at sensor
  if(sensor == BAD)
    put_1_in_shift_register_input();
  else
   put_0_in_shift_register_input();

// The end of the shift register shows if the object that WAS under the sensor N interrupts ago is good or bad
  if(end_of_shift_register_bit == 1)
   actuate_kicker();

// this belt segment is done, store new sensor reading, discard used kicker bit
shift_one_bit();

  }//while
}//main
That's pretty much the whole thing.. or IS it? There is no START/STOP function to turn it on and off. But from our pseudo-code, we see that we are just waiting between interrupts so that would be a good time to look at that.

You haven't really defined how the sensor operates or how to actuate the kicker so give that some thought, too.

Most important is to have all of the big pieces we know about hooked up and be able to trace the basic operation on paper. As you do that, questions about details like start/stop, kicker etc. will arise. Drill down into each of those until you have them figured out. Add those details to your pseudo-code until you don't have any more questions about the details.

Then, and ONLY then, does it make sense to start coding it. That's really how it's done.

Have fun!
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
If you haven't yet done it, make a simple sketch on paper of everything and run it in your head.
Have fun!
hi @JohnInTX

Your approach depends on the spacing I can't find solutions on the paper for rejection that doesn't depend on spacing.

My main problem is the spacing between each object what will happen if the gap between two objects will vary?

upload_2019-5-13_19-55-41.png
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Try increasing the resolution of the system by using smaller segments on the belt and increasing the number of bits in the shift register by a corresponding amount. You may find that your objects span more than one segment meaning more than one consecutive bits per object but that doesn’t matter. As an exercise, consider what it would do with an infinite number of segments and bits. You would have an exact linear image of the objects on the belt. But that would be overkill considering that things like the kicker and sensor have limited resolution e.g. if the kicker blows everything within 2” off the belt, it’s probably pointless to have much more resolution in the system.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I show another way to think about the shift register solution and show how to use a C integer to implement the shift register itself and how to add bits at the sensor and detect ‘1’ bits at the kicker.
.
@JohnInTX
Perhaps I am missing shift register understanding
C:
#include<stdio.h>

int main(void)
{
       int a = 0000 0000 0001;
       printf("\nNumber is Shifted By 1 Bit : %d",a << 1);
 
       printf("\nNumber is Shifted By 2 Bits : %d",a << 2);
 
       printf("\nNumber is Shifted By 3 Bits : %d",a << 3);
 
       printf("\nNumber is Shifted By 4 Bits : %d",a << 4);
 
       printf("\nNumber is Shifted By 5 Bits : %d",a << 5);
 
       printf("\nNumber is Shifted By 6 Bits : %d",a << 6);
 
       printf("\nNumber is Shifted By 7 Bits : %d",a << 7);
 
       printf("\nNumber is Shifted By 8 Bits : %d",a << 8);
    
       printf("\nNumber is Shifted By 9 Bits : %d",a << 9);
 
       printf("\nNumber is Shifted By 10 Bits : %d",a << 10);
 
       return(0);
}
Number is Shifted By 1 Bit : 2 gives 0000 0000 0000 0010

Number is Shifted By 2 Bits : 4 gives 0000 0000 0000 0100

Number is Shifted By 3 Bits : 8 gives 0000 0000 0000 1000

Number is Shifted By 4 Bits : 16 gives 0000 0000 0001 0000

Number is Shifted By 5 Bits : 32 gives 0000 0000 00100000

Number is Shifted By 6 Bits : 64 gives 0000 0000 0100 0000

Number is Shifted By 7 Bits : 128 gives 0000 0000 1000 0000

Number is Shifted By 8 Bits : 256 gives 0000 0001 0000 0000

Number is Shifted By 9 Bits : 512 gives 0000 0010 0000 0000

Number is Shifted By 10 Bits : 1024 gives 0000 0100 0000 0000

How to set input zero if object is good and how to set input one if object is good ?
 

JohnInTX

Joined Jun 26, 2012
4,787
In the code I posted in #102, for the sensor, I show how to use a bit wise OR in line 8 to set the LSbit in the shift register when the object is bad. In line 9 I show how to use a bit wise AND to test any bit within the shift register for a ‘1’. That’s for the kicker.
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
In the code I posted in #102, for the sensor, I show how to use a bit wise OR in line 8 to set the LSbit in the shift register when the object is bad. In line 9 I show how to use a bit wise AND to test any bit within the shift register for a ‘1’. That’s for the kicker.
@JohnInTX I am understanding something now
C:
unsigned int ShiftReg = 0; //  Init to 0
if (3600 pulses)
{
  reload_timer(3600);
  ShiftReg << 1;  // shift the integer shift register one bit left. LSbit = 0 after shift
  if (object_is_bad)
     ShiftReg |= 0x0001;  // bad object, put 1 in LSbit
  if(ShiftReg & 0x0400) // and if the #10 bit after shift is '1', kick it
    kick_the_object();
}
I didn't understand following statment you are performing AND logic
C:
if(ShiftReg & 0x0400) // and if the #10 bit after shift is '1', kick it
    kick_the_object();
assume ShiftReg value is 0000 0001 0000 0000
0000 0001 0000 0000 = ShiftReg
0000 0100 0000 0000 = 0x 0400

0000 0101 0000 0000 = result

What's the logic behind that statement. Are you just checking 11 bit only if it's high kick object?
 
Last edited:

djsfantasi

Joined Apr 11, 2010
9,163
@JohnInTX I am understanding something now
C:
unsigned int ShiftReg = 0; //  Init to 0
if (3600 pulses)
{
  reload_timer(3600);
  ShiftReg << 1;  // shift the integer shift register one bit left. LSbit = 0 after shift
  if (object_is_bad)
     ShiftReg |= 0x0001;  // bad object, put 1 in LSbit
  if(ShiftReg & 0x0400) // and if the #10 bit after shift is '1', kick it
    kick_the_object();
}
I didn't understand following statment you are performing AND logic
C:
if(ShiftReg & 0x0400) // and if the #10 bit after shift is '1', kick it
    kick_the_object();
assume ShiftReg value is 0000 0001 0000 0000
0000 0001 0000 0000 = ShiftReg
0000 0100 0000 0000 = 0x 0400

0000 0101 0000 0000 = result

What's the logic behind that statement. Are you just checking 11 bit only if it's high kick object?
First, that’s the idea. That is exactly what JohnInTx had in mind.

Second, how did you get that results? The operation is a bit wise AND (&), which results in a 1 if both corresponding bits in the operands are 1. In your example, here are no bit positions that have a 1 in the corresponding bit positions of the two operands. The result of your example is 0x0!

You performed a bit wise OR between the two operands. A bit wise or results in a 1 if any bit in either of the corresponding operands is a 1.
 

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTX I am understanding something now
assume ShiftReg value is 0000 0001 0000 0000

0000 0001 0000 0000 = ShiftReg
0000 0100 0000 0000 = 0x 0400

0000 0101 0000 0000 = result
What's the logic behind that statement. Are you just checking 11 bit only if it's high kick object?
You are using the OR function. For AND, both bits in a corresponding position must be 1 for the value to be non-zero:

0000 0001 0000 0000 = ShiftReg AND
0000 0100 0000 0000 = 0x 0400
--------------------------------
0000 0000 0000 0000 = 0 (FALSE)

0000 0101 0000 0000 = ShiftReg AND
0000 0100 0000 0000 = 0x 0400
--------------------------------
0000 0100 0000 0000 = not 0 (TRUE)

So you set your mask (the 0x4000) with one (and only one) bit set. When the shift register shifts left enough times to bring the 'BAD' bit (1) under the mask, the result of the AND is TRUE and you turn on the kicker. GOOD/BAD bits (0/1) are entered on the right end of the shift register. The shift register is shifted left one time per belt segment.

Using the AND mask as shown allows you to select which bit in the shift register operates the kicker. Set that mask value to match the length of the belt i.e. if there are 24 segments defined on the belt (by the encoder / divider) you set the mask to select the 24th bit in the shift register.

Why are you thinking about changing PICs? Personally, I don't like the 16F877 (or any midrange PIC) so I'm OK with it. But as long as you are thinking about a change, look up one that has the quadrature encoder module built in.

dangit.. @djsfantasi beat me to it again..:p

EDIT: You can experiment with the shift register stuff using the MPLABX simulator. Write your routines and check them out there. No hardware, no muss no fuss.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Y
Why are you thinking about changing PICs? Personally, I don't like the 16F877 (or any midrange PIC) so I'm OK with it. But as long as you are thinking about a change, look up one that has the quadrature encoder module built in..
I think The PIC16f877A is not enough fast to catch all the valid encoder states, If I use PIC16F877A, I do not get a rejection at the full-speed on the conveyor.
Rejection only happen at the 1/3 speed of conveyor belt
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@JohnInTX This was your idea
Code:
unsigned int ShiftReg = 0; //  Init to 0
if (3600 pulses)
{
  reload_timer(3600);
  ShiftReg << 1;  // shift the integer shift register one bit left. LSbit = 0 after shift
  if (object_is_bad)
     ShiftReg |= 0x0001;  // bad object, put 1 in LSbit
  if(ShiftReg & 0x0400) // and if the #10 bit after shift is '1', kick it
    kick_the_object();
}
I understand the idea now but having a problem to write code. I have written following code to follow the idea
C:
#include <xc.h>

#define _XTAL_FREQ 20000000

#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = ON
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF

#define ENCODER RC0
#define SENSOR RB1
#define KICKER RD4

void main(void)
{

    unsigned int ShiftReg = 0; //  Init to 0

    INTCON = 0; // No interrupts
    PORTC = 0b00000000; //Set all Pin to Low

    TRISC0 = 1; // RC0 Eencoder Pin
    TRISC1 = 1; // RC1 Sensor Pin
    TRISD0 = 0; // RD0 Kicker Pin
    TMR1H = 0xF7;        // 65536- 2165 = 63,371 is eual to 0xF78B
    TMR1L = 0x8B;

    TMR1ON  =  0;   // Stops Timer1
    TMR1CS =  1;   // Internal clock
    T1SYNC =  0;   // Synchronize external clock input
    T1OSCEN =  0;   // Oscillator is shut-off
    T1CKPS0 =  0;   //  1:1 prescale value
    T1CKPS1 =  0;

    TMR1IE = 1;      //Enable timer interrupt bit
    GIE =  1;         //Enable Global Interrupt
    PEIE = 1;        //Enable the Peripheral Interrupt

    TMR1ON = 1; //Start Timer1
    while(1)
   {
        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;        // KICKER ON
            __delay_ms(200);
            KICKER = 0;        // KICKER OFF

    }
}

void interrupt timer_isr()
{
  if(TMR1IF == 1)
  {
    TMR1IF  =  0;            // Clear timer interrupt flag
    TMR1ON = 0;            // stop timer
    TMR1H  = 0xF7 ;        // High byte F7
    TMR1L  = 0x8B;         // Low Byte 8B
  }
}
Does it follow your logic?
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
First, congratulations on the success so far. That's progress.
Does it follow your logic?
Operating the 10 bit shift register looks OK. The rest not so much.
The timer isn't what I was thinking. In #150 and #159 I introduce the idea of using TIMER1/CCP1 to prescale your encoder and automatically reset the timer. I said you will lose counts on the encoder if you stop and reload the timer. Use the COMPARE function like we discussed.

I think The PIC16f877A is not enough fast to catch all the valid encoder states, If I use PIC16F877A, I do not get a rejection at the full-speed on the conveyor.
Rejection only happen at the 1/3 speed of conveyor belt
Well, the first place I'd look is that 200msec delay in your interrupt routine. In #161 I said
Next, you have a delay inside your interrupt routine. That can't work. While you are merrily burning CPU cycles to show your LED, you will miss all of the encoder counts during that time. Interrupt routines in a PIC must be kept short and avoid doing I/O inside an interrupt routine. I show one way to beat that below.
and yet there is a delay in the interrupt routine. Blocking delays like that will cripple your program. And never, EVER put any kind of delay inside an interrupt routine, especially when you only have one. Interrupt service routines must be short and tight. Look at the code in #161 to see how to coordinate interrupts and main routines.

Logically, you don't want to control the kicker with any kind of fixed time, right? We all agreed that this was a distance-based system that kept track of everything based on the position of objects on the belt. Using time to determine when to kick an object was rejected because of the difficulty of keeping up with different belt speeds, yes? Even without the delay issue if you turn on the kicker for a fixed time, that doesn't work well for different belt speeds. A timed puff that works at low speeds may blow off multiple objects at high speeds. As a first order solution, just run the air-jet while there is a '1' output from the shift register and turn it off when there is a '0'. That will handle varying belt speeds and the cases where you have differently spaced objects.

You mentioned a faster processor. In #150, I examined some of that. A better processor may be a good thing but it won't help here. A 120MHz PIC32 will also fail to keep up with the system when it hits that same 200ms delay. Get rid of that first.
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
First, congratulations on the success so far. That's progress. .
@JohnInTX Thank's Thanks a lot, everybody for your contribution
Operating the 10 bit shift register looks OK. The rest not so much.
The timer isn't what I was thinking. In #150 and #159 I introduce the idea of using TIMER1/CCP1 to prescale your encoder and automatically reset the timer. I said you will lose counts on the encoder if you stop and reload the timer. Use the COMPARE function like we discussed.
I have modified the previous program. I hope it would better than previous
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
void main(void)
{

    unsigned int ShiftReg = 0; //  Init to 0
    INTCON = 0; // No interrupts
 
    PORTC = 0b00000000; //Set all Pin to Low
    TRISC0 = 1; // RC0 Eencoder Pin
    TRISC1 = 1; // RC1 Sensor Pin
    TRISD0 = 0; // 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)
  {
        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 =~ KICKER ;    
  }
}

void __interrupt() IRQ(void){
  // CCP1 Interrupt
  if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
  {
  CCP1IF = 0;

  }
}
Well, the first place I'd look is that 200msec delay in your interrupt routine. In #161 I said Logically, you don't want to control the kicker with any kind of fixed time, right? .
Okay, I will find the solution that doesn't need time.

EDIT: I haven't tested code on the board
 

djsfantasi

Joined Apr 11, 2010
9,163
Your code ALWAYS shifts the register to the left one bit. I think you only should shift it when the belt has moved one position. "while (1)" will excecute many times while the belt only moves a little bit. The problem here should be obvious. When the actual object has moved one position, you will have shifted its corresponding bit out of the shift register.

I've lost where you are actually, but when reading the encoder, you only want to shift the register when the belt has moved one position. I am ASSUMING your interrupt routine is what detects the condition of moving one position. In the interrupt routine, you would set a flag (and you may be doing that) when objects have moved one position.

You need an additional test in your main loop, to ONLY shift ther bits when this flag has been set.
 

JohnInTX

Joined Jun 26, 2012
4,787
Your code ALWAYS shifts the register to the left one bit. I think you only should shift it when the belt has moved one position. "while (1)" will excecute many times while the belt only moves a little bit. The problem here should be obvious. When the actual object has moved one position, you will have shifted its corresponding bit out of the shift register.

I've lost where you are actually, but when reading the encoder, you only want to shift the register when the belt has moved one position. I am ASSUMING your interrupt routine is what detects the condition of moving one position. In the interrupt routine, you would set a flag (and you may be doing that) when objects have moved one position.

You need an additional test in your main loop, to ONLY shift the bits when this flag has been set.
Good catch! The interrupt signal was what I was trying to show in the pseudo-code in #163. Hmmm..
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I am ASSUMING your interrupt routine is what detects the condition of moving one position. In the interrupt routine, you would set a flag (and you may be doing that) when objects have moved one position.
You need an additional test in your main loop, to ONLY shift ther bits when this flag has been set.
Good catch! The interrupt signal was what I was trying to show in the pseudo-code in #163. Hmmm..
@djsfantasi @JohnInTX I have done some changes
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

    PORTC = 0b00000000; //Set all Pin to Low

    TRISC0 = 1; // RC0 Eencoder Pin
    TRISC1 = 1; // RC1 Sensor Pin
    TRISD0 = 0; // 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)
  {
        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    
        if (gotIRQ)
        KICKER =~ KICKER ;
        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
  }
}
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
You are not waiting for 'gotIRQ' from the interrupt routine.
so @JohnInTX I think first need to check the flag
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 =~ KICKER ;
        gotIRQ = 0;  // acknowledge the interrupt
  }
 
Top