Read a semi-digital signal and save its pulse-length

I call it semi-digital because I’m using a photoresistor and I’m trying to capture a light beam.
The beam lasts between 10 and 500 ms.
The base-line value varies with the environment (hence the use of an analog pin).

I tried this code:

int sensorHigh = 0;
int sensorLight = 0;
long startHigh = 0;
long stopHigh = 0;
int lengthHigh = 0;

void setup() {
  while (millis() < 1500) {
    // record the maximum sensor value
    sensorValue = analogRead(A0);
    if (sensorValue > sensorHigh) {
      sensorHigh = sensorValue;
  sensorLight = sensorHigh * 1.3;

  for (byte i=0; i<10; i++) {

void loop() {
//  sensorValue = analogRead(A0);
//  Serial.println(analogRead(A0));
    if (analogRead(A0) > sensorLight) {
      startHigh = millis();
      while(analogRead(A0) > sensorLight) {
      stopHigh = millis();
      lengthHigh = stopHigh - startHigh;
      Serial.print("Top : ");

But it misses some beams (not seeing there are two different sent) from time to time

Any idea on how to improve it?

Do the missed beams have anything in common (short duration, short interval since the last beam, less bright, etc.)?

I think it's mostly due to the fact that there is a short time between two pulses.

I wondered if the analogRead() and serial instructions were too slow But when I plot it through serial, it's fine, so...

I guess a Timer Input capture with a 16 bits timer should be a good solution on an Atmega 328P.

This might be of interest to you as your then converting the analogue into digital. Another option might be to speed up the ADC speed (see here).

Photoresistors are not super fast, I’m looking at a datasheet for a common one that says “rise time: 55 ms, fall time: 20 ms”

I'm trying to read morse code from a flashlight to me more clear.

Here's what I get with a Serial.println(analogRead(A0)):


So it does detect the pulses well :)

Then the problem must be that the analogRead() value of the missed beams was less than sensorLight.

I suggest you take a slightly different approach. Rather than using the level of the reading from the analog pin, use the change in level since the previous reading. When you see a large positive increase from one reading to the next (eg.>+100), make a note of the value of millis() and set a flag to ignore any further large increases. When you see a large negative change (eg. <-100), calculate the length of the pulse by comparing the current value of millis() to the noted value, and reset the flag so that any further large negative changes are ignored.

pert> That might well be the case, sir!

PaulRB> I think I like it :)