Photogate final class and Robot revival

Concept summary and connections

Lesson Content

Edge-detection: when you have a signal and you only want to notice when it changes, you're doing edge detection. We can do this in software or in hardware.

The key in either case is that you have to have at least a brief period during which you can compare what it was before to what it is now. That means you need some kind of memory of the value, at least for a brief instant.

In code, this is simple. Just make a variable to hold the previous value of your sensor, and compare it to the newly-read value before you update the stored version:

bool beam_is_broken = false;

void loop() {
    bool beam_status = digitalRead(BEAM_PIN);
    if(beam_status != beam_is_broken) { // a change happened!
        Serial.print("Beam state changed to ");
        Serial.print(beam_status);
        Serial.print(", timestamp: ");
        Serial.println(millis());
    }
    beam_is_broken = beam_status;
}

In hardware, you need some way to compare the old with the new. One such way is with a differential amplifier. A differential amplifier is an op-amp circuit that amplifies the difference between its inputs. By wiring it so that the difference will have a momentary spike when the input signal changes, the op-amp can give you a spike whenever a change happens.

Using Interrupts

Most microcontrollers have a feature called interrupts, which lets you tell the microcontroller to watch a pin and let you know when it changes automatically. In arduino, this is done with the attachInterrupt function:

This example will toggle the output LED whenever the input on pin 2 changes (either rising or falling edge).

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  
  // INPUT_PULLUP attaches an internal 20k pull-up resistor to the input pin so 
  // that it is HIGH when there is no connection on the attached circuit.
  pinMode(interruptPin, INPUT_PULLUP);
  
  // digitalPinToInterrupt is a helper function to make sure the pin number you
  // want is actually the right one for an interrupt. Digital pin numbers don't 
  // necessarily match interrupt pin numbers, so you have to use this mapping to 
  // make sure you're actually monitoring the pin you have your wires connected to.
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

// Notice that loop doesn't do anything with the interruptPin at all! The arduino
// itself takes care of calling the ISR when an event happens. You can use the ISR
// to change some global data if you want so that loop can be aware of the state
// of things, or you can just do something directly in the ISR. In this case, the ISR
// controls the state variable, which the loop function uses to decide whether to 
// turn the LED on or off.
void loop() {
  digitalWrite(ledPin, state);
}

// blink is the Interrupt Service Routine (ISR) for this example. It will be called
// whenever the interrupt gets triggered, which in this case happens whenever the
// value on interruptPin **changes**
void blink() {
  state = !state;
}

Media resources

Practice