Following configuration:
- Arduino UNO R3
- Real Time Clock DS1307RTC
- LCD1602 Shield with buttons
- Photo resistor
- DHT11 (Temp & Humidity Sensor)
I need the function delay(1000) to display the seconds properly from the RTC to the LCD. But, that way I always have to keep the buttons pressed for up to 1 second until they react.
How can I workaround or solve this problem?
Idea 1: Multitasking would come in handy here :-) pseudocode:
task 1: listen for LCD buttons
task 2: display seconds with a delay of 1000ms
But there isn’t a way Arduino could multitask, isn’t it?
Idea 2: As far as I saw in the header files for the RTC, the smallest readable unit is seconds. Otherwise I could have used something like a millisecond reader in a while condition to listen for the buttons; pseudocode:
while (RTC-millisecond < 1000ms) {
// listen for buttons
// so a second passes, which gives the RTC time to display the seconds values
}
-
EDIT
updated code, thanks to @NickGammon and Gerben:
#include <LiquidCrystal.h>
#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <DHT.h>
// initialize the library with the numbers of the interface pins
// RS E D4 D5 D6 D7 (maybe wrong order)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// pins on which the sensor is connected
#define DHTPIN A1
#define PHOTOPIN A2
// initialize DHT sensor
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// define some values used by the panel and buttons
int lcd_key = 0;
int adc_key_in = 0;
//#define btnRIGHT 0
//#define btnUP 1
//#define btnDOWN 2
//#define btnLEFT 3
//#define btnSELECT 4
//#define btnNONE 5
// FSM
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
const long interval = 3000;
// prototypes
void print2digits(int number);
int read_LCD_buttons();
void setup() {
// open a serial connection to display values on PC
Serial.begin(9600);
// set up the number of columns and rows on the LCD
lcd.begin(16, 2);
// start DHT sensor
dht.begin();
}
void loop() {
// set variable from struct tmElements_t
tmElements_t tm;
/********* Reading from sensors *********/
/*** DHT sensor ***/
// Reading temp or RH takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float humid = dht.readHumidity();
float tempC = dht.readTemperature();
// Check if any reads failed and exit early (to try again).
if (isnan(humid) || isnan(tempC)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT reading failed!");
Serial.println("DHT reading failed!");
return;
}
// Compute heat index in Celsius (isFahreheit = false)
float hiC = dht.computeHeatIndex(tempC, humid, false);
/*** Photo resistor ***/
int lightReading = analogRead(PHOTOPIN);
/********* Print to PC over serial connection *********/
// ...
/********* Print values to LCD *********/
/* --- first line on LCD --- */
/*** RTC ***/
// set the cursor to LCD column 4, line 0 to center the clock
lcd.setCursor(4, 0);
// starts RTC reading and checks if it's working
if (RTC.read(tm)) {
static byte oldSecond = 60; // 60, because there is no 60'th second in a clock
// display only if time changes
if (tm.Second != oldSecond) {
oldSecond = tm.Second;
print2digits(tm.Hour);
lcd.print(':');
print2digits(tm.Minute);
lcd.print(':');
print2digits(tm.Second);
}
}
else {
lcd.clear();
lcd.setCursor(0, 0);
if (RTC.chipPresent()) {
lcd.print("Please run SetTime function");
} else {
lcd.print("DS1307 read error!");
}
delay(9000);
}
/* --- second line on LCD according to button --- */
lcd_key = ((lcd_key + read_LCD_buttons()) %3); // call button function, modulo 3 to cycle through
/** // Test buttons:
lcd.setCursor(1, 1);
lcd.print("lcd var:");
lcd.print(lcd_key); */
unsigned long currentMillis = millis(); // FSM used for displaying DHT and photo values without flikering
switch (lcd_key) {
case 0:
/*** Weekday and Date ***/
// display only if day changed
static byte oldDay = 99;
if (tm.Day != oldDay) {
oldDay = tm.Day;
lcd.setCursor(0, 1);
lcd.print(" "); // 16 spaces to clear second line before printing
lcd.setCursor(0, 1);
//lcd.print(dayShortStr((weekday() + 1) % 7 )); // (day+1)%7 calculation for Swiss layout
lcd.print(tm.Wday); // TEST
lcd.print(weekday()); // TEST
lcd.print(", ");
print2digits(tm.Day);
lcd.print('.');
print2digits(tm.Month);
lcd.print('.');
lcd.print(tmYearToCalendar(tm.Year));
}
break;
case 1:
/*** DHT Sensor ***/
if (currentMillis - previousMillis1 >= interval) {
previousMillis1 = currentMillis;
lcd.setCursor(0, 1);
lcd.print(" "); // 16 spaces to clear second line before printing
lcd.setCursor(1, 1);
lcd.print(hiC);
lcd.print("*C ");
lcd.setCursor(10, 1);
lcd.print(humid);
lcd.setCursor(12, 1);
lcd.print("%RH ");
}
break;
case 2:
/*** Photo resistor ***/
if (currentMillis - previousMillis2 >= interval) {
previousMillis2 = currentMillis;
lcd.setCursor(0, 1);
lcd.print(" "); // 16 spaces to clear second line before printing
lcd.setCursor(0, 1);
lcd.print("Light ");
lcd.setCursor(6, 1);
lcd.print(lightReading);
}
break;
}
}
// used to print 2 digits in the time values
void print2digits(int number) {
if (number >= 0 && number < 10) {
lcd.print('0');
}
lcd.print(number);
}
// read the buttons
int read_LCD_buttons() {
adc_key_in = analogRead(0);
//if (adc_key_in > 1000) return btnNONE; // 1st option since it will be the most likely result (speed reasons)
//if (adc_key_in < 50) return btnRIGHT;
//if (adc_key_in < 195) return btnUP; // replaced by below one
if (adc_key_in < 195) return 1; // my button up !
//if (adc_key_in < 380) return btnDOWN;
//if (adc_key_in < 555) return btnLEFT;
//if (adc_key_in < 790) return btnSELECT;
//return btnNONE; // when all others fail, return this...
return 0;
}