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 support@ccsinfo.com

Issues with while loop, Pulse width measure 1 CCP [16F690]

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



Joined: 27 Apr 2011
Posts: 10

View user's profile Send private message

Issues with while loop, Pulse width measure 1 CCP [16F690]
PostPosted: Thu Jun 09, 2011 9:05 am     Reply with quote

I am trying to flicker an LED off and on at a constant rate through one of the pins and then measure the pulse width through the use of the capture. I got it working by using another example on this forum (http://www.ccsinfo.com/forum/viewtopic.php?t=31470).

But when I try to store the pulse widths (and various other calculations) in arrays, my LED start flickering at a non-constant rate, and the text that was being displayed on my LCD started flickering off and on (or not on at all). When the output text would display, it would not be updated and remain as the same values from the first time it was displayed, which leads me to believe there is some issue with this loop.

Here is my code snippet:
Code:

while(1)
  {
    output_low(pin_C0);
    delay_ms(1000);
    output_high(pin_C0);
   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
      enable_interrupts(GLOBAL);

      pulse_width_ms = local_ccp_delta / 125;
      pulse_width_array[i]=pulse_width_ms;
      pwarray[i]=pulse_width_array[i];
      sum=sum+pwarray[i];
      printf(lcd_putc,"\f%lu ms", pulse_width_array[i]);      
      printf(lcd_putc,"\nsum=%lu", sum);
      got_pulse_width = FALSE;
     }
   delay_ms(1000);
   i++;
  }


I tried to debug the issue, but have ran out of ideas. I could not find any examples that addressed this issue either.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Jun 09, 2011 10:48 am     Reply with quote

Do you really see "flicker". A program period will last at least 2 seconds, that's slow blinking in my understanding. Because the remaining code is hidden, we can't know if the output can be expected to trigger a measurement for each output pulse. Possibly it doesn't.

So, to repeat the well-known standard answer: "Show a full working code that shows the problem. Tell your compiler version."

The LCD display will actually "flicker" on update, if a clear display is performed with "\f".
buler



Joined: 27 Apr 2011
Posts: 10

View user's profile Send private message

PostPosted: Thu Jun 09, 2011 12:10 pm     Reply with quote

FvM wrote:
Do you really see "flicker". A program period will last at least 2 seconds, that's slow blinking in my understanding. Because the remaining code is hidden, we can't know if the output can be expected to trigger a measurement for each output pulse. Possibly it doesn't.

So, to repeat the well-known standard answer: "Show a full working code that shows the problem. Tell your compiler version."

The LCD display will actually "flicker" on update, if a clear display is performed with "\f".


I do see my LED (connected to Pin c0) turning on and off at a non-constant rate. By LCD flicker I mean that the LCD will sometimes not display anything for approximately a second or two (and sometimes doesnt display anything at all). I had this part working prior and did not notice anything like this.

Here is complete code (I am using the example linked above as a base for this): Also since I am having issues anyway, My clock calculations for calculating an accurate ms pulse width are incorrect (I just left the default calculation from the example program), are there any good resources that would help me understand what the correct calculation should be?

Code:

#include <16F690.h>
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT
#use delay(clock=4000000)

#include "flex_lcd4203.c"

int8 capture_rising_edge;
int8 got_pulse_width;
int16  ccp_delta;


#int_ccp1
void ccp1_isr(void)
{
static int16 t1_rising_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;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_rising_edge = TRUE;
   ccp_delta = CCP_1 - t1_rising_edge;
   got_pulse_width = TRUE;
  }

}

main()
{
int16 pulse_width_ms,sum=0,local_ccp_delta,pwarray[],pulse_width_array[],i=0;

delay_ms(10);
lcd_init(); //Initialise LCD
// Clear the LCD.
printf(lcd_putc, "\f");
delay_ms(10);

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(1)
  { output_low(pin_C0);
   delay_ms(1000);
   output_high(pin_C0);
   if(got_pulse_width)
     {
         disable_interrupts(GLOBAL);
          local_ccp_delta = ccp_delta; 
          enable_interrupts(GLOBAL);
          pulse_width_ms = local_ccp_delta / (125);
     pulse_width_array[i]=pulse_width_ms;
     pwarray[i]=pulse_width_array[i];
     sum=sum+pwarray[i];
          printf(lcd_putc,"\f%lu ms", pulse_width_array[i]);      
     printf(lcd_putc,"\nsum=%lu", sum);

      got_pulse_width = FALSE;
     }
   delay_ms(1000);
   i++;
  }

}


Compiler version:3.249
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu Jun 09, 2011 12:21 pm     Reply with quote

I think, it's not guaranteed, that the interrupt will alway occur between these two instructions. You should add a short us delay.
Code:
   output_high(pin_C0);
   delay_us(2);
   if(got_pulse_width)


I also assume, that the pulse width measurement will overflow with 1 sec pulse duration. The V3 compiler should be O.K.
buler



Joined: 27 Apr 2011
Posts: 10

View user's profile Send private message

PostPosted: Thu Jun 09, 2011 12:52 pm     Reply with quote

FvM wrote:
I think, it's not guaranteed, that the interrupt will alway occur between these two instructions. You should add a short us delay.
Code:
   output_high(pin_C0);
   delay_us(2);
   if(got_pulse_width)


I also assume, that the pulse width measurement will overflow with 1 sec pulse duration. The V3 compiler should be O.K.


Thanks for the help. I tried a us delay of 4 which allowed for the program to function properly for a short period of time, however within a couple pulses the sum variable reset at about 1200ish (and the LCD display will clear itself and not resume for a pulse or two) and eventually pin C0 stayed high and did not go low. Also I noticed that every time I power on the circuit, I get a slightly different result. Sometimes the LED will flicker at a non constant rate (1s ON, 1s Off, ~.2s ON, 1s Off, 1s ON...etc)..

Could this be from the pulse width measurement overflowing? At the moment, since my clock calculations are incorrect, the pulse width is measuring at ~485.

EDIT: For whatever reason my program is working fine, not sure what I changed that fixed the issue. However my clock calculations are still off. Are there any good resources for figuring out how to correctly convert from the clock count to ms?

The program does reset when the "i" index reaches 20, is there a limit to an array with an undefined length?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 10, 2011 5:17 pm     Reply with quote

Quote:
void main()
{
int16 pulse_width_ms,sum=0,local_ccp_delta, pwarray[], pulse_width_array[], i=0;

These arrays don't acutally exist. You didn't allocate any RAM for the
elements, because you didn't specify a size for the arrays. These are
just uninitialized pointers. Due to the way that RAM comes up from
power-up, they are probably zero, but there's no guarantee. And if
they are zeroed, they're pointing to the start of your SFR registers and
any accesses to the arrays (which you do, in your program) will clobber
your SFR registers.

You must put in your required number of elements in the array
declarations above.
buler



Joined: 27 Apr 2011
Posts: 10

View user's profile Send private message

PostPosted: Tue Jun 14, 2011 1:28 pm     Reply with quote

PCM programmer wrote:
Quote:
void main()
{
int16 pulse_width_ms,sum=0,local_ccp_delta, pwarray[], pulse_width_array[], i=0;

These arrays don't acutally exist. You didn't allocate any RAM for the
elements, because you didn't specify a size for the arrays. These are
just uninitialized pointers. Due to the way that RAM comes up from
power-up, they are probably zero, but there's no guarantee. And if
they are zeroed, they're pointing to the start of your SFR registers and
any accesses to the arrays (which you do, in your program) will clobber
your SFR registers.

You must put in your required number of elements in the array
declarations above.


Thank you for the information. I have made the required corrections.

I am still a little confused on going from the timer count to actual ms. Is there any good resources out there on determining the correct calculations necessary to achieve this? The way I currently have it setup is incorrect.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 14, 2011 1:41 pm     Reply with quote

1. What is the pulse length value that you measure with your CCP
program, and what length did you expect to see ?

2. How do you know for sure that you are giving the PIC your expected
pulse length ? Did you measure it with an oscilloscope ?

3. Describe the external circuits and connections to your PIC that are
associated with this project. Give the PIC pin numbers that you have
made connections to, and describe the circuits in detail.
buler



Joined: 27 Apr 2011
Posts: 10

View user's profile Send private message

PostPosted: Tue Jun 14, 2011 2:26 pm     Reply with quote

PCM programmer wrote:
1. What is the pulse length value that you measure with your CCP
program, and what length did you expect to see ?

2. How do you know for sure that you are giving the PIC your expected
pulse length ? Did you measure it with an oscilloscope ?

3. Describe the external circuits and connections to your PIC that are
associated with this project. Give the PIC pin numbers that you have
made connections to, and describe the circuits in detail.


1. Right now I am displaying a pulse width of 1015 ms with the above program. I expect to see a pulse width of 1000 ms (determined by the program using the 1000ms delays between turning the LED off and on).

At the moment this is just a simple demo setup until I get my code working, it will eventually be receiving pulses with widths ~1sec (not the perfect pulse like it is now, but shouldn't vary too much)

2. I have measured a 1013.9ms pulse width using a multimeter capable of measuring pulse widths.

3. I have an LED connected to pin 16 (C0) which gets turned on and off by the program using the output_high/low commands along with delay_ms(). I then have a wire going from this pin to the capture port pin 5 (C5).
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jun 14, 2011 3:19 pm     Reply with quote

I made it work, but I modified your program in several ways. Here's the
output for a 100 ms input pulse. I also tested it with 200, 201, etc., and it
works. I tested this with your compiler version, vs. 3.249.
Quote:

100
100
100
100
100


See the revised test program below. I'm using a "low pin count" 16F690
board from Microchip, so I don't have an LCD on the board. Instead I
used a cheap software UART going to the PC and displayed the output
on Teraterm. Cheap means 2 wires, Tx and Gnd, and a DB-9 connector.

1. I got rid of all the array stuff. It's not needed for this test.
2. I initialized the pulse generation pin (Pin C0) to a low level.
3. I clear any existing CCP interrupt before starting.
4. I changed your pulse generation code to create a positive pulse at
the start of the loop. That way, your display code is not included in
the timing count.
5. I changed the generated pulse width to 100 ms, instead of your
proposed value of 1000 ms. That's because you have the Timer1
clock rate set at 125 KHz (4 MHz / 4 / 8 = 125 KHz). Timer1 can count
up to 65535, so the longest duration you can capture is about 524 ms.
I tested this, and it's a fact.
6. I reduced your loop delay at the end to 500 ms, just to speed up the
display update rate a little.
Code:

#include <16F690.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, PUT, BROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C2, INVERT)

int8 capture_rising_edge;
int8 got_pulse_width;
int16  ccp_delta;

#int_ccp1
void ccp1_isr(void)
{
static int16 t1_rising_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;
  }
else
  {
   setup_ccp1(CCP_CAPTURE_RE);
   capture_rising_edge = TRUE;
   ccp_delta = CCP_1 - t1_rising_edge;
   got_pulse_width = TRUE;
  }

}

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

got_pulse_width = FALSE;
capture_rising_edge = TRUE;

output_low(pin_C0);

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

while(1)
  {
   output_high(pin_C0);
   delay_ms(100);
   output_low(pin_C0);

   if(got_pulse_width)
     {
      disable_interrupts(GLOBAL);
      local_ccp_delta = ccp_delta; 
      enable_interrupts(GLOBAL);
      pulse_width_ms = local_ccp_delta / (125);

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

      got_pulse_width = FALSE;
     }

   delay_ms(500);
  }

}
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