PIC16F877A - Object Detection and Rejection - Timer Interrupt

Thread Starter

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


upload_2019-3-24_16-13-24.png

How to configure timer control Register?

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

Is it a correct configuration?
 

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.
 

Thread Starter

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
 

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?
 

MaxHeadRoom

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..
 

Thread Starter

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.
 

Thread Starter

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.

refrence link https://exploreembedded.com/wiki/PIC16f877a_Timer

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.
 

MaxHeadRoom

Joined Jul 18, 2013
20,407
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
If you are looking to learn C, there is the trial version of MikroC and the instruction manual PDF shows all the examples of code.
I only use assembler, but have used the mikroC manual in order to convert and decipher the different instructions to assembler.
Max.
 
Top