PIC16F877A - Object Detection and Rejection - Timer Interrupt

LesJones

Joined Jan 8, 2017
4,190
Hi Ian,
I would be interested to know the other forum that you mentioned that seems to be discussing the same topic. (Could it be the same person using a different name ?)

Les.
 

Ian Rogers

Joined Dec 12, 2012
1,136
I have experience in many languages.. C, C++, Pascal, Object Pascal, Java, Python, ASM on PC, ASM on PIC, ASM on AVR, ASM on Hitachi and Basic ( on many platforms ).. Played with Ruby, Pearl, and a shed load more... Never tried any of the A variants or Fortran or even cobalt for that matter.. But mainly C.

BUT!!! Pics are mainly done in C because the majority are designed with C optimisation in mind... It's a ton faster in C.. Happy with ASM though. Guess what.... Still hate debugging no matter what the language.. After a while syntax gets in your way..
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I have experience in many languages.. C, C++, Pascal, Object Pascal, Java, Python, ASM on PC, ASM on PIC, ASM on AVR, ASM on Hitachi and Basic ( on many platforms ).. Played with Ruby, Pearl, and a shed load more... Never tried any of the A variants or Fortran or even cobalt for that matter.. But mainly C.
.
@Ian Rogers Will you help me to convert ASM code into C language?

I've tried to write c code in my previous post #72

Code:
;*****************************************************************************
;
;  Module:  TM1divide
;
;  Version:03
;   Not using interrupts.
;   Output pin changed from RC2 to RD4  31/03/19
;    Preload value changed from
;
;
;*****************************************************************************
;I/O port useage
;Port A
;   RA0   (Pin 2)
;   RA1   (Pin 3)
;   RA2   (Pin 4)
;   RA3   (Pin 5)
;   RA4   (Pin 6)   NOTE this is an open drain output so a pulup resistor must be used.
;   RA5   (Pin 7)
;   RA6
;   RA7
;Port B
;   RB0t     (Pin 33)
;   RB1     (Pin 34)
;   RB2     (Pin 35)
;   RB3     (Pin 36)
;   RB4     (Pin 37)
;   RB5     (Pin 38)
;   RB6     (Pin 39)
;   RB7     (Pin 40)
;Port C
;   RC0   Encoder input pulse.     (Pin 15)
;   RC1   Use for sensor input.     (Pin 16) (Active low.)
;   RC2   (Pin 17)
;   RC3   (Pin 18)
;   RC4   (Pin 23)
;   RC5   (Pin 24)
;   RC6   TX data       (Pin 25)
;   RC7   RX data       (Pin 26)
;Port D
;   RD0     (Pin 19)
;   RD1     (Pin 20)
;   RD2     (Pin 21)
;   RD3     (Pin 22)
;   RD4   used for pulse output     (Pin 27)
;   RD5     (Pin 28)
;   RD6     (Pin 29)
;   RD7     (Pin 30)
;Port E
;   RE0      (Pin 8)
;   RE1     (Pin 9)
;   RE2     (Pin 10)
;*****************************************************************************
  list p=16f877A, st=OFF, x=OFF, n=0
  errorlevel -302
  errorlevel -306
  #include <p16f877A.inc>
   __CONFIG   _HS_OSC & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _LVP_OFF & _CPD_OFF & _CP_OFF
;  ******** RAM Locations ***********
;Bank 0
   CBLOCK   0x20   ;GPR' starts at 0x20
   ENDC       ;Must end at 07F
; CBLOCK not used as no register variables are needed
     ORG  0
RESET:  GOTO  Start
;Interrupt vector
     ORG  4     ;Should not get here as interrups are not being used
     retfie       ;Return from interupt
;*****************************************************************************
;
;  Function :  Main
;  Main application loop
;
;  Input:  None.
;
;  Output:  N/A
;
;*****************************************************************************
Start:
     clrf  STATUS  ; Select bank 0
     clrf  INTCON  ; No interrupts
     clrf  PCLATH  ; Code is in first bank
;         Now setup I/O ports
     bsf     STATUS, RP0       ;Select bank 1 registers
     movlw  0x03     ;Bits 0,1 inputs.
     movwf  TRISC
   movlw   0x00     ;All bits as outputs
     movwf  TRISD
     bcf  STATUS, RP0  ;back to bank 0 registers
Wait_trigger_L:       ;Loop waiting for trigger pulse from sensor to go low
   btfsc   PORTC,1
   goto   Wait_trigger_L
Wait_trigger_H:       ;Loop waiting for trigger pulse from sensor to go high
   btfss   PORTC,1
   goto   Wait_trigger_H
Init_TMR1:
;   Prescale 1:1           (Bits 4 & 5 = 0)
;   T1OSCEN Timer1 Oscillator Enable Control bit    (Bit 3 = 0)
;   T1SYNC             (Bit 2  = 0  )
;   TMR1CS            (Bit 1  = 1  )
;   TMR1ON             (Bit 0 = 0 )
     movlw  B'00000010'
     movwf  T1CON
Start_counter:
   movlw   0x82     ;These preset values give a count od 32001 pulses
   movwf   TMR1H
   movlw   0xFF
   movwf   TMR1L
   bcf   PIR1,TMR1IF   ;Clear interrupt flag
   bsf    T1CON,TMR1ON   ;Start TMR1
Count_Loop:     ;Wait for TMR1 overflow bit
   btfss    PIR1,TMR1IF   ;Test interrupt flag
   goto   Count_Loop
   bsf   PORTD,4       ; set output pulse high
   call    Delay100ms
   bcf   PORTD,4       ; set output pulse low
   goto   Start
;Subroutines.
;*****************************************************************************
;
;  Function :  Delay 100 mS
;
;
;  Input:  None
;
;  Output:  None
;
;*****************************************************************************
Delay100ms:
     clrf  INTCON  ; No interrupts
;   Prescale 1:8           (Bits 4 & 5 = 1)
;   T1OSCEN Timer1 Oscillator Enable Control bit    (Bit 3 = 0)
;   T1SYNC             (Bit 2  = 0 )
;   TMR1CS            (Bit 1  = 0  )
;   TMR1ON             (Bit 0 = 0 )
     movlw  B'00110000'
     movwf  T1CON
   bcf   PIR1,TMR1IF   ;Clear interrupt flag
   movlw   0x0B
   movwf   TMR1H
   movlw   0xDC
   movwf   TMR1L
   bsf    T1CON,TMR1ON   ;Start TMR1
D_Loop:
   btfss    PIR1,TMR1IF   ;Test interrupt flag
   goto   D_Loop
   bcf    T1CON,TMR1ON   ;Stop TMR1
   bcf   PIR1,TMR1IF   ;Clear interrupt flag
   return
;*****************************************************************************
  END  ; End of program
 
Last edited:

Ian Rogers

Joined Dec 12, 2012
1,136
Okay... This is my take...
C:
/*****************************************************************************
  Module:  TM1divide
  Version:03
  Not using interrupts.
Output pin changed from RC2 to RD4  31/03/19
  Preload value changed from
********************************************************************************/
#include <xc.h>
#define _XTAL_FREQ 20000000L
#pragma config FOSC=HS
#pragma config WDTE=OFF
/*
;*****************************************************************************
;
;  Function :  Main
;  Main application loop
;
;  Input:  None.
;
;  Output:  N/A
;
;*****************************************************************************/
void main(void)
 {
 INTCON =0; // No interrupts
 TRISC = 3; // RC0 & 1 inputs
 TRISD = 0; // Portd outputs
 T1CON = 2; // set timer1, Ext clock. 1:1 prescale
 PORTC = 0; 
 while(1)
 {
   while(RC1); // wait while high.
 while(!RC1); // wait while low.
 
 TMR1H = 0x82; // preset
 TMR1L = 0xFF; // timer
 TMR1IF = 0; // Clear interrupt flag
 TMR1ON = 1; // Start TMR1
 while(!TMR1IF); // Wait for timer spill
 TMR1ON = 0; // timer off
   RD4 = 1;  // set output pulse high
 __delay_ms(100);// Delay to see ouput ( inbuilt delay)
   RD4 = 0;  // set output pulse low
   } // go again
 }// end of program
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Okay... This is my take...]
@Ian Rogers Thank !!

This code is working perfectly
C:
#include <xc.h>

#define _XTAL_FREQ 20000000L

#pragma config FOSC=HS
#pragma config WDTE=OFF

void main(void)
{
    INTCON =0; // No interrupts
 
    PORTC = 0;
    TRISC = 3; // RC0 encoder & RC1sensor inputs
    TRISD = 0; // Portd outputs
 
    T1CON = 2; // set timer1, Ext clock. 1:1 prescale

 
    while(1)
   {
       while(RC1);        // wait while high.
       while(!RC1);       // wait while low.
     
       TMR1H = 0xBF;        // Load starting value
       TMR1L = 0x8C;
       TMR1IF = 0;         // Clear interrupt flag
       TMR1ON = 1;          // Start TMR1
    
       while(!TMR1IF);      // Wait for timer spill
    
       TMR1ON = 0;         // timer off
    
       RD4 = 1;            // set output pulse high
       __delay_ms(800);    // Delay to see ouput ( inbuilt delay)
       RD4 = 0;            // set output pulse low
   }
}
If there are a number of an object between the scanner and the rejection point. We need to have a counter running for each object.

Consider the number of objects is five then we should have run counter more than five

I want to set multiple counters ( 5) in the queue whenever the sensor triggers set the counter in FIFO
  • When the sensor triggers the first-time set counter 1 and when timer overflow, set output pulse high and Low
  • When the sensor triggers the second-time set counter 2 and when it timer overflow, set output pulse high and Low
  • When the sensor triggers the third-time set counter 3 and when it timer overflow, set output pulse high and Low
  • When the sensor triggers the forth-time set counter 4 and when it timer overflow, set output pulse high and Low
  • When the sensor triggers the fifth-time set counter 5 and when it timer overflow, set output pulse high and Low
How to set each counter in queue ?
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
We’ve seen this one before and this link was posted by a member (Max?) as an example of one solution. It’s implemented with a PLC but the principles would apply here as well.

Good luck!
https://accautomation.ca/plc-programming-example-shift-register-conveyor-reject/
@JohnlnTX Thank you for your helpful link But I really don't know PLC Programming

Making rejection in the queue is very difficult. I have been tried to understand PLC logic but it goes over my head
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
@LesJones can give idea
He said we need to have a counter running for each object. If there are a number of the object between the scanner and the rejection point. We have to set each counter for each object
 

LesJones

Joined Jan 8, 2017
4,190
You have already been told that the little program that I wrote only answers the origin question It CANNOT work with multiple items between the detector and reject point as it is using a physical counter in the PIC. (I chose this rather than a software counter as we can't get the TS to tell us the speed of the conveyor.) I like John's shift register idea but it may be difficult to implement with the excessively high resolution of the chosen encoder. There will be about 36000 counts between the detector and the reject point which are 1.2 metres apart. (So one count represents about 0.03mm) A shift register could be implemented in software but I think a 36000 bit shift register is impractical. I think a resolution of 3 mm would be good enough. (A 50 count per rev encoder would give this. (Or feed the existing encoder through a divide by 100 stage.))

Les.
 
Last edited:

Thread Starter

daljeet795

Joined Jul 2, 2018
295
. (I chose this rather than a software counter as we can't get the TS to tell us the speed of the conveyor.

A shift register could be implemented in software but I think a 36000 bit shift register is impractical. I think a resolution of 3 mm would be good enough. (A 50 count per rev encoder would give this. (Or feed the existing encoder through a divide by 100 stage.))

Les.
I don't know all the dimension of the conveyor to calculate speed. I tested the program on someone's place. I will measure all dimension and let you know the speed of the conveyor tomorrow.

so I think I have to purchase shift register that would accept serial data and give parallel output
 

djsfantasi

Joined Apr 11, 2010
9,163
A 36,000 bit software shift register would require more than 4,500 bytes of memory. In addition to the remainder of the code, pointers, et.al. Doable if you have sufficient resources in the processor.

But why are you using the encoder resolution to set the size of the shift register?
 

djsfantasi

Joined Apr 11, 2010
9,163
I might be getting it. From the inspection station to the reject station is 16,500 counts. That value represents the distance.

You don’t need a shift register. You need a FIFO list. Which is fairly simple to program. The maximum size of the list is equal to the number of objects that can fit from the inspection point to the reject point.

An object fails the inspection. You push the current counter+16500 into the list.

The reject station checks to see if there’s an item in the output of the list. If there is, when the counter equals the value read from the list, it activates and rejects the item.

And so on and so on.
 

MaxHeadRoom

Joined Jul 18, 2013
28,696
You don’t need a shift register. You need a FIFO list. Which is fairly simple to program. The maximum size of the list is equal to the number of objects that can fit from the inspection point to the reject point.

.
That is the method in the PLC post, Shift register = FIFO.
Max.
 
Top