Post the sketch in code tags for our mobile forum members!
Sketch is in post # 10
THX. Fifteen seconds is an eternity.
Looks like you don't have a spare LED and resistor to use in improving your demo.
I do, here you go:
{
"type": "wokwi-led",
"id": "led2",
"top": -31.56,
"left": -219.63,
"attrs": { "color": "red" }
},
{
"type": "wokwi-resistor",
"id": "r2",
"top": -100.0,
"left": -250.0,
"attrs": { "value": "1000" }
},
You'll have to do the wiring.
a7
Indeed. To the goal of writing this in a simple way, I took your diagram directly to code. Any example will need scrutiny - here we dispense with language features and ad-hoc mechanisms to make such careful study easier.
I used the IPO model which is a good match for the switch/case finite machinery.
// https://wokwi.com/projects/372326413257367553
// https://forum.arduino.cc/t/make-an-output-pin-behave-like-a-monostable-multivibrator/1155428/12
# define IR_Pin 2
# define LED_Pin 13
// just tosee that we are looping.
# define heartBeatLED_Pin 12
enum {IDOL = 0, LED_ON, LED_OFF, WAIT,};
unsigned long timer;
# define LED_ON_TIME 5000
# define NO_OBSTAKLE_WAIT_TIME 2000
void setup() {
Serial.begin(115200);
Serial.println("Hello World!\n");
pinMode(IR_Pin, INPUT);
pinMode(LED_Pin, OUTPUT);
pinMode(heartBeatLED_Pin, OUTPUT);
}
byte state = IDOL;
bool irActive;
unsigned long now;
bool ledOn;
void loop() {
delay(50);
digitalWrite(heartBeatLED_Pin, (millis() & 512) ? HIGH : LOW);
// I. inputs to the model - time and motion activity
now = millis();
irActive = digitalRead(IR_Pin) == HIGH;
// P. process the inputs given the current state and inputs
theFSM();
// O. use the process to set the outputs.
digitalWrite(LED_Pin, ledOn ? HIGH : LOW);
}
void theFSM() {
long elapsedTime = 0;
switch (state) {
case IDOL :
if (irActive) {
Serial.println("motion turns LED on");
state = LED_ON;
timer = now;
}
break;
case LED_ON :
ledOn = true;
elapsedTime = now - timer;
if (elapsedTime >= LED_ON_TIME) {
Serial.println("time turns LED off");
ledOn = false;
state = LED_OFF;
}
break;
case LED_OFF :
if (!irActive) {
Serial.println("IR signal gone, so");
timer = now;
state = WAIT;
}
break;
case WAIT :
elapsedTime = now - timer;
if (elapsedTime >= NO_OBSTAKLE_WAIT_TIME) {
Serial.println("after a bit more time, we reset");
timer = now;
state = IDOL;
}
break;
}
}
HTH and a tip 'o the hat to @paulpaulson tireless promoter of the IPO model.
a7
Not exactly, at least as far as I understand from your code.
Supposing after the led has switched off after the 5 seconds, the IR sensor is still delivering say pulses at 500ms as the object is coming in and out of the detection range, that is there is not a stable "non detect" phase lasting over 1 second your code would anyway ignore that and simply restart the whole cycle. Or am I missing something?
In terms of the state diagram in post #12, it appears that the path "IR detection triggered" from the state "No detection wait" is not implemented.
This is sufficiently close to my ideal, at least as a presentation for a new user, to cause me to abort my plans for throwing in yet another solution into this thread. However, I believe that it still needs "tweaking" in the same way that I pointed out in post #25 for Stefan's solution.
Yes. I am far away when I realize I coded it by using @StefanL38's version, not, as I claimed, by looking at your diagram.
When I am back in the lab I will do what I said I was going to.
Meanwhile another for once just hot not hellishly so, a day in the season that is, um, seasonable.
a7
const int IRval = 2; //Pin2 as IR sense pin.
const int LEDpin = 13;
int Time = 5000; // time delay.
void setup() {
pinMode(LEDpin, OUTPUT);
pinMode(IRval, INPUT);
}
void loop() {
if (digitalRead(IRval) == LOW) {
digitalWrite(LEDpin, HIGH);
delay(Time);
digitalWrite(LEDpin, LOW);
while (digitalRead(IRval) == LOW)
;
}
}
This code work but the problem is; LEDpin stays high when the obstacle is still there. LEDpin is suppose to go low after 5 seconds even if the obstacle is present.
LEDpin will go high again when the obstacle move away and comes back.
Thank you very much for your time.
Which of the multiple solutions that have appeared in this thread are you referring to?
Please forgive me, I am very new to this group. I appreciate the attention i am receiving.
i was referring to post #29
For post #28
This code work but the problem is; LEDpin stays high when the obstacle is still there. LEDpin is suppose to go low after 5 seconds even if the obstacle is present.
LEDpin will go high again when the obstacle move away and comes back.
Thank you very much for your time.
i see theLEDpin go LOW after 5 seconds regardless of the state of the IR pin which includes if the IR pin remains LOW after 5 sec
Here's the code from #24 fixed to account for actually looking at @6v6gt's state diagram.
I like the diagram notation and how the rules on the arcs go directly into code for each state.
I put labels on the print statements, they correspond to the five transition arcs in the digram. I left out the Start -> Waiting for detection arc, I just begin life in the first state.
I changed the time that the PIR stays HIGH after sensing motion. Fifteen seconds is an eternity. Furthermore, with a microprocessor available I would much rather do that latching in code, and let the PIR continue to go HIGH and LOW more closely with motion/no motion conditions.
I put a blue LED I had laying around on the PIR to get a raw sensor value. I do not know if IRL PIR sensors can drive an LED, so be careful if you try this for realz. Another benefit to simulation.
Corrected FSM to state diagram
// https://wokwi.com/projects/372337626147389441
// https://forum.arduino.cc/t/make-an-output-pin-behave-like-a-monostable-multivibrator/1155428/12
// this is meant to be the state diagram in post #12
// the PIR delayTime is set to 2 seconds in the *.json file
# define IR_Pin 2
# define LED_Pin 13
// just to see that we are looping.
# define heartBeatLED_Pin 12
enum {IDOL = 0, LED_ON, LED_OFF, WAIT,};
unsigned long timer;
# define LED_ON_TIME 5000
# define NO_OBSTAKLE_WAIT_TIME 2000
void setup() {
Serial.begin(115200);
Serial.println("Hello World!\n");
pinMode(IR_Pin, INPUT);
pinMode(LED_Pin, OUTPUT);
pinMode(heartBeatLED_Pin, OUTPUT);
}
byte state = IDOL;
bool irActive;
unsigned long now;
bool ledOn;
void loop() {
delay(50);
digitalWrite(heartBeatLED_Pin, (millis() & 512) ? HIGH : LOW);
// I. inputs to the model - time and motion activity
now = millis();
irActive = digitalRead(IR_Pin) == HIGH;
// P. process the inputs given the current state and inputs
theFSM();
// O. use the process to set the outputs.
digitalWrite(LED_Pin, ledOn ? HIGH : LOW);
}
void theFSM() {
long elapsedTime = 0;
switch (state) {
case IDOL :
if (irActive) {
Serial.println("A. motion turns LED on");
state = LED_ON;
timer = now;
}
break;
case LED_ON :
ledOn = true;
elapsedTime = now - timer;
if (elapsedTime >= LED_ON_TIME) {
Serial.println("B. time turns LED off");
ledOn = false;
state = LED_OFF;
}
break;
case LED_OFF :
if (!irActive) {
Serial.println("C. IR signal gone, so");
timer = now;
state = WAIT;
}
break;
case WAIT :
elapsedTime = now - timer;
if (irActive) {
Serial.println("D. IR signal still or again, so");
timer = now;
state = WAIT;
}
else if (elapsedTime >= NO_OBSTAKLE_WAIT_TIME) {
Serial.println("E. after a bit more time, we reset");
timer = now;
state = IDOL;
}
break;
}
}
a7
You will have to omit this input HIGH state with a timer function or a class or whatever. You have to know the trigger is set HIGH so you have to put it back manualy. Make a function with a counter that omits the ir if there“s even a obstacle. You can send me your sketch if you think you“re stuck. vanderpoortenrudy@hotmail.com I“ll try to get you get out of the problem. ![]()
An assumption appears to have entered the thread that the sensor the OP described as an IR sensor is a PIR , that is passive infrared sensor. I tend to believe it is a normal IR sensor (say of the type used in a line following robot) because of the "1 second" no detect condition before considering a re-trigger. Most PIR sensors anyway block for longer than that. Maybe the OP can tell us more.
I think he has left the building with a solution in his suitcase already .
anyway altos code with more self-explaining names and more comments what the code is doing
// https://wokwi.com/projects/372380727802934273
// https://forum.arduino.cc/t/make-an-output-pin-behave-like-a-monostable-multivibrator/1155428/12
// this is meant to be the state diagram in post #12
// the PIR delayTime is set to 2 seconds in the *.json file
# define IR_Pin 2
# define LED_Pin 13
// blink heartbeat-led just to see that we are looping.
# define heartBeatLED_Pin 12
enum {IDLE = 0, LED_ON, LED_OFF, WAIT,};
unsigned long snapshot_PIR_HIGH_detected;
unsigned long snapshot_PIR_went_LOW;
# define LED_ON_TIME 5000
# define NO_OBSTAKLE_WAIT_TIME 2000
void setup() {
Serial.begin(115200);
Serial.println("Hello World!\n");
pinMode(IR_Pin, INPUT);
pinMode(LED_Pin, OUTPUT);
pinMode(heartBeatLED_Pin, OUTPUT);
}
byte state = IDLE;
bool PIR_Sensor_HIGH;
unsigned long milliseconds_right_now;
bool ledOn;
void loop() {
delay(50);
digitalWrite(heartBeatLED_Pin, (millis() & 512) ? HIGH : LOW);
// I-P-O-model I)nputs-P)rocess-O)utput
// I. INPUTS to the model - time and motion activity
milliseconds_right_now = millis();
// when digitalRead(IR_Pin) delivers HIGH
// (digitalRead(IR_Pin) == HIGH) results in true
// HIGH == HIGH is true
// when digitalRead(IR_Pin) delivers LOW
// (digitalRead(IR_Pin) == HIGH) results in false
// LOW == HIGH is false
PIR_Sensor_HIGH = (digitalRead(IR_Pin) == HIGH);
// P. PROCESS the inputs given the current state and inputs
theFSM();
// RIGHT-BELOW-FSM
// O. OUTPUTS use the process to set the outputs.
if (ledOn == true) {
digitalWrite(LED_Pin, HIGH);
}
else {
digitalWrite(LED_Pin, LOW);
}
// shortest way to code the above if-else:
// digitalWrite(LED_Pin, ledOn ? HIGH : LOW);
}
void theFSM() {
unsigned long time_sincePIR_went_HIGH = 0;
unsigned long time_sincePIR_went_LOW = 0;
switch (state) {
// if variable "state" has value represented by the name "IDLE"
// mutually exclusive execute code below case IDLE:
case IDLE :
if (PIR_Sensor_HIGH) {
snapshot_PIR_HIGH_detected = milliseconds_right_now;
Serial.println("A. motion turns LED on");
state = LED_ON;
}
break; // IMMITIATELY jump down to END-OF-SWITCH
case LED_ON :
ledOn = true;
time_sincePIR_went_HIGH = milliseconds_right_now - snapshot_PIR_HIGH_detected;
if (time_sincePIR_went_HIGH >= LED_ON_TIME) {
Serial.println("B. time turns LED off");
ledOn = false;
state = LED_OFF;
}
break; // IMMITIATELY jump down to END-OF-SWITCH
case LED_OFF :
if (!PIR_Sensor_HIGH) {
Serial.println("C. IR signal gone, so");
snapshot_PIR_went_LOW = milliseconds_right_now;
state = WAIT;
}
break; // IMMITIATELY jump down to END-OF-SWITCH
case WAIT :
time_sincePIR_went_LOW = milliseconds_right_now - snapshot_PIR_went_LOW;
if (PIR_Sensor_HIGH) {
Serial.println("D. IR signal still or again, so");
time_sincePIR_went_LOW = milliseconds_right_now;
state = WAIT;
}
else if (time_sincePIR_went_LOW >= NO_OBSTAKLE_WAIT_TIME) {
Serial.println("E. after a bit more time, we reset");
//timer = milliseconds_right_now;
state = IDLE;
}
break; // IMMITIATELY jump down to END-OF-SWITCH
} // END-OF-SWITCH
// after a break; code-execution goes on here
// ==> jump back to RIGHT-BELOW-FSM
}
Yes, I did wonder about this:
@StefanL38 thank you taking the time to study my code.
Rant. Don't worry. I'm SMH, oh what have you done?
To say it isn't quite where I would have gone with it next, if anywhere, is an understatement.
I can't keep you from destroying my code with your improvements, but the comment I quote is a step I must vigorously object to.
First, it's spelled "immediately". Second, there is NO NEED TO SHOUT.
Third, it it absurd to comment language features that you somehow think shouldn't be part of what a person brings to studying my code.
Where does that end?
for (int ii = 0; ii < 10; ii++) { // ii runs from 0 to 9
Stupid and redundant. Or this, yes:
distance++: // add one to distance
Stupid, redundant and technically incorrect.
Now you add
// shortest way to code the above if-else:
// digitalWrite(LED_Pin, ledOn ? HIGH : LOW);
Why why why? Can you resist adding things to worry about? Many real programmers wouldn't bother to use that operator, in particular if the goal is to use the simplest code possible.
You might have instead complained and explained and changed this:
digitalWrite(heartBeatLED_Pin, (millis() & 512) ? HIGH : LOW);
The heart beat should be in a function. There it could be any code, even "blink without delay" straight out of the dreaded IDE.
I'd start with what I wrote, then in comments (or better, see bleow) show alternates of varying degrees of cleverness and verbosity and so forth.
Comments in general do not help. Piling them into such a short program is a travesty. You can say I should write a description or explanation, but in this case we areā¦
⦠trying to get noobs to read the code. Not the comments. They are distracting visual clutter, and I will admit to reading very few ever. Here I stopped mostly having never started, but after seeing the ridiculous one on the break statements.
OK, my bad. I took another look, I am so sorry I had to see
time_sincePIR_went_HIGH = milliseconds_right_now - snapshot_PIR_HIGH_detected;
Good grief. I have said I am not good at naming variables, but that line of code is no zero not at all any kind of improvement. now is "right now". snapshot? Please shoot me now. And I do mean right_now.
Look, there's one door and many keys. One hopes there is at least one key that will unlock the door for each who seeks entry.
The loop() is fifteen lines of code. I didn't think any comments were needed, but did want to remark on the clear delineation of the IPO model steps, which method you may have noted I linked to in the prose.
theFSM() is a bit longer, and but nicely expressive - you added no comments about what the code was actually doing, or how. All the comments are gratuitous distracting noise.
I have to stop looking, oh no! Too late!
} // END-OF-SWITCH
Who does that? It's the matching brace ending the switch/case statement. Which is within visual range, not hiding at all, even if we didn't have modern tools to see the structure more clearly.
I'm sorry at this point that I did not start by expunging from the code I started with all the things that I would have said (named) differently.
I don't like underscores in variable names. I don't add Pin to constants that refer to pins. To me, theLED can have no meaning other than being a pin name. I might say so at the point I define it, more likely not. Same with theMotor or theButton. Now in the weeds, I don't really care.
digitalWrite(theLED, HIGH);
What could we possibly understand that line of code to be doing?
Use my code however, I cannot keep you from doing. But please me no favors, take (or just leave) my name out of it.
a7