Using Capture and Compare mode together – PIC 12F1840

Home Forums Microcontrollers PIC Microcontroller Using Capture and Compare mode together – PIC 12F1840

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #13455
    GITANJALI
    Participant

    Hello,

    I am working on PIC 12F1840 and MPLABX IDE 3.35 . I have written a code for reading PWM pulse width at one pin and writing that value to another PWM pin. But, at the time of simulation in logic analyzer output PWM pulse is not continuous. Is it a correct way to use capture mode and compare mode in one code ?  Please check following code and guide me.

    /*
    * File: general.c
    * Author: Murumkar
    *
    * Created on 25 January, 2017, 9:27 AM
    
    *
    *
    * read input (freq 400Hz) RA2 pulse width and write to RA5 (PWM with freq 18Kz)
    *
    *
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <xc.h>
    #pragma config FOSC =INTOSC, PLLEN =OFF, WDTE =OFF, MCLRE =ON,
    #pragma config CLKOUTEN =OFF, IESO =OFF, FCMEN =OFF,CP =OFF, CPD =OFF,BOREN=OFF
    #pragma config WRT=OFF,STVREN=ON,BORV=LO,LVP=OFF
    
    unsigned char counter=0;//Overflow counter
    int count = 0;
    unsigned char timer1_value1 @ 0x2020;
    unsigned char timer1_value2 @ 0x2040;
    unsigned int timer1_value @ 0x2060;
    unsigned int Pulse @ 0x2080;
    unsigned int PulseWidth @ 0x20A0;
    
    delay()
    {
      int i;
      for(i=0;i<30;i++)
      {
        ;
      }
    }
    
    void pwm_start()
    {
      TRISAbits.TRISA2 = 1;
      APFCONbits.CCP1SEL = 0;
      CCP1CONbits.CCP1M = 0x05; // capture mode with each rising edge
      TRISAbits.TRISA2 = 0;
    
      TRISAbits.TRISA2 = 1; // RA2 as input
      ANSELAbits.ANSA2 = 0; // RA2 as Digital
    }
    
    void init_interrupt()
    {
      INTCONbits.GIE = 1; // enable global interrupt
      INTCONbits.PEIE = 1; // enable peripheral interrupt
      PIE1bits.TMR1IE = 1; // enable timer 1
      PIE1bits.CCP1IE = 1; // enable capture mode interrupt
    }
    
    void pwm_again_start()
    {
      TRISAbits.TRISA5 = 1; // RA5
      APFCONbits.CCP1SEL = 1; // CCP1 function on RA5
      CCP1CONbits.CCP1M = 0x0C; // PWM mode: P1A active-high; P1B active-high
      CCP1CONbits.P1M = 0x00; // Single output; P1A modulated; P1B assigned as port pins
      PR2 = 0xDD; //
      CCPR1L = 0x00; // UPDATE PWM TON=0
      CCP1CONbits.DC1B = 0x00; // the two LSbs of the PWM duty CYCLE
      PIR1bits.TMR2IF = 0; // TIMER2 FLAG CLEAR
      T2CONbits.T2CKPS = 0x00; // PRESCALER 1
      T2CONbits.TMR2ON = 1; // TIMER 1
      TRISAbits.TRISA5 = 0; //
    }
    
    void SetPWMDutyCyle(unsigned int duty_cycle_value)
    {
      CCP1CONbits.DC1B = duty_cycle_value & 0x03; // two LSbs of the PWM duty cycle.
      CCPR1L = (duty_cycle_value >> 2); // MSB VALUES
      while(PIR1bits.TMR2IF==1)
      {
        PIR1bits.TMR2IF =0;
      }
      T2CONbits.TMR2ON = 1; // TIMER 1*/
      delay();
    }
    
    void interrupt ISR()
    {
      if(PIE1bits.CCP1IE && PIR1bits.CCP1IF)
      {
        count++;
        if(count==1)
        {
          T1CONbits.TMR1ON = 1; // start timer 1
          PORTAbits.RA1 = ~PORTAbits.RA1;
          counter = 0;
          PIR1bits.CCP1IF = 0;
          CCP1CONbits.CCP1M = 0x04; // capture mode with each falling edge
          timer1_value1 = TMR1L;
          timer1_value2 = TMR1H;
          timer1_value = timer1_value1 + (((int)TMR1H) << 8);
        }
        else if(count==2)
        {
          count = 0;
          PORTAbits.RA1 = ~PORTAbits.RA1;
          INTCONbits.GIE = 0; // disable global interrupt
          INTCONbits.PEIE = 0; // disable peripheral interrupt
          PIE1bits.TMR1IE = 0; // disable timer 1
          PIE1bits.CCP1IE = 0; // disable capture mode interrupt
          counter = 0;
          PIR1bits.CCP1IF = 0;
          CCP1CONbits.CCP1M = 0x05; // capture mode with each rising edge
          timer1_value1 = TMR1L;
          timer1_value2 = TMR1H;
          Pulse = timer1_value1 + (((int)TMR1H) << 8);
          PulseWidth = Pulse - timer1_value;
          pwm_again_start();
          SetPWMDutyCyle(PulseWidth);
          pwm_start();
          init_interrupt();
        }
      }
    }
    
    void micro_init()
    {
      OSCCONbits.SPLLEN = 0; // PLL DISABLE
      OSCCONbits.IRCF = 0x0F; // 16 MHZ INTERNAL FREQ
      OSCCONbits.SCS = 0x02; // INTERNAL OSCILLATR BLOCK
    }
    
    void main()
    {
      micro_init();
      pwm_start();
    
      TRISAbits.TRISA1 = 0; // RA1 as output
      ANSELAbits.ANSA1 = 0; // RA1 as digital
    
      TRISAbits.TRISA2 = 1; // RA2 as input
      ANSELAbits.ANSA2 = 0; // RA2 as Digital
    
     TRISAbits.TRISA5 = 0; // RA5 as output
    
      init_interrupt();
      while (1)
      {
        ;
      }
    }
    

    thanking you ,

    Gitanjali

    #13460
    Ligo George
    Keymaster

    Can you please explain in details ?

    You can use a CCP module in Capture OR Compare OR PWM mode. It will work only in one mode at a time. You may use PIC microcontrollers with multiple CCP modules to use Capture and Compare mode together.

    #13462
    GITANJALI
    Participant

    Hi,

    I’m using PIC 12F1840 (single CCP module) and internal oscillator 16MHz. I want to read Pulse width of input signal at RA2 (input PWM frequency 400Hz). Generate new PWM out (output PWM frequency 18KHz) at RA5 with same pulse width reading at input PWM at RA2.

    steps i followed :

    1) Capture Mode: detected rising edge (interrupt detection) -> detected falling using capture mode (interrupt detection) at RA2, got pulse width (falling edge – rising edge)

    2) Compare Mode :  write pulse width to RA5 using compare mode

    Now, my problem is when controller is in compare mode at the same time my new rising or falling edge get detected system is not able to find new pulse width.

    thanking you,

    Gitanjali

     

     

    #13464
    Ligo George
    Keymaster

    As I told above, a single CCP will work only in one mode at a time. I think you should do like this.

    • You can use a normal input interrupt or on-change interrupt to detect rise and fall.
    • Start a timer when rise is detected and stop it when fall happens.
    • So you will get the time period from the timer count.
    • Use that CCP module only in PWM mode.
    • Just change the duty cycle based on the timer value.
    #13470
    GITANJALI
    Participant

    ok , thanks for your reply . 🙂

     

Viewing 5 posts - 1 through 5 (of 5 total)
  • You must be logged in to reply to this topic.
>