Skip to content

Commit 9f79ebf

Browse files
author
dasaki
committed
Auto calibrate mains freq and loop delay, reduce TIMER1_PERIOD_US
1 parent e02c517 commit 9f79ebf

File tree

4 files changed

+124
-92
lines changed

4 files changed

+124
-92
lines changed

ReflowController/ReflowController.ino

+110-57
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@
2727
#include <PID_AutoTune_v0.h>
2828
#endif
2929
// ----------------------------------------------------------------------------
30+
volatile uint32_t lastTicks = 0;
3031
volatile uint32_t timerTicks = 0;
3132
volatile uint8_t phaseCounter = 0;
32-
static const uint8_t TIMER1_PERIOD_US = 100;
33+
static const uint8_t TIMER1_PERIOD_US = 200;
3334
// ----------------------------------------------------------------------------
3435
uint32_t lastUpdate = 0;
3536
uint32_t lastDisplayUpdate = 0;
@@ -80,34 +81,41 @@ void setupPins(void) {
8081

8182
pinAsOutput(PIN_HEATER);
8283
digitalLow(PIN_HEATER); // off
83-
pinAsOutput(PIN_FAN);
84-
digitalHigh(PIN_FAN);
8584
pinAsInputPullUp(PIN_ZX);
8685
pinAsOutput(PIN_TC_CS);
8786
pinAsOutput(PIN_LCD_CS);
8887
pinAsOutput(PIN_TC_CS);
8988
#ifdef WITH_BEEPER
9089
pinAsOutput(PIN_BEEPER);
9190
#endif
92-
91+
#ifdef WITH_FAN
92+
pinAsOutput(PIN_FAN);
93+
digitalHigh(PIN_FAN);
94+
#endif
9395
}
9496
// ----------------------------------------------------------------------------
9597
void killRelayPins(void) {
9698
Timer1.stop();
9799
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
100104
//PORTD |= (1 << PIN_HEATER) | (1 << PIN_FAN); // off
101105
}
102106

103107
// ----------------------------------------------------------------------------
104108
// wave packet control: only turn the solid state relais on for a percentage
105109
// of complete sinusoids (i.e. 1x 360°)
106110

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
111119
typedef struct Channel_s {
112120
volatile uint8_t target; // percentage of on-time
113121
uint8_t state; // current state counter
@@ -117,25 +125,28 @@ typedef struct Channel_s {
117125
} Channel_t;
118126

119127
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
124132
};
125133

126134
// delay to align relay activation with the actual zero crossing
127-
uint16_t zxLoopDelay = 0;
135+
uint8_t zxLoopDelay = 0;
136+
128137

129-
#ifdef WITH_CALIBRATION
130138
// calibrate zero crossing: how many timerIsr happen within one zero crossing
131139
#define zxCalibrationLoops 128
140+
#define zxPerSecCalibrationTime 4000
141+
132142
struct {
133-
volatile int8_t iterations;
143+
volatile uint8_t iterations;
134144
volatile uint8_t measure[zxCalibrationLoops];
135145
} zxLoopCalibration = {
136146
0, {}
137147
};
138-
#endif
148+
149+
139150

140151
// ----------------------------------------------------------------------------
141152
// ZERO CROSSING ISR
@@ -164,11 +175,11 @@ void zeroCrossingIsr(void) {
164175

165176
ch = ((ch + 1) % CHANNELS); // next channel
166177

167-
#ifdef WITH_CALIBRATION
178+
168179
if (zxLoopCalibration.iterations < zxCalibrationLoops) {
169180
zxLoopCalibration.iterations++;
170181
}
171-
#endif
182+
172183
}
173184

174185
// ----------------------------------------------------------------------------
@@ -177,23 +188,22 @@ void zeroCrossingIsr(void) {
177188
// timer interrupt handling
178189

179190
void timerIsr(void) { // ticks with 100µS
180-
static uint32_t lastTicks = 0;
181191

182192
// phase control for the fan
183193
if (++phaseCounter > 90) {
184194
phaseCounter = 0;
185195
}
186-
196+
#ifdef WITH_FAN
187197
if (phaseCounter > Channels[CHANNEL_FAN].target) {
188198
digitalLow(Channels[CHANNEL_FAN].pin);
189199
}
190200
else {
191201
digitalHigh(Channels[CHANNEL_FAN].pin);
192202
}
193-
203+
#endif
194204
// 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))
197207
{
198208
if (Channels[CHANNEL_HEATER].action) digitalLow(Channels[CHANNEL_HEATER].pin); //digitalWriteFast(Channels[CHANNEL_HEATER].pin, HIGH);
199209
else digitalHigh(Channels[CHANNEL_HEATER].pin);//digitalWriteFast(Channels[CHANNEL_HEATER].pin, LOW);
@@ -207,11 +217,10 @@ void timerIsr(void) { // ticks with 100µS
207217

208218
timerTicks++;
209219

210-
#ifdef WITH_CALIBRATION
211-
if (zxLoopCalibration.iterations < zxCalibrationLoops) {
220+
221+
if (zxLoopCalibration.iterations < zxCalibrationLoops) {
212222
zxLoopCalibration.measure[zxLoopCalibration.iterations]++;
213-
}
214-
#endif
223+
}
215224
}
216225
// ----------------------------------------------------------------------------
217226
void abortWithError(int error) {
@@ -227,7 +236,6 @@ void setup() {
227236
#endif
228237

229238
setupPins();
230-
231239

232240
setupTFT();
233241

@@ -239,10 +247,6 @@ void setup() {
239247
loadLastUsedProfile();
240248
}
241249

242-
243-
244-
245-
246250
do {
247251
// wait for MAX chip to stabilize
248252
delay(500);
@@ -278,55 +282,103 @@ void setup() {
278282
displaySplash();
279283
#endif
280284

285+
Timer1.initialize(TIMER1_PERIOD_US);
286+
Timer1.attachInterrupt(timerIsr);
287+
attachInterrupt(INT_ZX, zeroCrossingIsr, RISING);
281288

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);
283306
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
285311
delay(400);
286312

287-
// FIXME: does not work reliably
313+
314+
float tempZxLoopDelay = 0;
288315
while (zxLoopDelay == 0) {
289316
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];
292319
}
293-
zxLoopDelay /= zxCalibrationLoops;
320+
zxLoopDelay = round(tempZxLoopDelay/(float)zxCalibrationLoops);
294321
zxLoopDelay -= 10; // compensating loop runtime
295322
}
296323
}
324+
325+
tft.fillRect_(0, 99, tft.width, 10, ST7735_WHITE);
326+
tft.setCursor(7, 99);
327+
tft.print("LOOP_DELAY = ");
297328
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...");
300342
#endif
301343

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();
307347

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
310362

311-
attachInterrupt(INT_ZX, zeroCrossingIsr, RISING);
312-
delay(100);
363+
delay(2000);
313364
}
314365

366+
315367
uint32_t lastRampTicks;
316368
uint32_t lastSoakTicks;
317369

318370
void updateRampSetpoint(bool down = false) {
319371
if (zeroCrossTicks > lastRampTicks + TICKS_PER_UPDATE) {
320372
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);
322374
lastRampTicks = zeroCrossTicks;
323375
}
324376
}
325377

326378
void updateSoakSetpoint(bool down = false) {
327379
if (zeroCrossTicks > lastSoakTicks + TICKS_PER_UPDATE) {
328380
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);
330382
lastSoakTicks = zeroCrossTicks;
331383
}
332384
}
@@ -475,7 +527,7 @@ void loop(void)
475527
collectTicks += airTemp[i].ticks;
476528
}
477529
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);
479531

480532
rampRate = tempDiff / timeDiff;
481533

@@ -526,7 +578,7 @@ void loop(void)
526578

527579
updateSoakSetpoint();
528580

529-
if (zeroCrossTicks - stateChangedTicks >= (uint32_t)activeProfile.soakDuration * TICKS_PER_SEC) {
581+
if (zeroCrossTicks - stateChangedTicks >= (uint32_t)activeProfile.soakDuration * ticksPerSec) {
530582
currentState = RampUp;
531583
}
532584
break;
@@ -551,7 +603,7 @@ void loop(void)
551603
Setpoint = activeProfile.peakTemp;
552604
}
553605

554-
if (zeroCrossTicks - stateChangedTicks >= (uint32_t)activeProfile.peakDuration * TICKS_PER_SEC) {
606+
if (zeroCrossTicks - stateChangedTicks >= (uint32_t)activeProfile.peakDuration * ticksPerSec) {
555607
currentState = RampDown;
556608
}
557609
break;
@@ -663,9 +715,10 @@ void loop(void)
663715
#endif
664716

665717
Channels[CHANNEL_HEATER].target = heaterValue;
666-
718+
#ifdef WITH_FAN
667719
double fanTmp = 90.0 / 100.0 * fanValue; // 0-100% -> 0-90° phase control
668720
Channels[CHANNEL_FAN].target = 90 - (uint8_t)fanTmp;
721+
#endif
669722
}
670723

671724

0 commit comments

Comments
 (0)