Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
d9b72aa8b5
|
|||
|
075ecdf1e2
|
|||
|
f2fbb9f205
|
|||
|
2d2051e6c2
|
|||
|
6be5a881e7
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
#include "menu.hpp"
|
||||
|
||||
/*
|
||||
* A helper class to facilitate drawing on a HD44780 LCD display.
|
||||
@@ -10,6 +11,10 @@ class Display {
|
||||
Display(uint8_t addr = 0x27, uint8_t cols = 20, uint8_t rows = 4);
|
||||
|
||||
void begin();
|
||||
void clear();
|
||||
void drawMenu(Menu& menu);
|
||||
|
||||
LiquidCrystal_I2C& getLCD();
|
||||
private:
|
||||
LiquidCrystal_I2C lcd;
|
||||
};
|
||||
|
||||
+11
-1
@@ -12,13 +12,22 @@
|
||||
* Note: The button is active LOW and requires a pull-up resistor, which can either be external (10kΩ)
|
||||
* or the internal pull-up resistor of the microcontroller (default).
|
||||
*/
|
||||
enum JoystickDirection {
|
||||
CENTER,
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
class Joystick {
|
||||
public:
|
||||
Joystick();
|
||||
|
||||
double getX() const;
|
||||
double getY() const;
|
||||
bool isPressed() const;
|
||||
|
||||
JoystickDirection getDirection() const;
|
||||
private:
|
||||
uint8_t vrx;
|
||||
uint8_t vry;
|
||||
@@ -26,4 +35,5 @@ class Joystick {
|
||||
|
||||
const uint8_t xOffset = 13;
|
||||
const uint8_t yOffset = 10;
|
||||
const uint8_t deadzone = 15; // Deadzone threshold to prevent jitter around the center position
|
||||
};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#define MENU_ITEM_COUNT 4
|
||||
#include <Arduino.h>
|
||||
#include "joystick.hpp"
|
||||
|
||||
typedef struct {
|
||||
String name;
|
||||
void (*action)();
|
||||
} Item;
|
||||
|
||||
class Menu {
|
||||
public:
|
||||
Menu(Item* items);
|
||||
void updateCurrentItem(JoystickDirection& direction);
|
||||
void execute();
|
||||
|
||||
Item& getItemAt(size_t index);
|
||||
size_t getCurrentItemIndex() const;
|
||||
private:
|
||||
Item items[MENU_ITEM_COUNT];
|
||||
int currentItem;
|
||||
};
|
||||
@@ -8,4 +8,25 @@ void Display::begin() {
|
||||
lcd.backlight();
|
||||
}
|
||||
|
||||
void Display::clear() {
|
||||
lcd.clear();
|
||||
}
|
||||
|
||||
void Display::drawMenu(Menu &menu) {
|
||||
clear();
|
||||
size_t currentItemIndex = menu.getCurrentItemIndex();
|
||||
for (size_t i = 0; i < MENU_ITEM_COUNT; i++) {
|
||||
lcd.setCursor(0, i);
|
||||
Item& item = menu.getItemAt(i);
|
||||
|
||||
if (i == currentItemIndex) {
|
||||
lcd.print("> " + item.name);
|
||||
} else {
|
||||
lcd.print(" " + item.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LiquidCrystal_I2C& Display::getLCD() {
|
||||
return lcd;
|
||||
}
|
||||
|
||||
@@ -20,3 +20,22 @@ double Joystick::getY() const {
|
||||
bool Joystick::isPressed() const {
|
||||
return digitalRead(sw) == LOW;
|
||||
}
|
||||
|
||||
// Determine the direction of the joystick based on the X and Y values, considering a deadzone to prevent jitter
|
||||
JoystickDirection Joystick::getDirection() const {
|
||||
double x = getX();
|
||||
double y = getY();
|
||||
|
||||
if (abs(x) < deadzone && abs(y) < deadzone) {
|
||||
return CENTER;
|
||||
} else if (y > deadzone) {
|
||||
return UP;
|
||||
} else if (y < -deadzone) {
|
||||
return DOWN;
|
||||
} else if (x > deadzone) {
|
||||
return RIGHT;
|
||||
} else if (x < -deadzone) {
|
||||
return LEFT;
|
||||
}
|
||||
return CENTER; // Default to CENTER if no direction is detected
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
Joystick joystick;
|
||||
Display display;
|
||||
|
||||
Item items[MENU_ITEM_COUNT] = {
|
||||
{"Feed", []() { Serial.println("Feeding..."); }},
|
||||
{"Play", []() { Serial.println("Playing..."); }},
|
||||
{"Sleep", []() { Serial.println("Sleeping..."); }},
|
||||
{"Clean", []() { Serial.println("Cleaning..."); }}
|
||||
};
|
||||
Menu menu(items);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {
|
||||
@@ -14,7 +22,19 @@ void setup() {
|
||||
|
||||
display.begin();
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
display.drawMenu(menu);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
JoystickDirection direction = joystick.getDirection();
|
||||
if (direction != JoystickDirection::CENTER) {
|
||||
menu.updateCurrentItem(direction);
|
||||
display.drawMenu(menu);
|
||||
}
|
||||
|
||||
if (joystick.isPressed()) {
|
||||
menu.execute();
|
||||
}
|
||||
|
||||
delay(250);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "menu.hpp"
|
||||
|
||||
Menu::Menu(Item* items) : currentItem(0) {
|
||||
for (int i = 0; i < MENU_ITEM_COUNT; i++) {
|
||||
this->items[i] = items[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::updateCurrentItem(JoystickDirection &direction) {
|
||||
switch (direction) {
|
||||
case JoystickDirection::UP:
|
||||
currentItem = (currentItem - 1 + MENU_ITEM_COUNT) % MENU_ITEM_COUNT;
|
||||
break;
|
||||
case JoystickDirection::DOWN:
|
||||
currentItem = (currentItem + 1) % MENU_ITEM_COUNT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::execute() {
|
||||
if (items[currentItem].action) {
|
||||
items[currentItem].action();
|
||||
}
|
||||
}
|
||||
|
||||
Item& Menu::getItemAt(size_t index) {
|
||||
return items[index];
|
||||
}
|
||||
|
||||
size_t Menu::getCurrentItemIndex() const {
|
||||
return currentItem;
|
||||
}
|
||||
Reference in New Issue
Block a user