# PIC16F877A - Object Detection and Rejection - Timer Interrupt

#### daljeet795

Joined Jul 2, 2018
282
I am using PIC16F877A and Compiler MPLABX XC8

I want to turn on LED on timer interrupt When a switch is pressed Counter goes from 0 to 22000 and when It reaches 22000 turns LED on

When switch would be pressed Timer would be load with 22000 counts when It would overflow Led would be turned ON in ISR

How to configure timer control Register?

T1SYNC = 1;
T1OSCEN = 1;
TMR1ON = 1;
TMR1CS = 1;
T1CKPS0 = 0;
T1CKPS1 = 0;

Is it a correct configuration?

#### shteii01

Joined Feb 19, 2010
4,644

#### spinnaker

Joined Oct 29, 2009
7,835
I am using PIC16F877A and Compiler MPLABX XC8

I want to turn on LED on timer interrupt When a switch is pressed Counter goes from 0 to 22000 and when It reaches 22000 turns LED on

When switch would be pressed Timer would be load with 22000 counts when It would overflow Led would be turned ON in ISR

View attachment 173159

How to configure timer control Register?

T1SYNC = 1;
T1OSCEN = 1;
TMR1ON = 1;
TMR1CS = 1;
T1CKPS0 = 0;
T1CKPS1 = 0;

Is it a correct configuration?

Check out the MCC feature in MPLab X. It will guide you though all of the configuration. Assuming PIC16F877A is supported. Not all chips are supported.

#### daljeet795

Joined Jul 2, 2018
282
I have seen some good information here https://exploreembedded.com/wiki/PIC16f877a_Timer
C:
#include<pic16f877a.h>

char value = 0;
#define SBIT_PS1  5
#define SBIT_PS0  4

void interrupt timer_isr()
{
if(TMR1IF==1)
{
value=~value;   // complement the value for blinking the LEDs
TMR1H=0x0B;     // Load the time value(0xBDC) for 100ms delay
TMR1L=0xDC;
TMR1IF=0;       // Clear timer interrupt flag
}
}

void main()
{
TRISD=0x00;    //COnfigure PORTD as output to blink the LEDs

T1CON = (1<<SBIT_PS1) | (1<<SBIT_PS0); // Timer0 with external freq and 8 as prescalar
TMR1H=0x0B;     // Load the time value(0xBDC) for 100ms delay
TMR1L=0xDC;
TMR1IE=1;       //Enable timer interrupt bit in PIE1 register
GIE=1;          //Enable Global Interrupt
PEIE=1;         //Enable the Peripheral Interrupt
TMR1ON = 1;     //Start Timer1

while(1)
{
PORTD = value;
}
}

I didn't understand this line T1CON = (1<<SBIT_PS1) | (1<<SBIT_PS0); // Timer0 with external freq and 8 as prescalar ?

I am just looking simple way to configure T1CON register

#### spinnaker

Joined Oct 29, 2009
7,835
I am just looking simple way to configure T1CON register

I already gave you a simple way. Did you try it?

#### AlbertHall

Joined Jun 4, 2014
9,627
I already gave you a simple way. Did you try it?
No you didn't. MCC is good but there is a new learning curve for it to add to understanding the PIC.

#### AlbertHall

Joined Jun 4, 2014
9,627
Your original code is running from an external crystal connected to T1OSI and T1OSO.
The second code you show is running from the PIC clock ( Fosc/4).
Which do you want to run from - do you have that second crystal connected?

Joined Jul 18, 2013
20,407
I thought the original intention was to input an encoder pulse into the TMT1 CLK input pin and load a preset value so TMR1 rolls over in a predetermined time and provides an interrupt?.
Max.

#### spinnaker

Joined Oct 29, 2009
7,835
No you didn't. MCC is good but there is a new learning curve for it to add to understanding the PIC.

I don't even understand your statement. What learning curve?? To add what? The code? MCC?

And it is completely your opinion if MCC is isn't a useful tool. I happen to think MCC is a very useful to understand how to setup a peripheral. It has turned the light on for me a number of times.

If you mean there is a learning curve to setup MCC, then you have to be kidding me. It takes 5 ot 10 minutes to figure out how to add it and maybe another 10 or 20 minutes on figuring out how to use it.

#### Ian Rogers

Joined Dec 12, 2012
741
I don't even understand your statement. What learning curve?? To add what? The code? MCC?

And it is completely your opinion if MCC is isn't a useful tool. I happen to think MCC is a very useful to understand how to setup a peripheral. It has turned the light on for me a number of times.

If you mean there is a learning curve to setup MCC, then you have to be kidding me. It takes 5 ot 10 minutes to figure out how to add it and maybe another 10 or 20 minutes on figuring out how to use it.
Whilst I agree to a point... I think MCC is turning Pic programming into Arduino style programming...Turning a port pin on and off now has a wrapper function, delays that I really never need...Far too much overhead... But!! For learning, yes!I think it works.. Even the diehard AVR freaks don't use Arduino..

#### daljeet795

Joined Jul 2, 2018
282
I thought the original intention was to input an encoder pulse into the TMT1 CLK input pin and load a preset value so TMR1 rolls over in a predetermined time and provides an interrupt?.
Max.
yes I am trying to use a timer to load pre determine count and when it over trigger output load

#### spinnaker

Joined Oct 29, 2009
7,835
Whilst I agree to a point... I think MCC is turning Pic programming into Arduino style programming...Turning a port pin on and off now has a wrapper function, delays that I really never need...Far too much overhead... But!! For learning, yes!I think it works.. Even the diehard AVR freaks don't use Arduino..

You sound like one of the assembler zealots.

While I COMPLETELY agree, it is always best to know the chip a well as possible. And that includes knowing how to program in assembler. What good is it going to do to the hobbyist when they are bogged down in all the details of hos the chip works? If it get the job done then who cares how it did it? You get the project working.

That said, when something does go wrong with the tools. the person that has a full understanding of how the chip works at an enormous advantage. So there is value in learning.

I would also expect the professional to know the chip all the way down to the register and assembler level but for the hobbyist it is your choice. I say get the job done using tools available but pay attention to what is going on.

#### Ian Rogers

Joined Dec 12, 2012
741
Horses for courses as they say.... No I hardly ever use ASM, but I have always been able to do what I need in C.. The only time assembler is used is to get things like graphical screens updated as quickly as humanly possible..

#### LesJones

Joined Jan 8, 2017
2,600
Here is a program that does what you want. (Assuming my understanding of your requirements is correct.) It is written in assembler as I don't know how to do it in "C". The comments may give you enough of an idea about how it works which may help you to write it in "C"

Code:
;*****************************************************************************
;
;  Module:  TM1divide
;
;  Version:02
;
;
;
;*****************************************************************************

;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 pullup 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   used for pulse output     (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     (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 interrupts are not being used
retfie       ;Return from interrupt
;*****************************************************************************
;
;  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
bcf  STATUS, RP0  ;back to bank 0 registers

Wait_trigger_L:       ;Loop waiting for trigger pulse from sensor to go low  (Button pressed.)
btfsc   PORTC,1
goto   Wait_trigger_L

Wait_trigger_H:       ;Loop waiting for trigger pulse from sensor to go high (Button released.)
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   0x0B
movwf   TMR1H
movlw   0xDC
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   PORTC,2       ; set output pulse high
call    Delay100ms
bcf   PORTC,2       ; 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

return
;*****************************************************************************

END  ; End of program
It turned out it could be done without using interrupts which save quite a few lines of code.
I used a push button to simulate the input that sensed the object.
The encoder output of the encoder was simulated with a signal generator running at a 100 Khz.
at the end of counting the pulses (62500 from the values that you used in post #4) it generates a 100 mS output pulse on port C bit 2.
A far as I could measure the delay between releasing the push button and the start of the 100 mS output was a bit over 620 mS which is close to the calculated time of 625 mS.
I think this could be done with an 8 pin PIC such as a PIC12F1840. The internal oscillator could be used on this which would save a crystal and two capacitors.

Les.

#### spinnaker

Joined Oct 29, 2009
7,835
TS is programming in C.

#### daljeet795

Joined Jul 2, 2018
282
Here is a program that does what you want. (Assuming my understanding of your requirements is correct.) It is written in assembler as I don't know how to do it in "C". The comments may give you enough of an idea about how it works which may help you to write it in "C"
Les.
Thank you Les

I tried to convert code into c programming as possible but I couldn't complete all because I don't understand assembly.

I have compiled code successfully

C:
// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON      //
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#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)

#define _XTAL_FREQ 8000000 //Specify the XTAL crystal FREQ
#include <xc.h>

void main(void)
{
TRISC0=1;     // Make RC0 pin as input encoder
TRISC1= 1;    // Make RC1 pin as input sensor
TRISC1= 0;    // Make RC2 pin as output

TMR1ON = 0; // Stops Timer1
TMR1CS = 1; // External clock from pin RC0/T1OSO/T1CKI (on the rising edge)
T1SYNC = 0; // Synchronize external clock input
T1OSCEN = 0; //Oscillator is shut-off
T1CKPS1 = T1CKPS0 = 0; // Assigned prescaler rate is 1:1

TMR1IF = 0; // TMR1 register overflow is cleared
TMR1H=0x82; // initial count values in timer1 register
TMR1L=0xff;
TMR1ON = 1;     //Start Timer1

while(1)
{

if ( TMR1IF==1)
{
RC0 = 1;  // LED on
__delay_ms(100);
RC0 = 0;  // LED off
}
}
}

Last edited:

#### LesJones

Joined Jan 8, 2017
2,600
I don't really understand how "C" works. I was under the impression the "C" normally uses timer1 for timing functions (For example delay) If I am correct then we would need to find out how to prevent C from using timer 1 so we have full control over it.

If you have managed to get control of timer 1 then you have got as far as starting the timer. Now you have to keep checking for bit zero of register PIR1 changing from a zero to a one. This indicates that TMR1 has overflowed. If I had used interrupts the program could carry on doing something else useful until the interrupt occurred. There is nothing else for the program to do until it needs to generate the output pulse. I have also used timer 1 to generate the 100 mS output pulse.

Les.

#### Ian Rogers

Joined Dec 12, 2012
741
Here's the defines.. They are just macro's
pic.h said:
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))