You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.ino 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #include <LiquidCrystal.h>
  2. #include <JC_Button.h>
  3. #include "Boiler.h"
  4. #define HIBERNATE_DELAY 5000
  5. #define TEMP_TRIGGER 10
  6. #define PIN_BTN_MODE 11
  7. #define PIN_BTN_MINUS 10
  8. #define PIN_BTN_PLUS 9
  9. #define PIN_LCD_LED 8
  10. #define PIN_LCD_RS 7
  11. #define PIN_LCD_ENABLE 6
  12. #define PIN_LCD_D0 5
  13. #define PIN_LCD_D1 4
  14. #define PIN_LCD_D2 3
  15. #define PIN_LCD_D3 2
  16. Button g_btnMode(PIN_BTN_MODE);
  17. Button g_btnMinus(PIN_BTN_MINUS);
  18. Button g_btnPlus(PIN_BTN_PLUS);
  19. Button* g_buttons[3] = {&g_btnMode, &g_btnMinus, &g_btnPlus};
  20. #define BUTTONS_COUNT (sizeof(g_buttons) / sizeof(*g_buttons))
  21. LiquidCrystal g_lcd(PIN_LCD_RS, PIN_LCD_ENABLE, PIN_LCD_D0, PIN_LCD_D1, PIN_LCD_D2, PIN_LCD_D3);
  22. UiStateEnum g_modeSequence[3] = {WaterSetting, HeaterSetting, Lighting};
  23. #define MODE_SEQUENCE_COUNT (sizeof(g_modeSequence) / sizeof(*g_modeSequence))
  24. BoilerState g_boilerState = {
  25. .water = {
  26. .current = 44,
  27. .setting = 44,
  28. .isActive = false
  29. },
  30. .heater = {
  31. .current = 44,
  32. .setting = 44,
  33. .isActive = false
  34. },
  35. .uiState = {
  36. .state = Lighting,
  37. .lastOpMs = 0,
  38. .modeSequenceIndex = MODE_SEQUENCE_COUNT - 1
  39. }
  40. };
  41. void printStateLine(char prefix, const BoilerLineState& boilerLineState, bool isModifying, bool isActive, LiquidCrystal lcd)
  42. {
  43. char curTmp[5], setTmp[5], tmp[17];
  44. dtostrf(boilerLineState.current / 2.0f, 2, 1, curTmp);
  45. dtostrf(boilerLineState.setting / 2.0f, 2, 1, setTmp);
  46. int count = snprintf(tmp, sizeof(tmp), "%c: %s [%s]%c%c", prefix, curTmp, setTmp, isModifying ? '<' : ' ', isActive ? 'o' : ' ');
  47. for (; count < 17; ++count)
  48. {
  49. tmp[count] = ' ';
  50. }
  51. tmp[count] = 0;
  52. lcd.print(tmp);
  53. }
  54. void printState(const BoilerState& boilerState, LiquidCrystal lcd)
  55. {
  56. lcd.setCursor(0, 0);
  57. printStateLine('S', boilerState.water, boilerState.uiState.state == WaterSetting, boilerState.water.isActive, lcd);
  58. lcd.setCursor(0, 1);
  59. printStateLine('C', boilerState.heater, boilerState.uiState.state == HeaterSetting, boilerState.heater.isActive, lcd);
  60. }
  61. void setup()
  62. {
  63. for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
  64. {
  65. g_buttons[i]->begin();
  66. }
  67. pinMode(PIN_LCD_LED, OUTPUT);
  68. digitalWrite(PIN_LCD_LED, 1);
  69. g_lcd.begin(16, 2);
  70. printState(g_boilerState, g_lcd);
  71. Serial.begin(9600);
  72. }
  73. void loop()
  74. {
  75. bool needLcdUpdate = false;
  76. unsigned long currentMs = millis();
  77. for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
  78. {
  79. g_buttons[i]->read();
  80. if (g_buttons[i]->isPressed())
  81. {
  82. g_boilerState.uiState.lastOpMs = currentMs;
  83. }
  84. }
  85. if (g_boilerState.uiState.state == Hibernate)
  86. {
  87. for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
  88. {
  89. if (g_buttons[i]->wasReleased())
  90. {
  91. g_boilerState.uiState.state = Lighting;
  92. digitalWrite(PIN_LCD_LED, 1);
  93. break;
  94. }
  95. }
  96. needLcdUpdate = true;
  97. }
  98. else
  99. {
  100. if (currentMs - g_boilerState.uiState.lastOpMs >= HIBERNATE_DELAY)
  101. {
  102. g_boilerState.uiState.state = Hibernate;
  103. digitalWrite(PIN_LCD_LED, 0);
  104. g_boilerState.uiState.modeSequenceIndex = MODE_SEQUENCE_COUNT - 1;
  105. needLcdUpdate = true;
  106. }
  107. else
  108. {
  109. if (g_btnMode.wasPressed())
  110. {
  111. g_boilerState.uiState.modeSequenceIndex =
  112. (g_boilerState.uiState.modeSequenceIndex + 1) % MODE_SEQUENCE_COUNT;
  113. g_boilerState.uiState.state = g_modeSequence[g_boilerState.uiState.modeSequenceIndex];
  114. needLcdUpdate = true;
  115. }
  116. else
  117. {
  118. temp_t* setting = NULL;
  119. if (g_boilerState.uiState.state == WaterSetting)
  120. {
  121. setting = &g_boilerState.water.setting;
  122. }
  123. else if (g_boilerState.uiState.state == HeaterSetting)
  124. {
  125. setting = &g_boilerState.heater.setting;
  126. }
  127. if (setting)
  128. {
  129. if (g_btnMinus.wasReleased())
  130. {
  131. --(*setting);
  132. }
  133. else if (g_btnPlus.wasReleased())
  134. {
  135. ++(*setting);
  136. }
  137. needLcdUpdate = true;
  138. }
  139. }
  140. }
  141. }
  142. if (!g_boilerState.water.isActive && (g_boilerState.water.current <= g_boilerState.water.setting - TEMP_TRIGGER))
  143. {
  144. g_boilerState.water.isActive = true;
  145. needLcdUpdate = true;
  146. }
  147. else if (g_boilerState.water.isActive && (g_boilerState.water.current >= g_boilerState.water.setting))
  148. {
  149. g_boilerState.water.isActive = false;
  150. needLcdUpdate = true;
  151. }
  152. if (needLcdUpdate)
  153. {
  154. printState(g_boilerState, g_lcd);
  155. }
  156. }