Capture Mode in PIC16F877A

Discussion in 'Embedded Systems and Microcontrollers' started by Fanfire174, May 16, 2018.

  1. Fanfire174

    Thread Starter Member

    Mar 13, 2018
    124
    0
    How to use capture mode in PIC16F877A (MPLABX). I have written simple code to turn on led on Every Rising Edge but its not working
    Please look at code, anything missing ? Please help..
    Code (Text):
    1.  
    2. void main(void)
    3. {
    4.    //Make all PORTD pins low
    5.    PORTA = 0;
    6.    PORTB = 0;
    7.    PORTC = 0;
    8.    PORTD = 0;
    9.  
    10. // Configured PORTD as Output
    11.    TRISA = 0;
    12.    TRISB = 0;
    13.    TRISD = 0;
    14.  
    15. //Configured RC2/CCP1 pin as input
    16.    TRISC2 = 1;    
    17.  
    18.    ADCON1 = 0x07;
    19.    CMCON = 0x07;
    20.  
    21. //CCP1 MODULE INITIALIZATION
    22.    CCPR1L = 0;       //Clear Lower byte of CCP Register
    23.    CCPR1H = 0;       //Clear Higher byte of CCP Register
    24.    T1CON = 0;        // Prescale in timer mode
    25.    CCP1CON = 0b00000101;
    26.    INTCON = 0xc0;    //Enabled Global interrupts & Peripherals interrupt
    27.  
    28.    while(1);
    29.  
    30. }
    31.  
    32. void interrupt CCP1_ISP()
    33. {
    34.    // CCP1 Interrupt
    35.    if(PIR1.CCP1IF == 1)   // if the CCP1 Interrupt flag is set...
    36.    {
    37.       PORTB.F5 = 1;
    38.       PIR1.CCP1IF = 0;
    39.    }
    40.  
    41.    else PORTB.F5 = 0;
    42. }
    43.  
     
  2. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    For a start you need to enable CCP interrupt.
    CCP1IE (PIE1<2>) = 1;
     
    Fanfire174 and JohnInTX like this.
  3. JohnInTX

    Moderator

    Jun 26, 2012
    3,340
    1,671
    That and:
    You turn the LED on on a capture interrupt but there is nothing that turns it off. The only source of interrupt is a rising edge capture and it will never execute the 'else' in the interrupt service routine.
    TIMER0 is not running so the capture value will always be 0000h.
    You don't need to clear CCPR1L/H, those will be loaded with the value of TIMER1 when it detects the rising edge.

    If you are just looking for the rising edge, consider using the external INT pin. You can select the polarity with the INTEDG bit in the OPTION_REG.

    Good luck!
     
    Fanfire174 likes this.
  4. Fanfire174

    Thread Starter Member

    Mar 13, 2018
    124
    0
    I am running following code but its not working
    Code (Text):
    1. void main(void)
    2. {
    3.    //Make all PORTD pins low
    4.    PORTA = 0;
    5.    PORTB = 0;
    6.    PORTC = 0;
    7.    PORTD = 0;
    8.  
    9. // Configured PORTD as Output
    10.    TRISA = 0;
    11.    TRISD = 0;
    12.    TRISB0 = 0; //RB0 as Output PIN
    13.  
    14. //Configured RC2/CCP1 pin as input
    15.    TRISC2 = 1;  
    16.    ADCON1 = 0x07;
    17.    CMCON = 0x07;
    18.  
    19. //CCP1 MODULE INITIALIZATION
    20.  
    21.    T1CON = 0;            // Prescale in timer mode
    22.    CCP1CON = 0b00000101;
    23.    INTCON = 0xc0;         //Enabled Global interrupts & Peripherals interrupt
    24.    CCP1IE = 1;        //Enabled CCP1 interrupt
    25.    while(1);
    26. }
    27.  
    28. void interrupt CCP1_ISP()
    29. {
    30.    // CCP1 Interrupt
    31.    if(CCP1IF == 1)   // if the CCP1 Interrupt flag is set...
    32.    {
    33.        RB0 = 1;       //LED ON
    34.        CCP1IF == 1;
    35.    }
    36. }
    37.  
     
  5. Ian Rogers

    Active Member

    Dec 12, 2012
    402
    98
    Timer 0 on those chips always run, it doubles as the watchdog ( when enabled ).. He never clears it though!!

    But you are correct... If he needs to see it working, the LED isn't going to show anything..

    Also the CCP1IF == 1; isn't right either... Try CCP1IF = 0;
     
    Fanfire174 likes this.
  6. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    The only thing I can see looking at the code is that timer1 is turned off.
    I am not sure if timer1 running is a requirement for capture mode so try:
    T1CON = 0x01;
     
    Fanfire174 likes this.
  7. Fanfire174

    Thread Starter Member

    Mar 13, 2018
    124
    0
    Hello albertHall and Ian

    I used below code but still no luck

    Code (Text):
    1. void main(void)
    2. {
    3.    //Make all PORTD pins low
    4.    PORTA = 0;
    5.    PORTB = 0;
    6.    PORTC = 0;
    7.    PORTD = 0;
    8.  
    9. // Configured PORTD as Output
    10.    TRISA = 0;
    11.    TRISD = 0;
    12.    TRISB0 = 0; //RB0 as Output PIN
    13.  
    14. //Configured RC2/CCP1 pin as input
    15.    TRISC2 = 1;
    16.  
    17.    ADCON1 = 0x07;
    18.    CMCON = 0x07;
    19.  
    20. //CCP1 MODULE INITIALIZATION
    21.    T1CON = 0x01;            // Prescale in timer mode
    22.    CCP1CON = 0b00000101;
    23.    INTCON = 0xc0;         //Enabled Global interrupts & Peripherals interrupt
    24.    CCP1IE = 1;        //Enabled CCP1 interrupt
    25.    while(1);
    26. }
    27.  
    28. void interrupt CCP1_ISP()
    29. {
    30.    // CCP1 Interrupt
    31.    if(CCP1IF == 1)   // if the CCP1 Interrupt flag is set...
    32.    {
    33.        RB0 = 1;       //LED ON
    34.        CCP1IF == 0;
    35.    }
    36. }
    37.  
     
  8. jpanhalt

    Expert

    Jan 18, 2008
    6,320
    1,192
    When I have done capture, I used TMR1, and it ran continuously. Unfortunately, I don't have code in C. Hopefully the comments will help. I used polling instead of an interrupt, but that is a small change.
    Code (ASM):
    1.  
    2. Start
    3.  
    4.      movlb     0              ;                                                 |B0
    5.      bcf       T1CON,TMR1ON   ;turn TMR1 off
    6.      clrf      TMR1H          ;                                                 |B0
    7.      clrf       TMR1L          ;                                                 |B0
    8.      bsf       T1CON,TMR1ON   ;turn TMR1 on                                     |B0
    9.      banksel   CCP1CON        ;                                                 |B5
    10.      movlw     b'00000101'    ;                                                 |B5
    11.      movwf     CCP1CON        ;CCP1 rising edge capture                         |B5      
    12.      movlb     0              ;                                                 |B0
    13.  
    14. _Data                         ;TMR1 runs continuously                           |B0
    15.      bcf       PIR1,CCP1IF    ;flag must be cleared after mode change           |B0
    16.      btfss     PIR1,CCP1IF    ;test CCP1 interrupt flag (interrupt not enabled) |B0
    17.      goto      $-1            ;                                                 |B0
    18.      banksel   CCP1CON        ;                                                 |B5
    19.      movf      CCPR1H,w       ;start time high byte                             |B5
    20.      movwf     CCP_T1H        ;save value in shadow register                    |B?
    21.      movf      CCPR1L,w       ;start time low byte                              |B5
    22.      movwf     CCP_T1L        ;save value in shadow register                    |B?
    23.  
     
  9. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    I am assuming you are using the XC8 compiler. If not then let me know.

    I have taken your program and fixed the 'CCP1IF == 0' and added config and XC.h include.
    The config assumes you are using the XT crystal oscillator. If this is wrong you should change this for whatever oscillator you are using.

    That program works in the simulator so maybe the problem is with either the button or the LED connections.
    I have further added some code to test the button and the LED. To make this work you should set the #define _XTAL_FREQ to whatever your oscillator frequency actually is (my code assumes 4MHz).

    Now when you run the program the LED should blink at a 1Hz rate.
    Then when you press the button (keep it pressed for at least a second) the LED should turn off.
    When you release the button, the program is ready to generate an interrupt and turn on the LED the next time the button is pressed.

    Code (Text):
    1.  
    2.  
    3. // PIC16F877A Configuration Bit Settings
    4.  
    5. // 'C' source line config statements
    6.  
    7. // CONFIG
    8. #pragma config FOSC = XT  // Oscillator Selection bits (XT oscillator)
    9. #pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT disabled)
    10. #pragma config PWRTE = ON  // Power-up Timer Enable bit (PWRT enabled)
    11. #pragma config BOREN = OFF  // Brown-out Reset Enable bit (BOR disabled)
    12. #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)
    13. #pragma config CPD = OFF  // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
    14. #pragma config WRT = OFF  // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
    15. #pragma config CP = OFF  // Flash Program Memory Code Protection bit (Code protection off)
    16.  
    17. // #pragma config statements should precede project file includes.
    18. // Use project enums instead of #define for ON and OFF.
    19.  
    20. #include <xc.h>
    21.  
    22. #define _XTAL_FREQ 4000000
    23.  
    24. void main(void)
    25. {
    26.   //Make all PORTD pins low
    27.   PORTA = 0;
    28.   PORTB = 0;
    29.   PORTC = 0;
    30.   PORTD = 0;
    31. // Configured PORTD as Output
    32.   TRISA = 0;
    33.   TRISD = 0;
    34.   TRISB0 = 0; //RB0 as Output PIN
    35. //Configured RC2/CCP1 pin as input
    36.   TRISC2 = 1;
    37.    
    38. // Test I/O pins
    39.   while(RC2 == 0)
    40.   {
    41.   RB0 = 1;
    42.   __delay_ms(500);
    43.   RB0 = 0;
    44.   __delay_ms(500);
    45.   }
    46.    
    47.   while(RC2 == 1)
    48.   ;
    49.   ADCON1 = 0x07;
    50.   CMCON = 0x07;
    51. //CCP1 MODULE INITIALIZATION
    52.   T1CON = 0x01;  // Prescale in timer mode
    53.   CCP1CON = 0b00000101;
    54.   INTCON = 0xc0;  //Enabled Global interrupts & Peripherals interrupt
    55.   CCP1IE = 1;  //Enabled CCP1 interrupt
    56.   while(1);
    57. }
    58. void interrupt CCP1_ISP()
    59. {
    60.   // CCP1 Interrupt
    61.   if(CCP1IF == 1)  // if the CCP1 Interrupt flag is set...
    62.   {
    63.   RB0 = 1;  //LED ON
    64.   CCP1IF = 0;
    65.   }
    66. }
    67.  
     
  10. Fanfire174

    Thread Starter Member

    Mar 13, 2018
    124
    0
    yes I am using XC8 compiler I used this code but still led doesn't turn ON

    Push button connected to RC2 and led connected RB0

    look at screenshot for connection
     
  11. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    Missing screenshot!
     
  12. Fanfire174

    Thread Starter Member

    Mar 13, 2018
    124
    0
    I am sorry.
    I am outside from home I have another screenshot but connection is wrong there. I will send you original when I will have to at my home. I am just showing you that I have this board and I am running code on this board

    Push button connected to RC2
    led connected RB0
     
  13. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    If you have a meter, measure the voltage on the RC2 pin of the uC with and without pressing the button.
     
  14. JohnInTX

    Moderator

    Jun 26, 2012
    3,340
    1,671
    Oops! I meant timer 1. Thanks.
    The test for CCP1IF==1 is correct to detect the CCP interrupt. It’s not really needed since there is only one interrupt source but it is good programming practice to check it.
     
  15. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    Yes, but good practice would check both the enable and the flag.
     
  16. JohnInTX

    Moderator

    Jun 26, 2012
    3,340
    1,671
    Agreed and checking the enable is necessary if more than one interrupt source is present and the interrupt in question can be disabled. If there is only one interrupt active and it's never turned off, you can get away without even checking the interrupt flag since that's the only way you'll get there with only one.

    But it is a good idea to check both IF and IE just to keep things standard. In assembler, I also check at the end of the interrupt routine for any stray interrupts i.e. none of the implemented ones caused the vector to the interrupt location and take remedial action if necessary.

    Cheers!
     
  17. JohnInTX

    Moderator

    Jun 26, 2012
    3,340
    1,671
    TIMER 0 shares the prescaler with the WDT but they are separate timers.
     
  18. Ian Rogers

    Active Member

    Dec 12, 2012
    402
    98
    I Have an oops as well.... The clearing of the flag is the one I meant!!
     
  19. Fanfire174

    Thread Starter Member

    Mar 13, 2018
    124
    0
    I have attached screenshot. I measured with multimeter show 0v volt in both case
     
  20. AlbertHall

    AAC Fanatic!

    Jun 4, 2014
    6,392
    1,485
    So that sounds like there is no pullup resistor on the switch.
    Can you give us a link to a manual for that development board?
     
Loading...