|
|
View previous topic :: View next topic |
Author |
Message |
mattthegamer463
Joined: 05 Jun 2011 Posts: 3
|
PIC18F2525 and OPT101 photogate timer project - has issues |
Posted: Sun Jun 05, 2011 12:14 am |
|
|
Hi folks, I'm new here and was hoping to get some pointers as to what I might be doing wrong with my project.
My project is building a photogate timing device, specifically for measuring the shutter speeds of film cameras.
I'm using CCS C to make hex files that I program into a PIC18F2525 using a JDM programmer. I have built a circuit that receives input from an OPT101 photodiode w/ integrated amplifier, so that when the output passes into logical high it causes an interrupt which activates a timer, and when it falls back down it deactivates the timer and writes it to a character LCD. Everything works fine except when the speeds get to 1/500th of a second and faster. The result is often garbage numbers.
I built a pulse circuit to pulse a LED a certain length of time when I press a button, to simulate an ideal camera shutter. Here were the test results:
pulse width (ms) measured duration
500 510.286
250 254.35
125 128.286
67 68.15
33 34.436
16 16.15
8 8.1
4 4
2 2
1 2.136
0.5 0.25
You can see it goes well for a while, even gets more accurate as the times decrease, then it goes screwy. It gets the same incorrect numbers over and over.
The light source seems to maybe play a part in the issue, when I use a camera flash it seems to be showing reasonable timings, and even measured a low-duration flash to be 0.300ms, 0.350 or 0.400, a very reasonable bunch of numbers. The slew rate of the OPT101 amplifier is 1V/us so it can't be that.
My code is below. At a glance, does anyone see any issues that might attribute to my problem? I can answer any questions that might arise.
Thanks very much!
Code: | #include "18F2525.h"
#fuses HS,NOWDT,NOPROTECT,NOLVP,INTRC
#use delay(clock=8000000)
#include "M:\PIC\Photogate timer with LCD\flex_lcd_photogate_final.c"
//==========================
int1 button, timer_en; //button used for ready button polling, timer_en used for ext interrupt first run, second run
int1 donebit = 0; //donebit used to end mid-sampling loop
long count, time, rem, divtest; //count is count of timer overflows, time is ms, rem is us, divtest is for adjustment
#int_timer0
void timer_isr()
{
count++;
// waste = 0;
set_timer0(108);
}
#int_ext
void ext_isr()
{
timer_en = !timer_en;
if(timer_en == 0)
{
enable_interrupts(int_timer0);
ext_int_edge(H_TO_L);
donebit = 0;
}
else if(timer_en == 1)
{
disable_interrupts(int_timer0);
donebit = 1;
}
}
readyprep()
{
count = 0; //reset count
timer_en = 1;
lcd_putc("\fReady\b"); // LCD ready indicator
ext_int_edge(L_TO_H);
enable_interrupts(int_ext);
enable_interrupts(global);
return 0;
}
math()
{
time = (count / 10); //convert to milliseconds
rem = count % 10; //modulus for microseconds
rem *= 50; // convert to microseconds
divtest = time % 2;
if(rem == 400, divtest == 1)
{
time = time + 1; //possibly necessary compensation value
rem = rem - 400; //possibly necessary compensation value
}
if(rem == 50)
{
rem = rem - 50;
}
return 0;
}
countroutine()
{
readyprep(); //prepares screen and vars
/* while(donebit == 0) //mid-sample waiting area
{
delay_us(3);
}
disable_interrupts(global);
disable_interrupts(int_timer0);
math(); //computes count into ms, us
/* if(count != 0)
{
readybit = 1;
} */
donebit = 0;
printf(LCD_putc,"\f%lu.%03lu ms \b", time, rem); //%lu for long ints
delay_ms(100);
return 0;
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1|RTCC_8_BIT); //setup timer
disable_interrupts(int_timer0);
disable_interrupts(global);
lcd_init(); // Always call this first.
delay_ms(100);
lcd_putc("\fFilm Shutter\nSpeed Timer\b"); // Startup message
//**** Main While Loop**********
while(1)
{
button = input(pin_A0);
if(button == 0)
{ countroutine(); } // go to countroutine if ready button was pressed
if(button == 1)
{ delay_us(3); } //maintains value until ready button pressed
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Sun Jun 05, 2011 2:13 am |
|
|
You have several separate problems.
First, problem is setting a timer _to_ a value in an ISR.
Problem is that it takes a _lot_ of time (in terms of clocks), to get into an ISR. Typically perhaps 30 instruction counts. So when you set the timer 'to' 108, it will have already counted a lot. Recorded times will therefore be inaccurate.
Generally, let the timer free run. Change your maths scaling to handle the real time interval, without trying to use 'msec'.
However, why not use the hardware available for this?. The CCP modules. Look at EX_CCPMP.C, which shows how to measure a pulse width with the CCP modules recording the rising and falling edges. Maximum pulse width of 33mSec at 8MHz, with the /1 prescaler as given, you have a choice of adding an extended timer (int_timer1, with the high word of a 32bit counter being incremented), or using a larger prescaler, depending on the range of numbers you actually need to use.
Then you talk about the slew rate of the OPT101 being 1V/uSec - re-read the data sheet. The figure you are quoting is the slew rate of the output op-amp only. The diode itself, takes time to respond to light, and this depends on the intensities involved, the load on the chip, the incident angle of the light, etc. etc... This is why you are seeing a much better response from the brighter photoflash.
Best Wishes |
|
|
mattthegamer463
Joined: 05 Jun 2011 Posts: 3
|
|
Posted: Sun Jun 05, 2011 10:17 am |
|
|
Thanks for the response.
I followed an example program I found to make a 100us timer, which is why I had added the 108 each time. You're saying I should just alter my math to work the full 256 counts into my milli/microsecond values? I'm not sure how I could do that without trial and error, but it makes sense.
I was unaware of the function of the CCP modules. I am reading into them now, they sound like just the right thing. However, you mention that the maximum pulse width at a clock speed of 8MHz and prescaler of 1 is 33mSec. Ideally I want to be able to measure from 1s down to 1ms accurately and without issues. If I switch to the CCP capture method, will I need to have an external button or something to re-set the counter prescaler to a higher value (for example, for high speed measurements, use prescaler of 1 and for longer ones use a prescaler of 64) and new math for the results? When you say adding an extended timer, do you mean like a nested timer set up? Like, when timer0 overflows, timer1 ticks once? I'm quite new to programming, I'm concerned that I won't be able to accomplish this without hours upon hours of time invested.
I looked at the OPT101 datasheet again and couldn't find any info about the diode's speed itself. However, its says the frequency response of the chip is 14kHz. I have seen rates on other photodiode chips and they are often in the nanosec-range, so I don't think that could be an issue.
I'll look into these things further and post if I have issues. Thanks.
EDIT
I just did some experimenting and a simluation in Proteus to see how the CCP works, and it works amazingly! I'm just really concerned that the long-pulse functionality is out of my grasp. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
mattthegamer463
Joined: 05 Jun 2011 Posts: 3
|
|
Posted: Sun Jun 05, 2011 5:54 pm |
|
|
Thanks PCM Programmer. I've got some promising numbers going, I need to finish the mechanical setup before I can determine if I need to work the code further. Thanks. |
|
|
|
|
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
|