#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
#include <avr/sleep.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
RTC_DS1307 rtc;
const int pins[] = {2, 3, 4, 5};
const int nbt = 4;
const int chipSelect = 10;
unsigned long udt[nbt] = {0, 0, 0, 0};
unsigned long debounceDelay = 50;
int bt[nbt] = {HIGH, HIGH, HIGH, HIGH};
int ubt[nbt] = {HIGH, HIGH, HIGH, HIGH};
int menuPage = 0;
int menuItem = 0;
bool inMenu = false;
bool displayNeedsUpdate = true;
bool inTimeAdjust = false;
bool inDataLog = false;
bool inAmostragem = false;
bool isLogging = false;
int samplingTime = 5;
unsigned long lastLogTime = 0;
int currentAnalogPin = 0;
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
for (int i = 0; i < nbt; i++) {
pinMode(pins[i], INPUT_PULLUP);
}
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
if (!SD.begin(chipSelect)) {
Serial.println("SD card não foi inicializado");
return;
}
Serial.println("SD card inicializado.");
updateDisplay();
Serial.println("Monitorando os botões.");
}
void loop() {
static unsigned long lastRefreshTime = 0;
if (!inMenu && !inTimeAdjust && !inDataLog && !inAmostragem && (millis() - lastRefreshTime >= 1000)) {
displayNeedsUpdate = true;
lastRefreshTime = millis();
}
if (displayNeedsUpdate) {
updateDisplay();
displayNeedsUpdate = false;
}
if (isLogging && (millis() - lastLogTime >= samplingTime * 1000)) {
logData();
lastLogTime = millis();
}
for (int i = 0; i < nbt; i++) {
if (handleButtonPress(i)) {
if (!inMenu && !inTimeAdjust && !inDataLog && !inAmostragem) {
inMenu = true;
menuPage = 0;
menuItem = 0;
} else if (inMenu) {
handleMenuNavigation(i);
} else if (inTimeAdjust) {
handleTimeAdjust(i);
} else if (inDataLog) {
handleDataLogMenu(i);
} else if (inAmostragem) {
handleAmostragemAdjust(i);
}
displayNeedsUpdate = true;
}
}
}
void handleMenuNavigation(int i) {
if (i == 0 || i == 3) {
menuPage = (menuPage + (i == 0 ? -1 : 1) + 4) % 4;
} else if (i == 1 || i == 2) {
menuItem = (menuItem + (i == 1 ? -1 : 1) + 2) % 2;
}
if (menuPage == 0 && menuItem == 1 && i == 2) { // REPOUSO
inMenu = false;
} else if (menuPage == 0 && menuItem == 0 && i == 2) { // AJUSTE
inTimeAdjust = true;
inMenu = false;
} else if (menuPage == 1 && menuItem == 1 && i == 2) { // DATA LOG
inDataLog = true;
inMenu = false;
} else if (menuPage == 3 && i == 2) { // SEL ANALÓGICA
currentAnalogPin = (currentAnalogPin + 1) % 4;
}
}
void handleTimeAdjust(int i) {
if (i == 0 || i == 3) {
inTimeAdjust = false;
inMenu = true;
} else if (i == 1 || i == 2) {
DateTime now = rtc.now();
if (i == 1) {
now = now - TimeSpan(0, 0, 1, 0);
} else {
now = now + TimeSpan(0, 0, 1, 0);
}
rtc.adjust(now);
}
}
void handleDataLogMenu(int i) {
if (i == 0 || i == 3) {
inDataLog = false;
inMenu = true;
} else if (i == 1 || i == 2) {
menuItem = (menuItem + (i == 1 ? -1 : 1) + 2) % 2;
if (i == 2) {
if (menuItem == 1) { // AMOSTRAGEM
inAmostragem = true;
inDataLog = false;
} else if (menuItem == 0) { // REGISTRO
isLogging = !isLogging;
if (isLogging) {
lastLogTime = millis();
Serial.println("Log start");
} else {
Serial.println("Log stop");
}
}
}
}
}
void handleAmostragemAdjust(int i) {
if (i == 0 || i == 3) {
inAmostragem = false;
inDataLog = true;
} else if (i == 1 || i == 2) {
samplingTime += (i == 1) ? -1 : 1;
if (samplingTime < 0) {
samplingTime = 0;
} else if (samplingTime > 3600) {
samplingTime = 3600;
}
}
}
bool handleButtonPress(int i) {
int reading = digitalRead(pins[i]);
if (reading != ubt[i]) {
udt[i] = millis();
}
if ((millis() - udt[i]) > debounceDelay) {
if (reading != bt[i]) {
bt[i] = reading;
if (bt[i] == LOW) {
Serial.print("Botão ");
Serial.print(i + 1);
Serial.print(" pressionado. Pin: ");
Serial.println(pins[i]);
ubt[i] = reading;
return true;
}
}
}
ubt[i] = reading;
return false;
}
void updateDisplay() {
lcd.clear();
lcd.setCursor(0, 0);
if (!inMenu && !inTimeAdjust && !inDataLog && !inAmostragem) {
DateTime now = rtc.now();
lcd.print("Tempo: ");
lcd.print(now.hour(), DEC);
lcd.print(':');
lcd.print(now.minute(), DEC);
lcd.print(':');
lcd.print(now.second(), DEC);
} else if (inMenu) {
switch (menuPage) {
case 0:
lcd.print(menuItem == 0 ? "> REPOUSO" : " REPOUSO");
lcd.setCursor(0, 1);
lcd.print(menuItem == 1 ? "> AJUSTE" : " AJUSTE");
break;
case 1:
lcd.print(menuItem == 0 ? "> DATA LOG" : " DATA LOG");
lcd.setCursor(0, 1);
lcd.print(menuItem == 1 ? "> COM RF" : " COM RF");
break;
case 2:
lcd.print(menuItem == 0 ? "> CONT PULSO" : " CONT PULSO");
lcd.setCursor(0, 1);
lcd.print(menuItem == 1 ? "> PWM MONO" : " PWM MONO");
break;
case 3:
lcd.print("> ANALOG SELECT");
lcd.setCursor(0, 1);
lcd.print("A");
lcd.print(currentAnalogPin);
break;
}
} else if (inTimeAdjust) {
DateTime now = rtc.now();
lcd.print("Ajuste:");
lcd.setCursor(0, 1);
lcd.print(now.hour(), DEC);
lcd.print(':');
lcd.print(now.minute(), DEC);
} else if (inDataLog) {
lcd.print(menuItem == 0 ? "> AMOSTRAGEM" : " AMOSTRAGEM");
lcd.setCursor(0, 1);
lcd.print(menuItem == 1 ? "> REGISTRO" : " REGISTRO");
if (isLogging) {
lcd.setCursor(15, 1);
lcd.print("*");
}
} else if (inAmostragem) {
lcd.print("Amostragem:");
lcd.setCursor(0, 1);
lcd.print(samplingTime);
lcd.print(" segundos");
}
Serial.println("Display atualizado");
}
float readBatteryVoltage() {
int rawValue = analogRead(A1);
return rawValue * (1.5 / 1023.0);
}
float readBatteryVoltageAdjusted() {
ADMUX = (ADMUX & 0xF0) | (1 << REFS1) | (1 << REFS0) | (2 & 0x07);
delay(10);
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));
int rawValue = ADC;
float voltage = rawValue * (1.1 / 1023.0);
return voltage * (1.5 / 1.1);
}
float readBatteryVoltageNoiseReduction() {
ADCSRA |= (1 << ADEN);
ADMUX = (1 << REFS1) | (1 << REFS0) | (3 & 0x07);
ADCSRA &= ~(1 << ADIE);
SMCR = (1 << SM0) | (1 << SM1);
SMCR |= (1 << SE);
ADCSRA |= (1 << ADSC);
sleep_cpu();
SMCR &= ~(1 << SE);
int rawValue = ADC;
float voltage = rawValue * (1.1 / 1023.0);
return voltage * (1.5 / 1.1);
}
void logData() {
DateTime now = rtc.now();
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
String dataString = String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second());
switch (currentAnalogPin) {
case 0:
dataString += " A0:" + String(analogRead(A0));
break;
case 1:
dataString += " A1:" + String(readBatteryVoltage(), 3);
break;
case 2:
dataString += " A2:" + String(readBatteryVoltageAdjusted(), 3);
break;
case 3:
dataString += " A3:" + String(readBatteryVoltageNoiseReduction(), 3);
break;
}
dataFile.println(dataString);
dataFile.close();
Serial.println("Data log: " + dataString);
} else {
Serial.println("Erro ao abrir datalog.txt");
}
}