CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Duration of the high and low levels using CCP1 module

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
aydi



Joined: 11 Aug 2010
Posts: 12

View user's profile Send private message

Duration of the high and low levels using CCP1 module
PostPosted: Sun Mar 26, 2017 12:50 am     Reply with quote

Good morning,

I want to compute the duration of the high and low levels of incoming signal.
The pulse duration (of the high and low levels) is random. The minimum duration is approximately 1.6ms and the maximum duration is 9.6ms. So i try to use the ccp1 module of the pic 16F877.

I try to test my code by an input signal with the duration of the high level=1ms and low level=4ms.

I get something like that:

high=229.05 ms
low=1.00 ms
high=1.00 ms
low=1.00 ms
high=1.00 ms
low=1.00 ms
high=1.00 ms
low=4.00 ms
high=1.00 ms
low=1.00 ms
high=4.00 ms
low=1.00 ms
high=1.00 ms
low=1.00 ms

could you please help me to get the good results


thanks an advance



Code:
#include <16F877A.h>
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected

#use delay(clock=4000000,RESTART_WDT)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

int8 capture_rising_edge;
int8 got_pulse_width,got_pulse_width1;
int16  ccp_delta;

#int_ccp1
void ccp1_isr(void)
{
static int16 t1_rising_edge,t1_falling_edge;

// If current interrupt is for rising edge.
if(capture_rising_edge)
  {
   setup_ccp1(CCP_CAPTURE_FE);
   capture_rising_edge = FALSE;
   t1_rising_edge = CCP_1;
   ccp_delta=CCP_1 - t1_falling_edge;
   got_pulse_width1 = TRUE;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_rising_edge = TRUE;
   t1_falling_edge = CCP_1;
   ccp_delta = CCP_1 - t1_rising_edge;
   got_pulse_width = TRUE;
  }

}


//====================================
void main()
{
float pulse_width_ms;
int16 local_ccp_delta;

got_pulse_width = FALSE;
capture_rising_edge = TRUE;

setup_ccp1(CCP_CAPTURE_RE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);

while(TRUE)
  {
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
     
      enable_interrupts(GLOBAL);

      pulse_width_ms =(float)local_ccp_delta/ (125);
      printf("haut=%F ms \n\r", pulse_width_ms);
      got_pulse_width = FALSE;
      delay_ms(0.1);
     }
     
     if(got_pulse_width1)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
     
      enable_interrupts(GLOBAL);

      pulse_width_ms =(float)local_ccp_delta/ (125);
      printf("bas=%F ms \n\r", pulse_width_ms);
      got_pulse_width1 = FALSE;
      delay_ms(0.1);
     }

  }

}
Ttelmah



Joined: 11 Mar 2010
Posts: 19477

View user's profile Send private message

PostPosted: Sun Mar 26, 2017 2:49 am     Reply with quote

The first wrong value, is because you only have one value the first time through the loop.
The later ones are because by the time you have done the printing, you have missed several edges.
Also delays do not accept fractional values. Integer only.

So you really should be recording both edges before you flag that you have the values, and then print both:
(parts only)

Code:

int1 got_widths=FALSE;
int16  t_high=0, t_low=0;

#int_ccp1
void ccp1_isr(void)
{
   static int16 t1_rising_edge,t1_falling_edge;
   static int1 have_rising=FALSE, have_falling=FALSE;
   static int1 start=TRUE;
   if (start)
   {
      //program the CCP for initial settings and exit
      start=FALSE;
      setup_ccp1(CCP_CAPTURE_RE);
      return; //exit and wait for the first rising edge
   }
   // If current interrupt is for rising edge.
   if(capture_rising_edge)
   {
      setup_ccp1(CCP_CAPTURE_FE);
      capture_rising_edge = FALSE;
      //Now if you have already recorded a _previous_ falling edge
      //can calculate delta
      t1_rising_edge = CCP_1;
      if (have_falling)
         t_low=t1_rising_edge-t1_falling_edge; //how long was the pulse low
      have_rising=TRUE; //have recorded a rising edge
   }
   else
   { //have captured falling edge
      setup_ccp1(CCP_CAPTURE_RE);
      capture_rising_edge = TRUE;
      t1_falling_edge = CCP_1;
      if (have_rising)
      {
         t_high = t1_falling_edge - t1_rising_edge; //how long high
         got_widths = TRUE;
      }
      have_falling=TRUE; //have recorded a falling edge
   }
}

//Then in the main - again parts only
    int16 local_high, local_low;
    int32 build_time;
    int16 mSec_time;
    #byte mSec_time=build_time+2;

    //when you want to display
    if (got_widths)
    {
       disable_interrupts(GLOBAL);
       local_high=t_high;
       local_low=t_low; //copy both values
       enable_interrupts(GLOBAL)

       build_time=l(int32)ocal_high*5242800;
       build_time+=32767; //gives effectively 4/5 rounding
       printf("haut=%5.2LW ms \n\r", mSec_time);  //print upper 16bits 
 
       build_time=l(int32)ocal_low*5242800;
       build_time+=32767; //gives effectively 4/5 rounding
       printf("bas=%5.2LW ms \n\r", mSec_time);   
       got_widths=FALSE;
    }               


Now note I don't use float, and the got_widths flag only gets set when _both_ edges have been recorded.

What is happening, is the incoming 'time', is multiplied by 5242800 in an int32. I've then 'cheated', and located a 16bit variable (mSec_time), into the same part of memory that the upper 2 bytes of this occupy. So the two variables are 'sharing' memory (you can also do this with a union).
I then just print this int16, using %W (which prints it like a float, with 2 'decimal' digits). Now reading the top two bytes is equivalent to dividing by 65536, but takes no time to do!...

So say the time was '1000'. You would divide by 125, to give 8.00mSec. That division at 4Mhz, would take 1650uSec. Then printing the result would take about another 12mSec. (division by 10.0 in floating point for every digit).

My 'cheat' method, takes about 1/3rd the time, and uses less code space. *52428 for 1000, would give 52428000. Then add 32767, and /65536, give 800, which the %w will display as 8.00. Exactly the same display, and smaller code, and a lot quicker (each digit will print faster as well...).

The key problem is that by the time you have printed a value, you have missed several other results. The second flag is therefore 'set', but the time recorded may be a high time or a low time, depending on what the last value recorded was. So you are actually getting in a cycle of just displaying the high time, but 'thinking' it is alternately the high and low time.....

Hence instead I record the two times as a pair, and keep these together.

You can improve the output speed massively (particularly with my maths trick), by upping the serial rate. Something like 57600bps, only takes 0.2mSec/character.
temtronic



Joined: 01 Jul 2010
Posts: 9215
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Mar 26, 2017 5:26 am     Reply with quote

couple of comments..
1) add 'errors' to the USE RS232(..options...)

2) delete 'restart_WDT' from the #USE delay(...options...)

3) add #FUSES PUT // enable Power Up Timer

4) use a 20MHz xtal , PIC runs 5X faster !
aydi



Joined: 11 Aug 2010
Posts: 12

View user's profile Send private message

PostPosted: Mon Mar 27, 2017 4:02 am     Reply with quote

now it's ok,

thank you very much for yours reply.

Very Happy
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group