hms11

ProgrammableRelayBoard.01

May 28th, 2025
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.95 KB | None | 0 0
  1. #include <Wire.h>
  2. #include <Adafruit_GFX.h>
  3. #include <Adafruit_SSD1306.h>
  4.  
  5. // === OLED ===
  6. #define SCREEN_WIDTH 128
  7. #define SCREEN_HEIGHT 64
  8. #define OLED_RESET -1
  9. #define OLED_ADDR 0x3C
  10. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  11.  
  12. // === Input Pins ===
  13. const uint8_t INPUT_PINS[4] = {7, 6, 5, 4}; // Inputs 1-4
  14. const uint8_t ENCODER_PIN_A = 2;
  15. const uint8_t ENCODER_PIN_B = 3;
  16. const uint8_t ENCODER_BUTTON = 8;
  17.  
  18. // === Analog Inputs ===
  19. const uint8_t SENSOR_PIN = A1; // Thermistor or Photoresistor
  20. const uint8_t BATTERY_PIN = A0; // Battery sense
  21.  
  22. // === Relay Outputs ===
  23. const uint8_t RELAY_PINS[4] = {10, 11, 12, 13}; // Relays 1-4
  24.  
  25. // === Rotary Encoder State ===
  26. volatile int encoderPos = 0;
  27. int lastReportedPos = 0;
  28. bool encoderButtonPressed = false;
  29.  
  30. // === Menu Navigation State ===
  31. #define MAX_MENU_DEPTH 4
  32.  
  33. struct MenuNode {
  34. const char* label;
  35. void (*action)(); // Function to call if selected
  36. MenuNode* parent;
  37. MenuNode** children;
  38. uint8_t childCount;
  39. };
  40.  
  41. MenuNode* currentMenu = nullptr;
  42. uint8_t currentIndex = 0;
  43.  
  44. MenuNode* menuStack[MAX_MENU_DEPTH];
  45. uint8_t indexStack[MAX_MENU_DEPTH];
  46. uint8_t menuDepth = 0;
  47.  
  48.  
  49. // === Encoder Interrupts ===
  50. void encoderISR() {
  51. static uint8_t oldState = 0;
  52. uint8_t newState = (digitalRead(ENCODER_PIN_A) << 1) | digitalRead(ENCODER_PIN_B);
  53. if ((oldState == 0b00 && newState == 0b01) || (oldState == 0b01 && newState == 0b11) ||
  54. (oldState == 0b11 && newState == 0b10) || (oldState == 0b10 && newState == 0b00)) {
  55. encoderPos++;
  56. } else {
  57. encoderPos--;
  58. }
  59. oldState = newState;
  60. }
  61.  
  62. void renderMenu() {
  63. display.clearDisplay();
  64. display.setTextSize(1);
  65. display.setCursor(0, 0);
  66. for (uint8_t i = 0; i < currentMenu->childCount; i++) {
  67. if (i == currentIndex) display.print("> ");
  68. else display.print(" ");
  69. display.println(currentMenu->children[i]->label);
  70. }
  71. display.display();
  72. }
  73.  
  74. void handleEncoder() {
  75. static int lastPos = 0;
  76. if (encoderPos != lastPos) {
  77. int delta = encoderPos - lastPos;
  78. lastPos = encoderPos;
  79. currentIndex = (currentIndex + delta + currentMenu->childCount) % currentMenu->childCount;
  80. renderMenu();
  81. }
  82.  
  83. if (digitalRead(ENCODER_BUTTON) == LOW) {
  84. delay(200); // Debounce
  85. MenuNode* selected = currentMenu->children[currentIndex];
  86. if (selected->childCount > 0) {
  87. if (menuDepth < MAX_MENU_DEPTH - 1) {
  88. menuStack[menuDepth] = currentMenu;
  89. indexStack[menuDepth] = currentIndex;
  90. menuDepth++;
  91. currentMenu = selected;
  92. currentIndex = 0;
  93. renderMenu();
  94. }
  95. } else if (selected->action) {
  96. selected->action();
  97. renderMenu(); // After action
  98. }
  99. }
  100. }
  101.  
  102. void showStatus() {
  103. // Display sensor/switch/relay status (to be implemented later)
  104. Serial.println("Status screen");
  105. }
  106.  
  107. void saveSettings() {
  108. Serial.println("Settings saved (placeholder)");
  109. }
  110.  
  111. MenuNode* inputItems[] = {
  112. new MenuNode{"Input 1 → Relay Map", nullptr, nullptr, nullptr, 0},
  113. new MenuNode{"Input 2 → Relay Map", nullptr, nullptr, nullptr, 0},
  114. new MenuNode{"Input 3 → Relay Map", nullptr, nullptr, nullptr, 0},
  115. new MenuNode{"Input 4 → Relay Map", nullptr, nullptr, nullptr, 0}
  116. };
  117. MenuNode inputConfig = { "Input Config", nullptr, nullptr, inputItems, 4 };
  118.  
  119. MenuNode* rootItems[] = {
  120. new MenuNode{"View Status", showStatus, nullptr, nullptr, 0},
  121. &inputConfig,
  122. new MenuNode{"Save Settings", saveSettings, nullptr, nullptr, 0}
  123. };
  124. MenuNode root = { "Main Menu", nullptr, nullptr, rootItems, 3 };
  125.  
  126. void setup() {
  127. // === Serial (optional for debug) ===
  128. Serial.begin(9600);
  129.  
  130. // === Inputs ===
  131. for (uint8_t i = 0; i < 4; i++) {
  132. pinMode(INPUT_PINS[i], INPUT_PULLUP);
  133. }
  134. pinMode(ENCODER_PIN_A, INPUT_PULLUP);
  135. pinMode(ENCODER_PIN_B, INPUT_PULLUP);
  136. pinMode(ENCODER_BUTTON, INPUT); // External hardware debounce
  137.  
  138. // === Outputs ===
  139. for (uint8_t i = 0; i < 4; i++) {
  140. pinMode(RELAY_PINS[i], OUTPUT);
  141. digitalWrite(RELAY_PINS[i], LOW); // Start relays OFF
  142. }
  143.  
  144. // === OLED Init ===
  145. if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
  146. Serial.println(F("OLED init failed"));
  147. while (true); // Loop forever
  148. }
  149. display.clearDisplay();
  150. display.setTextSize(1);
  151. display.setTextColor(SSD1306_WHITE);
  152. display.setCursor(0, 0);
  153. display.println(F("System Booting..."));
  154. display.display();
  155.  
  156. // === Encoder Interrupts ===
  157. attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), encoderISR, CHANGE);
  158. attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_B), encoderISR, CHANGE);
  159.  
  160.  
  161. }
  162.  
  163. void loop() {
  164. // Temporary test loop
  165. display.clearDisplay();
  166. display.setCursor(0, 0);
  167. display.print(F("Encoder: "));
  168. display.println(encoderPos);
  169. display.print(F("Input States: "));
  170. for (int i = 0; i < 4; i++) {
  171. display.print(digitalRead(INPUT_PINS[i]) == LOW ? "1" : "0");
  172. }
  173. display.display();
  174. handleEncoder();
  175. }
  176.  
Advertisement
Add Comment
Please, Sign In to add comment