Arduino: LCD won't turn off - arduino

a few days ago I started working with the Arduino. I've set up a small project with a DHT22 to read the temperature and humidity and write it to an LCD. That works without a problem. Now I want to only turn on the backlight of the LCD when I press a button. That mostly works too:
void loop() {
buttonState = digitalRead(BUTTONPIN);
currentMillisScreen = millis();
if (buttonState == HIGH) {
screenOn = true;
lcd.backlight();
}
// DHT22 related code in here
if (currentMillisScreen - previousMillisScreen >= SCREEN_ON_TIME) {
previousMillisScreen = currentMillisScreen;
screenOn = false;
lcd.noBacklight();
}
}
The problem is that with this code is that the Backlight won't always stay on for exactly 5 seconds. I thought putting the currentMillisScreen = millis() in the following if-Statement would fix it:
if (buttonState == HIGH) {
currentMillisScreen = millis();
screenOn = true;
lcd.backlight();
}
But if I do that, the Backlight won't turn off again and I don't understand why.

You are not updating currentMillisScreen in the loop and that is your problem. You just need to find different between currentTime (equal to millis()) and previous time that light turned on and if it reaches above the threshold then turn it off. Something like this:
#define SCREEN_ON_TIME 5000
bool screenOn = false;
void setup()
{
//setup
}
void loop()
{
buttonState = digitalRead(BUTTONPIN);
if (buttonState == HIGH)
{
previousMillisScreen = millis();
lcd.backlight();
screenOn = true;
}
// DHT22 related code in here
// if time passed above SCREEN_ON_TIME after we turned on light
if ((screenOn) && (millis() - previousMillisScreen >= SCREEN_ON_TIME))
{
lcd.noBacklight();
screenOn = false;
}
}

Related

Arduino interrupt button calls multiple ISRs

For a project I'm using an Arduino Mega2560 to control a couple of stepper motors with the AccelStepper library. It's the first time I'm using Arduino and I'm writing everything in Arduino IDE 2.0 (I also tried it with IDE 1.8 but no change). It's coming along quite nicely and it's a lot of fun! Everything seems to work as intended. Except for 1 thing.
I'm using 4 buttons to trigger certain events in my code, using the interrupt function. I'm doing this because the accelStepper library asks a lot of proccesing from the arduino and I need as many steps/sec as I can get. When 1 of the interrupts is activated it somehow calls another with it. I've removed everything from the code except the interrupt part to see if just the interrupts would work, but I still have the same issue. With this code I would expect to see a print in the serial of the button I pressed. However, when I press button one it sometimes prints both button 1 and button 2. When I press button 2 it always calls button 1 as well. Sometimes button 1 is printed first, sometimes button 2 is printed first. When I press button 3, button 2 is always called and when I press button 4, button 3 is always called.
As you can see in the code, I'm using port 18 through 21 as interrupt ports and their grounds are all connected to the same GND port on the Arduino. I tried disconnecting all the grounds and only connected button 1 with the Arduino GND. But somehow it still triggers button 2 as long as the cable of the button is still plugged into pin 19. Even though the ground of button 2 is not connected.
What am I doing wrong? Did I misunderstand how the interrupts with input_pullup works? Or am I doing something wrong in my code?
I'm running out of ideas so any help is appreciated!
// Define pins numbers
const int button1 = 18;
const int button2 = 19;
const int button3 = 20;
const int button4 = 21;
// Define variables
volatile bool button1Pressed = false;
volatile bool button2Pressed = false;
volatile bool button3Pressed = false;
volatile bool button4Pressed = false;
float timeTrigger1 = 0;
float timeTrigger2 = 0;
float timeTrigger3 = 0;
float timeTrigger4 = 0;
void setup() {
Serial.begin(9600);
Serial.println("Startup begins");
pinMode(button1, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(button1), interrupt1, FALLING);
pinMode(button2, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(button2), interrupt2, FALLING);
pinMode(button3, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(button3), interrupt3, FALLING);
pinMode(button4, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(button4), interrupt4, FALLING);
Serial.println("Startup finished");
}
void loop() {
if (button1Pressed) {
Serial.println("button 1 was pressed");
button1Pressed = false;
}
if (button2Pressed) {
Serial.println("button 2 was pressed");
button2Pressed = false;
}
if (button3Pressed) {
Serial.println("button 3 was pressed");
button3Pressed = false;
}
if (button4Pressed) {
Serial.println("button 4 was pressed");
button4Pressed = false;
}
}
void interrupt1() {
if (millis() - timeTrigger1 >= 500) {
timeTrigger1 = millis();
button1Pressed = true;
}
}
void interrupt2() {
if (millis() - timeTrigger2 >= 500) {
timeTrigger2 = millis();
button2Pressed = true;
}
}
void interrupt3() {
if (millis() - timeTrigger3 >= 500) {
timeTrigger3 = millis();
button3Pressed = true;
}
}
void interrupt4() {
if (millis() - timeTrigger4 >= 500) {
timeTrigger4 = millis();
button4Pressed = true;
}
}
EDIT: checking the button state once the ISR is called did the trick. Like the code below.
void interrupt1() {
if (millis() - timeTrigger1 >= 500 && digitalRead(button1)==LOW) {
timeTrigger1 = millis();
button1Pressed = true;
}
}

Why is my single button LED light control only working sometimes?

I just started getting into Arduino and I put together a very simple led control with one button to change the on and off state. When I push the button the light will come on, but it will only stay on about 50% of the time (so I have to push it multiple times until it actually stays on), and The same thing happens when I try to turn it off.
Is there some problem with my code? Or is it likely to be a wiring issue?
//define variables
int ledPin = 5;
int btnOnPin = 9;
bool isItOn = false;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(btnOnPin, INPUT_PULLUP);
}
void loop() {
if(digitalRead(btnOnPin) == LOW)
{
if(isItOn == false)
{
digitalWrite(ledPin, HIGH);
isItOn = true;
}
else if (isItOn == true)
{
digitalWrite(ledPin, LOW);
isItOn = false;
}
}
}
The button is connected to ground and pin9, the led is connected to ground, and pin5 through a 220ohm resistor.
This should be super simple, but for some reason I can't get it to work properly.
Thanks for any help
try putting the arduiton to sleep for a few milli seconds after changing its val
void loop() {
if(digitalRead(btnOnPin) == LOW)
{
if(isItOn == false)
{
digitalWrite(ledPin, HIGH);
isItOn = true;
}
else if (isItOn == true)
{
digitalWrite(ledPin, LOW);
isItOn = false;
}
sleep(K);
}

Problem with interruptions in Arduino Uno

I work with interruptions in Arduino UNO. In this project, I want to when the Door is opened the LED blink 10 times, and when the door is closed again, stop blinking the LED and exit the function. But in this code the LED only turn on and off once and it does not flash again.
My other problem is that, when the door is opened or closed, sometimes the opened or closed word appears several times in the Series monitor.
const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin
volatile int SensorState = LOW; // 0 close - 1 open wwitch
void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}
void DoAction()
{
SensorState = digitalRead(DOOR_SENSOR);
if (SensorState == HIGH) {
Serial.println("Opened");
blinkLED(10, 500);
}
else {
Serial.println("Closed");
}
}
void blinkLED(int repeats, int time)
{
for (int i = 0; i < repeats; i++) {
if (SensorState == HIGH) {
digitalWrite(LED_Red, HIGH);
delay(time);
digitalWrite(LED_Red, LOW);
delay(time);
}
else
return;
}
}
void loop()
{
}
You can't simply put a delay() on an interrupt's function. You need to just set a flag when the door is opened and based on that start blinkLED inside the main loop.
I also recommend you to use millis() function for an unblocking delay inside blinkLED function (e.g when you want to stop blinking while the door is closed).
const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin
// flag to check door is opened
volatile bool isOpened = false;
//flag to check already blinked
volatile bool isBlinked = false;
void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}
void DoAction()
{
if (digitalRead(DOOR_SENSOR) == HIGH)
{
//Serial.println("Opened");
isOpened = true;
}
else
{
isOpened = false;
isBlinked = false;
//Serial.println("Closed");
}
}
void blinkLED(int repeats, int time)
{
byte LEDState = LOW;
unsigned long delay_start = millis();
for (int i = 0; i < 2 * repeats; i++)
{
//Toggle LED state
if (LEDState == HIGH)
LEDState = LOW;
else
LEDState = HIGH;
// set value
digitalWrite(LED_Red, LEDState);
// some unblocking delay
while (millis() - delay_start < time)
{
// return if door is closed
if (!isOpened)
{
// turn off LED
digitalWrite(LED_Red, LOW);
return;
}
}
delay_start = millis();
}
isBlinked = true;
}
void loop()
{
// Check isBlinked beacue don't want to blink again until door is closed
if (isOpened && !isBlinked)
{
blinkLED(10, 500);
}
}

Arduino Multi-tasking

I'm trying to see if I can combine tasks that are currently being handled by two separate Arduino Unos onto a single Uno. I was shown the Adafruit guide to "multi-tasking" on the Arduino (Link) and thought I would give it a try.
I feel like I'm missing something really obvious, but my code is just not working...
I'm controlling a series of solenoids. They need to each act based on individual timing. I created a Solenoid class that handles telling the solenoid when to start and then monitor when to close it. For the life of me I can't see where my error is, but I never wind up satisfying my end condition.
class Solenoid {
//Class Variables
int solenoidPin;
long chargeTime;
long ventTime;
bool started = false;
unsigned long startMillis;
unsigned long endMillis;
unsigned long previousMillis;
int solenoidState;
//Constructor
public:
Solenoid(int pin, long charge, long vent) {
solenoidPin = pin;
pinMode(solenoidPin, OUTPUT);
chargeTime = charge;
ventTime = vent;
solenoidState = LOW;
previousMillis = 0;
}
void Start() {
Serial.println("Start called");
started = true;
}
void Update() {
//Check to see if it is time to change the state of the solenoid
unsigned long currentMillis = millis();
Serial.println("Update");
if((started == true) && (currentMillis-previousMillis <= chargeTime)) {
//Run
Serial.print("Run: Charge Time=");
Serial.print(chargeTime);
Serial.print(" current-previous=");
Serial.println(currentMillis-previousMillis);
previousMillis = currentMillis;
} else if ((started == true) && (currentMillis-previousMillis >= chargeTime)){
//Stop
Serial.println("Stop");
}
}
};
//Setup the solenoids
Solenoid solenoid1(13, 70, 70);
void setup() {
Serial.begin(115200);
Serial.println("Ready");
solenoid1.Start();
solenoid1.Update();
solenoid1.Update();
solenoid1.Update();
solenoid1.Update();
solenoid1.Update();
}
I'm just running everything in setup so I can see a few runs.
Can you help me with my clearer stupid mistake?
It's possible that the entire setup() void is executing faster than 70ms, meaning you never get to you end position before the 5 calls to solenoid1.Update() complete.
Try this:
class Solenoid {
//Class Variables
int solenoidPin;
long chargeTime;
long ventTime;
bool started = false;
unsigned long startMillis;
unsigned long endMillis;
unsigned long previousMillis;
int solenoidState;
//Constructor
public:
Solenoid(int pin, long charge, long vent) {
solenoidPin = pin;
pinMode(solenoidPin, OUTPUT);
chargeTime = charge;
ventTime = vent;
solenoidState = LOW;
previousMillis = 0;
}
void Start() {
Serial.println("Start called");
started = true;
}
void Update() {
//Check to see if it is time to change the state of the solenoid
unsigned long currentMillis = millis();
Serial.println("Update");
if((started == true) && (currentMillis-previousMillis <= chargeTime)) {
//Run
Serial.print("Run: Charge Time=");
Serial.print(chargeTime);
Serial.print(" current-previous=");
Serial.println(currentMillis-previousMillis);
previousMillis = currentMillis;
} else if ((started == true) && (currentMillis-previousMillis >= chargeTime)){
//Stop
Serial.println("Stop");
}
}
};
//Setup the solenoids
Solenoid solenoid1(13, 70, 70);
void setup() {
Serial.begin(115200);
Serial.println("Ready");
solenoid1.Start();
}
void loop(){
solenoid1.update()
}
The rest looks fine to me; if you still have issues try using explicit variable declarations instead of your constructor to troubleshoot if that's the issue.
Turns out I was erasing my own counter by setting previousMillis = currentMillis. Once I killed that, it started working. I added some other functionality since then, like a delayed start, but this is primarily the same code.
void Update() {
//Check to see if it is time to change the state of the solenoid
unsigned long currentMillis = millis();
if((started == true) && (currentMillis - startMillis <= startDelay)) {
//keep waiting
Serial.println("Waiting");
} else if((started == true) && (currentMillis - startMillis < (chargeTime + startDelay) )) {
//Run
Serial.print("Run ");
Serial.println(currentMillis - startMillis);
digitalWrite(solenoidPin, HIGH);
} else if ((started == true) && (currentMillis - startMillis >= (chargeTime + startDelay) )){
//Stop
Serial.print("Stop ");
Serial.println(currentMillis - startMillis);
digitalWrite(solenoidPin, LOW);
started = false;
}
}

Use a DS3231 RTC module and Arduino to fire function every other day

I'm attempting to create a timer which reminds me to do something ever other day, however it seems that my options with the DS3231 module allows me to set an hour or a day of the week. Unfortunately neither option is good enough (if only there were 8 days in a week) and i'm at a loss on how to tell it to fire every other day.
I considered the idea of setting a 'not_today' variable which will probably work but that has the downside of relying on the arduino and not the RTC which means if it loses power then that variable will reset.
It looks like the DS3231's alarm functionality doesn't really have this option and any code-based solution will have the aforementioned power-loss problems.
Is there an RTC module which can do what I need it to do?
User #RamblinRose pointed me in the direction of EEPROM writing and reading which I wasn't aware was possible. This solved my issue. Here is the full code for anyone else coming here and wanting a more comprehensive answer:
#include <DS3231.h>
#include <EEPROM.h>
// Init the DS3231 using the hardware interface
DS3231 rtc(SDA, SCL);
Time t;
bool active = false;
void setup()
{
// Setup Serial connection
Serial.begin(115200);
// Initialize the rtc object
rtc.begin();
pinMode(12, OUTPUT);
pinMode(11, INPUT_PULLUP);
// The following lines can be uncommented to set the date and time
// rtc.setDOW(MONDAY); // Set Day-of-Week to SUNDAY
// rtc.setTime(15, 51, 0); // Set the time to 12:00:00 (24hr format)
rtc.setDate(14, 9, 2017); // Set the date to January 1st, 2014
}
int blinker(int state = 1) {
if(state == 1) {
if (active == true) {
digitalWrite(12, HIGH); // turn the LED on (HIGH is the voltage level)
delay(500); // wait for a second
digitalWrite(12, LOW); // turn the LED off by making the voltage LOW
delay(500);
buttonCheck();
}
}
}
int buttonCheck() {
if(digitalRead(11) == 0) {
active = false;
blinker(0);
}
}
void loop()
{
t = rtc.getTime();
int hour = t.hour;
int min = t.min;
int sec = t.sec;
// // Send time to serial monitor (for debugging)
// Serial.print(hour);
// Serial.print(":");
// Serial.print(min);
// Serial.println(" ");
// Put there different timers in here for demo purposes
// Set activation time
if(hour == 13 && min == 31 && sec == 00) {
if(EEPROM.read(0) == 0) {
active = true;
EEPROM.write(0, 1);
Serial.println("Not run recently, activating");
} else {
active = false;
EEPROM.write(0, 0);
Serial.println("Run recently, skipping this one");
}
}
if(hour == 13 && min == 35 && sec == 00) {
if(EEPROM.read(0) == 0) {
active = true;
EEPROM.write(0, 1);
Serial.println("Not run recently, activating");
} else {
active = false;
EEPROM.write(0, 0);
Serial.println("Run recently, skipping this one");
}
}
if(hour == 13 && min == 45 && sec == 00) {
if(EEPROM.read(0) == 0) {
active = true;
EEPROM.write(0, 1);
Serial.println("Not run recently, activating");
} else {
active = false;
EEPROM.write(0, 0);
Serial.println("Run recently, skipping this one");
}
}
blinker();
delay(1000);
}

Resources