one-shot astable

I am trying to write a sketch for a “one-shot” (bistable multi-vibrator) to avoid an external device like a 555, but having difficulty with programming.

(I have tried much on both Arduino and the Net, without success. Hence my asking for help.)

The criteria for this “one-shot” is :

  1. When INPUT goes from LOW to HIGH, OUTPUT goes HIGH immediately and remains HIGH until PERIOD (time) has expired, after which OUTPUT goes LOW.

  2. During this PERIOD the OUTPUT remains HIGH, despite noise or other HIGH’s at INPUT during the PERIOD (time).

  3. If no HIGH’s after PERIOD time, the OUTPUT remains LOW.

  4. If a single HIGH pulse occurs immedately after PERIOD (time) has expired, OUTPUT switches back to HIGH again until another PERIOD has expired.

I have tried a lot of options from both Arduino and Google, without success.

The best I have tried is this sketch which doesn’t work.

I would appreciate help to correct this sketch or offer an alternative that works.

Thank you.

const int ledPin = 12 ;

const int buttonPin = 2 ;

int ledState = LOW;

int buttonState = 0 ;

long previousMillis = 2000;

long interval = 2000;

void setup() {

pinMode (ledPin, OUTPUT);

pinMode (buttonPin, INPUT) ;

}

void loop() {

// int currentMillis = 2000 ;

if (buttonPin == HIGH)

ledState = 1 ;

unsigned long currentMillis = millis();

if (currentMillis - previousMillis > interval)

{

previousMillis = currentMillis;

if (ledState == LOW)

ledState = HIGH;

else

ledState = LOW;

digitalWrite(ledPin, ledState);

}

}

I see several problems. You’re missing some braces, you’ve used a reserved word for a variable (interval, that’s why it’s red in the IDE), you’ve mixed up some variable types (probably not an issue) and you haven’t implemented the no re-trigger logic. Try this and see if it makes sense.

const int ledPin = 12;
const int buttonPin = 2;
const unsigned long Period = 2000;          //length of timer period in msecs

boolean ledState = 0;
boolean buttonState = 0;
unsigned long timerMillis = 0;

void setup() {
  pinMode (ledPin, OUTPUT);
  pinMode (buttonPin, INPUT);   //assumes a momentary SW to Vcc and a pull-down resistor ?
}
void loop() {
  if ((buttonPin == HIGH) && (ledState == 0)) {   //ignore input while timer is running
    ledState = 1 ;                        //set LED  on, also used to know if timer is running
    timerMillis = millis();               //remember time when input when high
  }

  if (millis() - timerMillis > Period) {  //test if period msecs elapsed since input went high
    ledState = 0;                         //if yes, all done timing, shut off LED
  }

  digitalWrite(ledPin, ledState);         //output LED state, whatever it might be
}

ps - code tags work betta than quotes. :mrgreen:

Okay. I tried your sketch just as I tried dozens before today but it didn’t fly.

Clearly the problem occurs after void loop() so I compared it to “Buttons” (in “Examples”).

I experimented and added

buttonState = digitalRead (buttonPin)

and changed your

if ((buttonPin == …

to

if ((buttonState == …

and it works!

(Is that because you wrote boolean buttonState = 0 and followed that with buttonPin?)

Thanks so much for your help. Really appreciated.

SOLVED!

Newbie10:
(Is that because you wrote boolean buttonState = 0 and followed that with buttonPin?)

It occurs because I didn't give it much thought and didn't test the code. You need to read a pin to know the input state. Neither your 1'st program nor mine did that. Doh ! You could eliminate the variable ButtonState and do this change instead. ``` if ((digitalRead(buttonPin) == HIGH) && (ledState == 0)) { ```

Of course! (You learn something new every minute…)

And by removing the " && (ledState == 0)" bit the sketch becomes a “signal/s stretcher” by adding the Period after the last INPUT high. Very useful when you need it, as I do.

Thanks again.

Now I have another one …

I need a “delay-on” timer.

  1. LED is off at start-up. When BUTTON (input) goes high (momentarily or continuously), timing Period starts with LED off.

  2. When Period has expired LED comes on and remains on, until BUTTON input goes low and at the same moment LED goes off.

My sketch works “opposite”, and LED comes on after Period at start-up, and also hangs for Period after BUTTON goes low.

Any ideas?

Thanks so much.

// one-shot / delay-ON... but starts led ON!

const int ledPin = 12;
const int buttonPin = 2;
const int startledPin = 13;
const unsigned long Period = 4000;       

boolean ledState = 0;
boolean buttonState = 0;
boolean startledState = 0;
unsigned long timerMillis = 0;

void setup() {
  pinMode (ledPin, OUTPUT);
  pinMode (startledPin, OUTPUT);
  pinMode (buttonPin, INPUT);   
}
void loop() {
  buttonState = digitalRead (buttonPin) ;
  if (buttonState == HIGH) // && (ledState == 0))    
{    ledState = 0 ;                        
    timerMillis = millis();               
  }
  if (millis() - timerMillis > Period) 
  { ledState = 1;                         
  }
  digitalWrite(ledPin, ledState);

Newbie10:
Any ideas?

Yes, I have an idea. You have all the learning material right there in front of you. Give it some thought. Experiment a bit. It's only software, it won't bite you.

That last code cannot compile. There are \ in the wrong place. Or improperly used to comment something out.

I blocked this part : // && (ledState == 0))

out while experimenting. Also left out a } at the very end. Result of experimenting again.

Have since then got it right - works like a treat!

Thanks anyway. Glad to see there’s another on this forum …

Sorry, yes it was the // in the if statement. Typo on my part.

No need for apology : I like so many of us, goof! It’s natural in the scientific environment. (But then some get a bit bitter about errors as I have found out…)

I have found the // very useful to temporarily erase something to test how it compiles or works in hardware. That way one can also SEE what you did last time; e.g. often I will copy/paste a line and place // at the start of the upper line while I wiggle/twiggle the 2nd line so I always know what came first.

As a matter of interest, I see very litte / no interest in “one-shot”/multivibrator variations. Seems that either all on the forum know how to write sketches like that, OR I am the only dummy OR nobody sees the need for them…

Just interested in your thoughts/comments…

Newbie10:

I have found the // very useful to temporarily erase something to test how it compiles or works in hardware. That way one can also SEE what you did last time; e.g. often I will copy/paste a line and place // at the start of the upper line while I wiggle/twiggle the 2nd line so I always know what came first.

I agree, but the // stays valid until the end of the line. /* */ is used to comment/disable a specific section of the line, or across multiple lines.

My mind is not working very wel to analyse code. So I will need some time to respond on the one-shot idea.

Yes, and OK with the // thing : I use that too! Very useful when experimenting.

The “one-shot” is little more than an extension of the classic “debounce” (with variations in Arduino-language), except that implementation sometimes gets tricky, i.e. making it do what YOU (or I) want it to. In my case I wanted to delay the alarm relay by 4 seconds to avoid high current during a motor’s start-up.

I have some experience in making harware one-shots using NAND-gates with hysteresis, for example, using caps, resistors and diodes to achieve almsot any variation, e.g. rising/falling edge detect, delay-on/off, delay-off/on, pulse extender…

But translating them into software is a horse with a different colour.

Just a thought in response to yours …

It’s probably just that one-shots are not that commonly needed in firmware. Even switch debouncing can be done inside a standard timed main() loop.

Here is pseudocode for a (retriggerable) one shot:

timer = 0
triggered = false
oneShotActive = false

LOOP:
    if (triggered)
    {
        triggered = false;
        timer = ONE_SHOT_TIMEOUT
        oneShotActive = true
    }
    else if (timer > 0)
    {
        timer--
    }
    else if (timer == 0)
    {
        oneShotActive = false
    }
ENDLOOP:

[edit: fixed a bug]