Project tutorial
Medicine Reminder and Vending Machine

Medicine Reminder and Vending Machine

A medicine vending machine to store and give doses via medicine bottles and alert patients at prescribed times.

  • 1,993 views
  • 4 comments
  • 27 respects

Components and supplies

Ardgen mega
Arduino Mega 2560 & Genuino Mega 2560
Alternatively, Arduino Nano or Uno can be used.
×1
Bourns pec11r 4215f s0024 image 75px
Rotary Encoder with Push-Button
This will be used to provide Dose Time input to the microcontroller.
×1
Sg90 servo motor 180 degrees sg90 micro
SG90 Micro-servo motor
Servo motors will be used to implement rack mechanism to drop medicine boxes. And clear the medicine rack if a patient misses a dose, so as to avoid confusion when next dose drops.
×5
DS3231 RTC Module
To keep track of time
×1
MP3 player module and speaker
This will play audio tones stored in SD card. Alternatively, a buzzer can be used to keep cost low.
×1
398 09
Adafruit RGB Backlight LCD - 16x2
To display upcoming medicine dose time.
×1
09590 01
LED (generic)
×1
IR sensor
To detect when a dose drops and is taken by patient to update information in SD card.
×1
Micro SD card module and SD card
Used to store dost history of the patient
×1

Necessary tools and machines

Apps and online services

About this project

There is no cure for CoViD-19 yet, although patients are given some medicines by nurses and doctors to ease the pain,increase immunity, and reduce symptoms. But this puts our Healthcare warriors at risk when they give the medicine to patients, thus I developed a machine that can take in the Medicine Doses of an Entire week, store them and supply them to the patient at the time set by the doctor once, at the start-up of the machine. This will ensure distancing from patients and nurses won't have to risk their lives to go and give medicine to the infected patient. Once the medicine is on the given rack from where the patient can take it, he/she is alerted via a speaker on the system to take the medicine. The data of when the medicine is taken is stored in an SD card for further reference by doctors to monitor the effect on symptoms by the given doze. This machine can also be used in houses where old patients forget to take medicines on time and need a caretaker to provide them each dose. For using it in households, there is one more feature added- Excercise and Food times of the patient can be stored and act as a reminder, and the machine can also act as an alarm clock and can store 3 alarms. Food and exercise times help patients since there are certain meds that need to be taken at proper intervals before or after food, thus having food on time is important.

Why use this?

Following lines are taken from an Economic Times post-

"The figure for health care workers infections has risen from 23,000 to we think more than 90,000, but that is still an underestimation because it is not (covering) every country in the world," Howard Catton, ICN's chief executive officer, told Reuters Television in its lakeside offices.

The 90,000 estimate is based on information collected on 30 countries from national nursing associations, government figures and media reports. The ICN represents 130 national associations and more than 20 million registered nurses. Catton, noting that 3.5 million cases of COVID-19 have been reported worldwide, said: "If the average health worker infection rate, about 6 percent we think, is applied to that, the figure globally could be more than 200,000 health workers infections today.

The World Health Organization (WHO), which is coordinating the global response to the pandemic, says that its 194 member states are not providing comprehensive figures on health worker infections as they grapple with the unprecedented crisis.

The above lines are taken from ET. These are the numbers of total cases and total nurses infected as of 6 May 2020. This shows that around 6% of health workers are getting infected by the deadly disease that has no cure yet. But how?

The health workers have PPE still they are getting infected. This is because they give medicines and different drugs to patients to ease their pain and monitor the effects for drawing conclusions and further studies. This alone puts them at a huge risk by keeping them at close proximity to give them just the medicine.

Working of proposed system-

When the machine is first booted, the user is asked to set the dose times for all the doses of each day. If two racks are used, up to 28 Doses can be stored in a single refill. Each day, 4 doses can be delivered according to the time set. The LCD displays upcoming doses. The rotary encoder is used to set the time for each dose. Servo motors are used to deliver the medicine to rack and clear the rack if the patient misses the dose. The IR sensor is used to detect the time at which the dose is dropped and taken by the patient and the data is stored in SD card in.csv format. Once the dose is delivered, the speaker plays a tone (a custom audio clip which is dubbing of person reminding to take the dose, followed by a ringtone) to alert the patient to take the dose. LED also blinks repeatedly to provide visual output.

How to assemble-

For assembling this system and delivering it to large quarantine centers, a small medicine holding rack can be created as shown below. All the connections and hardware should be enclosed inside a small case and the rack with wires is placed outside. Any hard material can be used to make this, I used cardboard for prototype and acrylic for the finished product that is demonstrated in the video at the end of the explanation.

Medicine vending rack mechanism using Two Servos-

Two servos can be used to deliver a medicine dose at the set time. They should be connected next to each other on opposite sides with a small flap to block the medicine. This rack should be inclined a little bit to ensure the medicine falls correctly. The rack has a simple rectangular design open from above to add the filled medicine doses to it. This rack can be easily replicated from the images. The dimensions are 24 x 5.4 x 3 cm cube.

Medicine Dose Boxes-

These medicine dose boxes are commercially available and they are usually used to store Homeopathy medicine. Due to the small form factor and good storing capability, they are perfect for our project. 2-3 different medicines of a particular doze can be easily stored in these boxes. If a certain person requires mode medicines in a single dose, bigger versions of these bottles can be used to accommodate more meds.

SD Card data logging-

The data which contains when the patient has taken the dose (or missed) is stored inside an SD card, thus doctors can review it at a later stage to see how a certain medicine dose affected the patient's symptoms. The first column is of data, second is the day, the next column is of the dose time set by the nurse, and next to is the column which contains the time at which the patient takes the dose. If he/she misses the dose, it is also stored in an SD card.

Demonstration video-

Demonstration

Conclusion-

This product can be easily replicated and placed in Covid-19 Quarantine centers next to patient beds to give them their medication on time. For the design of the product, only two racks with a small case for electronics can be made, keeping the cost low. These racks can be kept as shown in the small scale prototype shown above, or a product housing all the components can be made as shown in the demo video. Using this product will ensure safety to healthcare workers who provide medicines, by keeping them at distance from the infected person.

I intend to expand the scope of this project by adding Wi-Fi functionality and syncing it with an IoT Cloud to provide easy access to real-time medicine data of each patient in the hospital which can be monitored by a nurse at the reception through a computer.

Code

MedicineReminder.inoArduino
This code should be uploaded on Arduino MEGA2560 and all the functions and connections are mentioned in the code.
/*
* Development Board: Arduino MEGA2560 
* Project Name:   <Medicine Reminder and Vending Machine>
* Code Developed by:    <Mihir Khara>
* Filename:     <MedicineReminder.ino>
* Functions:    All functions expect and return void
*                <alarmCheck, regAlarmCheck, dataLoggingMissed, dataLoggingTaken, medFall,
*                medTaken, displayHistory, firstBoot, regAlarm, customMedTime, medTime, 
*                displayTime, isr, timerIsr, encoderButton, readRotaryEncoder>
* Global Variables: <  Booleans-
*                      checkTemp1, checkTemp2 , CcheckTemp1 , CcheckTemp2 ,
*                      isrflag , firstTime, up , down, middle, displaySwitch
*
*                      Integers-
*                      timer, cD, setHour, setMin, setDay, rA, hourAddr, minAddr, ChourAddr, 
*                      CminAddr, dayAddr, checkHour, checkMin, checkHourTempVar, checkMinTempVar,  
*                      CcheckHour, CcheckMin, CcheckHourTempVar, CcheckMinTempVar, checkDay, 
*                      alarmHour, alarmMin, currHour, currMin, currDay, pos, dozeCounter, 
*                      last, value, sd_x, sd_y, dataDay, dataMonth, dataYear, dataHourFall, 
*                      dataMinuteFall, dataHourTaken, dataMinuteTaken
*
*                      Strings-
*                      item1, item2, item3, item4, dataDayOfWeek >
*                           
*/

/* Library credits to all respected developers */
#include <Wire.h>
#include "RTClib.h"
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <ClickEncoder.h>
#include <TimerOne.h>
#include <SPI.h>
#include <SD.h>
#include <Servo.h>
#include <SoftwareSerial.h>
#include <DFMiniMp3.h>

//definition of pins
#define clearServo 10
#define r1p1 4
#define r1p2 5
#define r2p1 7
#define r2p2 6 
#define ChipSelect 53
#define SCK 52
#define MOSI 51
#define MISO 50
#define yled 36
#define rled 37
#define sensor 18
#define clk A0
#define dt A1
#define sw A2
#define rs 8
#define rw 9
#define d4 22
#define d5 23
#define d6 24
#define d7 25
LiquidCrystal lcd(rs, rw, d4, d5, d6, d7); 

//Booleans to control the alarm time which needs to be checked
boolean checkTemp1 = false;
boolean checkTemp2 = true;
boolean CcheckTemp1 = false;
boolean CcheckTemp2 = true;

volatile boolean isrflag = false ;    //variable used to detect the medicine drop
unsigned int timer = 0;
//variables for setting the doze times
int cD;             //custome doze
int setHour;
int setMin;
int setDay;
int rA;             //regular alarm

// In the entire code, similar variables will be found,
// for example hourAddr and ChourAddr 
// these variables have the same use, the normal variable handles the normal doze times, 
// and the variable with a C initial handles the custom doze times

//variables used to hold EEPROM addresses
int hourAddr = 2;
int minAddr  = 3;
int ChourAddr = 11;
int CminAddr  = 12;
int dayAddr   = 13;
boolean firstTime = true;     //varibale to detect if the machine is booted for the first time

//variables to check the current time with time set by care taker
int checkHour;
int checkMin;
int checkHourTempVar;
int checkMinTempVar;
int CcheckHour;
int CcheckMin;
int CcheckHourTempVar;
int CcheckMinTempVar;
int checkDay;
int alarmHour;
int alarmMin;

//variables to store current time
int currHour = 0;
int currMin  = 0;
int currDay  = 0;

//strings for displaying dozes on LCD
String item1;
String item2;
String item3;
String item4;

//booleans for reading the rotary encoder
boolean up = false;
boolean down = false;
boolean middle = false;
boolean displaySwitch = false;

//variables to write data to the sd card
int sd_x = 100;
int sd_y = 101;
int dataDay = 0; 
int dataMonth = 0;
int dataYear = 0; 
int dataHourFall = 0; 
int dataMinuteFall = 0;
int dataHourTaken = 0; 
int dataMinuteTaken = 0;
String dataDayOfWeek;

Servo r1s1,r1s2;          //servo objects
Servo r2s1,r2s2;          // r stands for rack, s stands for servo
Servo discardServo;       //object for servo used to empty the medicine rack
int pos = 0;              //variable for controlling servo position
int dozeCounter = 0;      //variable to count number of dozes delivered
RTC_DS3231 rtc;           //rtc object
File myFile;              //sd card file object
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
ClickEncoder *encoder;    //for rotary encoder
int16_t last, value;      

//the following code was found in the df player library and needed to be included in the main code
//it is used to create a df player object
class Mp3Notify
{
public:
  static void OnError(uint16_t errorCode)
  {
    // see DfMp3_Error for code meaning
    Serial.println();
    Serial.print("Com Error ");
    Serial.println(errorCode);
  }

  static void OnPlayFinished(uint16_t globalTrack)
  {
    Serial.println();
    Serial.print("Play finished for #");
    Serial.println(globalTrack);   
  }

  static void OnCardOnline(uint16_t code)
  {
    Serial.println();
    Serial.print("Card online ");
    Serial.println(code);     
  }

  static void OnCardInserted(uint16_t code)
  {
    Serial.println();
    Serial.print("Card inserted ");
    Serial.println(code); 
  }

  static void OnCardRemoved(uint16_t code)
  {
    Serial.println();
    Serial.print("Card removed ");
    Serial.println(code);  
  }
};
DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial);

//setup begins
void setup () 
{
  //all the objects are started and communication is established between the different modules interfaced
  pinMode(ChipSelect, OUTPUT);
  digitalWrite(ChipSelect, HIGH);
  delay(100);
  rtc.begin();
  lcd.begin(16,4);
  SD.begin(ChipSelect);
  Timer1.initialize(1000);
  Timer1.attachInterrupt(timerIsr); 

  EEPROM.write(1,1);                  //this is used to check if the machine is booted for the first time or not
  
  attachInterrupt(digitalPinToInterrupt(sensor),isr,RISING);  //interrupt attached to the sensor which detects med drop
  pinMode(rled,OUTPUT);
  digitalWrite(rled,LOW);

  //df player initializations
  mp3.begin();
  uint16_t volume = mp3.getVolume();
  mp3.setVolume(30);  
  uint16_t count = mp3.getTotalTrackCount();

  //rotary encoder initializations
  encoder = new ClickEncoder(dt, clk, sw); 
  encoder->setAccelerationEnabled(false);
  last = encoder->getValue();

  //servo initializations
  r1s1.attach(r1p1);  
  r1s2.attach(r1p2); 
  r2s1.attach(r2p1);  
  r2s2.attach(r2p2); 
  discardServo.attach(clearServo);
  r1s1.write(0);
  r1s2.write(90);
  r2s1.write(0);
  r2s2.write(90);
}

//loop begins
void loop () 
{   

    DateTime now = rtc.now();         //current time is read
    if(EEPROM.read(1))                //this condition checks if the machine is booted for the first time or not
    {
      firstBoot();                    //function to handle the first boot up is called
    }
    
    encoderButton();                  //rotary encoder is read
    if(middle)                        //system detects if encoder button is pressed
    {
      middle = false;
      displaySwitch = !displaySwitch;
    }

    if(displaySwitch)
    {
      displayTime();                  //if the system detects that the user has pressed the encoder button, time is displayed
    }

    if(!displaySwitch)                //if the system detects that the user has pressed the encoder button, doze history is displayed
    {
      displayHistory();
    } 
      
    alarmCheck();                     //function to check the prescription time set is called
    regAlarmCheck();                  //function to check the regular alarm is called


    //this part of the code reads the ISR Flag and IR sensor and decides if the medicine is taken by the user or not
    if(isrflag)                       
    {
      isrflag = false;
      delay(500);
      if(!digitalRead(sensor))
      { 
        medFall();                           //save the current time
        delay(500);
      }
      else if(digitalRead(sensor))
      { 
        medTaken();                          //save the current time
        dataLoggingTaken();                  //write the current time to sd card
        delay(500);
      }
    }
}

/*
*
* Function Name:  alarmCheck
* Input:    None
* Output:   None
* Logic:    This function checks the current time with the data of time set by user to deliver the dozes as per the prescription
            If the time matches, the medicine doze is delivered and user is alerted via a speaker and LED
            It also checks if the user has missed the doze or not and calls function to store data in sd card accordingly
* Example Call:   void alarmCheck()
*
*/
void alarmCheck()
{
  if(firstTime)                           //necessary initializations that need to be done first time the machine is booted
  {
    hourAddr = 2;
    minAddr  = 3;
    ChourAddr = 11;
    CminAddr  = 12;
    dayAddr   = 13;
    firstTime = false;
  }
  DateTime now = rtc.now();

  //this part of code checks the checkTemp2 variable and decides if the address of the eeprom should be incremented or not
  if(checkTemp2)
  { 
    checkHour = EEPROM.read(hourAddr);              
    checkMin  = EEPROM.read(minAddr);
    hourAddr += 3;
    minAddr  += 3;
    if(hourAddr > 8) hourAddr = 2;
    if(minAddr > 9)  minAddr  = 3;
    checkTemp2 = false;
  }

  //this part of code checks the checkTemp2 variable and decides if the address of the eeprom should be incremented or not
  if(CcheckTemp2)
  {
    CcheckHour = EEPROM.read(ChourAddr);
    CcheckMin  = EEPROM.read(CminAddr); 
    checkDay   = EEPROM.read(dayAddr); 
    ChourAddr += 3;
    CminAddr  += 3;
    dayAddr   += 3;
    if(ChourAddr > 29)  ChourAddr = 11;
    if(CminAddr  > 30)  CminAddr  = 12;
    if(dayAddr   > 31)  dayAddr   = 13;
    CcheckTemp2 = false;
  }

  currHour = now.hour();
  currMin  = now.minute(); 
  currDay  = now.dayOfTheWeek();


  //logic to check the current time with the time set by user beigns
  if(currHour == checkHour)
  {
    if(currMin == checkMin)
    {
      //variables for checking are updated everytime a doze is delivered 
      checkMinTempVar = currMin;
      checkHourTempVar = currHour;
      checkTemp2 = true;
      dozeCounter++;              // this counter decides which rack should be activated to deliver the doze
       if(dozeCounter < 15)
        {

                //logic for activating servo motors to deliver the medicine
                //two servos are activated one after the other to drop the medicine box
                for (pos = 90; pos >= 0; pos-= 10)
                {
                  r1s2.write(pos);
                  delay(15);
                }
               
                for (pos = 0; pos <= 90; pos+= 10)
                {
                  r1s2.write(pos);
                  delay(15);
                }
               

                for (pos = 0; pos <= 110; pos+= 10)
                {
                  r1s1.write(pos);
                  delay(15);
                }
                
                for (pos = 110; pos >= 0; pos-= 10)
                {
                  r1s1.write(pos);
                  delay(15);
                }

        }
        else if((dozeCounter > 14) && (dozeCounter < 29))
        {
                for (pos = 90; pos >= 0; pos-= 10)
                {
                  r2s2.write(pos);
                  delay(15);
                }

                for (pos = 0; pos <= 90; pos+= 10)
                {
                  r2s2.write(pos);
                  delay(15);
                }


                for (pos = 0; pos <= 110; pos+= 10)
                {
                  r2s1.write(pos);
                  delay(15);
                }

                for (pos = 110; pos >= 0; pos-= 10)
                {
                  r2s1.write(pos);
                  delay(15);
                }

                if(dozeCounter == 28) dozeCounter = 0;
        }

      //rapid blinking of led
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      //playing audio or ringtone through the speaker
      mp3.playMp3FolderTrack(4);  
      delay(2000);
      mp3.playMp3FolderTrack(7);  
      delay(60000);
    }
  }

  //if the patient haven't taken the medicine after 5 or 10 minutes, he/she is alerted again
  if(currHour == checkHourTempVar)
  {
    if((currMin == (checkMinTempVar + 5) || currMin == (checkMinTempVar + 10)) && (!digitalRead(sensor)))
    {
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      digitalWrite(rled,HIGH);
      delay(100);
      digitalWrite(rled,LOW);
      delay(100);
      mp3.playMp3FolderTrack(4);  
      delay(2000);
      mp3.playMp3FolderTrack(7);  
      delay(30000);
    }
    if(currMin == (checkMinTempVar + 15) && (!digitalRead(sensor)))
    {
      dataLoggingMissed();
      for (pos = 0; pos <= 110; pos += 10)
      {
        discardServo.write(pos);
        delay(15);
      }
      for (pos = 110; pos >= 0; pos -= 10)
      {
        discardServo.write(pos);
        delay(15);
      }
    }
  }

  //this part of code has the same logic as above, it checks for custom medicine dozes
  if(currDay == checkDay)
  {
    if(currHour == CcheckHour)
    {
      if(currMin == CcheckMin)
      {
        CcheckMinTempVar = currMin;
        CcheckHourTempVar = currHour;
        CcheckTemp2 = true;
        dozeCounter++;
        if(dozeCounter < 15)
        {
                for (pos = 90; pos >= 0; pos-= 10)
                {
                  r1s2.write(pos);
                  delay(15);
                }
               
                for (pos = 0; pos <= 90; pos+= 10)
                {
                  r1s2.write(pos);
                  delay(15);
                }
               

                for (pos = 0; pos <= 110; pos+= 10)
                {
                  r1s1.write(pos);
                  delay(15);
                }
                
                for (pos = 110; pos >= 0; pos-= 10)
                {
                  r1s1.write(pos);
                  delay(15);
                }

        }
        else if((dozeCounter > 14) && (dozeCounter < 29))
        {
                for (pos = 90; pos >= 0; pos-= 10)
                {
                  r2s2.write(pos);
                  delay(15);
                }

                for (pos = 0; pos <= 90; pos+= 10)
                {
                  r2s2.write(pos);
                  delay(15);
                }


                for (pos = 0; pos <= 110; pos+= 10)
                {
                  r2s1.write(pos);
                  delay(15);
                }

                for (pos = 110; pos >= 0; pos-= 10)
                {
                  r2s1.write(pos);
                  delay(15);
                }

                if(dozeCounter == 28) dozeCounter = 0;
        }
       
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        mp3.playMp3FolderTrack(4);  
        delay(2000);
        mp3.playMp3FolderTrack(7);  
        delay(60000);
      }
    }
    if(currHour == CcheckHourTempVar)
    {
      if((currMin == (CcheckMinTempVar + 5) || currMin == (CcheckMinTempVar + 10)) && (!digitalRead(sensor)))
      {
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        digitalWrite(rled,HIGH);
        delay(100);
        digitalWrite(rled,LOW);
        delay(100);
        mp3.playMp3FolderTrack(4);  
        delay(2000);
        mp3.playMp3FolderTrack(7);  
        delay(30000);
      }


      //this part of code checks that if the patient has not taken the doze after 20 minutes, the rack is cleared 
      // for the next medicine so that confusion to take the correct doze does'nt happen when the next doze drops
      //data is written to sd card that doze is missed
      if(currMin == (CcheckMinTempVar + 15) && (!digitalRead(sensor)))
      {
        dataLoggingMissed();
        for (pos = 0; pos <= 110; pos += 10)
        {
          discardServo.write(pos);
          delay(15);
        }
        for (pos = 110; pos >= 0; pos -= 10)
        {
          discardServo.write(pos);
          delay(15);
        }
      }
    }
  }

}

/*
*
* Function Name:  regAlarmCheck
* Input:    None
* Output:   None
* Logic:    This function checks the current time with the data of time set by user to activate the alarm
* Example Call:   void regAlarmCheck()
*
*/
void regAlarmCheck()
{
  DateTime now = rtc.now();
  alarmHour = now.hour();
  alarmMin = now.minute();
  if(alarmHour == EEPROM.read(32))     //time is checked with the stored time and alarm starts ringing accordingly
  {
    if(alarmMin == EEPROM.read(33))
    {
        mp3.playMp3FolderTrack(3);  
        delay(2000);
        mp3.playMp3FolderTrack(5);  
        delay(30000);
    }
  }
    if(alarmHour == EEPROM.read(35))
  {
    if(alarmMin == EEPROM.read(36))
    {
        mp3.playMp3FolderTrack(6);  
        delay(30000);
    }
  }
    if(alarmHour == EEPROM.read(38))
  {
    if(alarmMin == EEPROM.read(39))
    {
        mp3.playMp3FolderTrack(6);  
        delay(30000);
    }
  }
}

/*
*
* Function Name:  dataLoggingTaken
* Input:    None
* Output:   None
* Logic:    This function writes data to sd card
* Example Call:   void dataLoggingTaken()
*
*/
void dataLoggingTaken()
{ 
  //this string is written on sd card and it contains all the information of medicine doze
  String dataString = String(dataDay) + "." + String(dataMonth) + "." + String(dataYear) + ", " + String(dataDayOfWeek) + ", " + String(dataHourFall) + ":" + String(dataMinuteFall) + ", " + String(dataHourTaken) + ":" + String(dataMinuteTaken);
  myFile = SD.open("NewData.csv", FILE_WRITE);
    if (myFile) 
    {
      myFile.println(dataString);
      myFile.close();
    }
    EEPROM.write(sd_x, dataHourTaken);
    sd_x = sd_x + 2;
    EEPROM.write(sd_y, dataMinuteTaken);
    sd_y = sd_y + 2;
    if(sd_x > 106) sd_x = 100;
    if(sd_y > 107) sd_y = 101;
}

/*
*
* Function Name:  dataLoggingMissed
* Input:    None
* Output:   None
* Logic:    This function writes data to sd card
* Example Call:   void dataLoggingTMissed()
*
*/
void dataLoggingMissed()
{ 
  String dataString = String(dataDay) + "." + String(dataMonth) + "." + String(dataYear) + ", " + String(dataDayOfWeek) + ", " + String(dataHourFall) + ":" + String(dataMinuteFall) + ", " + "Missed";
  myFile = SD.open("NewData.csv", FILE_WRITE);
    if (myFile) 
    {
      myFile.println(dataString);
      myFile.close();
    }
    EEPROM.write(sd_x, 0);
    sd_x = sd_x + 2;
    EEPROM.write(sd_y, 0);
    sd_y = sd_y + 2;
    if(sd_x > 106) sd_x = 100;
    if(sd_y > 107) sd_y = 101;
}

/*
*
* Function Name:  medFall
* Input:    None
* Output:   None
* Logic:    This function updates the variables with the current time from RTC. It is called when the medicine doze falls
* Example Call:   void medFall()
*
*/
void medFall()
{  
  //reading the time medicine falls
  DateTime now = rtc.now();
  dataDay = now.day();
  dataMonth = now.month();
  dataYear = now.year();
  dataDayOfWeek = daysOfTheWeek[now.dayOfTheWeek()];
  dataHourFall = now.hour();
  dataMinuteFall = now.minute();
}

/*
*
* Function Name:  medTaken
* Input:    None
* Output:   None
* Logic:    This function updates the variables with the current time from RTC. It is called when the medicine doze is taken
* Example Call:   void medTaken()
*
*/
void medTaken()
{
  //reading the time medicine is taken
  DateTime now = rtc.now();
  dataHourTaken = now.hour(); 
  dataMinuteTaken = now.minute();
}

/*
*
* Function Name:  displayHistory
* Input:    None
* Output:   None
* Logic:    This function displays the dozes of the day on the LCD
* Example Call:   void displayHistory()
*
*/
void displayHistory()
{
  //the doze times are displayed on LCD
  item1 = "Doze 1:";
  item2 = "Doze 2:";
  item3 = "Doze 3:";
  item4 = "Doze 4:";
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(item1);
  lcd.print(EEPROM.read(2));
  lcd.print(":");
  lcd.print(EEPROM.read(3));
  lcd.setCursor(0,1);
  lcd.print(item2);
  lcd.print(EEPROM.read(5));
  lcd.print(":");
  lcd.print(EEPROM.read(6));
  lcd.setCursor(0,2);
  lcd.print(item3);
  lcd.print(EEPROM.read(8));
  lcd.print(":");
  lcd.print(EEPROM.read(9));
  lcd.setCursor(0,3);
  lcd.print(item4);
  lcd.print(EEPROM.read(ChourAddr));      //upcoming doze time is displayed
  lcd.print(":");
  lcd.print(EEPROM.read(CminAddr));
  delay(300);
}

/*
*
* Function Name:  firstBoot
* Input:    None
* Output:   None
* Logic:    This function is called only once. It takes the input from the user of the doze and alarm times according to the prescription
* Example Call:   void firstBoot()
*
*/
void firstBoot()
{
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print("Welcome New User");
  mp3.playMp3FolderTrack(8);  
  delay(6000);
  lcd.clear();
  delay(300);
  lcd.setCursor(0,0);
  lcd.print("Set time");
  lcd.setCursor(0,1);
  lcd.print("Doze 1");
  medTime();                    //function is called to set the time
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Set time");
  lcd.setCursor(0,1);
  lcd.print("Doze 2");
  medTime();
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Set time");
  lcd.setCursor(0,1);
  lcd.print("Doze 3");
  medTime();
  lcd.clear();
  delay(300);

  lcd.setCursor(0,0);
  lcd.print("Set time for");
  lcd.setCursor(0,1);
  lcd.print("custom dozes of");
  lcd.setCursor(0,2);
  lcd.print("each day");
  mp3.playMp3FolderTrack(1);  
  delay(6000);
  for(cD = 0; cD < 7; cD++) customMedTime(); //function is called to set the time

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Set time for");
  lcd.setCursor(0,1);
  lcd.print("alarms");
  delay(2000);
  for (rA = 0; rA < 3; rA++) regAlarm();   //function is called to set the time

  mp3.playMp3FolderTrack(2);    
  delay(3000); 
}

/*
*
* Function Name:  regAlarm
* Input:    None
* Output:   None
* Logic:    This function is called only once. It takes the input from the user of the alarm times
* Example Call:   void regAlarm()
*
*/
void regAlarm()
{
    lcd.clear();
    delay(300);
    setHour = 0;
    setMin = 0;
    lcd.setCursor(0,0);
    lcd.print("Set time");
    lcd.setCursor(0,2);
    lcd.print(setHour);
    lcd.print(":");
    lcd.print(setMin);
    medTime(); 
}

/*
*
* Function Name:  customMedTime
* Input:    None
* Output:   None
* Logic:    This function is called only once. It takes the input from the user of the custom doze times of each day
* Example Call:   void customMedTime()
*
*/
void customMedTime()
{   
    lcd.clear();
    delay(300);
    setHour = 0;
    setMin = 0;
    lcd.setCursor(0,0);
    lcd.print("Set time");
    lcd.setCursor(0,1);
    lcd.print(daysOfTheWeek[cD]);
    lcd.setCursor(0,2);
    lcd.print(setHour);
    lcd.print(":");
    lcd.print(setMin);
    medTime();
    EEPROM.write(dayAddr,cD);
    dayAddr  += 3;
}

/*
*
* Function Name:  medTime
* Input:    None
* Output:   None
* Logic:    This function is to store the input given by user in memory of the microcontroller.
* Example Call:   void medTime()
*
*/
void medTime()
{
  int temp = 1;
  setHour = 0;
  setMin = 0;
  while (temp == 1)           //hour is set
  {
    readRotaryEncoder();
    encoderButton();
    if(EEPROM.read(1))
    { 
      EEPROM.write(1,0);
      middle = false;
    }
    if(up)                  //checks if the encoder is rotated in upwards direction
    {
      setHour++;
      up = false;
      if (setHour > 23) setHour = 0;
      if (setHour < 0) setHour = 23;
    }
    else if(down)           //checks if the encoder is rotated in downwards direction            
    {
      setHour--;
      down = false;
      if (setHour < 0) setHour = 23;
      if (setHour > 23) setHour = 0;
    }
    lcd.setCursor(0,2);
    lcd.print(setHour);
    lcd.print(":");
    lcd.print(setMin);
    if(middle == true)    //checks if button is pressed
    { 
      middle = false;
      EEPROM.write(hourAddr, setHour); //time is set for the doze
      hourAddr += 3;
      temp = 2;
    }
  }
  while (temp == 2)           //minutes are set
  {
    readRotaryEncoder();
    encoderButton();
    if(up)
...

This file has been truncated, please download it to see its full contents.
Medicine Reminder and Vending Machine
The repository contains all the required hardware information, connections, explanation of product, libraries required along with code and apk for optional alarm app.

Schematics

Schematic
Schematic medicine reminder rrqd8fqkji
PCB Top view
Tv jhcjx3apkl
PCB bottom view
Bv tfqcpjjqb3
PCB Gerber
Gerber file of PCB designed in EasyEDA
_MXLQRDQPcM.Gerber
PCB .json file
This file can be opened on EasyEDA and can be edited.
_I5M9JwRVrs.PCB%20design

Comments

Similar projects you might like

Arduino-Based Bitcoin Candy Vending Machine

Project tutorial by Team Elkrem

  • 9,866 views
  • 19 comments
  • 58 respects

Snacks Vending Machine Powered By Arduino

Project tutorial by Sevenmojoe

  • 28,002 views
  • 15 comments
  • 110 respects

Coin Op Personal Vending Machine

Project tutorial by comptek4

  • 7,605 views
  • 15 comments
  • 37 respects

MeDuino: Smart Automatic Medicine Reminder

Project tutorial by ashraf_minhaj

  • 4,690 views
  • 0 comments
  • 14 respects

DIY Vending Machine using Arduino & 1Sheeld

Project tutorial by Mahmoud Ahmed

  • 11,534 views
  • 12 comments
  • 43 respects

Social Distancing Reminder – Coronavirus

Project tutorial by Arca_Ege

  • 3,008 views
  • 2 comments
  • 12 respects
Add projectSign up / Login