PIC16F877A - Object Detection and Rejection - Timer Interrupt

MaxHeadRoom

Joined Jul 18, 2013
28,618
Yes for a single item, once it is known that there can be more than one between detection and rejection then that puts a different spin on it.
The ideal is to have a drawing or photo the conveyor or process, if it is available and all the requirement listed, otherwise it is a drawn out process of info gathering.
Max.
 

LesJones

Joined Jan 8, 2017
4,174
Yes. As you have changed the number of pulses you want to count from 32001 to 40000 I will need to change the preload value to TMR1.
I suggest that you try the 3a version first and rotate the encoder at
about 1 rev per second (60 RPM) and count the time between flashes of the LED. I expect it to be every 6.4 second if the encoder is giving 5000 pulses per rev, 12.8 seconds if it is giving 2500 pulses per rev or 28.6 seconds if it is giving 1250 pulses per rev.

Les.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Yes. As you have changed the number of pulses you want to count from 32001 to 40000 I will need to change the preload value to TMR1.
I suggest that you try the 3a version first and rotate the encoder at
about 1 rev per second (60 RPM) and count the time between flashes of the LED. I expect it to be every 6.4 second if the encoder is giving 5000 pulses per rev, 12.8 seconds if it is giving 2500 pulses per rev or 28.6 seconds if it is giving 1250 pulses per rev.

Les.
Hello les
It's glad to tell you that your program is working for one object LED is getting triggered in some interval

Can you post your assembly code?

Which compiler are you using?

can you make assembly code if the sensor is active start to count 80000 pulses and triggered LED
 

LesJones

Joined Jan 8, 2017
4,174
Here is the source code for version 3a. To change it to version 3 (which enables the sensor input.) just comment out or remove the line
" goto Init_TMR1 ;Comment this line out to enable the sensor input. "
Anything after a semicolon on a line is just a comment so to comment out a line just put a semicolon at the start of the line.

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

   goto   Init_TMR1   ;Comment this line out to enable the sensor input.   


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
TMR1 is a 16 bit counter so it can only count to 0xFFFF (65535 decimal) so to count to 80000 you could set the prescaler value to 1:2 and set the count to be 40000. That would require a preload value of 65536 - 40000 = 25536 = 0x63C0
To change the the prescale value to 1:2 load T1CON with B'00010010' instead of B'00000010'
movlw B'00010010' ;The B means the value is binary so you can see each bit.
movwf T1CON
You can find a description of the assembler instructions on the data sheet for the PIC16F877A (From the Microchip website.)
I use MPASMX to assemble the source code. This is part of the MPLABX IDE which is a free download from Microchip. You will find mpasmx.exe here (x86)\Microchip\MPLABX\mpasmx\mpasmx.exe
You could use the full MPLBX IDE but I find it quicker to use just mpasmx.exe

Les.
 

LesJones

Joined Jan 8, 2017
4,174
I have worked out an alternative way to count 80000 pulses.
This is the modified counting part of the program.
Code:
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
;
;  Being modified to count up to 80000
;  First subtract 65536 from 80000 = 14464
;  Then count 14464 by preloading with 65536 - 14464 = 51072 = 0xC780
;   start the counter then it will overflow after 14464 counts
;   clear the overflow flag and let it count for another 65536 counts
;    The next overflow will be after a total of 80000 counts

Start_counter:
   movlw   0xC7     ;These preset values give a count  pulses
   movwf   TMR1H
   movlw   0x80
   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
   bcf   PIR1,TMR1IF   ;Clear interrupt flag

C_Loop2:
   btfss    PIR1,TMR1IF   ;Test interrupt flag
   goto   C_Loop2
   
   bsf   PORTD,4       ; set output pulse high
   call    Delay100ms
   bcf   PORTD,4       ; set output pulse low
   
   goto   Start
Here is a zip file containing the source and hex file for this version.

Les.
 

Attachments

Thread Starter

daljeet795

Joined Jul 2, 2018
295
I have worked out an alternative way to count 80000 pulses.
This is the modified counting part of the program.

Here is a zip file containing the source and hex file for this version.

Les.
Hello les, hope you are doing good

Have you enabled sensor output in this code?

I have tried this version TM1divide05a.zip and I think in this code sensor output is not enabled because I have tested it

I just removed the connection of the sensor but led was triggering
 

LesJones

Joined Jan 8, 2017
4,174
See the first two lines of post #48

Code:
   goto   Init_TMR1   ;Comment this line out to enable the sensor input. 


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:
The first line of the above part of the source code jumps past the code that waits for the sensor input. If you put a semicolon at the start of that line the assembler treats it as a comment and does not convert it to an instruction for the PIC.
Below is a zip file that contains the source file and .hex file that should wait for the sensor input pulse before starting to count.

Les.
 

Attachments

LesJones

Joined Jan 8, 2017
4,174
Your readings are meaningless. Convert the speed readings to pulses per second from the encoder. I had only tested the circuit up to 100 thousand pulses per second. I have just tried it at 2 million pulses per second and it is still working correctly. Your 4N25 opto couplers have rise and fall times of 2uS so that would limit the encoder signal to 250 Khz.

Can you give us the FULL background of this project so we don't have to keep guessing.

Les.
 

LesJones

Joined Jan 8, 2017
4,174
Hi Max,
I am just using a BC548 to convert the square wave output from my Hewlett Packard 209A oscillator to a 5 volt square wave.
I did not expect to need the unit to work to anything like as fast as 2 Mhz.

Les.
 

MaxHeadRoom

Joined Jul 18, 2013
28,618
But I was not only commenting because of the speed but the noise immunity in the industrial environment and the ability to keep it all 5v also.
Max.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
.
Can you give us the FULL background of this project so we don't have to keep guessing.
Les.
We have discussed before in my other thread

I am trying to make an automatic sorting machine that would be used to sort products. It has the capability to inspect good and faulty product on conveyor belt

This is one of example

upload_2019-4-3_0-28-18.png

Assume Product's are moving on conveyor belt one by one. If there is product available on the conveyor. Object sensor will detect product and it will enable scanner and scanner will decide to pass or fail product. If the product is faulty then send into rejection been. There may be a more than faulty product’s between scanner position and rejection position I need to be able to cleanly reject in that time

The speed of conveyor may not be constant so I am using an encoder to get the accurate position of the product on the conveyor so encoder will count pulses rather than the time unit

The diameter of the roller that the encoder is coupled is 50 mm

The distance between the scanner and the air jet is 1100 mm

Length of the product is 200mm

Space between two products is approx 25mm

There may be five products between scanner and rejection position

incremental Encoder 24 V DC 5000 PPR

Circumpherence = 50mm x Pi = 157mm

Note :- I am using one proximity sensor one encoder and LED for the experiment.

When a sensor detects the object, encoder start to generate pulses. I don't exactly how many pulses need to reject object so I assume 80000 pulses so when 80000 pulses complete triggered LED
 

Attachments

Last edited:

MaxHeadRoom

Joined Jul 18, 2013
28,618
I had that one but I am using another encoder (different model) 24V 500PPR coupled with the motor shaft on the machine
Did you check or confirm the nature of the output?
In many cases, the 24vdc versions are open collector which will not work in the configuration you show with the opto.
Max.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Yes. As you have changed the number of pulses you want to count from 32001 to 40000 I will need to change the preload value to TMR1.
Les.
Hello les
I am very closed for perfect rejection I guess need to count from 28000 to 31001 for perfect rejection than what changes I have to do in your program
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
 

LesJones

Joined Jan 8, 2017
4,174
Just change the values in lines 107 and 109.
movlw 0x82 moves the value 0x82 into the W register
movwf moves the contents of the W register (Which has just been set to 0x82) into TMR1H (The high byte of the 16 bit timer 1 register)

Les.
 

Thread Starter

daljeet795

Joined Jul 2, 2018
295
Just change the values in lines 107 and 109.
movlw 0x82 moves the value 0x82 into the W register
movwf moves the contents of the W register (Which has just been set to 0x82) into TMR1H (The high byte of the 16 bit timer 1 register)

Les.
if I want to count 29001 pulses then 29001 decimal number is equal to 7149 hex value

so timer1 is 16 bit wide

I think lower value 49 would be load in one register and Higher value should be load in another resistor
TMR1L = 49
TMR1H = 71

Is it correct value load in program to count 29001 pulses?
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   0x7149     ;These preset values give a count od 29001 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:

LesJones

Joined Jan 8, 2017
4,174
65536 - 29001 = 36535 = 0x8EB7 . 65536 is the overflow value of a 16 bit number so as we are incrementing the counter we need to subtract the required count from that number to give the number to pre-load the counter with. As the PIC16F877A is an 8 bit device and TMR1 is a 16 bit counter it has to be split into two registers each 8 bits wide for loading. These are TMR1H (High byte.) and TMR1L (Low byte.) So TMR1H needs to be loaded with 0x8E and TMR1L needs to be loaded with 0xB7.
You are doing two things wrong.
1 You are forgetting to subtract you required count from the overflow value.
2 You are trying to load a 16 bit value into an 8 bit register TMR1H The top 8 bits of TMR1

Les.
 

joeyd999

Joined Jun 6, 2011
5,237
Programming Notes:

I've been watching (casually) this thread. Here are some things I do to make 16 bit writes more intuitive:

1. Use the high and low assembler operators to extract the high and low bytes of the 16 bit number:

Code:
    movlw    high (0x8EB7)
    movwf    tmr1h
    movlw    low (0x8EB7)
    movwf    tmr1l
2. Even better: use equ to attach a 16 bit number to a label at the top of your code:

Code:
    CTMR1    equ 0x8EB7
    .
    .
    .
    movlw    high (CTMR1)
    movwf    tmr1h
    movlw    low (CTMR1)
    movwf    tmr1l
3. Don't be afraid to use decimal values, and even basic computations on constants. Let the assembler do the work! (assumption: radix = DEC):

Code:
    CTMR1    equ -29001
    .
    .
    .
    movlw    high (CTMR1 & 0xFFFF)
    movwf    tmr1h
    movlw    low (CTMR1 & 0xFFFF)
    movwf    tmr1l
(the "& 0xFFFF" is to force a 16 bit number and avoid an assembler warning.

4. Finally, use macros to generalize:

Code:
movdf    macro    freg,literal            ;move double literal (16 bit) to file regs
    movlw    high ((literal) & 0xffff)
    movwf    freg+1
    movlw    low ((literal) & 0xffff)
    movwf    freg
    endm
    .
    .
    .
    CTMR1    equ -29001
    .
    .
    .
    movdf    tmr1,CTMR1            ;load new value into 16 bit TMR1
(TMR1 -- as defined by the Microchip processor definition files -- is the same as TMR1L).

Double hint: on the recent assemblers, the access bit (access vs. banked ram) is set automatically depending on the location of the destination register. You still need the set up the BSR properly if the destination register is not in access RAM. This is not an issue for the TMR1 registers.
 
Last edited:
Top