Hi, I'm new and don't know a lot about coding.
I've spent hours and hours googling and trying to get this to work.
I need to turn on a pin for a few mS to trigger an external event
and I can't quite get from BlinkWithoutDelay / Debounce to a simple oneshot.
int gatePin = 11;
int buttonPin = 12;
long prevgateTime = 0;
int gateState;
long interval = 100;
void setup() {
pinMode(gatePin, OUTPUT);
pinMode(buttonPin, INPUT);
gateState = 0;
}
void loop() {
int button = digitalRead(buttonPin);
unsigned long prevgateTime = millis();
if (button == HIGH) {
digitalWrite(gatePin, HIGH);
gateState == HIGH;
unsigned long gateTime = millis();
if (gateTime - prevgateTime >= interval){
prevgateTime = gateTime;
digitalWrite(gatePin, LOW);
}
}
else {
digitalWrite(gatePin, LOW);
}
}
I'm trying to trigger it with a switch, just out of simplicity,
but it just turns on and stays on when the switch is pressed and turns off when I release the switch
When I get it to work properly I'd like to make a function out of it so I can insert it in to switchcase statements.
What am i doing wrong?
I'm having a hard time wrapping my head around this timing stuff, and it's primarily what I want to accomplish with MCU.
Modify your post and paste in the code with just simple copy & paste, and not Copy for Forum or what ever you used that added all the color /color tags & makes it quite unreadable.
Hi Jack, I am in the same boat, this is such a common occurrence with PLC's but seems no one is capable of writing a code for us to understand. They just point you to this site or that but with our limited knowledge we arent able to use that info to put this together. I am sure one day we will look back and go ...... oh how easy that was
For a oneshot, you're going to be better off detecting when the button became high, not when it is high. Try this:
int gatePin = 11;
int buttonPin = 12;
long interval = 100;
byte CurrButtonState,PrevButtonState;
unsigned long gateTime;
void setup()
{
pinMode(gatePin, OUTPUT);
pinMode(buttonPin, INPUT);
}
void loop()
{
CurrButtonState = digitalRead(buttonPin);
if (CurrButtonState == HIGH && PrevButtonState==LOW)
{
gateTime = millis();
digitalWrite(gatePin, HIGH);
}
if (millis()-gateTime >= interval)
{
digitalWrite(gatePin, LOW);
}
PrevButtonState = CurrButtonState;
}
Compiled, not tested.
It's a bit wasteful in that the gatePin is going to be asked to go low repeatedly when it already is. Similarly, that pin will be told to go high several times during any switch bounce. Neither of these things should impact the ability to fire the oneshot though.
Personally, I think it's better to test for a change in state, and then test what that change was (to pressed or to released).
if(currState != prevState)
{
// A state change happened
if(currState == HIGH)
{
// The change was to HIGH (whatever that means)
}
else
{
// The change was to LOW (whatever that means)
}
}
prevState = currState;
There may be cases where pressing the switch is the event of interest. There may be cases where releasing the switch is the event of interest. There may be cases where both events are of interest, when, for instance, you want to know how long the switch was pressed. This structure allows for all the events of interest to be observed.
That State_Machine article looks very interesting, I'm going to have to take some time to digest it.
OK! It works great like this:
int gatePin = 11;
int buttonPin = 12;
byte button, prevButton;
unsigned long gateTime;
long interval = 100;
void setup() {
pinMode(gatePin, OUTPUT);
pinMode(buttonPin, INPUT);
}
void loop() {
button = digitalRead(buttonPin);
if (button == HIGH && prevButton == LOW) {
gateTime = millis();
digitalWrite(gatePin, HIGH);
}
if (millis() - gateTime >= interval){
digitalWrite(gatePin, LOW);
}
prevButton = button;
}
my next step is to get it to run as a function.
the button press is of no consequence in the final program.
I'd like to call a function in different cases and have it run when those cases are true (eventually).
The button press is just a simple way to help me wrap my poor little brain around this small piece of coding.
the gate pin goes high and stays high
In my imagination the function should run when the switch is pressed.
If that worked, I could insert it in to a case statement.
How can I get it to work?
and why doesn't it work like that?
In my imagination the function should run when the switch is pressed.
And, indeed it should. It will be called exactly once, because it is only called when the switch becomes pressed (assuming, of course that the switch is indeed wired correctly - an assumption I'm not willing to make).
When you call that function, now is determined, and stored in gateTime. Then, now is determined again. mere nanoseconds later. Of course, it is unlikely that the value returned is any different, so now minus then is 0, which is not greater than interval (unless interval is 0), so the function returns without having done anything.
You need to keep in mind that the original code was making a decision whether to turn the pin on in one iteration of loop(), and finally deciding that it was time to turn it off many iterations later.
gateTime is the first NOW and millis() is the second NOW?
The value of millis() is now. You store that value in gateTime, once.
You can't really do all the work in oneshot(), unless you want to use delay(). You need to turn the pin on when the event of interest happens. You want to turn the pin off a fixed time later. That can't be done in one function, unless you call the function over and over.
theautomationguy:
Hi Jack, I am in the same boat, this is such a common occurrence with PLC's but seems no one is capable of writing a code for us to understand. They just point you to this site or that but with our limited knowledge we arent able to use that info to put this together. I am sure one day we will look back and go ...... oh how easy that was
I think the only problem is asking the question the way it can be understood.
So millis() is the time elapsed since the function was called?
No, millis() returns the time the Arduino has been running, in milliseconds. Or, at least it is the time since the last rollover, if the Arduino has been running more than 49+ days.
Instead of trying to create a function called oneShot(), think in terms of turning the pin back off.
int something = 0;
void loop()
{
switch(something)
{
case 0:
turnPinOn();
recordWhenThatHappened();
break;
}
turnPinOffIfItsTime();
}
Now, what goes in each function should be fairly obvious.
The last code you posted is turning the pin on, and resetting the time that that happened, on every pass through loop(), so it never becomes time to turn it off.
It really seems unlikely that you want to do exactly the same thing when the switch is pressed and when it is not pressed. Otherwise, there would be no reason to read the switch state.
It really seems unlikely that you want to do exactly the same thing when the switch is pressed and when it is not pressed. Otherwise, there would be no reason to read the switch state.
I know there is no need for a switch case when there is only 2 options,
I removed all the extemporaneous code so only the bare bones of what I'm getting at is apparent and clear.
What i'd like to use it for (once I understand it) has 10 cases and I need the gate pin to pulse for a few mS for 9 of the cases.
There's no switch/button in the project.
The button example is only an allegory to keep the code and the concepts short and simple so i can wrap my head around them. Once I get it working with a button I can incorporate it to the larger project.
The last code you posted is turning the pin on, and resetting the time that that happened, on every pass through loop(), so it never becomes time to turn it off.
How can I get it to pulse when I press it, and pulse when i release it?