PIC16F877A - Object Detection and Rejection - Timer Interrupt

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Why is 400PPR a better choice?
that encoder gives four option 400 500 5000 1024 PPR and previously suggested to use low resolutions encoder and It would work on 5V DC That's why I think it's best choice to use

What is the calculated input frequency at the desired max speed?
100K Pulses/sec
------------------- * 60 sec/min = 1200RPM max rotational speed.
5000PP/Rev

100K input frequency at the desired max speed?
 

JohnInTX

Joined Jun 26, 2012
4,787
that encoder gives four option 400 500 5000 1024 PPR and previously suggested to use low resolutions encoder and It would work on 5V DC That's why I think it's best choice to use
4 options in one encoder? Part number and datasheet please.
A lot of things were 'previously suggested'. Do you have the math that says that your current setup can't work? Or that 400PPR will?
Where does the current setup fail?
How is that addressed by a lower resolution encoder? Or at least see the last note below.
If you can't answer these questions, don't waste your money on a new encoder.

100K Pulses/sec
------------------- * 60 sec/min = 1200RPM max rotational speed.
5000PP/Rev

100K input frequency at the desired max speed?
100K Pulses/sec. Where is that from and what is the significance? I was kind of expecting that you work backwards from the belt speed, roller diameter, PPR to reach a max pulse freq for the max belt speed.

Important:
Can you afford 2 new encoders?
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Edit: the PIC should count a little over 4MHz so I don’t think that is your problem. The 4N25 should be good enough but your circuit could be better.
Thanks @JohnInTX for saving me from the big problem

You were right, The problem with the circuit not with. I made the circuit you suggested and now rejection is happening at the full speed of the belt
Can you afford 2 new encoders?
No, I thought PIC16f877A is not enough fast for this project and its counter, not counting pulses of the encoder at high speed But I was totally wrong

Moving to Next, as you suggested previously start/stop system.

assume Belt motor is controlling through VFD and VFD is controlling through 5V DC relay to start/ stop relay and relay is controlling through PIC16F877A

I want to start/ stop the belt from PC

Program: I have tested this program myself and it's working

C:
#define _XTAL_FREQ 2000000

#include <xc.h>
#include <stdio.h>
#include <conio.h>
// BEGIN CONFIG
#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
//END CONFIG
void putch(char data)
{       
    while(!TRMT);
    TXREG = data;
}
  char  getch ()
{
   if(OERR == 1){     // reset UART on overflow error
       CREN = 0;
       CREN = 1;
  }
  while(RCIF==0);   // Wait till the data is received
   return(RCREG);   // Return the received data to calling function
}

void send (char *s)
{
  while (*s != 0)   
  putch(*s++);   
}
void main(void) {
    char data;
    PORTD = 0b00000000;    //  All OFF
    TRISD = 0b00000000;
 
    TXSTA = 0b00100100;    // TX enabled, BRGH=1
    RCSTA = 0b10010000;    // Serial Port, Continuous Receive enabled
    SPBRG = 0x81;          // baud rate 9600
    while (1)
    {           
     data = getch();
     putch(data);
  
     switch(data){ 
       case '1':
        RD4 = 1;  // Relay ON (start belt)
        RD2 = 1;  // Green Light ON
        break;
       case '0':
         RD4 = 0;   // Relay OFF (stop belt)
         RD2 = 0;  //  Red Light OFF
    
        }
    }
}

I would need your guideline to integrate this program into program in #291
 

JohnInTX

Joined Jun 26, 2012
4,787
I want to start/ stop the belt from PC
Boy, who didn't see this coming?

C:
#include <xc.h>
#include <stdio.h>
#include <conio.h>
// CONFIG
#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
//END CONFIG
#define ENCODER RC0
#define SENSOR  RC1
#define KICKER  RD0
#define _XTAL_FREQ 20000000
__bit gotIRQ;  // signals main that an interrupt occurred
__bit PCisScanning;  // 1 = we sent a scan request to the PC and expect a reply
unsigned char PCreply; // holds reply from PC
enum {STOP, RUN} OpMode;  // belt can be running or stopped

// PC commands
#define PC_SCAN_REQ '1'
#define PC_IRQ_TICK '0'
#define PC_BAD_OBJECT 'B'
#define PC_RUN_BELT 'R'
#define PC_STOP_BELT 'S'

void putch(unsigned char data){
  while(!TRMT);
  TXREG = data;
}
unsigned char getch()
{
  if(OERR == 1){  // reset UART on overflow error
  CREN = 0;
  CREN = 1;
  }
  while(RCIF==0);  // Wait till the data is received
  return(RCREG);  // Return the received data to calling function
}
// checkPC: checks UART, returns a char received or '\0' if none - does not wait on receive
unsigned char checkPC(void){
  if(OERR == 1){  // reset UART on overflow error
  CREN = 0;
  CREN = 1;
  }
  if(RCIF)  // if a char has been received
  return RCREG;  // return the char
  else
  return ('\0');  // else, return 00
}

void startBelt(void)
{
  // add whatever starts the belt <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

void stopBelt(void)
{
  // add whatever stops the belt  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

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

  OpMode = STOP;  // init to stopped
  stopBelt();

  INTCON = 0;  // No interrupts
  TRISC = 0b00000011; // RC0 Encoder Pin RC1 Sensor Pin
  TRISD = 0b00000000; // RD0 Kicker pin

  TXSTA = 0b00100100;  // TX enabled, BRGH=1
  RCSTA = 0b10010000;  // Serial Port, Continuous Receive enabled
  SPBRG = 0x81;  // baud rate 9600

  //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
  //Set CCPR1H and CCPR1L (16 bits) to the number of encoder pulses e
  CCPR1H = 0x03;
  CCPR1L = 0x84;
  CCP1IF = 0;
  CCP1IE = 1;  //Enabled CCP1 interrupt
  INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt

  while (1)
  {
  //---------------- STOPPED  ---------------------------
  while (OpMode == STOP)
  {
  while ((PCreply = getch())!= PC_RUN_BELT);  // wait for PC
  OpMode = RUN;  // set to run mode
  startBelt();  // and fire it up
  }// while STOP

  //------------------ RUNNING  ---------------------------
  while (OpMode == RUN)
  {
  if (gotIRQ)  // belt segment has passed
  {
  gotIRQ = 0;  // acknowledge the interrupt ** ALWAYS and before any delay **
  ShiftReg <<= 1;  // shift the integer shift register one bit left. LSbit = 0 after shift

  if (SENSOR == 1) // if there is an object present
  {
  putch(PC_SCAN_REQ);  // ask the PC to scan the object
  PCisScanning = 1;  // note that we ARE expecting a reply from PC
  }
  else
  {
  putch(PC_IRQ_TICK);  // you only need this if the PC needs to know about each segment on the belt
  // it also tells the PC that the comms are still working
  PCisScanning = 0;  // note that we are NOT expecting a reply from PC
  }

  // while the PC is (maybe) scanning, use that time to see if you need to kick
  if(ShiftReg & 0x0400)  // if the #10 bit after shift is '1', kick the object at end of belt
  {
  KICKER = 1;  // set output pulse high
  __delay_ms(40);  // *groan* Delay to see output ( inbuilt delay)
  KICKER = 0;  // set output pulse low
  }// kicker

  // now if we expect a reply from PC wait for it but not forever
  // if not, just back to top of loop
  if(PCisScanning == 1)
  {
  //wait for the PC reply OR another interrupt
  while(((PCreply = checkPC()) == '\0') && !gotIRQ);

  if(PCreply == PC_BAD_OBJECT)  // if got a reply before an interrupt AND it's 'B'..
  ShiftReg |= 0x0001;  // bad object, put 1 in LSbit

  if(PCreply == PC_STOP_BELT)  // received STOP instead of BAD
  OpMode = STOP;

  // here you can add some error processing if you got the next
  // interrupt before the PC replied i.e. dead PC or belt too fast
  // you can also decode other responses from the PC here.  Note
  // that you don't have to process a 'G' response if all you want
  // to know is if the scan was bad.  You could decode 'G' to know
  // that the PC was working and the comms were good if you want.

  } // process wait for PC
  } // gotIRQ

  // no IRQ or done processing IRQ, check for STOP
  if((PCreply = checkPC()) == PC_STOP_BELT)  // PC command between IRQs?
  OpMode = STOP;

  if (OpMode == STOP)  // if anything generated STOP..
     stopBelt();  // stop belt and do other loop
  }// while RUN

  } // main while loop
}//main


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
Boy, who didn't see this coming?
@JohnInTX Thanks again. you have helped me so much

Am I running fast because I think Sometimes we go astray from our path So we need a person who brings us to the right path?

I wanted to add some of the safety features like fire Alarm but I did not even try to do that. And what can I add to the new features to make an efficient system?

Edit :I thought I should go back once more. I'm reading all the advice given to me and studying codes. I learned a lot of things and I also enjoyed a lot
 
Last edited:

djsfantasi

Joined Apr 11, 2010
9,163
@JohnInTX Thanks again. you have helped me so much

Am I running fast because I think Sometimes we go astray from our path So we need a person who brings us to the right path?

I wanted to add some of the safety features like fire Alarm And what can I add to the new features to make efficient system
I’m still watching. I think the right path is to concentrate on the base problem. When you have other ideas like a Fire Alarm, document them and don’t think about them until you have accomplished your primary goal.

And don’t tackle anything else until you have nothing to add to your list. Actually. It would have been nice to have made this list before you started because sometimes knowing a desired feature affects the overall design.

Each feature needs to have a completed design. Purpose, requirements, description, effect...
 

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTX Thanks again. you have helped me so much
You got help from a lot of very generous members here and you should thank them as well but from me, you're welcome, I need the exercise sometimes.

@JohnInTX Am I running fast because I think Sometimes we go astray from our path So we need a person who brings us to the right path?
Agreed as long as you have laid out a path to follow. The design lays out the path. If you have carefully solved the problem with your design and documented the solution, you will find that the actual coding is easy and usually works first time. That is why I kept on you about the speed issue. My design (and I did have one, with sketches and calculations even) said that it should keep up. By having faith in that preliminary work and staying on the path as it were, we not only avoided lots of random coding trial and error but also avoided purchasing some expensive but unneeded encoders. So yes, it's handy to have someone who will keep you focused on the path but really that someone should be you. And it will be as you get some experience and confidence.

I wanted to add some of the safety features like fire Alarm but I did not even try to do that. And what can I add to the new features to make an efficient system?
OK, I did not see that one coming. :D
Assuming that this one works, I would stamp it with Ver 1.0 and use it, despite its many shortcomings. Take what you learned doing it and use that to design Ver 2.0 (**NOW WITH FIRE ALARM!!**). Mentally trace 1.0 and ask yourself things like 'I sent a request to the PC, what happens if I don't hear back?' and 'hmm... if the PC is dead, how do I stop this thing?' and yes, 'It's on FIRE, now what??' :eek: See where you would change 1.0 to fix some of those. (I think you'll find that while the building blocks (timer, interrupt, shift register, kicker etc) are there, a better overall structure would help. @djsfantasi Mentioned robustness as a prime goal. That seemed a bit out of reach at the time but if you proceed at all, that should be a serious consideration early in the design.

Edit :I thought I should go back once more. I'm reading all the advice given to me and studying codes. I learned a lot of things and I also enjoyed a lot
I think that is an excellent idea. As I mentioned before, a lot of skilled and experienced members here gave you some really good information. A careful read in the context of how this project bounced around and how it could have been more directed would be invaluable.

Finally, kudos to you for sticking with it and working hard. Not everyone we see here does that so- well done!
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
You got help from a lot of very generous members here and you should thank them as well but from me, you're welcome, I need the exercise sometimes.
I mean thank you all,
@LesJones gave me a good start @MaxHeadRoom given good advice @Ian Rogers helped me to convert assembly code into c code @djsfantasi suggested queue idea @JohnInTX You helped me on coding

everyone's work is appreciated

Here are few points want to discuss

I don't really know. I would always recommend 18F over 16F if you are looking to upgrade have at it but consider looking at some that have built-in quadrature encoder modules. A parametric search on Microchip.com will help you there. But in any case, you'll have to have a firm idea of the features/performance that your application requires and use those as a guide.
Just my .02
1) I don't think I need to replace 877A but I would like to collect 18F for learning. I saw PIC18F4331 has Quadrature Encoder Interface (QEI) feature. What would be the advantage (QEI) feature in PIC18F4331?

So a simple photo cell detector could be used as a counter from detection position to rejection position.
Going back to my sensor on the conveyor itself, it would be a simple solution as the conveyor position required to move the item to the reject position could be measured exactly by rotating proximity flag etc.
Which can also be termed an encoder, I just prefer, Rotary Sensor
Max.
2) I am interested to know How can we reject object without encoder because
we can save cost of encoder cost of sensor is less than encoder cost
 
Last edited:

jpanhalt

Joined Jan 18, 2008
11,087
I mean thank you all,
@LesJones gave me a good start @MaxHeadRoom given good advice @Ian Rogers helped me to convert assembly code into c code @djsfantasi suggested queue idea @JohnInTX You helped me on coding

everyone's work is appreciated

Here are few points want to discuss


1) I don't think I need to replace 877A but I would like to collect 18F for learning. I saw PIC18F4331 has Quadrature Encoder Interface (QEI) feature. What would be the advantage (QEI) feature in PIC18F4331?
You need to focus the the result. Follow your spirit later.

If you want to get rid of the encoder, and given that there can be a variable number of devices between detection and rejection, why not just pop a spot of fluorescent dye (I am fond of rhodamine) on the bad items. Then all the kicker needs to do is see the dye and make the object die.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
You need to focus the the result. Follow your spirit later.
@jpanhalt @@JohnInTX

I made a serious mistake to understand scanner interfacing. the sensor doesn’t send a signal to PC it sends a signal to the scanner. the scanner will only enable if the sensor is activated
upload_2019-6-5_16-12-44.png
when an object is in front of sensor PIC will enable the scanner and the scanner will give a pass/ fail signal to PORT of PC and PIC will see the pass/ fail signal if an object is good to do nothing or if its bad activate kicker

modified version of code
C:
#include <xc.h>
#include <stdio.h>
#include <conio.h>

// CONFIG
#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
//END CONFIG

#define ENCODER RC0
#define SENSOR  RC1
#define KICKER  RD0
#define BELT    RD1
#define SCANNER_TRIGGER  RD2

#define _XTAL_FREQ 20000000

__bit gotIRQ;  // signals main that an interrupt occurred


unsigned char PCreply; // holds reply from PC

enum {STOP, RUN} OpMode;  // belt can be running or stopped
// PC commands

#define PC_IRQ_TICK '0'
#define PC_BAD_OBJECT 'B'
#define PC_RUN_BELT 'R'
#define PC_STOP_BELT 'S'
void putch(unsigned char data){
  while(!TRMT);
  TXREG = data;
}

unsigned char getch()
{
  if(OERR == 1){  // reset UART on overflow error
  CREN = 0;
  CREN = 1;
  }
  while(RCIF==0);  // Wait till the data is received
  return(RCREG);  // Return the received data to calling function
}

// checkPC: checks UART, returns a char received or '\0' if none - does not wait on receive
unsigned char checkPC(void){
  if(OERR == 1){  // reset UART on overflow error
  CREN = 0;
  CREN = 1;
  }
  if(RCIF)  // if a char has been received
  return RCREG;  // return the char
  else
  return ('\0');  // else, return 00
}
void startBelt(void)
{
   BELT == 1;
}
void stopBelt(void)
{
   BELT == 0;
}
void main(void)
{
  char data;
  unsigned int ShiftReg = 0; //  Init to 0
  OpMode = STOP;  // init to stopped
  stopBelt();
  INTCON = 0;  // No interrupts
  TRISC = 0b00000011; // RC0 Encoder Pin RC1 Sensor Pin
  TRISD = 0b00000000; // RD0 Kicker pin
  TXSTA = 0b00100100;  // TX enabled, BRGH=1
  RCSTA = 0b10010000;  // Serial Port, Continuous Receive enabled
  SPBRG = 0x81;  // baud rate 9600
  //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
  //Set CCPR1H and CCPR1L (16 bits) to the number of encoder pulses e
  CCPR1H = 0x03;
  CCPR1L = 0x84;
  CCP1IF = 0;
  CCP1IE = 1;  //Enabled CCP1 interrupt
  INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt
  while (1)
  {
  //---------------- STOPPED  ---------------------------
  while (OpMode == STOP)
  {
  while ((PCreply = getch())!= PC_RUN_BELT);  // wait for PC
  OpMode = RUN;  // set to run mode
  startBelt();  // and fire it up
  }// while STOP
  //------------------ RUNNING  ---------------------------
  while (OpMode == RUN)
  {
  if (gotIRQ)  // belt segment has passed
  {
  gotIRQ = 0;  // acknowledge the interrupt ** ALWAYS and before any delay **
  ShiftReg <<= 1;  // shift the integer shift register one bit left. LSbit = 0 after shift
  if (SENSOR == 1) // if there is an object present
  {
      SCANNER_TRIGGER == 1;
  }
  else
  {
     SCANNER_TRIGGER == 0;
   
  }
  if(ShiftReg & 0x0400)  // if the #10 bit after shift is '1', kick the object at end of belt
  {
     KICKER = 1;  // set output pulse high
     __delay_ms(40);  // *groan* Delay to see output ( inbuilt delay)
     KICKER = 0;  // set output pulse low
  }// kicker
  //wait for the PC reply OR another interrupt
  while(((PCreply = checkPC()) == '\0') && !gotIRQ);
  if(PCreply == PC_BAD_OBJECT)  // if got a reply before an interrupt AND it's 'B'..
  ShiftReg |= 0x0001;  // bad object, put 1 in LSbit
  if(PCreply == PC_STOP_BELT)  // received STOP instead of BAD

  OpMode = STOP;
  } // process wait for PC
} // gotIRQ
  // no IRQ or done processing IRQ, check for STOP
  if((PCreply = checkPC()) == PC_STOP_BELT)  // PC command between IRQs?
  OpMode = STOP;
  if (OpMode == STOP)  // if anything generated STOP..
     stopBelt();  // stop belt and do other loop
 
  } 
}//main
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 couldn't test code because of holiday But I hope it should be work
 
Last edited:

Ian Rogers

Joined Dec 12, 2012
1,136
The pic16f877a is more than man enough for the task at hand, the t1clk input can be as much a 50Mhz the timer can handle it.
A full QEI is also not required as no direction is needed.. Keep it simple as you have done..
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Hello again
@LesJones @MaxHeadRoom @Ian Rogers @djsfantasi @JohnInTX

I am facing big problem in logic

The problem is when the sensor detects the object, the scanner should be enabled at the exact position to make pass/fail position

object detection and rejection should be done on the basis of the encoder. I mean when a sensor detects object count the x encoder pulses to enable the scanner and when scanner enables count pulse between scanner and kicker to reject object

upload_2019-6-8_19-56-53.png
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
So as you've drawn it:
Sensor picks up an object at #11 but scanner is at #10. The system has to 'remember' that there was an object at #11 and trigger the scanner at #10 yes?

You can make the shift register do double-duty here - examine the SR for '1' at more than one place:
  • At #11, if there is an object, put a '1' in the shift register in bit #11.
  • At the next interrupt (meaning that the belt has travelled ONE object length), that '1' bit shows up at #10. Examine the shift register at that point.
  • If there is a '1' there, trigger the scanner.
  • When you get the result of the scan, REPLACE the '1' bit that triggered the scanner with a '1' or '0' representing the result of the scan. That '1' or '0' will propagate through the SR as before to control the kicker.

Note that now you have one physical shift register that is treated as two logical shift registers. The original one runs from bit #10 to bit #1 as before. The new one runs from bit #11 to bit #10. #10 is the boundary point where the meaning of the bits in the SR change from 'object detected' to 'result of the scan'.

The shift register is longer by one bit. You'll have to take that into account with your bit set/clear and bit detection operations. You've numbered the bits backwards in your sketch but if #11 is the LSbit of the shift register then (based on the earlier bit assignments):

The 'object detected' bit is 0x0001
The 'scan request' bit is 0x0002
The 'scan result' bit is ALSO 0x0002, the SR has NOT shifted between scan request and scan result
The 'kick control' bit has moved one bit to 0x08000

On each interrupt:
If you detect an object you do (ShiftReg |= 0x0001) t0 set that bit. (Object detected)
If (ShiftReg & 0x0002) request a scan (previous detected object is now under scanner)

If (scan is GOOD)
(ShiftReg &= ~0x0002) // CLEAR the kick bit, just leave it set if BAD
If (ShiftReg & 0x0800) // the previously detected BAD object is now at the kicker
Kickit();

Right now, I don't have a lot of time to help you, sorry. But to me, that seems the most direct solution. Others may have a better idea.

Good luck!
 
Last edited:

djsfantasi

Joined Apr 11, 2010
9,163
So as you've drawn it:
Sensor picks up an object at #11 but scanner is at #10. The system has to 'remember' that there was an object at #11 and trigger the scanner at #10 yes?

You can make the shift register do double-duty here - examine the SR for '1' at more than one place:
  • At #11, if there is an object, put a '1' in the shift register in bit #11.
  • At the next interrupt (meaning that the belt has travelled ONE object length), that '1' bit shows up at #10. Examine the shift register at that point.
  • If there is a '1' there, trigger the scanner.
  • When you get the result of the scan, REPLACE the '1' bit that triggered the scanner with a '1' or '0' representing the result of the scan. That '1' or '0' will propagate through the SR as before to control the kicker.

Note that now you have one physical shift register that is treated as two logical shift registers. The original one runs from bit #10 to bit #1 as before. The new one runs from bit #11 to bit #10. #10 is the boundary point where the meaning of the bits in the SR change from 'object detected' to 'result of the scan'.

The shift register is longer by one bit. You'll have to take that into account with your bit set/clear and bit detection operations. You've numbered the bits backwards in your sketch but if #11 is the LSbit of the shift register then (based on the earlier bit assignments):

The 'object detected' bit is 0x0001
The 'scan request' bit is 0x0002
The 'scan result' bit is ALSO 0x0002, the SR has NOT shifted between scan request and scan result
The 'kick control' bit has moved one bit to 0x08000

On each interrupt:
If you detect an object you do (ShiftReg |= 0x0001) t0 set that bit. (Object detected)
If (ShiftReg & 0x0002) request a scan (previous detected object is now under scanner)

If (scan is GOOD)
(ShiftReg &= ~0x0002) // CLEAR the kick bit, just leave it set if BAD
If (ShiftReg & 0x0800) // the previously detected BAD object is now at the kicker
Kickit();

Right now, I don't have a lot of time to help you, sorry. But to me, that seems the most direct solution. Others may have a better idea.

Good luck!
I don’t want to confuse things, but you have to make sure that a new requirement is met.

The time it takes to scan the object must be less than the time it takes to move the object from edge detection to scanning.

That’s the time between interrupts. If scanning takes longer than that. When you try to set the reject bit, the shift register will have moved on.

This is not an insurmountable problem. Your code will have to account for the difference in time.

Let’s say that it takes less than
2 x dTime(interrupt).​
Meaning you don’t have enough time to scan but the shift register only moves one position. Then you reset the edge detection pin before scanning and you set the good/bad bit in the next position if the shift register.

Using John’s numbering scheme, it looks like this:
  • 0x0001 = Edge detected?
  • 0x0002 = perform scan (takes >1 & <2 interrupt cycles)
  • 0x0003 = if scan = bad, set to 1; I’d scan = good, set to 0
  • 0x0400 = reject if bit is set.

Note, the register bit positions are dependent on the time.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@djsfantasi @JohnInTX first step at one time

assume there is only sensor and scanner on the belt
Take a look at this pseudo code. It's not original code when the sensor detects the object, the scanner should be scan the object
C:
#include <xc.h>

#pragma config FOSC = HS  // 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 SCANNER RD0

#define _XTAL_FREQ 20000000

__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 Scanner
 
  //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
//Set CCPR1H and CCPR1L (16 bits) to the number of encoder pulses e.g. for 795
    CCPR1H = 0x03;
    CCPR1L = 0x84;
    CCP1IF = 0;
    CCP1IE = 1;  //Enabled CCP1 interrupt
    INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt
    while(1)
  {
if (gotIRQ)
  {
     gotIRQ = 0;  // acknowledge the interrupt ** ALWAYS and before the delay **
     ShiftReg <<= 1;  // shift the integer shift register one bit left. LSbit = 0 after shift
  if (SENSOR == 1)
  ShiftReg |= 0x0001;  // object, put 1 in LSbit
  if(ShiftReg & 0b00100000){  // and if the #5 bit after shift is '1', enable scanner
  SCANNER = 1;  // set output pulse high
 
  }
  }// gotIRQ
} // while
}// main
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
  }
}
Does it make any sense for detection and scanning only?

Edit : Do not pay much attention to the register value of the counter. I have just taken an example
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Yes, everything so far depends on all processing done within one interrupt time. @djsfantasi describes a way to fix that.
Here's a quick sketch I did before dj's post showing how one shift register does double duty. As dj says, you might have to adjust the particular bits picked off.

Back to my own mess..

EDIT: answering dj's post but again, you are coding first, not last. Figure out the solution FIRST, then code it. It also looks like the code you edited is not the latest version. Hard to keep up with that..
 

Attachments

Top