ECE 4180 Medication Adherence Smart Pill-Dispenser Prototype
Smart Pill-Dispenser
Group Member: Xiannan Di, Yuhao Lin, Zhipeng Shao
Description
This design is created for ECE 4180 final project as well as for an initial prototype of ECE 4011/4012 Senior Design project. For more information on our Senior Design project on Medication Adherence, please check out our proposal.
This prototype utilizes nRF52 board's built-in BLE function to receive commands from smartphone app. The LCD screen will display the commanded number of pills each time. The dispenser, based on a small geared DC motor driven by MOSFET, revolves and drops the specified amount of pills at a constant rate.
Parts List
- Nordic nRF52-DK
- uLCD-144-G2 128 by 128 Smart Color LCD
- Power MOSFET breakout board
- DC Motor
- SN74HC04 inverter
Software

The nRF Connect is a mobile app developed by Nordic Semiconductor. It is available on both iOS and Android, and supports BLE communication with the nRF52-DK board.
Schematic

Source Code
main.cpp
#include "mbed.h"
#include "ble/BLE.h"
#include "uLCD_4DGL.h"
uLCD_4DGL uLCD(p6,p8,p11);
BLEDevice ble;
DigitalOut led(LED1);
PwmOut Ctrl(p19);
DigitalOut drop_led(LED2);
uint16_t PILL_SERVICE_UUID = 0xA000; // service UUID
uint16_t readCharUUID = 0xA001; // read characteristic UUID
uint16_t writeCharUUID = 0xA002; // write characteristic UUID
int pill_num = 0;
const static char DEVICE_NAME[] = "PILL_DROP";
static const uint16_t uuid16_list[] = {PILL_SERVICE_UUID};
static uint8_t readValue[1] = {0};
ReadOnlyArrayGattCharacteristic<uint8_t, sizeof(readValue)> readChar(readCharUUID, readValue);
static uint8_t writeValue[1] = {0};
WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(writeValue)> writeChar(writeCharUUID, writeValue);
// Set up pill service
GattCharacteristic *characteristics[] = {&readChar, &writeChar};
GattService pillService(PILL_SERVICE_UUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
//(void) params;
BLE::Instance().gap().startAdvertising();
}
/*
* handle writes to writeCharacteristic
*/
void writeCharCallback(const GattWriteCallbackParams *params)
{
// check to see what characteristic was written, by handle
if(params->handle == writeChar.getValueHandle() && params->len == 1) {
pill_num = params->data[0];
led = params->data[0];
uLCD.printf("%x pill(s)\n\r",pill_num);//
//(params->data[0] == 0x00) ? printf("\n\rled on ") : printf("\n\rled off "); // print led toggle
for(int i = 1; i <= pill_num; i++){
Ctrl = 0.95f;
drop_led = 1;
wait(7);
Ctrl = 1.0f;
drop_led = 0;
wait(5);
}
//Pill drop code
ble.updateCharacteristicValue(readChar.getValueHandle(), params->data,params->len);
}
// update the readChar with the value of writeChar
}
/*
* main loop
*/
int main(void)
{
Ctrl = 1.0f;
/* Initialization */
ble.init();
ble.gap().onDisconnection(disconnectionCallback);
ble.gattServer().onDataWritten(writeCharCallback);
/* setup advertising */
// BLE only, no classic BT
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
/* 1000ms. */
ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
ble.addService(pillService);
ble.gap().startAdvertising();
uLCD.printf("Hello, BLE connection successful\n\r");
// infinite loop waiting for BLE interrupt events
while (true) {
ble.waitForEvent(); //Save power
}
}
Photos

Demo Video
Please log in to post comments.
