Hacking my Automatic Cat Feeder with RFID (seeking help)


Goal: Have the rfid tag on my cats collar trigger the feeder to activate

I disassembled the cat feeder and connected the motor to the Arduino. It runs off a digital out pin just fine. The LCD displays everything well. I think the error is in my code. I opted for using a series of if statements but I can also see how while statements could have been used instead.

Problem: When the code runs it ends up displaying to the LCD "wait for 429417 [minutes]"

Disclaimer: I am quite new to this language. I have experience in r, however.

//LCD
 //• Displays the time until the next availble feeding 
   //• TIME: HH:mm
     //• adjusted with an hour and minute button
//   • LAST FED: HH:mm
 //• When a feeding is activated, a time counts down the time until the next feeding
  // • FEEDING DELAY: mm:ss
//RFID/MOTOR
 //• When card is scanned
   //• Motor activates for 1 second
     //• deactivates for 3 minutes
       //• Constraints: allow only 2 feedings every 8h
#include <MFRC522.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);

#define SS_PIN 53
#define RST_PIN 5
#define MOTOR_PIN 2

const long MOTOR_ON_TIME = 1000; //1sec
const long MOTOR_OFF_TIME = 10000; //3min 180000
const long MOTOR_LIMIT = 28800000;  //8 hours: The wait after MAXfeedings is reached

unsigned long lastMillis = 0;
unsigned long feedings = 0;
unsigned long MAXfeedings = 3; //set the max number of feeding for the MOTOR_LIMIT

bool scanning = false;

MFRC522 rfid(SS_PIN, RST_PIN);

void setup() {
  lcd.init();
  rfid.PCD_Init();
  lcd.backlight();
  Serial.begin(9600);
  SPI.begin();
  pinMode(MOTOR_PIN, OUTPUT);
  lcd.print("Setup Complete");
  delay(5000);
  lcd.clear();
}

void loop() {
unsigned long currentMillis = millis();     //set the current time

  //If the time from the last feeding is more than 8h then reset feedings
  if(currentMillis < lastMillis + MOTOR_LIMIT){
    feedings = 0;
  };

  if(feedings >= MAXfeedings){
    feedings = 0;
    const int hours = (MOTOR_LIMIT - (currentMillis - lastMillis))/1000/60/60;
    const long min = (MOTOR_LIMIT - (currentMillis - lastMillis))/1000/60 - (hours * 60);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Wait for: ");
    lcd.print(hours);
    lcd.print("h ");
    lcd.print(min);
    lcd.print("m");
    currentMillis = millis();
    delay(100);
    return;
  } else if(currentMillis >= lastMillis + MOTOR_OFF_TIME){
      lcd.clear();
      lcd.setCursor(0, 0);
      //print the seconds until the feeding is an option to the lcd
      lcd.print("Wait for: ");
      lcd.print((MOTOR_OFF_TIME - (currentMillis - lastMillis))/1000);
      lcd.print("s");
      currentMillis = millis();
      delay(100);
      return;
  } else {
      lcd.print("Scanning");
      delay(100);
      scanning = true;
  }
 
  if(scanning == false){
    return;
  } else if(!rfid.PICC_IsNewCardPresent()){
    return;
  } else {
    feedings = feedings + 1;               //increment feedings up one
    lastMillis = currentMillis;            //set the last feeding to now
    lcd.print("Dispensing");     //print to lcd
    delay(3000) ;         // wait 3 seconds while lcd is on
    digitalWrite(MOTOR_PIN, HIGH);         //activate motor
    delay(1000);                           //wait 1 sec
    digitalWrite(MOTOR_PIN, LOW);         //de-activate motor
    return;
  }
} 

Actually it is printing "Wait for 428417s", but the s is off the end of the line.

When this if statement is true, (currentMillis - lastMillis) will be greater then MOTOR_OFF_TIME, which would result in a negative number for the seconds, but since the calculation is done with unsigned integers, the number underflows and results in a very large positive number, which is what you see displayed.
If this if statement is true, you also are exiting the loop() function, before you reach any code that will change the value of lastMillis, so you are probably stuck here forever.

  } else if (currentMillis >= lastMillis + MOTOR_OFF_TIME) {
    lcd.clear();
    lcd.setCursor(0, 0);
    //print the seconds until the feeding is an option to the lcd
    lcd.print("Wait for: ");
    lcd.print((MOTOR_OFF_TIME - (currentMillis - lastMillis)) / 1000);
    lcd.print("s");
    currentMillis = millis();
    delay(100);
    return;

ah! Yep,

reversing the inequality to: <=
and
creating lastMillis with: unsigned long lastMillis = 0.0 - MOTOR_LIMIT;

..fixed that

Thank you

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.