I have code that creates a sequential signal with 4 LEDS. It cascades to the right. This works when I hold down the input button. What I need help with is having the code run exactly the same when there is an input signal of .5s HIGH --> .5s LOW (repeat). So what I am thinking in terms of pseudo-code is a code that keeps reading a HIGH signal as long as the signal is not low for more than .5s.
//LED outputs
int LED_5 = 6;
int LED_6 = 7;
int LED_7 = 8;
int LED_8 = 9;
//right turn signal
int RTS_IN = A0;
//state variable for switch case statements
int stateRightTurn = 0;
//time variable
unsigned long t = 0;
//interval is the time spacing between case statements
unsigned long interval = 100;
//time for shutting off the code
unsigned long off = 600;
void setup()
{
Serial.begin(9600);
//inputs
pinMode(RTS_IN, INPUT);
//right turn signal output from left to right
pinMode(LED_5, OUTPUT);
pinMode(LED_6, OUTPUT);
pinMode(LED_7, OUTPUT);
pinMode(LED_8, OUTPUT);
}
void loop()
{
StateRight();
}
//sequential turn signals
void StateRight()
{
switch (stateRightTurn)
{
case 0: //idle
if (digitalRead(RTS_IN) == HIGH)
{
Serial.println("0000");
t = millis();
SwitchRightLedsOff();
stateRightTurn = 1;
}
break;
case 1: //One LED On
if (digitalRead(RTS_IN) == LOW)
{
Serial.println("1111-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (millis() > t + interval)
{
Serial.println("1111-HHHHHHHH");
t = millis();
digitalWrite(LED_5, HIGH);
stateRightTurn = 2;
}
break;
case 2: // Two LEDs On
if (digitalRead(RTS_IN) == LOW)
{
Serial.println("2222-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (millis() > t + interval)
{
Serial.println("2222-HHHHHHHH");
t = millis();
digitalWrite(LED_6, HIGH);
stateRightTurn = 3;
}
break;
case 3: //Three LEDs On
if (digitalRead(RTS_IN) == LOW)
{
Serial.println("3333-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (millis() > t + interval)
{
Serial.println("3333-HHHHHHHH");
t = millis();
digitalWrite(LED_7, HIGH);
stateRightTurn = 4;
}
break;
case 4: //Four LEDs On
if (digitalRead(RTS_IN) == LOW)
{
Serial.println("4444-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (millis() > t + interval)
{
Serial.println("4444-HHHHHHHH");
t = millis();
digitalWrite(LED_8, HIGH);
stateRightTurn = 5;
}
break;
case 5: //No LEDs on
if (digitalRead(RTS_IN) == LOW)
{
Serial.println("5555-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (millis() > t + interval)
{
Serial.println("55555-HHHHHHHH");
SwitchRightLedsOff();
stateRightTurn = 0;
}
break;
}
}
//method to switch LEDs off
void SwitchRightLedsOff()
{
digitalWrite(LED_5, LOW);
digitalWrite(LED_6, LOW);
digitalWrite(LED_7, LOW);
digitalWrite(LED_8, LOW);
}
2 Answers 2
If I understand your requirements correctly, you could use a variable to determine if your sequential lights should be flashing or not. If the input signal is LOW
for more than 1/2 second, the variable should change to LOW
, telling the Arduino to stop flashing your sequential lights.
Let's pretend that your input signal is at the correct voltage and is very accurate with it's time keeping. At the 501ms mark, with no HIGH
input signal, your lights should stop flashing.
A simple timer and state variable may work. Here is a test sketch.
// Sketch uses 1144 bytes (3%) of program storage space.
// Global variables use 19 bytes (0%) of dynamic memory.
class MillisTimer{
private:
unsigned long m_timeInMilliSeconds;
unsigned long m_previousMillis;
byte m_timerActive;
public:
MillisTimer(unsigned long timeInMilliSeconds):
m_timeInMilliSeconds(timeInMilliSeconds),
m_timerActive(0),
m_previousMillis(0){
}
bool Update(){
if(m_timerActive && (millis() - m_previousMillis >= m_timeInMilliSeconds)){
m_previousMillis += m_timeInMilliSeconds;
return 1;
}
else{
return 0;
}
}
void Start(){
m_timerActive = 1;
}
void Stop(){
m_timerActive = 0;
}
void ReStart(){
m_timerActive = 1;
m_previousMillis = millis();
}
byte IsActive(){
return m_timerActive;
}
};
// Make a copy of the object to work with.
MillisTimer MyTimer(501);
byte inputPin = 2;
byte signalActive = 0;
void setup(){
// NOTE: Pull-down resistor required if input floating.
pinMode(inputPin, INPUT);
MyTimer.Start();
// Timer status indicator for testing purposes.
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}
void loop(){
if(digitalRead(inputPin) == HIGH){
signalActive = 1;
MyTimer.ReStart();
}
if(MyTimer.Update()){
signalActive = 0;
}
// Test ouput of "signalActive" variable using built in LED on an Uno.
if(signalActive == 1){
digitalWrite(LED_BUILTIN, HIGH);
}
else{
digitalWrite(LED_BUILTIN, LOW);
}
}
-
I am trying to get this work. I will let you know.Myles– Myles2022年03月14日 14:00:03 +00:00Commented Mar 14, 2022 at 14:00
Assuming that digitalRead(RTS_IN)
is the input, I'd read it once at the top of the loop and save the timestamp if it is HIGH, and then use the condition millis() - timestamp <= 500
as a latched input variable.
I'd also do the rest of the Input (i.e.: millis()) at the top of the function, convert the time comparisons from absolutes into intervals, and consider factoring the not-enabled case out of the switch's cases.
Untested code:
//LED outputs
int LED_5 = 6;
int LED_6 = 7;
int LED_7 = 8;
int LED_8 = 9;
//right turn signal
int RTS_IN = A0;
//state variable for switch case statements
int stateRightTurn = 0;
//time variable
unsigned long t = 0;
//interval is the time spacing between case statements
unsigned long interval = 100;
//time for shutting off the code
unsigned long off = 600;
void setup()
{
Serial.begin(9600);
//inputs
pinMode(RTS_IN, INPUT);
//right turn signal output from left to right
pinMode(LED_5, OUTPUT);
pinMode(LED_6, OUTPUT);
pinMode(LED_7, OUTPUT);
pinMode(LED_8, OUTPUT);
}
void loop()
{
StateRight();
}
//sequential turn signals
void StateRight()
{
const int latchInterval = 500; // ms
static unsigned long lastHigh = -latchInterval; // initialize into the rolled-over past
unsigned long now = millis();
int inState = digitalRead(RTS_IN);
if (inState == HIGH) { //update timer
lastHigh = now;
}
bool enabled = (now - lastHigh <= latchInterval) ; // latched on for 500 ms after off
switch (stateRightTurn)
{
case 0: //idle
if (enabled)
{
Serial.println("0000");
t = now;
SwitchRightLedsOff();
stateRightTurn = 1;
}
break;
case 1: //One LED On
if (!enabled)
{
Serial.println("1111-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (now - t > interval)
{
Serial.println("1111-HHHHHHHH");
t = now;
digitalWrite(LED_5, HIGH);
stateRightTurn = 2;
}
break;
case 2: // Two LEDs On
if (!enabled)
{
Serial.println("2222-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (now - t > interval)
{
Serial.println("2222-HHHHHHHH");
t = now;
digitalWrite(LED_6, HIGH);
stateRightTurn = 3;
}
break;
case 3: //Three LEDs On
if (!enabled)
{
Serial.println("3333-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (now - t > interval)
{
Serial.println("3333-HHHHHHHH");
t = now;
digitalWrite(LED_7, HIGH);
stateRightTurn = 4;
}
break;
case 4: //Four LEDs On
if (!enabled)
{
Serial.println("4444-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (now - t > interval)
{
Serial.println("4444-HHHHHHHH");
t = now;
digitalWrite(LED_8, HIGH);
stateRightTurn = 5;
}
break;
case 5: //No LEDs on
if (!enabled)
{
Serial.println("5555-LOWLOWLOW");
SwitchRightLedsOff();
stateRightTurn = 0;
}
else if (now - t > interval)
{
Serial.println("55555-HHHHHHHH");
SwitchRightLedsOff();
stateRightTurn = 0;
}
break;
}
}
//method to switch LEDs off
void SwitchRightLedsOff()
{
digitalWrite(LED_5, LOW);
digitalWrite(LED_6, LOW);
digitalWrite(LED_7, LOW);
digitalWrite(LED_8, LOW);
}
-
This worked perfectly! I understand it as well. I was trying to do something with the same thought processMyles– Myles2022年03月11日 17:50:41 +00:00Commented Mar 11, 2022 at 17:50
-
The trick is turning your input(s) into the helpful "an input is LOW for a certain amount of time" timer-based state variable that your code can use.Dave X– Dave X2022年03月12日 03:13:51 +00:00Commented Mar 12, 2022 at 3:13
t
to the other side of the>
sign in expressions like this:(millis() > t + interval)
so that you are always comparing intervals rather than timestamps. // Your proposed solution is a debouncing, or lock-out of a low inputs for 0.5s after the last observed high.