Arnov Sharma
Published © MIT

MEDIC Mini

Medic Mini is a handheld ESP32-C6 device that checks symptoms using simple button inputs.

BeginnerFull instructions provided10 hours77
MEDIC Mini

Things used in this project

Hardware components

ESP32 C6 1.47
×1
Espressif ESP32 C6 devkit
×1
PCBWay Custom PCB
PCBWay Custom PCB
×1

Software apps and online services

Arduino IDE
Arduino IDE
Fusion
Autodesk Fusion

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

STEP FILE

Schematics

SCH

Code

MAIN CODE

C/C++
#include <Arduino_GFX_Library.h>

// LCD pin map for ESP32-C6
#define LCD_MOSI 6
#define LCD_SCLK 7
#define LCD_CS   14
#define LCD_DC   15
#define LCD_RST  21
#define LCD_BL   22
// Button pins
#define BTN_YES     9
#define BTN_NO      18
#define BTN_UNSURE  19
const char* symptoms[] = {
"Headache",
"Fever",
"Cough",
"Fatigue",
"Nausea"
};
const int symptomCount = sizeof(symptoms) / sizeof(symptoms[0]);
int responses[symptomCount]; // -1 = not answered, 0 = No, 1 = Yes, 2 = Not Sure
int currentSymptom = -1;
bool symptomDrawn = false;
enum ScreenState {
SCREEN_STARTUP,
SCREEN_SYMPTOM,
SCREEN_RESULT
};
ScreenState currentScreen = SCREEN_STARTUP;
ScreenState lastScreen = SCREEN_STARTUP;
// Button states
bool lastYes = false;
bool lastNo = false;
bool lastUnsure = false;
unsigned long lastInputTime = 0;
const unsigned long inputLockout = 300;
Arduino_DataBus *bus = new Arduino_ESP32SPI(
LCD_DC, LCD_CS, LCD_SCLK, LCD_MOSI, GFX_NOT_DEFINED
);
Arduino_GFX *gfx = new Arduino_ST7789(
bus,
LCD_RST,
2,
true,
172,
320,
34, 0,
34, 0
);
// Stable press detection
bool isStablePress(int pin, bool& lastState) {
bool current = digitalRead(pin) == LOW;
bool pressed = current && !lastState;
lastState = current;
return pressed;
}
void drawStartup() {
gfx->fillScreen(BLACK);
// Title split: Medic / Mini
gfx->setTextSize(3);
gfx->setTextColor(CYAN);
gfx->setCursor(20, 40);
gfx->println("Medic");
gfx->setCursor(20, 80);
gfx->println("Mini");
// Subtitle split: Symptom / Checker
gfx->setTextSize(2);
gfx->setTextColor(WHITE);
gfx->setCursor(20, 130);
gfx->println("Symptom");
gfx->setCursor(20, 160);
gfx->println("Checker");
// Red medical plus sign
gfx->fillRect(80, 220, 20, 60, RED);  // vertical bar
gfx->fillRect(60, 240, 60, 20, RED);  // horizontal bar
}
void drawSymptomPrompt(const char* symptom, int response) {
gfx->fillScreen(BLACK);
gfx->setTextSize(2);
gfx->setTextColor(WHITE);
gfx->setCursor(10, 80);
gfx->println("Do you have");
gfx->setCursor(10, 110);
gfx->print(symptom);
gfx->println("?");
// Centered response label
gfx->setTextSize(3);
int centerX = 86;
if (response == 1) {
gfx->setTextColor(GREEN);
gfx->setCursor(centerX - 30, 180);
gfx->println("Yes");
} else if (response == 0) {
gfx->setTextColor(RED);
gfx->setCursor(centerX - 30, 180);
gfx->println("No");
} else if (response == 2) {
gfx->setTextColor(YELLOW);
gfx->setCursor(centerX - 70, 180);
gfx->println("Not Sure");
}
}
void drawResult() {
gfx->fillScreen(BLACK);
gfx->setCursor(10, 60);
gfx->setTextSize(2);
gfx->setTextColor(GREEN);
gfx->println("Processing...");
delay(1000);
int yesCount = 0;
for (int i = 0; i < symptomCount; i++) {
if (responses[i] == 1) yesCount++;
}
gfx->fillScreen(BLACK);
gfx->setTextSize(2);
gfx->setTextColor(WHITE);
if (yesCount >= 3) {
gfx->setCursor(10, 100);
gfx->println("Possible");
gfx->setCursor(10, 170);
gfx->println("match:");
gfx->setCursor(10, 210);
gfx->setTextColor(YELLOW);
gfx->println("Flu or Viral");
} else if (yesCount == 2) {
gfx->setCursor(10, 100);
gfx->println("Mild symptoms");
gfx->setCursor(10, 140);
gfx->println("Monitor &");
gfx->setCursor(10, 170);
gfx->println("rest");
} else {
gfx->setCursor(10, 100);
gfx->println("No major");
gfx->setCursor(10, 140);
gfx->println("match found");
}
gfx->setCursor(10, 200);
gfx->setTextSize(1);
gfx->setTextColor(CYAN);
gfx->println("Press YES to restart");
}
void setup() {
pinMode(LCD_BL, OUTPUT);
digitalWrite(LCD_BL, HIGH);
pinMode(BTN_YES, INPUT_PULLUP);
pinMode(BTN_NO, INPUT_PULLUP);
pinMode(BTN_UNSURE, INPUT_PULLUP);
for (int i = 0; i < symptomCount; i++) {
responses[i] = -1;
}
gfx->begin();
drawStartup();
}
void loop() {
unsigned long now = millis();
if (currentScreen != lastScreen) {
if (currentScreen == SCREEN_STARTUP) {
drawStartup();
} else if (currentScreen == SCREEN_RESULT) {
drawResult();
}
lastScreen = currentScreen;
}
if (currentScreen == SCREEN_SYMPTOM &&
currentSymptom < symptomCount &&
!symptomDrawn) {
drawSymptomPrompt(symptoms[currentSymptom], responses[currentSymptom]);
symptomDrawn = true;
}
if (currentScreen == SCREEN_STARTUP &&
(isStablePress(BTN_YES, lastYes) || isStablePress(BTN_NO, lastNo) || isStablePress(BTN_UNSURE, lastUnsure))) {
currentSymptom = 0;
currentScreen = SCREEN_SYMPTOM;
symptomDrawn = false;
delay(300);
}
if (currentScreen == SCREEN_SYMPTOM && currentSymptom < symptomCount) {
if (now - lastInputTime > inputLockout) {
if (isStablePress(BTN_YES, lastYes)) {
responses[currentSymptom] = 1;
drawSymptomPrompt(symptoms[currentSymptom], 1);
delay(500);
currentSymptom++;
symptomDrawn = false;
lastInputTime = now;
} else if (isStablePress(BTN_NO, lastNo)) {
responses[currentSymptom] = 0;
drawSymptomPrompt(symptoms[currentSymptom], 0);
delay(500);
currentSymptom++;
symptomDrawn = false;
lastInputTime = now;
} else if (isStablePress(BTN_UNSURE, lastUnsure)) {
responses[currentSymptom] = 2;
drawSymptomPrompt(symptoms[currentSymptom], 2);
delay(500);
currentSymptom++;
symptomDrawn = false;
lastInputTime = now;
}
if (currentSymptom >= symptomCount) {
currentScreen = SCREEN_RESULT;
}
}
}
if (currentScreen == SCREEN_RESULT && isStablePress(BTN_YES, lastYes)) {
for (int i = 0; i < symptomCount; i++) {
responses[i] = -1;
}
currentSymptom = 0;
currentScreen = SCREEN_SYMPTOM;
symptomDrawn = false;
delay(300);
}
}

Credits

Arnov Sharma
355 projects • 361 followers
I'm Arnov. I build, design, and experiment with tech—3D printing, PCB design, and retro consoles are my jam.

Comments