#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <Encoder.h> // Include the Rotary Encoder library
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Initialize 16x2 LCD
#define buzzer 3
#define motorDriver 4
#define sensor 2
volatile long pulse;
unsigned long lastTime;
float volume;
float desiredFlowRate = 4.5; // Default desired flow rate
float desiredVolume = 0.0; // Variable to store the desired volume set by the user
Encoder myEncoder(A0, A1); // Initialize Rotary Encoder
bool backlightOn = true; // Variable to track the backlight status
// configure keypad (from LAB03)
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}};
const byte rowPins[ROWS] = {13, 12, 11, 10};
const byte colPins[COLS] = {9, 8, 7, 6};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
unsigned long startTime;
//const unsigned long animationDuration = 5000; // Duration of animation in milliseconds
bool menuDisplayed = false; // Track if the menu is currently displayed or not
//bool animationRunning = true; // Flag to control animation running
char selectedMode = ' '; // Default selected mode is none
bool flowDetectionRunning = false; // Flag to indicate if flow detection is running
void setup()
{
pinMode(buzzer, OUTPUT);
pinMode(sensor, INPUT);
pinMode(motorDriver, OUTPUT);
//pinMode(5,OUTPUT);
Serial.begin(9600);
lcd.init();
lcd.backlight();
startTime = millis(); // Record the start time
//Liters per Minute
attachInterrupt(0, increase, FALLING);
//attachInterrupt(sensor, increase, FALLING);
}
void displayMenu()
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("A: Continuous");
lcd.setCursor(0, 1);
lcd.print("B: Flow Control");
menuDisplayed = true;
}
void loop() {
char key = keypad.getKey(); // Get the key pressed
if (key != NO_KEY) {
tone(buzzer, 1300, 50); // Play tone for keypress
if (key == '*') { // If asterisk (*) key is pressed
if (!menuDisplayed) { // If menu is not already displayed
displayMenu(); // Display the menu
//stopAnimation(); // Stop the animation
}
} else if (key == '#') { // If '#' key is pressed
stopMode(); // Stop the current mode
} else if (menuDisplayed) { // If menu is displayed
if (key >= 'A' && key <= 'C' && selectedMode == ' ') { // If a valid mode key is pressed and no mode is currently running
selectedMode = key;
switch (selectedMode) {
case 'B':
modeC(); // Enter Mode C
break;
}
} else if (selectedMode != ' ') { // If mode is selected
// Handle mode-specific button presses here
}
}
}
}
void stopMode() {
// Stop the current mode
if (flowDetectionRunning) {
stopFlowDetection(); // Stop flow detection if running
}
// Reset mode-related variables and return to mode selection screen
selectedMode = ' ';
menuDisplayed = false;
//animationRunning = true;
}
void stopFlowDetection() {
// Stop the flow detection process
// You may need to implement this function based on your requirements
// Reset PWM to zero
//analogWrite(motorDriver, 0);
flowDetectionRunning = false; // Reset flow detection flag
}
void displayModeC(float actualVolume)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set Point:");
lcd.setCursor(0, 1);
lcd.print("Actual: ");
lcd.print(actualVolume, 1); // Display the actual accumulated volume
lcd.print(" mL");
}
void modeC() {
// Display Mode C menu with initial volume (0.0 mL)
displayModeC(0.0);
// Get the desired volume from the user
float setVolume = getSetVolume();
// Start flow detection
if (flowDetectionRunning) {
detectFlow(setVolume);
}
}
float getSetVolume() {
// Get the desired volume from the user using the keypad
// This function should wait until the user presses '*' to confirm the input
float volume = 0.0;
bool volumeEntered = false;
while (!volumeEntered) {
char key = keypad.getKey();
if (key >= '0' && key <= '9') {
volume = volume * 10 + (key - '0');
lcd.setCursor(10, 0);
lcd.print(volume);
} else if (key == '*') {
volumeEntered = true;
flowDetectionRunning = true; // Set flow detection flag
}
}
return volume;
}
void detectFlow(float setVolume) {
unsigned long lastTime = 0;
unsigned long interval = 1000; // Interval for flow rate calculation (in milliseconds)
unsigned long totalPulses = 0;
float totalVolume = 0.0;
lcd.setCursor(8, 1);
lcd.print(" "); // Clear previous value
while (true) {
unsigned long currentTime = millis();
if (currentTime - lastTime >= interval) {
// Calculate flow rate every 'interval' milliseconds
float flowRate = (pulse - totalPulses) * 60.0 / (interval * 7.5); // Assuming 7.5 pulses per liter
totalPulses = pulse;
lastTime = currentTime;
// Update total volume
totalVolume += flowRate / 1000.0; // Convert flow rate from L/min to L/s, then accumulate
// Update LCD with actual accumulated volume under "Actual: " section
lcd.setCursor(8, 1);
lcd.print(totalVolume, 1); // Print actual accumulated volume with 1 decimal place
lcd.print(" mL");
// Check if accumulated volume meets or exceeds set volume
if (totalVolume >= setVolume) {
// If accumulated volume meets or exceeds set volume, stop the pump
analogWrite(motorDriver, 0); // Stop the pump
flowDetectionRunning = false; // Reset flow detection flag
menuDisplayed = false; // Return to mode selection
break;
}
}
}
}
void increase()
{
pulse++;
}