Search code examples
cmicrocontrollerpicmicrochippulse

pulse width using pic 18f4550


I want to measure pulse duration using only one CCP model in capture mode with a pic 18f4550, so I try to detect the rising edge in first time, when a rising edge is detected the timer1 turn on and the capture mode change to falling edge, with this method I have to measure the pulse width, but the code I use doesn't work well!! it was good when I used two CCP model. if anyone could help, I will be grateful.

#include <stdio.h>
#include <stdlib.h>

#include "osc_config.h"
#include "LCD_8bit_file.h"
#include <string.h>



void main()
{
    unsigned long comtage;
    unsigned long DEPHASAGE[20];
    float Deph_tempo;
    
    TRISCbits.TRISC2=1;
   
    
    IRCF0=1;     
    IRCF1=1;
    IRCF2=1;  
    
    LCD_Init();
    
    LCD_String_xy(0,0,"Deph.tempo"); 
 
    PIE1bits.CCP1IE=1;
    PIR1bits.CCP1IF=0; 
    
    
    CCP1CON=0b00000101; 
    CCPR1=0;        
    
    T1CONbits.RD16=1;
    T1CKPS0=0;
    T1CKPS1=0;
    TMR1CS=0;
    
    TMR1IF=0; 
    TMR1=0; 
        
        
    while(1)        
    {    
        
     
       if(PIR1bits.CCP1IF==1){ 
        
        TMR1ON=1; 
        PIR1bits.CCP1IF=0;
        
        CCP1CON=0b00000100;
        
        while(!(PIR1bits.CCP1IF==1)) 
            
         comtage= TMR1; 
         PIR1bits.CCP1IF=0;
         
           Deph_tempo = (((float)comtage /30.518)/65536 ); 
            sprintf(DEPHASAGE,"%.5f  ",Deph_tempo); 

            LCD_String_xy(2,0,DEPHASAGE);
            
       }
         
        TMR1=0;
        TMR1ON=0; 
        CCP1CON=0b00000101;
    }                              
}


Solution

  • Reducing the number of instructions being exceuted while waiting for CCP1IF will increase precision. Have you tried this?

    // ...
    
    while (1)        
    {    
        CCP1CON         = 0b00000101;
        PIR1bits.CCP1IF = 0;
        TMR1ON          = 0; 
        TMR1            = 0;
    
        // if your comms with the LCD use interrupts:
        //
        // disable interrupts here 
    
        while (!PIR1bits.CCP1IF)
            ;
    
        TMR1ON          = 1; 
        CCP1CON         = 0b00000100;
        PIR1bits.CCP1IF = 0;
        
        while (!PIR1bits.CCP1IF)
           ; 
    
        compte = TMR1; 
        
        // if your comms with the LCD use interrupts:
        //
        // enable interrupts here 
    
        // refresh display
    
        // if your comms with the LCD use interrupts:
        //
        // you may want to add a small delay here, to
        // allow for comms to the LCD to end.
        // this may not be necessary, depending on the
        // signal frequency. 
    }
    
    // ...
    

    If that doesn't work, you should check that the LCD is NOT using interruots.

    If it does, you should:

    • disable interrupts before reading a sample
    • keep interrupts disabled while timing
    • enable interrupts before updating the display
    • add a delay before taking the next sample, the delay should be long enough for the LCD buffer to empty.

    That's for a solution without using interrupts... I think you'll get better results using pin change interrupts and a free running timer.

    EDIT: After writing this solution, I found the bug in your code, around these lines of code:

        while(!(PIR1bits.CCP1IF==1))   // this is missing a ;
            
         comtage= TMR1;                // this line gets executed in the loop
                                       // and adds instructions to the 
                                       // loop, this probably more than                     
                                       // halves the precision of your 
                                       // results.
    
                                       // the imprecision is increased with
                                       // your code that runs after the if block