ATTINY Camera trap - how to make it blink

Hi everyone,

I tried to reopen an old topic but it's closed. One of the members to which I am still grateful, (6v6gt) helped me out by writing a great bit of code for a camera trap on an ATTINY85.

Basically when a signal from the sensor is detected (the sensor itself going LOW when the beam is broken sends a HIGH output to the ATTINY), the TRIGGER output goes HIGH for a minimum time of 500ms, but if the signal continues for 10 seconds the TRIGGER output goes LOW and an error LED lights up and locks the circuit until the sensor goes LOW again.

This is to prevent the camera trap from going nuts and continuously firing when an IR beam is misaligned by being bumped or runs out of power. I have had cameras burn out expensive flashes from a runaway sensor output several times so this circuit locking with an error LED after 10 seconds is absolutely required.

I have several outputs:
BEAM - shows confirmation of receiving a beam from the IR transmitter
TRIGGER - outputs through an LED to a 3N25 opto isolator connected to the camera
ERROR_PIN - The LED that shows when the circuit is locked due to an error

So, the story is that I am now using wireless transmitters to send signals from the sensor controller to the camera and the brand I am using needs pulsed outputs for multiple photos to be taken.

First of all I tried making the TRIGGER output flash with the Blink Test using a delay-->on--->delay--->off code. This worked well except it insisted on going through the entire sequence every time it was triggered. I needed it to stop and return to the non-triggered state "BEAM_TRUE" as soon as the beam was detected again.

So I tried adding a 555 to the output which also worked well when used on a 5.5v circuit on a 4xAA power supply but when put on a series of 81650 batteries for longer life in the field with an LM7805 5v regulator the 555 refused to blink more than once.

My question is how do I add a code to make the TRIGGER output blink at around 3Hz until it either locks because it has been triggered too long or reverts back to the BEAM_TRUE state the moment the beam is re established? It's been driving me nuts so any help would be very appreciated. Thanks!

const int SENSOR = 3;
const int BEAM = 2;
const int TRIGGER = 1;
const int ERROR_PIN = 0;

bool detect = false ;

enum class State { BEAM_TRUE = 1 , BEAM_BREAK = 2 , PENDING_NO_DETECTION = 3 } ;
State state ;

uint32_t enteredDetectionAtMs = 0 ;

void setup() {

  pinMode(SENSOR, INPUT);
  pinMode(BEAM, OUTPUT);

  state = State::BEAM_TRUE ;


void loop() {

  detect = digitalRead(SENSOR);
  if ( detect == HIGH ) digitalWrite(BEAM, HIGH);
  else digitalWrite(BEAM, LOW); ;

  switch ( state ) {

    case State::BEAM_TRUE : {

        if ( detect == LOW ) {
          state = State::BEAM_BREAK ;
          enteredDetectionAtMs = millis() ;
          digitalWrite(TRIGGER, HIGH); //!!
        break ;

    case State::BEAM_BREAK : {

        if ( millis() - enteredDetectionAtMs > 10000UL ) {
          state = State::PENDING_NO_DETECTION ;
          digitalWrite(TRIGGER, LOW);  //!!
          digitalWrite(ERROR_PIN, HIGH);  // !!
        else if ( detect == HIGH ) {   //!!
          state = State::BEAM_TRUE ;   //!!
          digitalWrite(TRIGGER, LOW); //!!

        break ;

    case State::PENDING_NO_DETECTION : {
        if ( detect == HIGH ) {
          state = State::BEAM_TRUE ;
          digitalWrite(ERROR_PIN, LOW);

        break ;

Add another clause in the beam break state.

Currently, you check for lockout, else you check to see if the beam is no longer broken. If neither is true (i.e. a final else), use blink without delay to toggle the trigger.

Is there a "blink" code for, say 3Hz that doesn't involve a delay command at all? Thanks