|
|
View previous topic :: View next topic |
Author |
Message |
buler
Joined: 27 Apr 2011 Posts: 10
|
Issues with while loop, Pulse width measure 1 CCP [16F690] |
Posted: Thu Jun 09, 2011 9:05 am |
|
|
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
|
|
Posted: Thu Jun 09, 2011 10:48 am |
|
|
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
|
|
Posted: Thu Jun 09, 2011 12:10 pm |
|
|
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
|
|
Posted: Thu Jun 09, 2011 12:21 pm |
|
|
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
|
|
Posted: Thu Jun 09, 2011 12:52 pm |
|
|
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
|
|
Posted: Fri Jun 10, 2011 5:17 pm |
|
|
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
|
|
Posted: Tue Jun 14, 2011 1:28 pm |
|
|
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
|
|
Posted: Tue Jun 14, 2011 1:41 pm |
|
|
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
|
|
Posted: Tue Jun 14, 2011 2:26 pm |
|
|
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
|
|
Posted: Tue Jun 14, 2011 3:19 pm |
|
|
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);
}
} |
|
|
|
|
|
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
|