How can I programme an Arduino to perform an action once and once only?

How can I programme an Arduino so that when a rain sensor indicates that it is raining, it runs a stepper motor once and once only, and then effectively shuts down until it is manually reset?

Context: I have built a prototype window auto-close unit that combines a rain sensor, an Elegoo Uno R3, a Pololu High-Power Stepper Motor Driver 36v4 and a 24v/4.2A stepper motor into a single unit - all powered by a 24v/5A mains adapter (240v UK). The unit is completely portable and self-contained - there is no data or power connection to a laptop, PC, WiFi router or similar device.

It performs a very simple, one-off operation. Whenever it starts to rain, the motor is activated, turning a pulley that reels in a wire cable that closes a top-hung Velux window from near-horizontal (open) to 45 degrees (closed). That’s it. The window stays shut until the householder wakes up, checks that it has stopped raining, and then manually re-sets the unit as needed.

I have combined a generic stepper motor sketch from Pololu with a rain sensor sketch - see below. The problem is that as currently programmed, whenever it starts to rain the Arduino will constantly re-check the sensor reading and then constantly re-start the motor. This would be great for a car windscreen wiper, but in my case it would end up breaking the motor, the cable, my electronics and/or the window. So I need to break that loop. What would people suggest?

Thanks!

#include <SPI.h>
#include <HighPowerStepperDriver.h>

const uint8_t CSPin = 4;

// This period is the length of the delay between steps, which controls the
// stepper motor's speed.
const uint16_t StepPeriodUs = 300;

HighPowerStepperDriver sd;

int rainsense = 0; // analog sensor input pin 0
int activatemotor = 11; // digital output pin 11 - activate 5v supply from Arduino to motor controller
int countval = 0; // counter value starting from 0 and goes up by 1 every second

void setup() {

  //Rain sensor setup
  Serial.begin(9600);
  pinMode(activatemotor, OUTPUT);
  pinMode(rainsense, INPUT);

  //Stepper motor setup
  {
    SPI.begin();
    sd.setChipSelectPin(CSPin);

    // Give the driver some time to power up.
    delay(1);

    // Reset the driver to its default settings and clear latched status
    // conditions.
    sd.resetSettings();
    sd.clearStatus();

    // Set the current limit. You should change the number here to an appropriate
    // value for your particular system.
    sd.setCurrentMilliamps36v4(4200);

    // Set the number of microsteps that correspond to one full step.
    sd.setStepMode(HPSDStepMode::MicroStep32);
  }
}

void loop()
{
  int rainSenseReading = analogRead(rainsense);
  Serial.println(rainSenseReading); // serial monitoring message
  delay(250);
  // The rain sensor produces a value from 0 (wet) to 697 (dry), using the 3.3v feed from the Arduino.
  // In the following line, you can set the amount of rain needed for the motor to be activated.
  if (rainSenseReading <= 400) {

    // If it is raining, then enable the motor outputs.
    sd.enableDriver();
    delay(1000);

    // Step in the specified direction and for the specified number of times.
    sd.setDirection(1);
    for (unsigned int x = 0; x < 32000; x++)
    {
      sd.step();
      delayMicroseconds(StepPeriodUs);
    }
    sd.disableDriver();
  }
}

notice the addition of bool DoTheThing =. true;?

#include <SPI.h>
#include <HighPowerStepperDriver.h>

bool DoTheThing = true; //see loop()

const uint8_t CSPin = 4;

// This period is the length of the delay between steps, which controls the
// stepper motor's speed.
const uint16_t StepPeriodUs = 300;

HighPowerStepperDriver sd;

int rainsense = 0; // analog sensor input pin 0
int activatemotor = 11; // digital output pin 11 - activate 5v supply from Arduino to motor controller
int countval = 0; // counter value starting from 0 and goes up by 1 every second

void setup() {

  //Rain sensor setup
  Serial.begin(9600);
  pinMode(activatemotor, OUTPUT);
  pinMode(rainsense, INPUT);

  //Stepper motor setup
  {
    SPI.begin();
    sd.setChipSelectPin(CSPin);

    // Give the driver some time to power up.
    delay(1);

    // Reset the driver to its default settings and clear latched status
    // conditions.
    sd.resetSettings();
    sd.clearStatus();

    // Set the current limit. You should change the number here to an appropriate
    // value for your particular system.
    sd.setCurrentMilliamps36v4(4200);

    // Set the number of microsteps that correspond to one full step.
    sd.setStepMode(HPSDStepMode::MicroStep32);
  }
}

void loop()
{

if( DoTheThing )
{
  int rainSenseReading = analogRead(rainsense);
  Serial.println(rainSenseReading); // serial monitoring message
  delay(250);
  // The rain sensor produces a value from 0 (wet) to 697 (dry), using the 3.3v feed from the Arduino.
  // In the following line, you can set the amount of rain needed for the motor to be activated.
  if (rainSenseReading <= 400) {

    // If it is raining, then enable the motor outputs.
    sd.enableDriver();
    delay(1000);

    // Step in the specified direction and for the specified number of times.
    sd.setDirection(1);
    for (unsigned int x = 0; x < 32000; x++)
    {
      sd.step();
      delayMicroseconds(StepPeriodUs);
    }
    sd.disableDriver();
  }
DoTheThing=false;
}

Now loop() will only run your code once.

Wow - thanks for the fast response Idahowalker. Really appreciate that.

Unfortunately when I tried to upload, I got the following error message:

Arduino: 1.8.13 (Windows 10), Board: “Arduino Uno”
4:18: error: expected primary-expression before ‘.’ token
bool DoTheThing =. true;

The dot is a typo - remove it.

wildbill:
The dot is a typo - remove it.

Thanks, fixed. +1

That's done the trick - many thanks!

I'm not sure if waking up to damp carpets is a big worry in Idaho, but you might just have helped this English family to sleep more easily on those rare hot summer nights... :sleeping:

Instead of a reset, add a button to the project that when a press is detected changes the DoTheThing back to true.

Then you could add in a LED that indicates if the program is running or stalled.

You are welcome, +1.

The traditional way to "do something once" is to put it in setup() instead of loop().

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.