#include <Stepper.h>
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
// Configs
#define STEPPER_STEP_PIN 9
#define STEPPER_DIR_PIN 8
#define STEPPER_STEPS_PER_REVOLUTION 800.0
#define STEPPER_MAX_RPM 400
#define KEYPAD_ROWS_COUNT 4
#define KEYPAD_COLS_COUNT 4
const byte KEYPAD_ROW_PINS[KEYPAD_ROWS_COUNT] = {28, 30, 32, 34};
const byte KEYPAD_COL_PINS[KEYPAD_COLS_COUNT] = {42, 44, 46, 48};
const char KEYPAD_KEYS_MAP[KEYPAD_ROWS_COUNT][KEYPAD_COLS_COUNT] = {
{'1', '2', '3', 'U'},
{'4', '5', '6', 'L'},
{'7', '8', '9', 'R'},
{'T', '0', 'S', 'D'}
};
#define LCD_I2C_ADDRESS 0x27
#define LCD_COLS_COUNT 16
#define LCD_ROWS_COUNT 2
#define RELAYS_COUNT 2
const int RELAYS_PINS[RELAYS_COUNT] = {10, 11};
#define SERIAL_SPEED 9600
#define KEYS_CONTINUE 'U'
#define KEYS_REMOVE 'D'
#define KEYS_RESET 'T'
#define KEYS_START 'S'
#define KEYS_STOP 'T'
// Init stepper
Stepper stepper(STEPPER_STEPS_PER_REVOLUTION, STEPPER_DIR_PIN, STEPPER_STEP_PIN);
// Init LCD
LiquidCrystal_I2C lcd(LCD_I2C_ADDRESS, LCD_COLS_COUNT, LCD_ROWS_COUNT);
// Init keypad
Keypad keypad = Keypad(makeKeymap(KEYPAD_KEYS_MAP), KEYPAD_ROW_PINS, KEYPAD_COL_PINS, KEYPAD_ROWS_COUNT, KEYPAD_COLS_COUNT);
// Init relays
struct Relay {
int pin;
bool status;
};
Relay relays[RELAYS_COUNT];
void init_relays() {
for (int i = 0; i < RELAYS_COUNT; i++) {
relays[i].pin = RELAYS_PINS[i];
pinMode(relays[i].pin, OUTPUT);
relays[i].status = false;
digitalWrite(relays[i].pin, LOW);
}
}
void toggle_relay(int relay_number) {
int index = relay_number - 1 ;
relays[index].status = !relays[index].status;
digitalWrite(relays[index].pin, relays[index].status ? HIGH : LOW);
}
void set_relay(int relay_number, bool status) {
int index = relay_number - 1 ;
relays[index].status = status;
digitalWrite(relays[index].pin, status ? HIGH : LOW);
}
void toggle_relays() {
for (int i = 1; i <= RELAYS_COUNT; i++) {
toggle_relay(i);
}
}
void set_relays(bool status) {
for (int i = 1; i <= RELAYS_COUNT; i++) {
set_relay(i, status);
}
}
// Setup
void setup() {
lcd.init();
lcd.backlight();
Serial.begin(SERIAL_SPEED);
Serial.println();
display_intro();
init_relays();
set_relay(2, true);
}
void loop() {
int speed = int_prompt("ENTER SPEED:", STEPPER_MAX_RPM, KEYS_REMOVE, KEYS_CONTINUE);
Serial.print("speed: ");
Serial.println(speed);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" (SPEED SAVED): ");
lcd.setCursor(5, 1);
lcd.print(speed);
lcd.setCursor(12, 1);
lcd.print("rpm");
delay(2000);
lcd.clear();
bool direction = bool_prompt("SELECT:", "SUCTION", 'L', "PUMPING", 'R');
char* direction_text = direction ? "SUCTION" : "PUMPING";
Serial.print("direction: ");
Serial.println(direction_text);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" (OPERATION): ");
lcd.setCursor(0, 1);
lcd.print(direction_text);
delay(500);
lcd.setCursor(8, 1);
lcd.print(">");
delay(100);
lcd.setCursor(9, 1);
lcd.print(">");
delay(100);
lcd.setCursor(10, 1);
lcd.print(">");
delay(2000);
int time = time_prompt("SET THE TIME:", KEYS_RESET, KEYS_CONTINUE);
Serial.print("time: ");
Serial.println(time);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("PRESS: START");
lcd.setCursor(0, 1);
lcd.print(" STOP");
char key;
while (true) {
key = keypad.getKey();
if (key == KEYS_RESET) {
break;
}
if (key != KEYS_START) {
continue;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("MOTOR IS RUNNING");
stepper.setSpeed(speed);
int step_per_second = ((float)speed * STEPPER_STEPS_PER_REVOLUTION) / 60.0;
Serial.print("step per second: ");
Serial.println(step_per_second);
set_relay(1, true);
set_relay(2, false);
int seconds = time;
char key;
while ((key = keypad.getKey()) != KEYS_STOP && seconds) {
lcd.setCursor(0, 1);
lcd.print(seconds_to_time_str(seconds));
bool completed_steps = stepper_step(step_per_second, direction, KEYS_STOP);
if (!completed_steps) {
break;
}
seconds--;
}
stepper.step(0);
lcd.setCursor(0, 1);
lcd.print(seconds_to_time_str(seconds));
set_relay(1, false);
set_relay(2, true);
break;
}
}
bool stepper_step(int steps, bool dir, char break_key) {
char key;
while (steps) {
key = keypad.getKey();
if (key == break_key) {
return false;
}
stepper.step(dir ? 1 : -1);
steps--;
}
return true;
}
void display_intro() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ** SAZETEB ** ");
delay(2000);
lcd.setCursor(0, 1);
lcd.print(">");
lcd.setCursor(15, 1);
lcd.print("<");
delay(100);
lcd.setCursor(1, 1);
lcd.print(">");
lcd.setCursor(14, 1);
lcd.print("<");
delay(500);
lcd.setCursor(2, 1);
lcd.print("INFUSIONPUMP");
delay(3000);
lcd.setCursor(0, 1);
String text = " ";
lcd.print(text);
for (int x = 0; x <= 14; x++) {
lcd.scrollDisplayRight();
delay(100);
}
delay(500);
lcd.clear();
}
int int_prompt(String text, int max_value, char remove_key, char break_key) {
Serial.print("[int prompt] ");
Serial.print(text);
Serial.print(" ");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(text.c_str());
if (max_value) {
lcd.setCursor(9, 1);
String max_label = "MAX=";
max_label.concat(max_value);
lcd.print(max_label.c_str());
}
String input;
char key;
while ((key = keypad.getKey()) != break_key) {
if (key) {
Serial.print(key);
}
if (key_is_number(key)) {
String new_input = input;
new_input.concat(key);
if (new_input.toInt() > max_value) continue;
input.concat(key);
lcd.setCursor(0, 1);
lcd.print(input.c_str());
} else if (key == remove_key) {
input.remove(input.length() - 1);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(text.c_str());
if (max_value) {
lcd.setCursor(9, 1);
String max_label = "MAX<";
max_label.concat(max_value);
lcd.print(max_label.c_str());
}
lcd.setCursor(0, 1);
lcd.print(input.c_str());
}
}
Serial.println();
return input.toInt();
}
bool bool_prompt(String text, String first_item, char first_item_key, String second_item, char second_item_key) {
Serial.print("[bool prompt] ");
Serial.print(text);
Serial.print(" ");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(text);
delay(500);
lcd.setCursor(8, 0);
lcd.print("<");
delay(500);
lcd.setCursor(9, 0);
lcd.print(first_item);
delay(500);
lcd.setCursor(8, 1);
lcd.print(">");
delay(500);
lcd.setCursor(9, 1);
lcd.print(second_item);
char key;
while (true) {
key = keypad.getKey();
if (key) {
Serial.print(key);
}
if (key == first_item_key) {
Serial.println();
return 1;
}
if (key == second_item_key) {
Serial.println();
return 0;
}
}
}
int time_prompt(String text, char reset_key, char break_key) {
Serial.print("[time prompt] ");
Serial.print(text);
Serial.print(" ");
const int size = 4;
char time[size] = {'0', '0', '0', '0'};
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(text.c_str());
lcd.setCursor(0, 1);
lcd.print("00:00");
char key = reset_key;
while ((key = keypad.getKey()) != break_key) {
if (key) {
Serial.print(key);
}
if (key == reset_key) {
for (int i = 0; i < size; i++) {
time[i] = '0';
}
lcd.setCursor(0, 1);
lcd.print("00:00");
continue;
}
if (!key_is_number(key)) {
continue;
}
lcd.setCursor(0, 1);
for (int i = 0; i < size; i++) {
time[i] = i == (size - 1) ? key : time[i + 1];
lcd.print(time[i]);
if (i == 1) {
lcd.print(":");
}
}
}
String input;
for (int i = 0; i < size; i++) {
input.concat(time[i]);
}
Serial.println();
return time_str_to_seconds(input);
}
int time_str_to_seconds(String time) {
int minutes = time.substring(0, 2).toInt();
int seconds = time.substring(2, 4).toInt();
return (minutes * 60) + seconds;
}
String seconds_to_time_str(int input_seconds) {
int minutes = input_seconds / 60;
int seconds = input_seconds % 60;
String minutesString = String(minutes);
if (minutes < 10) {
minutesString = "0" + minutesString;
}
String secondsString = String(seconds);
if (seconds < 10) {
secondsString = "0" + secondsString;
}
return minutesString + ":" + secondsString;
}
int key_to_int(char key) {
return key - 48;
}
bool key_is_number(char key) {
int number = key_to_int(key);
bool is_number = number >= 0 && number <= 9;
return is_number;
}