#include <SD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
#include <Wire.h>
#include <EEPROM.h>
#include <RTClib.h>
LiquidCrystal_I2C lcd(0x27,20,4);
//6050
const int MPU = 0x68; // MPU6050 I2C address
//float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
//float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
//float roll, pitch, yaw;
float GyroErrorX, GyroErrorY, GyroErrorZ;
//float elapsedTime, currentTime, previousTime;
int c = 0;
//sd
#define CS_PIN 10
//inicializar pulsadores
int but1 = 3;
int but2 = 4;
int but3 = 5;
int but4 = 7;
int buzzer = 6;
int servoPin = 9;
//variables de control
int time = 8; //horas entre comidas
int timeMin = 0; //minutos entre comidas
int Hour, Min;
int last_feed_hour;
int next_feed_hour;
int last_feed_min;
int next_feed_min;
//Time t;
//6050
unsigned long prevTime = 0;
unsigned long period = 2000;
const uint8_t buttonPins[] = {3, 4, 5 ,7};
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
//int portionAngle = 180;
int portions = 8;
boolean servoOn;
int pinServo = 9; //servo = D9
int pos = 0; //variable que almacena la posición en grados del servo
File root;
Servo servo;
RTC_DS1307 rtc;
void setup() {
//LCD setup
servo.attach(servoPin); // Se configura el pin del servo
for (byte i = 0; i < 4; i++) {
//pinMode(ledPins[i], OUTPUT);
pinMode(buttonPins[i], INPUT_PULLUP);
}
servo.attach(servoPin);
servo.write(92);
//LCD setup
lcd.init(); // initialize the lcd
lcd.backlight(); //se enciende los leds de iluminación
lcd.setCursor(3,0); //col 3 fila 0
lcd.print("Hello, world!"); //mensaje a imprimir en lcd
lcd.setCursor(2,1);
lcd.print("Ywrobot Arduino!");
lcd.setCursor(0,2);
delay(1000);
lcd.clear(); //tras un delay se limpia la pantalla
//se carga de la memoria la siguiente hora y minuto
last_feed_hour = EEPROM.read(2);
next_feed_hour = EEPROM.read(3);
last_feed_min = EEPROM.read(4);
next_feed_min = EEPROM.read(5);
Serial.begin(115200);
//SD SETUP
Serial.print("Initializing SD card... ");
if (!SD.begin(CS_PIN)) {
Serial.println("Card initialization failed!");
while (true);
}
Serial.println("initialization done.");
Serial.println("Files in the card:");
root = SD.open("/");
printDirectory(root, 0);
Serial.println("");
// Example of reading file from the card:
File textFile = SD.open("wokwi.txt");
if (textFile) {
Serial.print("wokwi.txt: ");
while (textFile.available()) {
Serial.write(textFile.read());
}
textFile.close();
} else {
Serial.println("error opening the file!");
}
// 6050 SETUP
//Serial.begin(19200);
Wire.begin(); // Initialize comunication
Wire.beginTransmission(MPU); // Start communication with MPU6050 // MPU=0x68
Wire.write(0x6B); // Talk to the register 6B
Wire.write(0x00); // Make reset - place a 0 into the 6B register
Wire.endTransmission(true); //end the transmission
// Call this function if you need to get the IMU error values for your module
calculate_IMU_error();
delay(20);
}
void loop() {
// nothing happens after setup finishes.
DateTime now = rtc.now();
Hour = (now.hour());
Min = (now.minute());
if ((Hour == next_feed_hour) && (Min == next_feed_min)){
Serial.print("Success!!!!!!!!!!");
delay(2000);
servoOn = true;
last_feed_hour = Hour;
last_feed_min = Min;
next_feed_min = Min + timeMin;
if (next_feed_min > 59){
//si el intervalo del siguiente minuto de la ola que surge del ultimo suspiro
//supera 59 se resta para obtener el minuto correspondiente
//si supera lo 60 segundo se debe sumar una unidad a la hora siguiente
next_feed_hour = Hour + time + 1;
next_feed_min = next_feed_min - 60;
}else{
next_feed_hour = Hour + time;
}
//finalmente, si llega a 24 o mayor se resta al horario PM
if (next_feed_hour > 23){
next_feed_hour = next_feed_hour - 24;
}
EEPROM.write(2, last_feed_hour);
EEPROM.write(3, next_feed_hour);
EEPROM.write(4, last_feed_min);
EEPROM.write(5, next_feed_min);
}
if (servoOn){
//se cambia el mensaje del
Serial.println("Testing");
delay(5000);
servoOn = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Ejecutando");
//se activa el zumbador
/*analogWrite(buzzer, 400);
delay(400);
digitalWrite(buzzer, LOW);*/
//puesta en marcha del servo
for (pos = 1; pos < portions; pos++) { // una iteración es un grado del servo
servo.write(180); // escritura de la posición y movimiento
delay(500); // tiempo para que el servo alcance los grados
}
servo.write(92);
}
unsigned long currTime = millis();
if (currTime - prevTime >= period){
DateTime now = rtc.now();
lcd.clear();
lcd.setCursor(0,0);
//lcd.print("It's feeding time my ");
lcd.print("Next Feed ");
lcd.print(next_feed_hour);
lcd.print(":");
lcd.print(next_feed_min);
lcd.setCursor(0,1);
lcd.print("Hora actual: ");
lcd.print((now.hour(), DEC));
lcd.print(":");
lcd.print((now.minute(), DEC));
lcd.setCursor(0,2);
lcd.print("Porciones: ");
lcd.print(portions);
/*Serial.print("Hora actual: ");
Serial.println(now.second(), DEC);*/
prevTime += period;;
//6050 CODE
Wire.beginTransmission(MPU);
Wire.write(0x43); // Gyro data first register address 0x43
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers
GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet
GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
// Correct the outputs with the calculated error values
GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
GyroY = GyroY - 2; // GyroErrorY ~(2)
GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)
if ((GyroX > 45) || (GyroY > 45) || (GyroX < -45) || (GyroY < -45)){
//Serial.println("Se ha producido la accion de la volcasión!!!");
lcd.clear();
lcd.print("Volcado");
}
}
//este boton cambia las porciones
for (byte i = 0; i < 4; i++) {
//byte buttonPin = buttonPins[i];
if (digitalRead(buttonPins[0]) == LOW) {
portions++;
if (portions > 20){
portions = 2;
}
lcd.clear();
lcd.print("Portion increased +1 ");
delay(200);
}
//Este la hora de comida
if (digitalRead(buttonPins[1]) == LOW) {
lcd.clear();
lcd.print("dgc");
delay(1000);
}
//Minutos de comida
if (digitalRead(buttonPins[2]) == LOW) {
lcd.clear();
lcd.print("nani");
delay(1000);
}
//argo hase
if (digitalRead(buttonPins[3]) == LOW) {
lcd.clear();
lcd.print("ahhh");
delay(1000);
}
}
}
//SD CODE
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void calculate_IMU_error() {
// We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
// Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
c = 0;
// Read gyro values 200 times
while (c < 200) {
Wire.beginTransmission(MPU);
Wire.write(0x43);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
GyroX = Wire.read() << 8 | Wire.read();
GyroY = Wire.read() << 8 | Wire.read();
GyroZ = Wire.read() << 8 | Wire.read();
// Sum all readings
GyroErrorX = GyroErrorX + (GyroX / 131.0);
GyroErrorY = GyroErrorY + (GyroY / 131.0);
GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
c++;
}
//Divide the sum by 200 to get the error value
GyroErrorX = GyroErrorX / 200;
GyroErrorY = GyroErrorY / 200;
GyroErrorZ = GyroErrorZ / 200;
// Print the error values on the Serial Monitor
lcd.clear();
lcd.setCursor(0,0); //col 3 fila 0
lcd.print("GyroErrorX: ");
lcd.println(GyroErrorX);
lcd.setCursor(0,1); //col 3 fila 0
lcd.print("GyroErrorY: ");
lcd.println(GyroErrorY);
lcd.setCursor(0,2); //col 3 fila 0
lcd.print("GyroErrorZ: ");
lcd.println(GyroErrorZ);
delay(200);
}