-
Notifications
You must be signed in to change notification settings - Fork 10
/
Thermostat_OLED_WIP.ino.ino
375 lines (325 loc) · 12.3 KB
/
Thermostat_OLED_WIP.ino.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
/*
* 3D Printing Filament Dehydrator Control Module
*
* This sketch will control the heater element(s) of a standard Food Dehydrator
* to enable drying various 3d printing filament to their suggested dryinh tempertaure and time.
*
* An Arduino is used to display and capture menu selections through 3 momentary push buttons.
* Pre stored values for targetted temperature will be compared to the inputs from a DS18b20 Dallas digital temperature sensor.
* Results of this comparision will then be used to control the heater element relay via 5v signal.
*
* ####-WARNING-#### Timer function is ONLY for reference, NO ACTION to the dehydrator will be executed by the module through timer functions.
* The reason for this non-action is to prevent the filament to re-absorb humidity in case of long running time after auto-shutdown of heater element.
* Buzzer / Alarm might be added in the future
*
* BOM (Bill of Material):
* Qty - Desc
* 1 - Arduino Pro-Mini or other
* 1 - OLED Display
* 1 - DS18B20 Dalla temp sensor
* 1 - Single Relay Module
* 1 - 120/220VAC to 5DC converter (Any phone charger or other adapter
* 3 - Momentary on Push Buttons
* 3 - 10K Resistor
* 1 - 4.7K Resistor
*
* Wiring Diagram..........:
* 3D printed enclosure....:
* This code GitHub........: https://github.com/MirageC79/FilamentDryer_Controller
*
* Library Used: (V1.1)
* - OneWire.h from Paul Stoffregen...............https://github.com/PaulStoffregen/OneWire
* - Addafruit GFX:...............................https://github.com/adafruit/Adafruit-GFX-Library
* - Addafruit SSD1306............................https://github.com/adafruit/Adafruit_SSD1306
* - Arduino Temperature Control by milesburton...https://github.com/milesburton/Arduino-Temperature-Control-Library
*
* Created by:
* Olivier Royer-Tardif (alias MirageC)
* October 12th, 2018
*
* Revision Log:
*
* Version DATE DESC RELEASED BY:
* V1 12-Oct-2018 Initial release Olivier Royer-Tardif
* V1.1 05-Jan-2019 Library Used listed Olivier Royer-Tardif
*
* Known Bugs
* 1 - Memory issue if any additionnal variables added.
* 2 - "Set Timer" menu not functionnal
*
*/
/* Library References:
- https://github.com/adafruit/Adafruit-GFX-Library
- https://github.com/adafruit/Adafruit_SSD1306
*/
/*----------------USER DEFINED-----------------------*/
#define ONE_WIRE_BUS 5
#define CONTROL_RELAY 3
/*---------------------------------------------------*/
#include "FilamentDryerMenu.h"
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SPI.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH 16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
B00000001, B11000000,
B00000001, B11000000,
B00000011, B11100000,
B11110011, B11100000,
B11111110, B11111000,
B01111110, B11111111,
B00110011, B10011111,
B00011111, B11111100,
B00001101, B01110000,
B00011011, B10100000,
B00111111, B11100000,
B00111111, B11110000,
B01111100, B11110000,
B01110000, B01110000,
B00000000, B00110000
};
#if (SSD1306_LCDHEIGHT != 32) // Check if the right LCD parameter being used in function of the OLED unit connected
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
/*-----------------------GLOBAL VARIABLES-----------------------------*/
byte setTemp = 0; // Store target temperature from menu table
unsigned int setTime = 0; // Store drying time from menu table
char setKeyw[5]; // Store 4 letter material keyword from menu table
bool heaterStat = 1; // Heating request **Status is inverted: 1=off 0=on due to pullup resistors**
bool dotHeat = 1; // Flashing dot while heating
byte setMode = 0; // 1: Thermostat display, 0 = Main Menu Type, 2 = Set timer,
unsigned long lastmillis = 0; // Last time flashing dot changed to on/off
unsigned long lastmillisSensor = 0; // Last time temp sensor was querried
byte pageSelect;
byte BTN[] = {7, 8, 9};
byte BtnStat[] = {HIGH, HIGH, HIGH};
byte previous[] = {HIGH, HIGH, HIGH}; // Last button status
unsigned long millis_held[] = {0, 0, 0}; // How long the button was held (milliseconds)
unsigned long firstTime[] = {0, 0, 0}; // Time Stamp when button is first pressed
unsigned long millisStart = 0;
byte selectedPos = 0;
byte previousPos = 0;
MenuItems *mAddress;
float sensorTemp;
/************************************************************SETUP************************************************************************/
void setup() {
//Serial.begin(115200);
//sensors.begin(); // initiate sensors library
pinMode(3, OUTPUT);
for (int i = 0; i < 3; i++) {
pinMode(BTN[i], INPUT);
}
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32)
// init done
// Show image buffer on the display hardware.
// Since the buffer is intialized with an Adafruit splashscreen
// internally, this will display the splashscreen.
display.display();
delay(500);
setMode = 0; // open menu on powerup
}
/**********************************************************MENU SELECTION******************************************************************/
int MenuSelection() {
byte tmp_setMode;
byte tmp_setTemp;
unsigned int tmp_setTime;
char tmp_setKeyw[5];
MenuItems Menu1[] = {
// DESC ShortDESC sMode T t
{"- Exit", "", 1, 0, 0},
{"- Select Material", "", 2, 0, 0},
{"- Set timer", "", 1, 0, 0} // Function to be implemented in the future
};
MenuItems Menu2[] = {
// DESC ShortDESC sMode T t
{"<-Return", "", 0, 0, 0},
{"- PLA......45C 4h", "PLA", 1, 45, 240},
{"- ABS......60C 2h", "ABS", 1, 60, 120},
{"- PETG.....65C 2h", "PETG", 1, 65, 120},
{"- NYLON... 70C 12h", "NYLN", 1, 70, 720},
{"- PVA......45C 4h", "PVA", 1, 45, 240},
{"- TPU/TPE..50C 4h", "TPE", 1, 50, 240},
{"- ASA......60C 4h", "ASA", 1, 60, 240},
{"- PP.......55C 6h", "PP", 1, 55, 360},
{"- Dsscnt...65C 3h", "Dsct", 1, 65, 180},
{"- Test.....29C 1m", "Test", 1, 29, 60}
};
MenuItems *m;
byte nItem1 = sizeof Menu1 / sizeof Menu1[0];
byte nItem2 = sizeof Menu2 / sizeof Menu2[0];
byte nItemS;
switch (setMode) {
case 0:
nItemS = nItem1;
m = Menu1;
break;
case 2:
nItemS = nItem2;
m = Menu2;
break;
}
if (BtnStat[1] == LOW && selectedPos > 0 ) {
selectedPos += -1;
} else if (BtnStat[2] == LOW && selectedPos < nItemS - 1) {
selectedPos += 1;
}
BtnStat[1] = HIGH;
BtnStat[2] = HIGH;
ClearBuffer();
display.setTextSize(1);
display.setTextColor(WHITE);
int menupage = (selectedPos / 3) * 3;
display.print("Main Menu p ");
display.print((selectedPos + 3) / 3);
display.print("/");
display.println(ceil(nItemS / 3), 0);
for (int i = menupage; i < selectedPos + 3 && i < nItemS ; i++) {
mAddress = m + i;
if (i == selectedPos) {
display.print("*");
tmp_setMode = (*mAddress).mode;
tmp_setTemp = (*mAddress).drytemp;
tmp_setTime = (*mAddress).drytime;
strcpy(tmp_setKeyw, (*mAddress).shortdesc);
} else {
display.print(" ");
}
display.println((*mAddress).desc);
}
display.display();
ClearBuffer();
if (BtnStat[0] == LOW) {
setMode = tmp_setMode;
setTemp = tmp_setTemp;
setTime = tmp_setTime;
strcpy(setKeyw,tmp_setKeyw);
selectedPos = 0;
millisStart = millis();
BtnStat[0] = HIGH;
}
return 0;
}
/*******************************************************GET BUTTON STATUS****************************************************************/
byte ButtonStatus(byte btn) {
byte r = HIGH;
byte statbtn = digitalRead(BTN[btn]);
if (statbtn == LOW && previous[btn] == HIGH && (millis() - firstTime[btn]) > 50) {
firstTime[btn] = millis(); // Take time stamp when first pressed. 200 milliseconds acts as debouncing.
}
millis_held[btn] = (millis() - firstTime[btn]); // Count how many milliseconds the button has been pressed for.
if (statbtn == HIGH && previous[btn] == LOW && millis_held[btn] >= 50) {
r = LOW;
}
previous[btn] = statbtn;
return r;
}
/********************************************************CLEAR DISPLAY BUFFER***********************************************************/
void ClearBuffer() {
display.clearDisplay();
display.setCursor(0, 0);
}
/******************************************************DISPLAY THERMOSTAT FUNCTION******************************************************/
void Thermostat() {
ClearBuffer(); // text display tests
display.setTextSize(1);
display.setTextColor(WHITE);
unsigned long tSec;
unsigned long dHour;
int dMin;
int dSec;
if ((setTime * 60) <= ((millis() - millisStart) / 1000)) {
tSec = 0;
}else{
tSec = ((setTime * 60) - ((millis() - millisStart) / 1000));
}
dHour = tSec / 3600;
dMin = tSec / 60;
dMin = dMin % 60;
dSec = tSec % 60;
if (heaterStat == 1) {
if (dotHeat == 1) {
display.print("*");
} else {
display.print(" ");
}
if (millis() > lastmillis + 500) {
lastmillis = millis();
dotHeat = !dotHeat;
}
display.print(" HEATING... ");
}else{
display.print(" Standby ");
}
display.println(setKeyw);
display.println("Actual: Target:");
display.setTextSize(2);
display.print(sensors.getTempCByIndex(0), 1);
display.setTextSize(1);
display.print(" ");
if (setTemp < 100) {display.print(" ");}
if (setTemp < 10) {display.print(" ");}
display.print(setTemp, 1);
display.println("C");
display.print(" ");
if (dHour < 10) { display.print("0");}
display.print(dHour);
display.print(":");
if ((dMin)< 10){display.print("0");}
display.print(dMin);
display.print(":");
if (dSec < 10){display.print("0");}
display.print(dSec);
display.display();
display.clearDisplay();
if (BtnStat[0] == LOW) {
setMode = 0;
BtnStat[0] = HIGH;
}
}
/**********************************************************************************************************************************
* *
* MAIN LOOP *
* *
**********************************************************************************************************************************/
void loop() {
if (millis() > lastmillisSensor + 500) {
lastmillisSensor = millis();
sensors.requestTemperatures();
}
sensorTemp = sensors.getTempCByIndex(0);
if ((heaterStat == 0) && (sensorTemp < (setTemp - 2))) {
digitalWrite(3, HIGH);
heaterStat = 1;
} else if ((heaterStat == 1) && (sensorTemp >= setTemp)) {
digitalWrite(3, LOW);
heaterStat = 0;
}
for (int i = 0; i < 3; i++) {
BtnStat[i] = ButtonStatus(i);
}
switch (setMode) {
case 0:
MenuSelection();
//delay(100);
break;
case 1:
Thermostat();
break;
case 2:
MenuSelection();
break;
}
}/***************************************************************THE END***********************************************************/