Compare commits
5 Commits
511beae681
...
d9b72aa8b5
| Author | SHA1 | Date | |
|---|---|---|---|
|
d9b72aa8b5
|
|||
|
075ecdf1e2
|
|||
|
f2fbb9f205
|
|||
|
2d2051e6c2
|
|||
|
6be5a881e7
|
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <LiquidCrystal_I2C.h>
|
#include <LiquidCrystal_I2C.h>
|
||||||
|
#include "menu.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A helper class to facilitate drawing on a HD44780 LCD display.
|
* 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);
|
Display(uint8_t addr = 0x27, uint8_t cols = 20, uint8_t rows = 4);
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
|
void clear();
|
||||||
|
void drawMenu(Menu& menu);
|
||||||
|
|
||||||
|
LiquidCrystal_I2C& getLCD();
|
||||||
private:
|
private:
|
||||||
LiquidCrystal_I2C lcd;
|
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Ω)
|
* 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).
|
* or the internal pull-up resistor of the microcontroller (default).
|
||||||
*/
|
*/
|
||||||
|
enum JoystickDirection {
|
||||||
|
CENTER,
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
LEFT,
|
||||||
|
RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
class Joystick {
|
class Joystick {
|
||||||
public:
|
public:
|
||||||
Joystick();
|
Joystick();
|
||||||
|
|
||||||
double getX() const;
|
double getX() const;
|
||||||
double getY() const;
|
double getY() const;
|
||||||
bool isPressed() const;
|
bool isPressed() const;
|
||||||
|
|
||||||
|
JoystickDirection getDirection() const;
|
||||||
private:
|
private:
|
||||||
uint8_t vrx;
|
uint8_t vrx;
|
||||||
uint8_t vry;
|
uint8_t vry;
|
||||||
@@ -26,4 +35,5 @@ class Joystick {
|
|||||||
|
|
||||||
const uint8_t xOffset = 13;
|
const uint8_t xOffset = 13;
|
||||||
const uint8_t yOffset = 10;
|
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();
|
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 {
|
bool Joystick::isPressed() const {
|
||||||
return digitalRead(sw) == LOW;
|
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;
|
Joystick joystick;
|
||||||
Display display;
|
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() {
|
void setup() {
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
while (!Serial) {
|
while (!Serial) {
|
||||||
@@ -14,7 +22,19 @@ void setup() {
|
|||||||
|
|
||||||
display.begin();
|
display.begin();
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
display.drawMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
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