27
27
#include < PID_AutoTune_v0.h>
28
28
#endif
29
29
// ----------------------------------------------------------------------------
30
+ volatile uint32_t lastTicks = 0 ;
30
31
volatile uint32_t timerTicks = 0 ;
31
32
volatile uint8_t phaseCounter = 0 ;
32
- static const uint8_t TIMER1_PERIOD_US = 100 ;
33
+ static const uint8_t TIMER1_PERIOD_US = 200 ;
33
34
// ----------------------------------------------------------------------------
34
35
uint32_t lastUpdate = 0 ;
35
36
uint32_t lastDisplayUpdate = 0 ;
@@ -80,34 +81,41 @@ void setupPins(void) {
80
81
81
82
pinAsOutput (PIN_HEATER);
82
83
digitalLow (PIN_HEATER); // off
83
- pinAsOutput (PIN_FAN);
84
- digitalHigh (PIN_FAN);
85
84
pinAsInputPullUp (PIN_ZX);
86
85
pinAsOutput (PIN_TC_CS);
87
86
pinAsOutput (PIN_LCD_CS);
88
87
pinAsOutput (PIN_TC_CS);
89
88
#ifdef WITH_BEEPER
90
89
pinAsOutput (PIN_BEEPER);
91
90
#endif
92
-
91
+ #ifdef WITH_FAN
92
+ pinAsOutput (PIN_FAN);
93
+ digitalHigh (PIN_FAN);
94
+ #endif
93
95
}
94
96
// ----------------------------------------------------------------------------
95
97
void killRelayPins (void ) {
96
98
Timer1.stop ();
97
99
detachInterrupt (INT_ZX);
98
- digitalHigh (PIN_FAN);
99
- digitalHigh (PIN_HEATER);
100
+ #ifdef WITH_FAN
101
+ digitalHigh (PIN_FAN);
102
+ digitalHigh (PIN_HEATER);
103
+ #endif
100
104
// PORTD |= (1 << PIN_HEATER) | (1 << PIN_FAN); // off
101
105
}
102
106
103
107
// ----------------------------------------------------------------------------
104
108
// wave packet control: only turn the solid state relais on for a percentage
105
109
// of complete sinusoids (i.e. 1x 360°)
106
110
107
- #define CHANNELS 2
108
- #define CHANNEL_HEATER 0
109
- #define CHANNEL_FAN 1
110
-
111
+ #ifdef WITH_FAN
112
+ #define CHANNELS 2
113
+ #define CHANNEL_HEATER 0
114
+ #define CHANNEL_FAN 1
115
+ #else
116
+ #define CHANNELS 1
117
+ #define CHANNEL_HEATER 0
118
+ #endif
111
119
typedef struct Channel_s {
112
120
volatile uint8_t target; // percentage of on-time
113
121
uint8_t state; // current state counter
@@ -117,25 +125,28 @@ typedef struct Channel_s {
117
125
} Channel_t;
118
126
119
127
Channel_t Channels[CHANNELS] = {
120
- // heater
121
- { 0 , 0 , 0 , false , PIN_HEATER },
122
- // fan
123
- { 0 , 0 , 0 , false , PIN_FAN }
128
+ { 0 , 0 , 0 , false , PIN_HEATER } // heater
129
+ # ifdef WITH_FAN
130
+ ,{ 0 , 0 , 0 , false , PIN_FAN } // fan
131
+ # endif
124
132
};
125
133
126
134
// delay to align relay activation with the actual zero crossing
127
- uint16_t zxLoopDelay = 0 ;
135
+ uint8_t zxLoopDelay = 0 ;
136
+
128
137
129
- #ifdef WITH_CALIBRATION
130
138
// calibrate zero crossing: how many timerIsr happen within one zero crossing
131
139
#define zxCalibrationLoops 128
140
+ #define zxPerSecCalibrationTime 4000
141
+
132
142
struct {
133
- volatile int8_t iterations;
143
+ volatile uint8_t iterations;
134
144
volatile uint8_t measure[zxCalibrationLoops];
135
145
} zxLoopCalibration = {
136
146
0 , {}
137
147
};
138
- #endif
148
+
149
+
139
150
140
151
// ----------------------------------------------------------------------------
141
152
// ZERO CROSSING ISR
@@ -164,11 +175,11 @@ void zeroCrossingIsr(void) {
164
175
165
176
ch = ((ch + 1 ) % CHANNELS); // next channel
166
177
167
- # ifdef WITH_CALIBRATION
178
+
168
179
if (zxLoopCalibration.iterations < zxCalibrationLoops) {
169
180
zxLoopCalibration.iterations ++;
170
181
}
171
- # endif
182
+
172
183
}
173
184
174
185
// ----------------------------------------------------------------------------
@@ -177,23 +188,22 @@ void zeroCrossingIsr(void) {
177
188
// timer interrupt handling
178
189
179
190
void timerIsr (void ) { // ticks with 100µS
180
- static uint32_t lastTicks = 0 ;
181
191
182
192
// phase control for the fan
183
193
if (++phaseCounter > 90 ) {
184
194
phaseCounter = 0 ;
185
195
}
186
-
196
+ # ifdef WITH_FAN
187
197
if (phaseCounter > Channels[CHANNEL_FAN].target ) {
188
198
digitalLow (Channels[CHANNEL_FAN].pin );
189
199
}
190
200
else {
191
201
digitalHigh (Channels[CHANNEL_FAN].pin );
192
202
}
193
-
203
+ # endif
194
204
// wave packet control for heater
195
- if (Channels[CHANNEL_HEATER].next > lastTicks // FIXME: this looses ticks when overflowing
196
- && timerTicks > Channels[CHANNEL_HEATER].next )
205
+ if (( Channels[CHANNEL_HEATER].next > lastTicks) // FIXME: this looses ticks when overflowing
206
+ && ( timerTicks > Channels[CHANNEL_HEATER].next ) )
197
207
{
198
208
if (Channels[CHANNEL_HEATER].action ) digitalLow (Channels[CHANNEL_HEATER].pin ); // digitalWriteFast(Channels[CHANNEL_HEATER].pin, HIGH);
199
209
else digitalHigh (Channels[CHANNEL_HEATER].pin );// digitalWriteFast(Channels[CHANNEL_HEATER].pin, LOW);
@@ -207,11 +217,10 @@ void timerIsr(void) { // ticks with 100µS
207
217
208
218
timerTicks++;
209
219
210
- # ifdef WITH_CALIBRATION
211
- if (zxLoopCalibration.iterations < zxCalibrationLoops) {
220
+
221
+ if (zxLoopCalibration.iterations < zxCalibrationLoops) {
212
222
zxLoopCalibration.measure [zxLoopCalibration.iterations ]++;
213
- }
214
- #endif
223
+ }
215
224
}
216
225
// ----------------------------------------------------------------------------
217
226
void abortWithError (int error) {
@@ -227,7 +236,6 @@ void setup() {
227
236
#endif
228
237
229
238
setupPins ();
230
-
231
239
232
240
setupTFT ();
233
241
@@ -239,10 +247,6 @@ void setup() {
239
247
loadLastUsedProfile ();
240
248
}
241
249
242
-
243
-
244
-
245
-
246
250
do {
247
251
// wait for MAX chip to stabilize
248
252
delay (500 );
@@ -278,55 +282,103 @@ void setup() {
278
282
displaySplash ();
279
283
#endif
280
284
285
+ Timer1.initialize (TIMER1_PERIOD_US);
286
+ Timer1.attachInterrupt (timerIsr);
287
+ attachInterrupt (INT_ZX, zeroCrossingIsr, RISING);
281
288
282
- #ifdef WITH_CALIBRATION
289
+
290
+ doCalibration ();
291
+
292
+ setupMenu ();
293
+
294
+ delay (100 );
295
+ }
296
+
297
+ /*
298
+ * Calibrate main loop delay
299
+ * Calibrate zero cross tick per second (i.e.: detect Mains AC frequency)
300
+ *
301
+ */
302
+ void doCalibration () {
303
+
304
+ // loop delay calibration
305
+ tft.fillRect_ (0 , 99 , tft.width , 29 , ST7735_WHITE);
283
306
tft.setCursor (7 , 99 );
284
- tft.print (" Calibrating... " );
307
+ tft.print (" Calibrating LOOP_DELAY" );
308
+ #ifdef SERIAL_VERBOSE
309
+ Serial.print (" Calibrating LOOP_DELAY" );
310
+ #endif
285
311
delay (400 );
286
312
287
- // FIXME: does not work reliably
313
+
314
+ float tempZxLoopDelay = 0 ;
288
315
while (zxLoopDelay == 0 ) {
289
316
if (zxLoopCalibration.iterations == zxCalibrationLoops) { // average tick measurements, dump 1st value
290
- for (int8_t l = 0 ; l < zxCalibrationLoops; l++) {
291
- zxLoopDelay += zxLoopCalibration.measure [l];
317
+ for (uint8_t l = 0 ; l < zxCalibrationLoops; l++) {
318
+ tempZxLoopDelay += zxLoopCalibration.measure [l];
292
319
}
293
- zxLoopDelay /= zxCalibrationLoops;
320
+ zxLoopDelay = round (tempZxLoopDelay/( float ) zxCalibrationLoops) ;
294
321
zxLoopDelay -= 10 ; // compensating loop runtime
295
322
}
296
323
}
324
+
325
+ tft.fillRect_ (0 , 99 , tft.width , 10 , ST7735_WHITE);
326
+ tft.setCursor (7 , 99 );
327
+ tft.print (" LOOP_DELAY = " );
297
328
tft.print (zxLoopDelay);
298
- #else
299
- zxLoopDelay = DEFAULT_LOOP_DELAY;
329
+ #ifdef SERIAL_VERBOSE
330
+ Serial.print (" LOOP_DELAY = " );
331
+ Serial.println (zxLoopDelay);
332
+ #endif
333
+ delay (1000 );
334
+
335
+ // zero cross ticks per second detection ( depends on mains frequency 50Hz / 60h )
336
+
337
+ tft.fillRect_ (0 , 109 , tft.width , 19 , ST7735_WHITE);
338
+ tft.setCursor (7 , 109 );
339
+ tft.print (" Detect mains frequency..." );
340
+ #ifdef SERIAL_VERBOSE
341
+ Serial.print (" Detect mains frequency..." );
300
342
#endif
301
343
302
- // setupMenu();
303
- menuExit (Menu::actionDisplay); // reset to initial state
304
- MenuEngine.navigate (&miCycleStart);
305
- currentState = Settings;
306
- menuUpdateRequest = true ;
344
+ volatile float zxTicksStartCalibration = zeroCrossTicks;
345
+ volatile float zxTicksCalibration = 0 ;
346
+ volatile uint32_t startMillis = millis ();
307
347
308
- Timer1.initialize (TIMER1_PERIOD_US);
309
- Timer1.attachInterrupt (timerIsr);
348
+ while (millis ()-startMillis < zxPerSecCalibrationTime);
349
+ zxTicksCalibration = zeroCrossTicks-zxTicksStartCalibration;
350
+ ticksPerSec = round (1000 *zxTicksCalibration/(float )zxPerSecCalibrationTime);
351
+
352
+ tft.fillRect_ (0 , 109 , tft.width , 10 , ST7735_WHITE);
353
+ tft.setCursor (7 , 109 );
354
+ tft.print (" MAINS FREQUENCY = " );
355
+ tft.print (ticksPerSec/2 );
356
+ tft.print (" Hz" );
357
+ #ifdef SERIAL_VERBOSE
358
+ Serial.print (" MAINS FREQUENCY = " );
359
+ Serial.print (ticksPerSec/2 );
360
+ Serial.println (" Hz" );
361
+ #endif
310
362
311
- attachInterrupt (INT_ZX, zeroCrossingIsr, RISING);
312
- delay (100 );
363
+ delay (2000 );
313
364
}
314
365
366
+
315
367
uint32_t lastRampTicks;
316
368
uint32_t lastSoakTicks;
317
369
318
370
void updateRampSetpoint (bool down = false ) {
319
371
if (zeroCrossTicks > lastRampTicks + TICKS_PER_UPDATE) {
320
372
double rate = (down) ? activeProfile.rampDownRate : activeProfile.rampUpRate ;
321
- Setpoint += (rate / (float )TICKS_PER_SEC * (zeroCrossTicks - lastRampTicks)) * ((down) ? -1 : 1 );
373
+ Setpoint += (rate / (float )ticksPerSec * (zeroCrossTicks - lastRampTicks)) * ((down) ? -1 : 1 );
322
374
lastRampTicks = zeroCrossTicks;
323
375
}
324
376
}
325
377
326
378
void updateSoakSetpoint (bool down = false ) {
327
379
if (zeroCrossTicks > lastSoakTicks + TICKS_PER_UPDATE) {
328
380
double rate = (activeProfile.soakTempB -activeProfile.soakTempA )/(float )activeProfile.soakDuration ;
329
- Setpoint += (rate / (float )TICKS_PER_SEC * (zeroCrossTicks - lastSoakTicks)) * ((down) ? -1 : 1 );
381
+ Setpoint += (rate / (float )ticksPerSec * (zeroCrossTicks - lastSoakTicks)) * ((down) ? -1 : 1 );
330
382
lastSoakTicks = zeroCrossTicks;
331
383
}
332
384
}
@@ -475,7 +527,7 @@ void loop(void)
475
527
collectTicks += airTemp[i].ticks ;
476
528
}
477
529
float tempDiff = (airTemp[NUM_TEMP_READINGS - 1 ].temp - airTemp[0 ].temp );
478
- float timeDiff = collectTicks / (float )(TICKS_PER_SEC );
530
+ float timeDiff = collectTicks / (float )(ticksPerSec );
479
531
480
532
rampRate = tempDiff / timeDiff;
481
533
@@ -526,7 +578,7 @@ void loop(void)
526
578
527
579
updateSoakSetpoint ();
528
580
529
- if (zeroCrossTicks - stateChangedTicks >= (uint32_t )activeProfile.soakDuration * TICKS_PER_SEC ) {
581
+ if (zeroCrossTicks - stateChangedTicks >= (uint32_t )activeProfile.soakDuration * ticksPerSec ) {
530
582
currentState = RampUp;
531
583
}
532
584
break ;
@@ -551,7 +603,7 @@ void loop(void)
551
603
Setpoint = activeProfile.peakTemp ;
552
604
}
553
605
554
- if (zeroCrossTicks - stateChangedTicks >= (uint32_t )activeProfile.peakDuration * TICKS_PER_SEC ) {
606
+ if (zeroCrossTicks - stateChangedTicks >= (uint32_t )activeProfile.peakDuration * ticksPerSec ) {
555
607
currentState = RampDown;
556
608
}
557
609
break ;
@@ -663,9 +715,10 @@ void loop(void)
663
715
#endif
664
716
665
717
Channels[CHANNEL_HEATER].target = heaterValue;
666
-
718
+ # ifdef WITH_FAN
667
719
double fanTmp = 90.0 / 100.0 * fanValue; // 0-100% -> 0-90° phase control
668
720
Channels[CHANNEL_FAN].target = 90 - (uint8_t )fanTmp;
721
+ #endif
669
722
}
670
723
671
724
0 commit comments