Beginner here. Just got my kit today. I have searched this forum as well as a slew of other sites and I am not able to find a sketch for a "RETRIGGERABLE ONE-SHOT TIMER". I have a push button INPUT circuit to pin 2 and an LED OUTPUT circuit from pin 13. I want the LED to come on when I push the button and stay ON for 10 seconds. If I push the button again, before that 10 seconds is up, I want it to stay lit 10 seconds after my last press of the button. When I say "push the button", I dont mean "hold it down", I mean like you would click a mouse button (finger down/up). Thank you so much for your help!
I believe you will find something close to what you want in the Arduino cookbook. It would probably be called something else. Why not draw a flow chart and when you get that the code should be easy. Try by starting a countdown timer, when it is not zero turn on your LED, each time you press the button load the timer with the delay time. Take a look at some of the examples that come with the IDE.
Have a look at state change detection, which shows you how to see that a button has become newly pressed. (That 21st century tutorial is an update which uses the built-in pullup resistors.)
Ignore the part about incrementing the counter- you don't need that.
Then capture the time of the new press into a variable say buttonPressedAt using millis(), and then each time through loop() check in an if() to see if the new (ever increasing) millis() - buttonPressedAt >= 10000 (10 seconds in milliseconds).
Something like:
//pins
const uint8_t pinLED = LED_BUILTIN;
const uint8_t pinTrigger = 2;
//variables
uint8_t trigLast; //holds last trigger input state
uint32_t timeLED; //times the LED on period
void setup()
{
//set the trigger as input pullup (switch must connect pin to GND when closed)
pinMode( pinTrigger, INPUT_PULLUP );
//establish "last" state for next trigger switch read
trigLast = digitalRead( pinTrigger );
//set LED pin as output
pinMode( pinLED, OUTPUT );
}//setup
void loop()
{
uint32_t timeNow = millis(); //get the millis() time now
//if the LED is on now (pin is high)
if( digitalRead( pinLED ) == HIGH )
{
//has the LED been on for 10-seconds?
if( (timeNow - timeLED) >= 10000ul )
//yes; turn it off
digitalWrite( pinLED, LOW );
}//if
//call ReadTrigger once per loop (so very fast)
//we only actually read the trigger once every
//50mS so most times we just come back from ReadTrigger
//without actually reading the pin
ReadTrigger();
}//loop
void ReadTrigger( void )
{
//static variable stays around even after ReadTrigger ends
//lets us keep track of the time since the last trigger read
static uint32_t timeReadTrigger=0;
//get the millis time now
uint32_t timeNow = millis();
//read the trigger input once every 50 milliseconds
if( (timeNow - timeReadTrigger) >= 50ul )
{
//going to read switch; save the time now so we can read
//it again 50mS from now etc...
timeReadTrigger = timeNow;
//read the pin
uint8_t trigNow = digitalRead( pinTrigger );
//does it read differently from last time?
if( trigNow != trigLast )
{
//yes; save this new value as the last
trigLast = trigNow;
//is the new reading low (so pin went from HIGH to LOW)?
if( trigNow == LOW )
{
//yes; turn on the LED and...
digitalWrite( pinLED, HIGH );
//...remember the time we turned it on
//loop() will use this time to see if 10-sec
//has elapsed
//every press we set this to the current millis
//and so will act as a "retrigger"
timeLED = timeNow;
}////if trigger pin is low now
}//if trigger now doesn't equal trigger last
}//if 50mS has elapsed
}//ReadTrigger
From an older post..
#include <timeObj.h>
#include <mechButton.h>
const int trigger = 2; //Pin 2 as trigger pin.
const int output = 13; //Pin 13 as Output pin.
bool LEDOn;
mechButton trigButton(trigger);
timeObj LEDTimer(10.0 * 1000.0,false); // Create a 10 sec timer.
void setup(void) {
LEDOn = false;
pinMode(output, OUTPUT);
}
void loop(void) {
if (!trigButton.trueFalse()) { // If the button has been pressed..
digitalWrite(output, HIGH); // Turn on your LED
LEDTimer.start(); // Start your LED timer.
LEDOn = true; // Make a note of it.
while(!trigButton.trueFalse()) { // While the button is still being held..
if (LEDTimer.ding()) { // If the timer expires while button is held down.
digitalWrite(output,LOW); // Shut the damn thing off anyway.
LEDOn = false; // Make a note of it.
}
}
}
if (LEDOn && LEDTimer.ding()) { // If the LED is on AND timer has expired..
digitalWrite(output,LOW); // Shut off the LED.
LEDOn = false; // Make a not of it.
}
}
If you want to try this you'll need the LC_baseTools library from the library manager.
Good luck!
-jim lee
jimLee:
From an older post..#include <timeObj.h>
#include <mechButton.h>
const int trigger = 2; //Pin 2 as trigger pin.
const int output = 13; //Pin 13 as Output pin.
bool LEDOn;
mechButton trigButton(trigger);
timeObj LEDTimer(10.0 * 1000.0,false); // Create a 10 sec timer.
void setup(void) {
LEDOn = false;
pinMode(output, OUTPUT);
}
void loop(void) {
if (!trigButton.trueFalse()) { // If the button has been pressed..
digitalWrite(output, HIGH); // Turn on your LED
LEDTimer.start(); // Start your LED timer.
LEDOn = true; // Make a note of it.
while(!trigButton.trueFalse()) { // While the button is still being held..
if (LEDTimer.ding()) { // If the timer expires while button is held down.
digitalWrite(output,LOW); // Shut the damn thing off anyway.
LEDOn = false; // Make a note of it.
}
}
}
if (LEDOn && LEDTimer.ding()) { // If the LED is on AND timer has expired..
digitalWrite(output,LOW); // Shut off the LED.
LEDOn = false; // Make a not of it.
}
}
If you want to try this you'll need the LC_baseTools library from the library manager. Good luck! -jim lee
Thank you SO MUCH, Jim Lee!!! This is precisely what I needed! It works perfect! Now, for my own good, I will study this sketch to see why it works.
You are very welcome!
-jim lee
You haven't said how you much already know about programming.
hm both code-examples are medium advanced. They are a possability to learn. But for a real newbee they jump in
somewhere in the middle and leave out important basics.
If you are very new to programming
Take a look into this tutorial:
It is easy to understand and has a good mixture between explaining important concepts and example-codes to get you going. So give it a try and report your opinion about this tutorial.
best regards Stefan
@OP
1. Please, check if the following sketch works as soft based re-triggerable one shot for 10-sec pulse width. This sketch has used MillisCounter for the time delay.
void setup()
{
pinMode(2, INPUT_PULLUP); //with internal pull-up
pinMode(13, OUTPUT);
}
void loop()
{
if (digitalRead(2) == LOW) //cjeckig if K1 connected at DPin-2 is pressed
{
digitalWrite(13, HIGH);
unsigned long presentMillis = millis();
while (millis() - presentMillis < 10000) //checking if 10-sec is over or not
{
if (digitalRead(2) == LOW) //checking if DPin-2 is at LOW state
{
presentMillis = millis() + 10000UL; //reload 10-sec
}
}
digitalWrite(13, LOW);
}
}
2. Please, check if the following sketch works as soft based re-triggerable one shot for 4-sec pulse width. This sketch has used TC1 of the MCU for the time delay.
void setup()
{
pinMode(2, INPUT_PULLUP); //with internal pull-up
pinMode(13, OUTPUT);
//---------------------
TCCR1A = 0x00; //upcounting mode of TC1
TCCR1B = 0x00; //TC1 is STOP
}
void loop()
{
if (digitalRead(2) == LOW) //cjeckig if K1 connected at DPin-2 is pressed
{
startTimer(); //for 4-sec
while (bitRead(TIFR1, 0) != HIGH) //checking if 4-sec is over
{
if (digitalRead(2) == LOW) //checking if DPin-2 is at LOW state
{
startTimer(); //re-trigger 4-sec Timer; load TCNT1 on the fly
}
}
bitSet(TIFR1, 0); //TOV1 is clear
stopTimer();
}
}
void startTimer()
{
TCNT1 = 0x0BDC; //4-sec time delay
TCCR1B = 0x05;
digitalWrite(13, HIGH);
}
void stopTimer()
{
TCCR1B = 0x00;
digitalWrite(13, LOW);
}
I'm gonna reply with the same example that I replied with on another thread since it's the same question but with an LED and a button instead of a motor and a PIR sensor.
Use a simple state machine such as this.
#define RUN_TIME_MS 30000
#define TIMEOUT_MS 1000
enum CurrentMotorTaskState {
READY,
RUNNING,
TIMEOUT
};
static uint8_t trigger = 0;
void motorTask(void) {
static enum CurrentMotorTaskState currentState = READY;
static uint32_t t = 0;
switch (currentState) {
case READY:
if (trigger) {
t = millis();
// Start the motor here
currentState = RUNNING;
}
break;
case RUNNING:
if (millis() - t >= RUN_TIME_MS) {
// Stop the motor here
t += RUN_TIME_MS;
currentState = TIMEOUT;
}
break;
case TIMEOUT:
if (millis() - t >= TIMEOUT_MS) {
currentState = READY;
}
break;
}
}
void sensorTask(void) {
// Read the sensor value and set the trigger variable
trigger = 1;
}
void setup() {
// Initialize stuff here
}
void loop() {
sensorTask();
motorTask();
}
To extend the amount of time the LED is on you would continuously increase the 't' variable while the state is running. To detect an actual press you should use a debouncing technique.
Hey guys,
while-loops are blocking code.
if you post example-code you should go beyond this unspeakably terrible examples of the Arduino-IDE.
You should introduce newbees to non-blocking timing right from the start.
best regards Stefan
StefanL38:
Hey guys,while-loops are blocking code.
if you post example-code you should go beyond this unspeakably terrible examples of the Arduino-IDE.
You should introduce newbees to non-blocking timing right from the start.
best regards Stefan
I agree with this. While the program the OP seems to have decided to use, technically does what it is supposed to do, it would stop the rest of the program from doing anything if the button is held down.
GolamMostafa:
@OP1. Please, check if the following sketch works as soft based re-triggerable one shot for 10-sec pulse width. This sketch has used MillisCounter for the time delay.
void setup()
{
pinMode(2, INPUT_PULLUP); //with internal pull-up
pinMode(13, OUTPUT);
}
void loop()
{
if (digitalRead(2) == LOW) //cjeckig if K1 connected at DPin-2 is pressed
{
digitalWrite(13, HIGH);
unsigned long presentMillis = millis();
while (millis() - presentMillis < 10000) //checking if 10-sec is over or not
{
if (digitalRead(2) == LOW) //checking if DPin-2 is at LOW state
{
presentMillis = millis() + 10000UL; //reload 10-sec
}
}
digitalWrite(13, LOW);
}
}
**2.** Please, check if the following sketch works as soft based re-triggerable one shot for 4-sec pulse width. This sketch has used TC1 of the MCU for the time delay.
void setup()
{
pinMode(2, INPUT_PULLUP); //with internal pull-up
pinMode(13, OUTPUT);
//---------------------
TCCR1A = 0x00; //upcounting mode of TC1
TCCR1B = 0x00; //TC1 is STOP
}
void loop()
{
if (digitalRead(2) == LOW) //cjeckig if K1 connected at DPin-2 is pressed
{
startTimer(); //for 4-sec
while (bitRead(TIFR1, 0) != HIGH) //checking if 4-sec is over
{
if (digitalRead(2) == LOW) //checking if DPin-2 is at LOW state
{
startTimer(); //re-trigger 4-sec Timer; load TCNT1 on the fly
}
}
bitSet(TIFR1, 0); //TOV1 is clear
stopTimer();
}
}
void startTimer()
{
TCNT1 = 0x0BDC; //4-sec time delay
TCCR1B = 0x05;
digitalWrite(13, HIGH);
}
void stopTimer()
{
TCCR1B = 0x00;
digitalWrite(13, LOW);
}
can you explain where the 4 seconds comes from in your code. Thanks
@GolamMostafa
where the 4sec delay comes from?
regards
My tutorial How to write Timers and Delays in Arduino covers one shot and repeating and re-triggering timers
abdelhmimas:
where the 4sec delay comes from?
1. Architecture of TC1 (Timer/Counter 1) Module of ATmega328P MCU.
Figure-1:
2. ** Working Principle of TC1/TCNT1 of Fig-1** and the calculation of 4 sec time delay
(1) TC1/TCNT1 is working as Timer-1 as its driving clock (clkTC1) is coming from internal oscillator. The value of clkTC1 is: 16x1016/1024 = 15625 Hz.
(2) The TOV1 flag (TC1 Overflow Flag) assumes LH-state when the content of TCNT1 turns from all 1s to al 0s.
(3) If TCNT1 is initialized to 0 (0x0000), then its count sequence is: 0x0000 (0) --> 0x0001 (1) ----> 0xFFFFF (all 1s = 65535) ---> 0x10000 (all 0s)with an overflow bit which enters into TOV1 flag.
(4) If we initialize TCNT1 with an initial value of 0x0000 (0), the TOV1 will assume LH-state after counting 65 536 (0x10000) pulses. The time delay would be: 65536/15625 = 4.194304 sec.
(5) In order to get an exact 4 sec time delay, we must preset TCNT1 with some non-zero initial value (n) so that TOV1 assumes LH-state once TCNT1 has finished counting 4x15625 = 62,500 pulses.
(6) Let us find the value of n of Step-2(5):
Total_Count = preset_count + count_for_4sec
0x10000 = n + 4x15625
==> n = 0x10000 - 4x15625
==> n = 65536 - 62500 = 3036
==> n = 0x0BDC in hex base
3. Codes to check that 4-sec time delay has elapsed.
TCCR1A = 0x00; //TC1 is in up counting mode
TCCR1B = 0x00; //TC1 is at STOP condition
TCNT1 = 0x0BDC; //TCNT1 is loaded with a preset value for 4 sec time delay
TCCR1B = 0x05; //START TC1 with clkTC1 = 15625 Hz; divide by 1024
while (TOV1 != HIGH)
{
; //check and wiat until TOV1 is set; means 4 sec time has elapsed or not
}
bitSet(TIFR1, 0); //TOV1 flag is cleared
TCNT1 = 0x0BDC; //reload CNT1 with preset value for 4 sec time delay/code]
Note: If you want to achieve 10 sec time delay using TC1, then you have to play with "System Clock Prescaler"; in that case, all system functions like delay() function, millis() function and etc. will not be functioning correctly.
@golammostafa
Nice.
Would be easier if you set the timer counter in CTC mode, with the exact 4 seconds value loaded to the compare register.
In this case, you will have the compare interrupt routine instead of overflow.
You will not need to worry about the preset value.
Thanks
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.