I'm building a programmable resin pump for my resin printer. The goal is to enable the ability to set a print volume and print time provided by the printer. The pump would then pump at full speed to cover the build plate, then continue at a lower speed to continue filling until the print is complete. Other features would be added as needed.
The problem that I'm having is that I can control everything by typing the commands on the keyboard, but the interrupt is not working as expected. Only the Left and Right commands work, but Up and Enter do nothing, and Down freezes the Arduino. The other buttons aren't connected yet.
When commands are issued via keyboard or button successfully, the command is printed to the serial terminal, e.g. #CMD# UP.
When using the buttons, Up and Enter (center) do nothing. Left and Right function properly, but Down begins to return the command and freezes the Arduino at #C so that even the keyboard commands do nothing.
I've tried changing the byte values of Up, Down, Left, Right, and Enter to a number of different values, but no change was noted.
What is going wrong?
Sketch
/*
Sub Menu
https://lcdmenu.forntoh.dev/examples/submenu
*/
#include <ItemSubMenu.h>
#include <ItemInput.h>
#include <LcdMenu.h>
#include <utils/commandProccesors.h>
// #define is an alternate way of declaring a const
#define LCD_ROWS 4
#define LCD_COLS 20
#define COMMONPIN 2
const byte BUTTONPINS[] = {4,5,6,7,8,9,10,11};
// Define commands as
#define UP 56 // NUMPAD 8
#define DOWN 50 // NUMPAD 2
#define LEFT 52 // NUMPAD 4
#define RIGHT 54 // NUMPAD 6
#define ENTER 53 // NUMPAD 5
#define BACK 55 // NUMPAD 7
#define BACKSPACE 8 // BACKSPACE
#define CLEAR 46 // NUMPAD .
// Assigned based on the hardware directional buttons
const byte commandOrder[8] = {UP,DOWN,LEFT,RIGHT,ENTER,BACK,BACKSPACE,CLEAR};
unsigned long lastFire = 0;
extern MenuItem* autofillMenu[];
extern MenuItem* semiautofillMenu[];
extern MenuItem* manualfillMenu[];
extern MenuItem* selfcleanMenu[];
extern MenuItem* settingsMenu[];
#define CHARSET_SIZE 10
// Charset used for entering values
char charset[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
// Active index of the charset
int8_t charsetPosition = -1;
// Declare the call back functions
void setVolumeCallback(char* value);
void setTimeCallback(char* value);
// Define the main menu
MAIN_MENU(
ITEM_BASIC(" Resin Pump"),
ITEM_SUBMENU("Auto Fill", autofillMenu),
ITEM_SUBMENU("Semi-Auto Fill", semiautofillMenu),
ITEM_SUBMENU("Manual Pump", manualfillMenu),
ITEM_SUBMENU("Self-Clean", selfcleanMenu),
ITEM_SUBMENU("Settings", settingsMenu));
// Auto-Fill
SUB_MENU(autofillMenu, mainMenu,
ITEM_BASIC(" Auto Fill"),
ITEM_INPUT("Set Vol. (ml)", "200", setVolumeCallback), // defalt to 200 ml (create a variable)
ITEM_INPUT("Set Time", "hh:mm", setTimeCallback), // default to 0's (create a variable)
ITEM_BASIC("Start") // Execute the command to fill the vat over the specified time span.
);
// Semi-Auto Fill
SUB_MENU(semiautofillMenu, mainMenu,
ITEM_BASIC(" Semi-Auto Fill"),
ITEM_INPUT("Set Vol. (ml)", "200", setVolumeCallback), // defalt to 200 ml (create a variable)
ITEM_BASIC("Start") // Execute the command to fill the vat immediately.
);
// Manual Control
SUB_MENU(manualfillMenu, mainMenu,
ITEM_BASIC(" Manual Control"),
ITEM_BASIC("Fill (out)"), // Execute the command to pump out,
ITEM_BASIC("Empty (in)"), // Execute the command to pump in,
ITEM_BASIC("Stop") // Execute the command to stop pumping.
);
// Self-Clean
SUB_MENU(selfcleanMenu, mainMenu,
ITEM_BASIC(" Self-Clean"),
ITEM_BASIC("Start"));
// Settings
SUB_MENU(settingsMenu, mainMenu,
ITEM_BASIC(" Settings"),
ITEM_BASIC("Max Volume of Vat"),
ITEM_BASIC("Default Volume"),
ITEM_BASIC("Resin Amount"),
ITEM_BASIC("Resin Overhead"),
ITEM_BASIC("Pump Flow Rate"),
ITEM_BASIC("Default Pump Speed"),
ITEM_BASIC("Print Start Delay"));
LcdMenu menu(LCD_ROWS, LCD_COLS);
void setup() {
Serial.begin(9600);
configureCommon();
menu.setupLcdWithMenu(0x27, mainMenu);
attachInterrupt(digitalPinToInterrupt(COMMONPIN), pressInterrupt, FALLING);
}
void loop() {
// TODO: Remove check for serial and Serial.read, these will be replaced
// by physical buttons and an interrupt.
if (!Serial.available())
return;
char command = Serial.read();
processMenuCommand(menu, command, charsetPosition, charset, CHARSET_SIZE, UP, DOWN, ENTER, BACK, CLEAR, BACKSPACE, LEFT, RIGHT);
}
/**
- Define callbacks
*/
// setVolume is share with both Auto Fill and Semi-Auto Fill
void setVolumeCallback(char* value) {
// Do stuff with value
Serial.print(F("# "));
Serial.println(value);
}
void setTimeCallback(char* value) {
// Do stuff with value
Serial.print(F("# "));
Serial.println(value);
}
/*** Begin Button Interrupt Watching ***/
void pressInterrupt() { // ISR
if (millis() - lastFire < 200) { // Debounce
return;
}
lastFire = millis();
configureDistinct(); // Setup pins for testing individual buttons
for (int i = 0; i < sizeof(BUTTONPINS) / sizeof(int); i++) { // Test each button for press
if (!digitalRead(BUTTONPINS[i])) {
execCommand(i);
}
}
configureCommon(); // Return to original state
}
void configureCommon() {
pinMode(COMMONPIN, INPUT_PULLUP);
for (int i = 0; i < sizeof(BUTTONPINS) / sizeof(int); i++) {
pinMode(BUTTONPINS[i], OUTPUT);
digitalWrite(BUTTONPINS[i], LOW);
}
}
void configureDistinct() {
pinMode(COMMONPIN, OUTPUT);
digitalWrite(COMMONPIN, LOW);
for (int i = 0; i < sizeof(BUTTONPINS) / sizeof(int); i++) {
pinMode(BUTTONPINS[i], INPUT_PULLUP);
}
}
void execCommand(int buttonIndex) {
byte command = commandOrder[buttonIndex];
processMenuCommand(menu, command, charsetPosition, charset, CHARSET_SIZE, UP, DOWN, ENTER, BACK, CLEAR, BACKSPACE, LEFT, RIGHT);
}
