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

Problem measuring pulse width with one CCP
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

Problem measuring pulse width with one CCP
PostPosted: Sun Sep 10, 2017 7:29 am     Reply with quote

I'm having a problem measuring a negative pulse width coming from an IR receiver (tsop31230) in order to distinguish two different negative pulses sent from the transmitter. One with a negative pulse width of 1.3ms and the other of 2.3ms. The delay (dms) is increased or decreased (for the purpose of a dimmer) according to the different pulses. However the lamp starts to behave erratically when there are pulses being received... ccs v.5.008

Code:

#include <16F1827.h>
#fuses  NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(internal=4000000)


int8 capture_falling_edge;
int8 got_pulse_width;
int16  ccp_delta;
int8 dms=6;


#int_ccp4
void ccp4_isr(void)
{
static int16 t1_falling_edge;

// If current interrupt is for falling edge.
if(capture_falling_edge)
  {
   setup_ccp4(CCP_CAPTURE_RE);
   capture_falling_edge = FALSE;
   t1_falling_edge = CCP_4;
  }
else
  {
   setup_ccp4(CCP_CAPTURE_FE);
   capture_falling_edge = TRUE;
   ccp_delta = CCP_4 - t1_falling_edge;
   got_pulse_width = TRUE;
  }

}

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

got_pulse_width = FALSE;
capture_falling_edge = TRUE;

clear_interrupt(INT_EXT);
ext_int_edge(1, H_TO_L);
enable_interrupts(INT_EXT);
setup_ccp4(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );
enable_interrupts(INT_CCP4);
enable_interrupts(GLOBAL);

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

      pulse_width_ms = local_ccp_delta / 125;
     
     }
   
   
if (pulse_width_ms>2){
dms--;
if (dms<2){dms=2;}
}

if (pulse_width_ms<2){
dms++;
if (dms>7) {dms=7;}
}
}
}



#INT_EXT
void ext_int (void){

delay_ms(dms);
output_high(PIN_A0);
delay_us(10);
output_low(PIN_A0);
}



The code is taken from a PCM Programmer's post. Any ideas?

thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Sep 10, 2017 9:38 am     Reply with quote

You have a really early vs. 5 compiler. It may not even support CCP4.
I didn't check.

Is this a Proteus project or is it in real hardware ? If Proteus, it may
not support CCP4. Or it may not work anyway.

Assuming it's real hardware,
1. What is the Vdd voltage of your PIC ?

2. Are the negative pulses full scale ?
i.e., are the high and low signal levels going from 0v to Vdd ?

3. Are the negative pulses clean, square, digital waveforms ?
Or do they have a large RC time constant curve on their edges ?

4. What triggers the External interrupt ? Is it a push-button switch ?
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Sun Sep 10, 2017 10:06 am     Reply with quote

This is in real hardware. The compiler does support CCP4 as i used it in a different project. Vdd is 5 Volts. The pulses are full scale and very clean. The external interrupt is being triggered by the zero crossing pulses from a 4n38.
When i plug in my board the lamp does stay on dimmed with the pre-selected delay (dms=6). However when ir signal arrives at the tsop and the PIC, i am not getting the correct results.

thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Sep 10, 2017 2:41 pm     Reply with quote

First get rid of your dms++, #int_ext, etc., code.
Use serial output from the PIC with a printf statement to display the
pulse width output on a terminal window on the PC. This will prove if
the CCP4 capture is working correctly in this program. Maybe it worked
correctly in some previous project, but first prove that it works OK in
the current program.

If that works, add the dms++, dms-- code. Use a printf statement to
display the value of dms. See if that works correctly with the CCP code.

And also, put a delay_ms(500) at the end of your while(1) loop. This will
slow it down enough to see the results of the above tests.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Sep 12, 2017 12:58 am     Reply with quote

I did this test.

I used two of the older style PicDem2-Plus boards. One board has an
18F46K22 and it generates the 1.3ms and 2.3ms pulses. I have jumper
bringing the pulses over to a 2nd PicDem2-Plus board that has a 16F1827
on it. I also have a ground jumper between the two boards. Both boards
run at +5v. I first tested that it works with vs. 5.074. Then I installed
vs. 5.008 (your version) and it works with that one too. Vs. 5.008
was only used to compile the 16F1827 program.

It displays the following output on the TeraTerm window. Based on the
pulses sent by the other PicDem2-Plus board, this output is correct:
Code:

1
2
1
2
1
2
1
2
1
2
1
2
1
2


This proves that the CCP4 pulse width capture is working OK, and
whatever problem exists, it's in your dms code or your #int_ext code.

Also, you didn't tell us what the repetition rate of your pulses are.
I chose a pulse spacing that convenient for me. You can see that
in the 18F46K22 pulse generation code further below.

Here is the pulse width capture program. It's your program with the
dms code and the #int_ext code commented out. All I wanted to do was
verify that the pulse width capture works. The output is sent to a PC
through a DB-9 serial cable and is displayed on a TeraTerm window.
Code:
#include <16F1827.h>
#fuses  NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(internal=4000000)
#use rs232(baud=9600, UART1, ERRORS)


int8 capture_falling_edge;
int8 got_pulse_width;
int16 ccp_delta;
// int8 dms=6;


#int_ccp4
void ccp4_isr(void)
{
static int16 t1_falling_edge;

// If current interrupt is for falling edge.
if(capture_falling_edge)
  {
   setup_ccp4(CCP_CAPTURE_RE);
   capture_falling_edge = FALSE;
   t1_falling_edge = CCP_4;
  }
else
  {
   setup_ccp4(CCP_CAPTURE_FE);
   capture_falling_edge = TRUE;
   ccp_delta = CCP_4 - t1_falling_edge;
   got_pulse_width = TRUE;
  }

}

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

got_pulse_width = FALSE;
capture_falling_edge = TRUE;

// clear_interrupt(INT_EXT);
// ext_int_edge(1, H_TO_L);
// enable_interrupts(INT_EXT);

setup_ccp4(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8 );

enable_interrupts(INT_CCP4);
enable_interrupts(GLOBAL);

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

      pulse_width_ms = local_ccp_delta / 125;
      got_pulse_width = FALSE;  // *** ADDED THIS LINE ***

      printf("%lu\n\r", pulse_width_ms); 
     }



delay_ms(500);

   
/*   
if (pulse_width_ms>2){
dms--;
if (dms<2){dms=2;}
}

if (pulse_width_ms<2){
dms++;
if (dms>7) {dms=7;}
}
*/
 
   }
}


/*
#INT_EXT
void ext_int (void){

delay_ms(dms);
output_high(PIN_A0);
delay_us(10);
output_low(PIN_A0);
}

*/


Here is the pulse generation program. It's very simple.
Code:

#include <18F46K22.h>
#fuses INTRC_IO, NOWDT, BROWNOUT, PUT, NOPBADEN
#use delay(clock=4M)

#define PULSE_OUT_PIN  PIN_D7

//======================================
void main()
{
output_high(PULSE_OUT_PIN);  // Init pin to inactive level
                                                                     

while(TRUE)
  {
   output_low(PULSE_OUT_PIN);
   delay_us(1300);   // 1.3 ms negative pulse
   output_high(PULSE_OUT_PIN);
 
   delay_ms(500);   // Wait 1/2 second between pulses
 
   output_low(PULSE_OUT_PIN);
   delay_us(2300);   // 2.3 ms negative pulse
   output_high(PULSE_OUT_PIN);
 
   delay_ms(500);   // Wait 1/2 second between pulses
  }                                       

}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Sep 13, 2017 1:05 am     Reply with quote

One more thing about your program, which I think comes from here:
http://www.ccsinfo.com/forum/viewtopic.php?t=31470&start=6

The isr in your posted code sets a flag when the capture is complete.
Quote:

#int_ccp4
void ccp4_isr(void)
{
static int16 t1_falling_edge;

// If current interrupt is for falling edge.
if(capture_falling_edge)
{
setup_ccp4(CCP_CAPTURE_RE);
capture_falling_edge = FALSE;
t1_falling_edge = CCP_4;
}
else
{
setup_ccp4(CCP_CAPTURE_FE);
capture_falling_edge = TRUE;
ccp_delta = CCP_4 - t1_falling_edge;
got_pulse_width = TRUE;
}

}


But then in your main loop, you don't ever clear the flag. The code in
the link does clear the flag. You left that part out and it's probably
the main cause of your problems:
Code:

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

      pulse_width_ms = local_ccp_delta / 125;
     
     }

   .
   .
   .
  }
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Wed Sep 13, 2017 9:19 am     Reply with quote

Thanks a lot for your replies and time PCM.
Sorry for not replying earlier, i am kind of
busy this week but i will try to make the
proper changes that you pointed out and do
the tests also. As far as the repetition rate goes,
i simply receive one negative pulse from the tsop
(whenever two buttons are pressed) with different pulse widths.
Will post soon.
thanks
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Fri Sep 15, 2017 10:48 am     Reply with quote

Ok i cleared the flag but it still doesn't work perfectly. I only get the dms to change when
the pulse width is larger than 3ms and even then it doesn't change
with every push of the button. There must be something wrong with
the pulse widths but i am unable to check them via rs232, so i
opened another topic in an attempt to solve that.
thanks
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 9:40 am     Reply with quote

Ok, i did the rs232 tests and i am indeed getting the correct delays.
Even when i include the part of the code you left out i still get correct results.
So there must be some issue with the timing i'm guessing and that's why i'm having problems with the dimming part?

thanks
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 10:55 am     Reply with quote

One big problem you have (if the remarked sections are put back), is delays both inside and outside an interrupt.
This implies that you will be getting a warning from the compiler 'interrupts disabled to prevent reentrancy', and interrupts will be disabled in the main code for the entire delay here. Also while it is in INT_EXT, and the delays are being generated, you could have a situation where the flag is set, but the first time has been updated, and not the second, which will give wrong values....
You need to re-think how to generate the pulse.
Consider using a timer interrupt to do this. Just set a timer to expire in the time you want for the DMS, and exit the EXT interrupt handler immediately.
Then when this expires set your pin A0 high, and use delay_cycles(10) for the pulse. Delay cycles does not usually use the delay library, so won't generate the reentrancy problem, and the short 10uSec delay won't cause overflow problems. This way the long delay is being done by a hardware timer instead of using software delays.
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Thu Sep 21, 2017 8:24 am     Reply with quote

I got a bit confused about the timer interrupt part of your comment..
This is what i came up with..
Code:
#INT_EXT // zero crossing
void ext_int (void){
flag=1;

}

#INT_TIMER0
void timer0_int(void){

set_timer0(65286);
counter=counter-1;
if (counter==0 && flag==1){

counter=5; // dms=5ms, when the clock is at 8MHz
output_high(PIN_A0);
//delay_us(10);
delay_cycles(10);
output_low(PIN_A0);
flag=0;
}
}

..but it didn't work. The lamp wouldn't light up at all.
Could you be a bit more detailed or tell me what i'm missing here?
thanks
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Thu Sep 21, 2017 9:15 am     Reply with quote

You need a pulse, a time after the trigger edge.

You had this being done by having a programmable time in the interrupt.

This would prevent interrupts being enabled in all the delays outside.

To generate the same effect you need to generate a programmable delay with the timer. But to do this _you_ are going to have to work out how long to program the timer for (_you_ will have to work out what value needs to go into the timer counter to give the required delay). You need to setup the delay in the INT_EXT ISR, clear the interrupt, and enable it. Then when the timer interrupt triggers do the pulse and disable it.

There has been example code for doing a programmable delay like this posted here in the past.
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Sun Sep 24, 2017 9:46 am     Reply with quote

Ok, i changed the code a bit:
Code:
#INT_EXT
void ext_int (void){

set_timer1(dms);
clear_interrupt(int_timer1);
enable_interrupts(INT_TIMER1);
}

#INT_TIMER1
void timer1_int(void){
output_high(PIN_A0);
delay_us(10);
output_low(PIN_A0);

disable_interrupts(INT_TIMER1);
}

Code:
if (pulse_width_ms>11){
delay_ms(50);
dms=dms-500;

if (dms<63786){dms=63786;}
}

if (pulse_width_ms<7){
delay_ms(50);
dms=dms+500;

if (dms>65036) {dms=65036;}
}
}

The numbers on dms are all correct (checked with oscilloscope), i am also getting the correct incrementation on dms (checked with terminal) but the lamp seems to dim both ways with either of the pulse_width_ms. I'm guessing there is a problem when i disable int_timer1 since it is also used in the CCP?
thanks
temtronic



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

View user's profile Send private message

PostPosted: Sun Sep 24, 2017 9:57 am     Reply with quote

OK, silly question but.... the variable dms, do you declare it as 8 bit or 16 bit ?

You've made a lot of changes, so perhaps post your latest, full test program.

Jay
irmanao



Joined: 08 Apr 2015
Posts: 77

View user's profile Send private message

PostPosted: Sun Sep 24, 2017 10:46 am     Reply with quote

16bit
Code:

#include <16F1827.h>
#fuses   PLL, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(internal=8000000)
#use rs232(baud=9600,xmit=PIN_B5,rcv=PIN_B2,bits=8,ERRORS)
int8 capture_falling_edge;
int8 got_pulse_width;
int16 ccp_delta;
int16 dms=64036;
//int flag=0;
int counter;

#int_ccp4
void ccp4_isr(void)
{
static int16 t1_falling_edge;

// If current interrupt is for falling edge.
if(capture_falling_edge)
  {
   setup_ccp4(CCP_CAPTURE_RE);
   capture_falling_edge = FALSE;
   t1_falling_edge = CCP_4;
  }
else
  {
   setup_ccp4(CCP_CAPTURE_FE);
   capture_falling_edge = TRUE;
   ccp_delta = CCP_4 - t1_falling_edge;
   got_pulse_width = TRUE;
  }
}
//====================================
void main()
{//#rom 0x8008 = {0x19ff}

int16 pulse_width_ms;
int16 local_ccp_delta;

got_pulse_width = FALSE;
capture_falling_edge = TRUE;
 clear_interrupt(INT_EXT);
 ext_int_edge(1, H_TO_L);
 enable_interrupts(INT_EXT);
setup_ccp4(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
set_timer2(dms);
enable_interrupts(INT_CCP4);
enable_interrupts(GLOBAL);

while(TRUE)
  {//output_high(PIN_A0);
//delay_ms(dms);
//output_low(PIN_A0);
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta;
      enable_interrupts(int_timer1);
      pulse_width_ms = local_ccp_delta /250;
      got_pulse_width = FALSE;  // *** ADDED THIS LINE ***

   //  printf("%lu\n\r", pulse_width_ms);
printf("%lu\n\r", dms);
   
if (pulse_width_ms>11){
delay_ms(50);
dms=dms-500;

if (dms<63786){dms=63786;}
}

if (pulse_width_ms<7){
delay_ms(50);
dms=dms+500;

if (dms>65036) {dms=65036;}
}
}
   }
}

#INT_EXT
void ext_int (void){

set_timer1(dms);
clear_interrupt(int_timer1);
enable_interrupts(INT_TIMER1);
}

#INT_TIMER1
void timer1_int(void){


output_high(PIN_A0);
delay_us(10);

output_low(PIN_A0);

disable_interrupts(INT_TIMER1);
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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