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 5.2KB

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