PIC16F877A - Object Detection and Rejection - Timer Interrupt

Thread Starter

daljeet795

Joined Jul 2, 2018
295
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..
First, I thought, after made a drawing post #315 then wrote a code
I mentioned there it's not original its pseudocode,

I thought that if this method works then I can go for further steps. Combining all together makes it difficult for me

I am looking to integrate code in 331 latest version
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
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..
@djsfantasi What is meaning of this line "0x0002 = perform scan (takes >1 & <2 interrupt cycles)"
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
The example assumes a scan takes more than 1 and less than 2 interrupt cycles
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();
@djsfantasi That I didn't understand Why need 1 and less than 2 interrupt cycles
 
Last edited:

djsfantasi

Joined Apr 11, 2010
9,237
You don’t need that range. You need to code for the situation where the time it takes to scan is within that range.

Your original logic won’t work if the scan time is longer than the time between interrupts.

The example I gave works when the scan time is between 1-2 times the interrupt range. If it was 2-3 times, then the original code AND my example wouldn’t work. But the algorithm does work with different constants.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@JohnInTX @djsfantasi assume there are 11 objects

0x0001 00 00 0000 0001 Object detected

0x0002 00 00 0000 0010 scan request

0x0003 00 00 0000 0011 if scan = bad, set to 1; If scan = good, set to 0

0x0004 01 00 0000 0000 reject if bit is set

if (SENSOR == 1)
ShiftReg |= 0x0001; // object detected

0x0002 00 00 0000 0010 scan request

How to send a scan request and get scan reply What would be the condition?
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
if (SENSOR == 1)
ShiftReg |= 0x0001; // object detected

0x0002 00 00 0000 0010 scan request

How to send a scan request and get scan reply What would be the condition?
I'm sorry, I have no idea what you are asking here. I would have thought that all of that would have been resolved above????
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I'm sorry, I have no idea what you are asking here. I would have thought that all of that would have been resolved above????
@JohnInTX I am really sorry but I didn't understand the logic
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.
C:
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;  // bad object, put 1 in LSbit

  if (ShiftReg & 0x0002)

     Scanner = 1;  // enable
    __delay_ms(30);  // response time
     Scanner = 0;  //  disable

  if (scan == bad)

  if (ShiftReg & 0x0800)


      KICKER = 1;  // set output pulse high
      __delay_ms(40);
      KICKER = 0;  // set output pulse low

   }
}
 

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTX I am really sorry but I didn't understand the logic
Think about it.
The change in how the scanner works really does not change the system logic. At some point you request a scan and get a reply. So your 'request a scan' now triggers the scanner and 'get a reply' comes from the PC. So what? The LOGIC of the problem is the same. Change the hardware interface and get on with it.

You added a new thing: the sensor location and scanner location are now separated. So what? How are we handling the fact that the sensor/scanner and kicker are separated? Answer: by picking off the relevant bits in the shift register. The shift register follows the belt and bits in it tell you what is happening on the belt. TRUE: separating the sensor and scanner extended the shift register AND the bits mean different things depending on whether they are between the sensor and scanner OR the scanner or the kicker.

You could use multiple shift registers, one for each function (sensor to scan request and scan result to kicker) but since they DO NOT OVERLAP, you can use the same physical shift register and just know that if you are at the 'scan request' point, a '1' in the shift register means 'scan the object' and the bits between the scanner and kicker mean 'kick the object'.

Right now, I would work on the assumption that the scan result is returned quickly and within the same interrupt segment.

You need to have that working in your mind before you can proceed.

Good luck!
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Think about it.
The change in how the scanner works really does not change the system logic. At some point you request a scan and get a reply. So your 'request a scan' now triggers the scanner and 'get a reply' comes from the PC. So what? The LOGIC of the problem is the same. Change the hardware interface and get on with it.
!
@JohnInTX I do not understand where my thinking goes wrong

bit0 tell the sensor position and bit1 tell the scanner position

I think Logic should be work in the following manner
C:
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)       // bad object,
        ShiftReg |= 0x0001; //  put 1 in LSbit

     ShiftReg = 0x0002;     //'scan request' bit is 0x0002

     Scanner = 1;          // set output high
     __delay_ms(30);       // response time
     Scanner = 0;          //  set output low

     if (scan == bad)      // if scan = bad, set to 1;
      ShiftReg = 0x0300;
     else
       ShiftReg = 0x0001;  //I’d scan = good, set to 0

     if (ShiftReg & 0x0800)  a//if the #11 bit after shift is '1', kick it
      KICKER = 1;  // set output high
      __delay_ms(40);
      KICKER = 0;  // set output low
   }
}
 

JohnInTX

Joined Jun 26, 2012
4,787
The shift resister bits correspond to segments on the belt.
There are 3 bits in the n-bit shift register that matter
  • At the sensor
  • At the scanner
  • At the kicker
The shift register is shifted at each interrupt so that the bits in the shift register 'follow' the objects along the belt.
ONE interrupt occurs as the belt travels ONE segment length.

When the interrupt occurs, there are 3 things to do:
1) If SENSOR senses an object, put a '1' in the shift register bit that corresponds to the sensor.
2a) If the shift register bit at the SCANNER is '1' request a scan of the object.
2b) Wait for the reply - it needs to come quickly.
2c) If the SCANNER REPLY says 'bad object' set the bit at the scanner location. When that bit travels to the kicker, it's corresponding object will be kicked .
2d) If the SCANNER REPLY says 'good', clear the bit at the scanner location. When that bit travels to the kicker it will NOT be kicked because it is '0'
3) At the KICKER, if the corresponding bit is '1' kick it. (indicating that a 'bad' object has traveled along the belt and is now at the kicker).
Repeat for every interrupt.

I don't know how to explain it any better.
Good luck.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I don't know how to explain it any better.
Good luck.
@JohnInTX I think my code is doing the same as you explain. Do not this?
Pherphs I'm making mistake converting logic into code
1) If SENSOR senses an object, put a '1' in the shift register bit that corresponds to the sensor.
C:
[LIST=1]
[*] if (SENSOR == 1)     // bad object,
[*]        ShiftReg |= 0x0001; //  put 1 in LSbit
[/LIST]
If the shift register bit at the SCANNER is '1' request a scan of the object.
C:
[LIST=1]
[*]ShiftReg = 0x0002;   //'scan request' bit is 0x0002
[*]

[*]     Scanner = 1;         // set output high
[*]     __delay_ms(30);     // response time
[*]     Scanner = 0;         //  set output low
[/LIST]
2c) If the SCANNER REPLY says 'bad object' set the bit at the scanner location. When that bit travels to the kicker, it's corresponding object will be kicked .
2d) If the SCANNER REPLY says 'good', clear the bit at the scanner location. When that bit travels to the kicker it will NOT be kicked because it is '0'
C:
[LIST=1]
[*]if (scan == bad)     // if scan = bad, set to 1;
[*]      ShiftReg = 0x0300;
[*]     else
[*]       ShiftReg = 0x0001; //I’d scan = good, set to 0
[/LIST]

3) At the KICKER, if the corresponding bit is '1' kick it. (indicating that a 'bad' object has traveled along the belt and is now at the kicker).
C:
[LIST=1]
[*] if (ShiftReg & 0x0800) a//if the #11 bit after shift is '1', kick it
[*]      KICKER = 1; // set output high
[*]      __delay_ms(40);
[*]      KICKER = 0; // set output low
[/LIST]
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Is that pseudo-code?
ShiftReg = 0x0002; //'scan request' bit is 0x0002
This does not test a bit in the shift register. Also, does the trigger to the scanner have to be 30ms long? You are adding considerable delays into the loop.
  • if (scan == bad) // if scan = bad, set to 1;
  • [*] ShiftReg = 0x0300;
  • [*] else
[*] ShiftReg = 0x0001; //I’d scan = good, set to 0
What are you trying to do here? You are assigning 16 bit values to the shift register. The shift register mechanism requires you set/clear/test only ONE bit at a time. That's what the logical operations are doing.
 

djsfantasi

Joined Apr 11, 2010
9,237
May I suggest backing up and getting away from code for a bit?

Imagine you’re in a big room, with a bell on the wall. There is a line of your friends, each carrying a bucket and an object. They each have a racing bib on with a number.

The numbers look like this:
  • 0x0001 or 1 - the sensor is here
  • 0x0002 or 2 - the scanner is here
  • 0x0004 or 4
  • 0x0008 or 8
  • 0x0010 or 16
  • 0x0020 or 32
  • 0x0040 or 64
  • 0x0080 or 128
  • 0x0100 or 256
  • 0x0200 or 513
  • 0x0400 or 1024 - rejection happens here
Your friends have to pass the bucket and object they’re holding to the left every time the bell rings. The bell is your interrupt.

The line is a shift register. The buckets contain the bits. And the number on each friend is the value of the bit position they represent.

Then, at the first position, 0x0001, you need another friend, with a bucket of tennis balls. This friend is your sensor. When the bell rings, if he senses an object, he puts a ball (representing a ‘1’ bit) into the bucket.

The bell rings. Everyone passes their bucket along. This is repeated for every bell ring or interrupt.

Another friend, in front of 0x002, is your scanner. If the bucket in front of him has a ball, he scans the object. If the scan is good, he takes the tennis ball out of the bucket. If it’s bad, he makes sure there is a ball in the bucket.

Down at the other end of the line, a third friend, 0x0400, is your reject mechanism. If after a bell ring, the bucket in front of him has a ball, he rejects the object.

If you get this, we can review the necessary code.
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@JohnInTX @djsfantasi

pseudo-code for logical operations
C:
  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)       // bad object,
        ShiftReg |= 0x0001; //  put 1 in LSbit
      
     if ( ShiftReg == 0x0002)    //'scan request' bit is 0x0002  
        Scanner = 1;          // set output high
        __delay_ms(30);       // response time
        Scanner = 0;          //  set output low

    if (scan == bad)      // if scan = bad, set to 1;
        ShiftReg = 0x0002;
   
 
      if (scan == good)   //  scan = good, set to 0
          ShiftReg = 0x0001;
    
     if (ShiftReg & 0x0800)  //if the #11 bit after shift is '1', kick it
      KICKER = 1;  // set output high
      __delay_ms(40);
      KICKER = 0;  // set output low
   }
}
 

djsfantasi

Joined Apr 11, 2010
9,237
@JohnInTX @djsfantasi

pseudo-code for logical operations
C:
  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)       // bad object,
        ShiftReg |= 0x0001; //  put 1 in LSbit
     
     if ( ShiftReg == 0x0002)    //'scan request' bit is 0x0002 
        Scanner = 1;          // set output high
        __delay_ms(30);       // response time
        Scanner = 0;          //  set output low

    if (scan == bad)      // if scan = bad, set to 1;
        ShiftReg = 0x0002;
  

      if (scan == good)   //  scan = good, set to 0
          ShiftReg = 0x0001;
   
     if (ShiftReg & 0x0800)  //if the #11 bit after shift is '1', kick it
      KICKER = 1;  // set output high
      __delay_ms(40);
      KICKER = 0;  // set output low
   }
}

Looks much better! But...

It gets lost here.

Code:
    if (scan == bad)      // if scan = bad, set to 1;
        ShiftReg = 0x0002;
 
      if (scan == good)   //  scan = good, set to 0
          ShiftReg = 0x0001;
What are you setting in the line right after the comment “scan = bad, set to 1”? (You have the same problem in the next if statement)

You want to set the bit at the same position as 0x0002. Not the entire shift register. Your line of code sets the entire shift register to 0x0002. What is the result of doing that?

I’ll tell you. You reset all of the bits. Any object that previously was designated as “bad” is suddenly set to “good”.

Don’t post complete code... Just tell me in words how you would set bit in position 0x0002 to a ‘1’? You actually do it correctly earlier in the code.

Let me make an observation. You often confuse a value with a bit position.

Answer my question and it will help me provide an answer that should be less confusing.

In between our replies, take a look at logical operators. I think a review will help.

Waiting for your reply!
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I’ll tell you. You reset all of the bits. Any object that previously was designated as “bad” is suddenly set to “good”.

Don’t post complete code... Just tell me in words how you would set bit in position 0x0002 to a ‘1’? You actually do it correctly earlier in the code.

Let me make an observation. You often confuse a value with a bit position.

Answer my question and it will help me provide an answer that should be less confusing.

Just tell me in words how you would set bit in position 0x0002 to a ‘1’?

Waiting for your reply!
@djsfantasi

let's assume we need to set clear and test three bits in shift registers
  • sensor bit
  • scanner bit
  • kicker bit
If a scan is bad, set the bit at the scanner location.

If a scan is good, clear the bit at the scanner location.

(ShiftReg &= 0x0002) // set scanner bit if object is BAD

(ShiftReg &=~ 0x0002) // clear scanner bit if object is good
 

djsfantasi

Joined Apr 11, 2010
9,237
So I asked how you would do this? But anyway, here is how I’d do it. The example only shows how to set/reset the second bit. What would you change for the others?

The technique I’m about to describe is called bit masking. If it helps, you can read up on the technique to help you understand.

I’m going to get technical here. It may be confusing to you at first, but hang in there. You’ll need to know this information for your preferred solution. I’ll support it, a little bit at a time.

To set a bit in the position represented by 0x0002 (important bit of information) the following code will do it for you. Pretty easy

ShiftReg |= 0x0002 // set bit2 to ‘1’


To set the seventh bit, not that your application needs to do this... (I present it as another example for you to work out) ... you would use the line
ShiftReg |= 0x0040​

To reset (set to ‘0’) a bit in the position represented by 0x0002, the following code will do it for you. Warning: it’s much less intuitive.

ShiftReg &= (~0x0002)
// set bit2 to ‘0’


If we invert the value 0x0002 (that’s what ‘(~0x0002)’ does in the code; it changes all bits to their opposite value) we get a sequence of bits that are equal to ‘1’ in all positions, except the position designated by 0x0002.

In binary, that is,
11111111111101​

When we AND this mask/value with the shift register. We get the contents back - except for the position specified by 0x0002! That bit will be a ‘0’.

0x0002 is not necessarily a value. Nor is 0x0001 nor 0x0400. They are positions specified by its binary contents.

It is most definitely NOT a ‘value’ of the entire shift register.

It is a value at a ‘position’ within the shift register. And that’s what makes it confusing. Generally we are using it to refer to a position, but sometimes as a value. As long as you remain aware of the difference, you’ll be ok.

I encourage you to work out these examples without looking at your code. Your code will confuse you and hamper your understanding of what you need to do. Once you understand these examples, it will be much simpler to correct your code.
 

LesJones

Joined Jan 8, 2017
4,511
You also seem to be ignoring the fact that the object moves 159mm in the 30 mS that you allow for the scanner to respond. (Assuming that you are still using 5.3 metres per second for the conveyor speed.)

Les.
 

djsfantasi

Joined Apr 11, 2010
9,237
You also seem to be ignoring the fact that the object moves 159mm in the 30 mS that you allow for the scanner to respond. (Assuming that you are still using 5.3 metres per second for the conveyor speed.)

Les.
We know that. A solution has been presented, but we need to get past setting and resetting bits in the shift register first.

We will address that issue later.
 
Top