Hi,
I'm trying to create a shutter tester for an analog camera. I have taken the ideas from the other projects found on internet.
I have three photodiodes, I enter in a do-while lopp and I check if each diode receives light, then I store in start and stop the values of micros().
Whith this code I check the time spent in a single do-while cycle without entry into the if statements; it gives me 670 microseconds.
Since I want to check exposure times of 1/1000 of seconds I think that 0.67 milliseconds for each loop is too much (I can have an error of 67%). There is a way to speed up the code?
Thanks in advice.
Luigi
unsigned long start_a, start_b, start_c,a;
unsigned long stop_a, stop_b, stop_c,b;
int soglia = 700;
int isteresi = 5;
int measure = 3;
int fired_a = 2;
int fired_b = 2;
int fired_c = 2;
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args) write(args);
#else
#define printByte(args) print(args,BYTE);
#endif
byte customChar[8] = {
0b01000,
0b11000,
0b01001,
0b01010,
0b00100,
0b01000,
0b10000,
0b00000
};
LiquidCrystal_I2C LCD(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
void setup() {
// Put your setup code here, to run once:
//Serial.begin(9600);
LCD.init(); // initialize the lcd
LCD.backlight();
LCD.createChar(0, customChar);
LCD.home();
}
void loop() {
do {
a = micros();
if ((analogRead(A3) < soglia) && (fired_a == 2)){
start_a = micros();
fired_a--;
}
if ((analogRead(A3) > soglia + isteresi) && (fired_a == 1)){
stop_a = micros();
fired_a--;
measure--;
}
if ((analogRead(A1) < soglia) && (fired_b == 2)){
start_b = micros();
fired_b--;
}
if ((analogRead(A1) > soglia + isteresi) && (fired_b == 1)){
stop_b = micros();
fired_b--;
measure--;
}
if ((analogRead(A2) < soglia) && (fired_c == 2)){
start_c = micros();
fired_c--;
}
if ((analogRead(A2) > soglia + isteresi) && (fired_c == 1)){
stop_c = micros();
fired_c--;
measure--;
}
b = micros();
measure = 0;
} while (measure > 0);
LCD.setCursor(0, 0);
LCD.print(a);
LCD.setCursor(9, 0);
LCD.print(b);
LCD.setCursor(9, 1);
LCD.print(b-a);
delay(3000);
LCD.clear();
delay(500);
}
Thanks to all, I will check both solutions.
I know that I do not loop in the do-while, I have used this solution in this script for plot the result (I could have moved the print in the while loop, I know).
I’m using a Arduino NANO compatible board with the old boot loader.
About the digital interrupt and the hardware timer, I don’t know how to use the timer, I have to study; for the digital interrupt you would use the direct analog output to trigger it?
have a look at digital-logic-levels
the Nano would probably by OK with a level over 2.5 to 3.0 volts for logic 1 - use attachInterrupt() to attach an interrupt handler to to a specified GPIO pin
realised the code in the link in post 3 uses micros() to time events which would work ok the Nano
I have used photodiodes with lm393 circuit, like this one on Aliexpress: https://it.aliexpress.com/item/1005006047488202.html
I have searched for the photo IC listed in this project (GitHub - srozum/film_camera_tester: DIY Film Camera Tester) but they seem unavailable in Italy. Then I have added the resistor and capacitor as reported in the project above, I have done no other circuit.
For the test with the oscilloscope I don’t have one.
int pin = 7; // Pin connected to the pulse signal
unsigned long duration;
void setup() {
Serial.begin(9600);
pinMode(pin, INPUT);
}
void loop() {
duration = pulseIn(pin, HIGH); // Measure the duration of the HIGH pulse
Serial.print("Pulse width: ");
Serial.println(duration); // Print the pulse width in microseconds
delay(1000); // Wait for a second before the next measurement
}
Here is a simple circuit I used with a 74HC14 as the input device. Should work on 3 or 5V. The output can go to pin 7 to be comparable with the code. If you want the logic reversed you can swap the resistor and diode or add another gate. start with maybe 100K for the resistor.
Which is probably close to the best you can do with a Nano and the internal ADC, if you want to do all three analogReads(). Any other fine tuning (reducing complexity, removing statements) is unlikely to gain you much, as the analogReads() really dominate your code; almost everything else is one or a few clock cycles at 16 MHz.
To improve conversion times much beyond that, I think you're into adding a fast external ADC, and reading it at the fastest clock rate available, likely on SPI; doable, but more complex. Unless someone's aware of a fast parallel ADC; that can be read in parallel with a port read on the Nano, using 8 Nano pins as digital inputs(not sure there are 8 on any single port, though). That would provide a much faster read cycle, so then it's back to the conversion time of the external ADC. And, lot of faffing around, I think.
Or, better, just move to a different Arduino, with a faster ADC and more horsepower in the CPU.
Not my forte, so I'll defer to others. There must be something more performance oriented than the Nano, by now.
edit - However, I think you should also look at different techniques, as being suggested by others - you only need go/nogo from what I understand, and are using the ADC purely due to signal level; better to convert to digital outside the Nano. The suggestion in post #10 above might be perfectly adequate, and is limited only by the diode's response time and sensitivity. Propagation time across the gate will be several nanoseconds, IIRC.
The solution in post 10 is interesting, but for now I don’t have photodiode alone. Another question I have is: the program stops at the pulseIn command waiting the end of the pulse?
The pulseIn() function takes the following parameters: pin, value, and an optional timeout.
pin: The Arduino pin number (configured as INPUT, INPUT_PULLUP, or INPUT_PULLDOWN).
value: The type of pulse to read (HIGH or LOW). The function waits for the specified transition (LOW to HIGH for HIGH, HIGH to LOW for LOW), starts timing, waits for the opposite transition, and stops timing.
timeout (optional): The maximum time in microseconds to wait for the complete pulse. The default is one second.
Returns
The function returns the pulse length in microseconds as an unsigned long. It returns 0 if the timeout occurs before a complete pulse is received.
Key Characteristics
pulseIn() is a blocking function, meaning program execution pauses until a pulse is detected or the timeout is reached. It works best for pulses between 10 microseconds and 3 minutes, though accuracy can vary. For very long pulses or non-blocking operation, pulseInLong() or using interrupts are suggested alternatives.
So TAYQ, yes, it stays within the function until complete, or timeout.
Are you now looking for a function that isn't blocking? Because analogRead(), in it's base form, is also blocking.
If you're interested in the source for pulseIn(), it can likely be found on your computer, in a file named wiring_pulse.c, somewhere in the Arduino installation.
Also, be aware, for both your technique and one using pulseIn(), one needs to consider the possibility of a timer interrupt in the middle of your sensitive timing measurement. Techniques that utilize a hardware counter may not have that vulnerability, depending on their approach.
YMMV.
With advice in post 14 and 19 the time spent in the while-do cicle is 50 or 60 us; I think it is a good value.
I know that the analogRead is blocking, but only when it is evaluating the input. In an analog camera there are two curtains, the second starts the travel at a percentage of the travel of the first curtain, the percentage depend on the shutter speed. At faster shutter speed there is a narrow slot, but at 1/60 the second curtain starts when the first arrives at the end, so all three sensors are receiving light; so I need to start the timer in sequence, but they must count simultaneusly.
About the interrupt: I have tried to use them, but I need one interrupt for the rising edge and one for de falling edge on all three sensors, so 6 interrupt and my NANO has only 2 interrupt pin; perhaps there is a better way to use them, but I don't know it.