I am using Arduino with a simple momentary button to un-latch a door. The latch is a small 12VDC solenoid and I also use a bi-color LED to indicate status. This script will be moved from Uno to Nano when it's complete.
The following sketch seems to work very reliably. If I press and hold the button for a couple of seconds, the LED goes green and the latch opens.
Ideally, I'd like to press the button and have the latch unlock for a set period of time (eg: 2 seconds so it doesn't rely on the user holding the button closed). I've been experimenting with a heap of millis and debounce examples from YouTube but it's just causing me confusion. I was hoping someone might help with a simple code suggestion, or give me some practical pointers?
// As a person wanting to access a room through a closed gate,
// pressing a button activates a 0.4a 12vdc solendoid to release the lock,
// and change a red led to green to indicate momentary access.
int buttonPin = 2; // Momentary switch button
int solenoidPin = 4; // Transistor via 1k resistor
int led_green = 6; // Indicates unlocked door - solenoid pin magnetised
int led_red = 8; // Indicates locked door - solenoid pin released
// Run once to initialise variables and pin modes.
// Set pins for bi-color led and solenoid as outputs.
// The button pin utlises the onboard resistor which inverts mode behaviour
void setup() {
pinMode(solenoidPin, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_red, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP); // set arduino pin to enable the internal pull-up resistor
}
// Continually monitor, test and respond to changes.
void loop() {
int buttonState = digitalRead(buttonPin); // read the button state
if (buttonState == LOW) { // The button is being pressed
digitalWrite(solenoidPin, HIGH); // Tell the transistor to switch on
digitalWrite(led_green, HIGH); // Power to green anode via resistor (common-cathode bi-color led)
digitalWrite(led_red, LOW); // Stop power to red
} else if (buttonState == HIGH) { // The button is unpressed
digitalWrite(solenoidPin, LOW); // Tell the transistor to switch off
digitalWrite(led_green, LOW); // Stop power to green
digitalWrite(led_red, HIGH); // Power to red anode via resistor (common-cathode bi-color led)
}
}
The simplest would be to record the millis() when the button goes low, and then use a separate if statement to turn it off:
Here's a untested snippet:
...
static unsigned long lastOnMs = 0;
if (buttonState == LOW) { // The button is being pressed
lastOnMs = millis();
digitalWrite(solenoidPin, HIGH); // Tell the transistor to switch on
digitalWrite(led_green, HIGH); // Power to green anode via resistor (common-cathode bi-color led)
digitalWrite(led_red, LOW); // Stop power to red
}
if (digitalRead(solenoidPin) == HIGH && millis() - lastOnMs > 2000) { // time to turn off
digitalWrite(solenoidPin, LOW); // Tell the transistor to switch off
digitalWrite(led_green, LOW); // Stop power to green
digitalWrite(led_red, HIGH); // Power to red anode via resistor (common-cathode bi-color led)
}
This uses the digitalRead(solenoidPin) as a state variable for tracking the state of the solenoid activity, and relies on lastOnMs to keep track of the time of the last press. I'd expect this to keep the solenoid on 2000ms past the end of the button press.
It doesn't do any debouncing, it just acts like a motor control contactor with a timeout.
ETA: below @Delta_G is using a better term "Latch"-- you latch it on with the first if() and set up a separate if() condition to un-latch it.
Thanks guys, this really helped. I only had to add initialising the red led status in setup, it all seems to work well.
Sketch code
//====================================================================================
// As a person wanting to access a room through a closed gate,
// pressing a button activates a 0.4a 12vdc solendoid to release the lock,
// and change a red led to green to indicate momentary access.
//====================================================================================
int buttonPin = 2; // Momentary switch button
int solenoidPin = 4; // Transistor via 1k resistor
int led_green = 6; // Indicates unlocked door - solenoid pin magnetised
int led_red = 8; // Indicates locked door - solenoid pin released
int unlockedTime = 2000; // How long the door should remain unlocked
boolean doorOpen = false; // When the program starts, the door is in locked state
unsigned long startTime; // Use this variable to compare time elapsed
// Run once to initialise variables and pin modes.
// Set pins for bi-color led and solenoid as outputs.
// The button pin utlises the onboard resistor which inverts mode behaviour
void setup() {
pinMode(solenoidPin, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_red, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP); // Set arduino pin to enable the internal pull-up resistor
digitalWrite(led_red, HIGH); // Set the red led when the program starts
}
// Continually monitor, test and respond to changes.
void loop() {
int buttonState = digitalRead(buttonPin); // Read the button state
if (buttonState == LOW) { // The button has been pressed
startTime = millis(); // Reset the start time variable
doorOpen = true; // Enables the doorOpen logic to run
}
if (doorOpen) {
if (millis() - startTime >= unlockedTime) {
// Check if it has been unlocked for long enough
doorOpen = false; // If it has, reset this boolean back to false
digitalWrite(solenoidPin, LOW); // Tell the transistor to switch off
digitalWrite(led_green, LOW); // Stop power to green
digitalWrite(led_red, HIGH); // Power to red anode via resistor (common-cathode bi-color led)
} else {
// It needs to stay open longer
digitalWrite(solenoidPin, HIGH); // Tell the transistor to switch on
digitalWrite(led_green, HIGH); // Power to green anode via resistor (common-cathode bi-color led)
digitalWrite(led_red, LOW); // Stop power to red
}
}
}
look this over
adds 2 sec timer, handles debounce with a single delay()
// As a person wanting to access a room through a closed gate,
// pressing a button activates a 0.4a 12vdc solendoid to release the lock,
// and change a red led to green to indicate momentary access.
int buttonPin = 2; // Momentary switch button
int solenoidPin = 4; // Transistor via 1k resistor
int led_green = 6; // Indicates unlocked door - solenoid pin magnetised
int led_red = 8; // Indicates locked door - solenoid pin released
const unsigned long TwoSec = 2000;
unsigned long msecPeriod;
unsigned long msecLst;
byte butLst;
enum { Off = LOW, On = HIGH };
// -----------------------------------------------------------------------------
// Run once to initialise variables and pin modes.
// Set pins for bi-color led and solenoid as outputs.
// The button pin utlises the onboard resistor which inverts mode behaviour
void setup() {
pinMode(solenoidPin, OUTPUT);
pinMode(led_green, OUTPUT);
pinMode(led_red, OUTPUT);
digitalWrite(led_red, On);
pinMode(buttonPin, INPUT_PULLUP);
butLst = digitalRead (buttonPin);
}
// Continually monitor, test and respond to changes.
void loop()
{
unsigned long msec = millis ();
if (msecPeriod && msec - msecLst >= msecPeriod) {
msecPeriod = 0;
digitalWrite(solenoidPin, Off);
digitalWrite(led_green, Off);
digitalWrite(led_red, On);
}
byte but = digitalRead(buttonPin); // read the button state
if (butLst != but) {
butLst = but;
delay (20); // debounce
if (LOW == but) {
msecLst = msec;
msecPeriod = TwoSec;
digitalWrite(solenoidPin, On);
digitalWrite(led_green, On);
digitalWrite(led_red, Off);
}
}
}