Hello,
I am trying to program a couple of features for a project.
First feature would be triggering the alarm after X time has passed
(for now just to test the concept I have put every 10 seconds led
that represents alarm turns on, later it will be buzzer that turns on every x hours).
Second feature would be resetting the alarm by holding a button pressed for 3 seconds (in this case resetting means turning off LED and starting the alarm count again, later it will mean turning off buzzer and continuing the rest of code until alarm turns back on).
Since my goal is to make when alarm is on no other code should be executed, only thing that should happen is for LED (buzzer) until the button is pressed for 3 seconds then it should go back to regular loop.
I am having some trouble in thinking of proper way to write the code, should I trigger some kind of interrupt for alarm or avoid that?
So far this is what I have got but I cant reset the alarm:
const int LED_PIN = 13;
const int rfa = 7;
const long BLINK_INTERVAL = 10000;
bool alarmState = false;
int startPressed = 0;
int holdTime = 0;
int prevState = LOW;
bool buttonReleased = false;
unsigned long previousMillis = 0;
unsigned long currentMillis;
void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(rfa, INPUT);
}
void loop() {
if(alarmState == false) {
currentMillis = millis();
digitalWrite(LED_PIN, LOW);
if (currentMillis - previousMillis >= BLINK_INTERVAL) {
alarmState = true;
}
}
else if (alarmState == true) {
digitalWrite(LED_PIN, HIGH);
int state = digitalRead(rfa);
if(state != prevState)
{
if (state == HIGH) {
buttonReleased = false;
startPressed = millis();
}
else {
buttonReleased = true;
}
prevState = state;
}
if (buttonReleased == true) {
holdTime = millis() - startPressed;
if (holdTime >= 3000)
{
digitalWrite(LED_PIN, LOW);
alarmState = false;
previousMillis = currentMillis;
}
buttonReleased = false;
startPressed=0;
}
}
}
I can't look closely right now, but I note you have not made any use of the serial monitor.
Put
Serial.begin(115200);
in your setup() function.
Then sprinkle Serial.print() liberally about your code, to check the values of key variables and to confirm that they inform the flow of your code properly.
shouldn't the Button be checked when alarmState is both set and cleared?
since alarmState is false by default, the BLINK_INTERVAL needs to timeout before the else if where the button is check is invoked
since there are 2 timers, it would be clearer if the flags were named for the timer: alarmTimer, buttonTimer, possibly set to the time period
buttons are typically connected between the pin and ground, the pin configured as INPUT_PULLUP to use the internal pullup resistor which pulls the pin HIGH and when pressed, the button pulls the pin LOW.
The button is actually rf receiver that can be programmed to work as toggle or momentary button output (meaning when I press a button on a remote, rf receiver gives 5v on its output either while button is pressed or until button is pressed second time).
What happens is this:
First it prints out all 1s until 10 seconds pass, then it prints 2 and then all 3s. When I press button for reset it prints out 4 then 3s again until I release the button 3-4 seconds after at which point it prints out 5 6 8 and back to 3s. So basically it skips over if loop where I check if holdTime is greater out than 3 seconds.
Even if you are fully 100 percent confident, it always makes sense to leave as many things out as you can whilst struggling working on a part that can be separately perfected.
Ok I have tested a bit more and alarm is actually being reseted now (led goes off) butfor very very short time (not even few seconds) before it turns on again.
Ill try gcjr code in a minute. As for rf receiver I currently dont have a press button at my place so I work with rf but I have tested it with multimeter and code with just it and led and works fine so far.
P.S.
The time between me resetting alarm and it turning on again seems to be different every time, probably depending on at what time I let the button go.
if (alarmSet) {
Serial.println ("alarm reset");
digitalWrite (LED_PIN, LOW); // otherwise the LED gets randomly left on or off
}
Second, there does not appear to be any delay in the reset. @tuadru told us
resetting the alarm by holding a button pressed for 3 seconds
and so far "a button" is the same button that raises the alarm.
Lastly, it seems that alarm condition reset is only accomplished with a brief stab of the button - dwelling on the button reinitiates the alarm sequence: a long period of the LED being on, followed by blinking.
Now my own version doesn't work at all and it is time to go to the beach. , .
Maybe I didnt explain it properly @gcjr , I care about button state only when alarm is triggered and use it only to reset/disable the alarm. I dont want to check button state when alarmState is false. I have tried the simulator you have sent @alto777 , have put pushbutton that is pulled down so it simulates my rf receiver that gives HIGH when button is pressed. So far it is behaving same as irl, I manage to reset the alarm but it goes back to being triggered much faster than 10 seconds. Also hope your missus didn't have to wait too long
Eureka! Code works now, just had to move currentMillis= millis(); outside of if loop.
const int LED_PIN = 13;
const int rfa = 7;
const long ALARM_TIMER = 10000;
const long BUTTON_TIMER = 3000;
bool alarmState = false;
int startPressed = 0;
int holdTime = 0;
int prevState = LOW;
bool buttonReleased = false;
unsigned long previousMillis = 0;
unsigned long currentMillis;
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
pinMode(rfa, INPUT);
}
void loop() {
currentMillis = millis();
if(alarmState == false) {
Serial.println("1");
digitalWrite(LED_PIN, LOW);
if (currentMillis - previousMillis >= ALARM_TIMER) {
alarmState = true;
Serial.println("2");
}
}
else if (alarmState == true) {
digitalWrite(LED_PIN, HIGH);
Serial.println("3");
int state = digitalRead(rfa);
if(state != prevState)
{
if (state == HIGH) {
buttonReleased = false;
Serial.println("4");
startPressed = millis();
}
else {
buttonReleased = true;
Serial.println("5");
}
prevState = state;
}
if (buttonReleased == true) {
Serial.println("6");
holdTime = millis() - startPressed;
if (holdTime >= BUTTON_TIMER)
{
Serial.println("7");
digitalWrite(LED_PIN, LOW);
alarmState = false;
previousMillis = currentMillis;
}
buttonReleased = false;
startPressed=0;
Serial.println("8");
}
}
}
Now only change I want to make is actually to reset alarm as soon as button is pressed for 3 seconds without needing to pull the finger off the button.
Actually when alarmState is false (which is by default in the begining), the alarm (which at this time is LED) is off. Then every 10 seconds alarm should be triggered (LED on) and it can only be turned off/resetted by pressing the button and holding it down for 3 seconds. At this point only thing I want to change from my last posted code is for alarm to be turned off after button was held down for 3 seconds (without the need for the button to be released, just as soon as it was held down for 3 seconds).
Because at first I wanted to register how long button was pressed and compare that to 3 seconds and if its greater than 3 then alarm should be turned off. But now thinking more about it I think its better if I just turn off alarm once button was pressed for 3 seconds and not register when it was released (there will be no need for that then.
I don't know which part of code is confusing so I'll try to explain again:
I track whether the alarm is on or off with alarmState variable.
When the variable is false it means it is off, when it's true then it is on.
Alarm in this case is represented with LED light which is off when alarm is off (hence digitalWrite(LED_PIN, LOW);). Alarm should be triggered every 10 seconds (hence the if loop where I check if 10 seconds have passed and then I put alarmState as true). Now when alarm is triggered, LED is turned ON. Only way to turn off the alarm is by pressing the button, holding it down for 3 seconds or more and then releasing it. Now I want to change the last part so that the button doesn't need to be released but as long as it was held down for 3 seconds it should turn off the alarm and LED light. I hope it is more clear now.