Medicine Reminder using Arduino & RTC

2,864 views

Introduction

A medicine reminder system using an Arduino UNO with RTC library and EEPROM is a highly practical and innovative solution for anyone who struggles to remember their medication schedule. This system utilizes the powerful capabilities of Arduino technology, along with real-time clock (RTC) and EEPROM memory storage, to create a customizable and reliable reminder system that can help individuals stay on top of their medication routines.

By automating the process of medication reminders, this system can help improve adherence to prescribed medication regimens, ultimately leading to better health outcomes and a better quality of life.

Hardware Components

You will require the following hardware for Medicine Reminder.

ComponentsValueQty
Arduino UNO1
RTC ModuleDS32311
Push Button4
ResistorΩ4
Buzzer1
LCD Display16X21
Potentiometer1
Breadboard1
Jumper Wires1

Code Explanation

  1. The necessary libraries are imported at the beginning of the code:
#include <LiquidCrystal.h>
#include <Wire.h>
#include <RTClib.h>
#include <EEPROM.h>
  1. Various global variables are declared:
int pushVal = 0;
int val;
int val2;
int addr = 0;
RTC_DS3231 rtc;
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
#define getWellsoon 0
#define HELP_SCREEN 1
#define TIME_SCREEN 2
int pushpressed = 0;
const int ledPin = 13;
int ledState = LOW;
int Signal = 0;
int buzz = 13;
int push1state, push2state, push3state, stopinState = 0;
int push1Flag, push2Flag, Push3Flag = false;
int push1pin = 9;
int push2pin = 8;
int push3pin = 7;
int stopPin = A0;
int screens = 0;
int maxScreen = 2;
bool isScreenChanged = true;
long previousMillis = 0;
long interval = 500;
unsigned long currentMillis;
long previousMillisLCD = 0;
long intervalLCD = 2000;
unsigned long currentMillisLCD;
int buzz8amHH = 8;
int buzz8amMM = 00;
int buzz8amSS = 00;
int buzz2pmHH = 14;
int buzz2pmMM = 00;
int buzz2pmSS = 00;
int buzz8pmHH = 20;
int buzz8pmMM = 00;
int buzz8pmSS = 00;
int nowHr, nowMin, nowSec;
  1. Several functions are defined:
void gwsMessege();
void helpScreen();
void timeScreen();

4. The first function is setup(), which runs only once when the Arduino is powered on or reset.

void setup() {

5. The function initializes the serial communication at a baud rate of 9600, which can be used for debugging the code.

Serial.begin(9600);

6. The function checks if a Real-Time Clock (RTC) module is connected to the Arduino board.

if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
}

7. If the RTC is not connected, the code prints a message on the serial monitor and stops execution with an infinite loop.

8. The function checks if the RTC has lost power. If it has, it prints a message on the serial monitor.

if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
}

9. The function sets the time on the RTC module manually to the date and time mentioned in the code or uses the current time if the comment is removed from the code.

rtc.adjust(DateTime(2019, 1, 10, 7, 59, 30));

10. The function initializes an LCD with 16 columns and 2 rows and clears the screen.

lcd.begin(16, 2);
lcd.clear();

11. The function prints a welcome message on the LCD.

lcd.setCursor(0, 0);
lcd.print("Welcome To");
lcd.setCursor(0, 1);
lcd.print("Circuit DIY");

12. The function sets the pinMode of the push button pins, stop pin, and LED pin. It also reads the previously saved value of push button and sets the state of push buttons accordingly.

pinMode(push1pin, INPUT_PULLUP);
pinMode(push2pin, INPUT_PULLUP);
pinMode(push3pin, INPUT_PULLUP);
pinMode(stopPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);

delay(200);

Serial.println(EEPROM.read(addr));
val2 = EEPROM.read(addr);

switch (val2) {
  case 1:
    Serial.println("Set for 1/day");
    push1state = 1;
    push2state = 0;
    push3state = 0;
    pushVal = 1;
    break;
  case 2:
    Serial.println("Set for 2/day");
    push1state = 0;
    push2state = 1;
    push3state = 0;
    pushVal = 2;
    break;
  case 3:
    Serial.println("Set for 3/day");
    push1state = 0;
    push2state = 0;
    push3state = 1;
    pushVal = 3;
    break;
}

13. In the loop() function, there are three calls to functions named push1(), push2(), and push3(), which set the frequency of the reminder. Depending on which push button is pressed, the pushVal variable is set to 1, 2, or 3, which determines the number of times the user needs to be reminded to take their medicine each day.

void loop() {
  push1(); // call to set once/day
  push2(); // call to set twice/day
  push3(); // call to set thrice/day
  ...
}

14. Next, there are a series of if statements that check the value of pushVal to determine when the reminders need to be sent. If pushVal is 1, the reminder is set to go off at 8am. If pushVal is 2, the reminder is set to go off at 8am and 8pm. If pushVal is 3, the reminder is set to go off at 8am, 2pm, and 8pm. Each reminder time corresponds to a specific function call (at8am(), at2pm(), at8pm()), which checks the current time and determines whether the reminder should be triggered.

if (pushVal == 1) {
  at8am(); // function to start buzzing at 8am
} else if (pushVal == 2) {
  at8am();
  at8pm(); // function to start buzzing at 8pm
} else if (pushVal == 3) {
  at8am();
  at2pm(); // function to start buzzing at 2pm
  at8pm();
}

15. The push1(), push2(), and push3() functions are called within the loop() function, and they each check the state of a specific push button (push1state, push2state, and push3state, respectively). If a push button is pressed, its corresponding state variable is set to 1, and the other state variables are set to 0. The function then writes the push button value to a specific memory address using the EEPROM.write() function. Finally, the function sets the pushVal variable to the appropriate value (1, 2, or 3) and displays a message on an LCD screen before clearing the screen after 1.2 seconds.

void push1() {
  if (push1state == 1) {
    push1state = 0;
    push2state = 0;
    push3state = 0;
    EEPROM.write(addr, 1);
    Serial.print("Push1 Written : "); Serial.println(EEPROM.read(addr)); // for debugging
    pushVal = 1;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Reminder set ");
    lcd.setCursor(0, 1);
    lcd.print("for Once/day !");
    delay(1200);
    lcd.clear();
  }
}
// push2() and push3() functions follow a similar structure, with appropriate changes for each reminder frequency

16. stopPins(): This function is used to stop buzzing when the user pushes the stop push button. It clears the LCD screen and displays a message for a delay of 1200 milliseconds. The code snippet is as follows:

void stopPins() {
  if (stopinState == 1) {
    pushpressed = 1;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Take Medicine  ");
    lcd.setCursor(0, 1);
    lcd.print("with Warm Water");
    delay(1200);
    lcd.clear();
  }
}

17. startBuzz(): This function is used to start buzzing at a defined interval. It checks if the stop push button is not pressed and if the current time minus previous time is greater than the defined interval. If the condition is satisfied, it starts buzzing and toggles the LED. The code snippet is as follows:

void startBuzz() {
  if (pushpressed == 0) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(ledPin, ledState);
    }
  } else if (pushpressed == 1) {
    ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}

18. at8am(), at2pm(), and at8pm(): These functions are used to start buzzing at specific times of the day. Each function checks if the current time is greater than or equal to the defined time and then calls the startBuzz() function. The code snippets are as follows:

void at8am() {
  DateTime now = rtc.now();
  if (int(now.hour()) >= buzz8amHH) {
    if (int(now.minute()) >= buzz8amMM) {
      if (int(now.second()) > buzz8amSS) {
        startBuzz();
      }
    }
  }
}

void at2pm() {
  DateTime now = rtc.now();
  if (int(now.hour()) >= buzz2pmHH) {
    if (int(now.minute()) >= buzz2pmMM) {
      if (int(now.second()) > buzz2pmSS) {
        startBuzz();
      }
    }
  }
}

void at8pm() {
  DateTime now = rtc.now();
  if (int(now.hour()) >= buzz8pmHH) {
    if (int(now.minute()) >= buzz8pmMM) {
      if (int(now.second()) > buzz8pmSS) {
        startBuzz();
      }
    }
  }
}

19. changeScreen(): This function is used to switch between different screens on an LCD display after a defined interval. It checks if the current time minus previous time is greater than the defined interval and switches to the next screen. The code snippet is as follows:

void changeScreen() {
  if (currentMillisLCD - previousMillisLCD > intervalLCD) {
    previousMillisLCD = currentMillisLCD;
    screens++;
    if (screens > maxScreen) {
      screens = 0;
    }
    isScreenChanged = true;
  }
  if (isScreenChanged) {
    isScreenChanged = false;
    switch (screens) {
      case getWellsoon:
        gwsMessege();
        break;
      case HELP_SCREEN:
        helpScreen();
        break;

Schematic

Make connections according to the circuit diagram given below.

Installing Arduino IDE

First, you need to install Arduino IDE Software from its official website Arduino. Here is a simple step-by-step guide on “How to install Arduino IDE“.

Installing Libraries

Before you start uploading a code, download and unzip the following libraries at /Progam Files(x86)/Arduino/Libraries (default), in order to use the sensor with the Arduino board. Here is a simple step-by-step guide on “How to Add Libraries in Arduino IDE“.

Code

Now copy the following code and upload it to Arduino IDE Software.

#include <LiquidCrystal.h>
#include <Wire.h>
#include <RTClib.h>
#include <EEPROM.h>

int pushVal = 0;                           
int val;
int val2;
int addr = 0;
RTC_DS3231 rtc;
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;                 // lcd pins
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

#define getWellsoon 0                                           
#define HELP_SCREEN 1
#define TIME_SCREEN 2

//bool pushPressed;                               //flag to keep track of push button state 
int pushpressed = 0;
const int ledPin =  13;                       // buzzer and led pin
int ledState = LOW;
int Signal = 0;
int buzz = 13;                                      
int push1state, push2state, push3state, stopinState = 0;     // 
int push1Flag, push2Flag, Push3Flag = false;              // push button flags 
int push1pin = 9;
int push2pin = 8;
int push3pin = 7;
int stopPin = A0;
int screens = 0;              // screen to show
int maxScreen = 2;            // screen count

bool isScreenChanged = true;
long previousMillis = 0;           
long interval = 500;                   // buzzing interval
unsigned long currentMillis;
long previousMillisLCD = 0;    // for LCD screen update
long intervalLCD = 2000;          // Screen cycling interval
unsigned long currentMillisLCD;
//   Set Reminder Change Time
int buzz8amHH = 8;          //    HH - hours         ##Set these for reminder time in 24hr Format 
int buzz8amMM = 00;          //    MM - Minute
int buzz8amSS = 00;          //    SS - Seconds
int buzz2pmHH = 14;          //    HH - hours
int buzz2pmMM = 00;          //    MM - Minute
int buzz2pmSS = 00;          //    SS - Seconds
int buzz8pmHH = 20;          //    HH - hours
int buzz8pmMM = 00;          //    MM - Minute
int buzz8pmSS = 00;          //    SS - Seconds
int nowHr, nowMin, nowSec;                     // to show current mm,hh,ss

// All messeges
void gwsMessege(){               // print get well soon messege
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Stay Healthy :)");     // Give some cheers
    lcd.setCursor(0, 1);
    lcd.print("Get Well Soon :)");    // wish 
}
void helpScreen() {              // function to display 1st screen in LCD
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Press Buttons");
    lcd.setCursor(0, 1);
    lcd.print("for Reminder...!");

 }
void timeScreen() {              // function to display Date and time in LCD screen
  DateTime now = rtc.now();             // take rtc time and print in display
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Time:");
    lcd.setCursor(6, 0);
    lcd.print(nowHr = now.hour(), DEC);
    lcd.print(":");
    lcd.print(nowMin = now.minute(), DEC);
    lcd.print(":");
    lcd.print(nowSec = now.second(), DEC);
    lcd.setCursor(0, 1);
    lcd.print("Date: ");
    lcd.print(now.day(), DEC);
    lcd.print("/");
    lcd.print(now.month(), DEC);
    lcd.print("/");
    lcd.print(now.year(), DEC);
}
void setup() {

  Serial.begin(9600);                      // start serial debugging
  if (! rtc.begin()) {                      // check if rtc is connected 
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
  }

//    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));            // uncomment this to set the current time and then comment in next upload when u set the time
  rtc.adjust(DateTime(2019, 1, 10, 7, 59, 30));                // manual time set

  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Welcome To");                                      // print a messege at startup
  lcd.setCursor(0, 1);
  lcd.print("Circuit Digest");

  delay(1000);

  pinMode(push1pin, INPUT_PULLUP);                                    // define push button pins type
  pinMode(push2pin, INPUT_PULLUP);
  pinMode(push3pin, INPUT_PULLUP);
  pinMode(stopPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  delay(200);
  Serial.println(EEPROM.read(addr));
  val2 = EEPROM.read(addr);                         // read previosuly saved value of push button to start from where it was left previously
  switch (val2) {
    case 1:
      Serial.println("Set for 1/day");
      push1state = 1;
      push2state = 0;
      push3state = 0;
      pushVal = 1;
      break;
    case 2:
      Serial.println("Set for 2/day");
      push1state = 0;
      push2state = 1;
      push3state = 0;
      pushVal = 2;

      break;
    case 3:
      Serial.println("Set for 3/day");
      push1state = 0;
      push2state = 0;
      push3state = 1;
      pushVal = 3;
      break;
  }
}
void loop() {
  push1();                                             //call to set once/day 
  push2();                                             //call to set twice/day 
  push3();                                             //call to set thrice/day 
    if (pushVal == 1) {                                // if push button 1 pressed then remind at 8am
    at8am();                                           //function to start uzzing at 8am 
  }
  else if (pushVal == 2) {                             // if push button 2 pressed then remind at 8am and 8pm
    at8am();                                            
    at8pm();                                           //function to start uzzing at 8mm
  }
  else if (pushVal == 3) {                             // if push button 3 pressed then remind at 8am and 8pm
    at8am();
    at2pm();                                            //function to start uzzing at 8mm
    at8pm();

  }
  currentMillisLCD = millis();                         // start millis for LCD screen switching at defined interval of time
  push1state = digitalRead(push1pin);                  // start reading all push button pins
  push2state = digitalRead(push2pin);
  push3state = digitalRead(push3pin);
  stopinState = digitalRead(stopPin);

  stopPins();                                            // call to stop buzzing
  changeScreen();                                        // screen cycle function

}
// push buttons
void push1() {                   // function to set reminder once/day 
  if (push1state == 1) {
    push1state = 0;
    push2state = 0;
    push3state = 0;
//    pushPressed = true;
    EEPROM.write(addr, 1);
    Serial.print("Push1 Written : "); Serial.println(EEPROM.read(addr));  // for debugging
    pushVal = 1;                                             //save the state of push button-1 
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Reminder set ");
    lcd.setCursor(0, 1);
    lcd.print("for Once/day !");
    delay(1200);
    lcd.clear();
  }
}
void push2() {                      //function to set reminder twice/day
  if (push2state == 1) {
    push2state = 0;
    push1state = 0;
    push3state = 0;
//    pushPressed = true;
    EEPROM.write(addr, 2);
    Serial.print("Push2 Written : "); Serial.println(EEPROM.read(addr));
    pushVal = 2;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Reminder set ");
    lcd.setCursor(0, 1);
    lcd.print("for Twice/day !");
    delay(1200);
    lcd.clear();
  }
}
void push3() {                    //function to set reminder thrice/day
  if (push3state == 1) {
    push3state = 0;
    push1state = 0;
    push2state = 0;
//    pushPressed = true;
    EEPROM.write(addr, 3);
    Serial.print("Push3 Written : "); Serial.println(EEPROM.read(addr));
    pushVal = 3;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Reminder set ");
    lcd.setCursor(0, 1);
    lcd.print("for Thrice/day !");
    delay(1200);
    lcd.clear();
  }
}
void stopPins() {                   //function to stop buzzing when user pushes stop push button
  if (stopinState == 1) {
//    stopinState = 0;
//    pushPressed = true;
    pushpressed = 1;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Take Medicine  ");
    lcd.setCursor(0, 1);
    lcd.print("with Warm Water");
    delay(1200);
    lcd.clear();
  }
}
void startBuzz() {                    // function to start buzzing when time reaches to defined interval
//  if (pushPressed == false) {
 if (pushpressed == 0) {
    Serial.println("pushpressed is false in blink");
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;         // save the last time you blinked the LED
      Serial.println("Start Buzzing");
      if (ledState == LOW) {                  // if the LED is off turn it on and vice-versa:
        ledState = HIGH;
      }  else {
        ledState = LOW;
      }
      digitalWrite(ledPin, ledState);
    }
  }
  else if (pushpressed == 1) {
    Serial.println("pushpressed is true");
    ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}
void at8am() {                      // function to start buzzing at 8am
  DateTime now = rtc.now();
  if (int(now.hour()) >= buzz8amHH) {
    if (int(now.minute()) >= buzz8amMM) {
      if (int(now.second()) > buzz8amSS) {
        /////////////////////////////////////////////////////
        startBuzz();
        /////////////////////////////////////////////////////
      }
    }
  }
}

void at2pm() {                          // function to start buzzing at 2pm
  DateTime now = rtc.now();
  if (int(now.hour()) >= buzz2pmHH) {
    if (int(now.minute()) >= buzz2pmMM) {
      if (int(now.second()) > buzz2pmSS) {
        ///////////////////////////////////////////////////
        startBuzz();
        //////////////////////////////////////////////////
      }
    }
  }
}
void at8pm() {                           // function to start buzzing at 8pm
  DateTime now = rtc.now();
  if (int(now.hour()) >= buzz8pmHH) {
    if (int(now.minute()) >= buzz8pmMM) {
      if (int(now.second()) > buzz8pmSS) {       
        /////////////////////////////////////////////////////
        startBuzz();
        /////////////////////////////////////////////////////
      }
    }
  }
}
//Screen Cycling
void changeScreen() {                 //function for Screen Cycling
  // Start switching screen every defined intervalLCD
  if (currentMillisLCD - previousMillisLCD > intervalLCD)             // save the last time you changed the display
  {
    previousMillisLCD = currentMillisLCD;
    screens++;
    if (screens > maxScreen) {
      screens = 0;  // all screens over -> start from 1st
    }
   isScreenChanged = true;
  }
  // Start displaying current screen
  if (isScreenChanged)   // only update the screen if the screen is changed.
  {
    isScreenChanged = false; // reset for next iteration
    switch (screens)
    {
      case getWellsoon:
        gwsMessege();                // get well soon message
        break;
      case HELP_SCREEN:              
        helpScreen();               // instruction screen
        break;
      case TIME_SCREEN:
        timeScreen();                  // to print date and time
        break;
      default:
        //NOT SET.
        break;
    }
  }
}

Working Explanation

In the beginning of the code, The sketch defines several variables and constants, including pins for push buttons, LEDs, and a buzzer. It also defines the screens to be displayed on an LCD screen and the times for reminders to be set.

The setup function initializes the RTC module and LCD display and sets the initial display message. It also sets the pins for the push buttons and reads a value from the EEPROM to determine the previous state of the push buttons. The loop function checks the current time and compares it to the reminder times set in the sketch. If the current time matches one of the reminder times and the corresponding push button is pressed, the LED and buzzer are activated. The function also cycles through the different LCD screens depending on which push button is pressed.

Applications

  • Medication adherence
  • Disease management
  • Elderly care
  • Post-operative care
  • Chronic disease management
  • Clinical trials
  • Mobile health
  • Telemedicine
  • Personal health monitoring
  • Pharmacy management.