diff --git a/TemperatureController/CHANGELOG.md b/TemperatureController/CHANGELOG.md index a49b49d1adfa7687ecfbc23be6b9cbc69d2102e2..e468af602227607eafd27273e44cbd7f19e573d5 100644 --- a/TemperatureController/CHANGELOG.md +++ b/TemperatureController/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG +## 2.0.0 + +_PID calculation changed to fraction, for upgrade reduce PID factors (Kp, Ki) by factor 1000._ + +### Changed + +* Duty cycle is fraction of period instead per mille. +* Cycle period unit is ms instead of second, allowing 1 ms duty cycle. +* Duty cycle time resolution is µs instead of ms. + + ## 1.4.0 ### Added diff --git a/TemperatureController/TemperatureController.ino b/TemperatureController/TemperatureController.ino index 7cbed48d1abdf5180485a21c7aed6f9e00f6aed7..0027555fd44034cd92814a1d7183ad43127e9ed3 100644 --- a/TemperatureController/TemperatureController.ino +++ b/TemperatureController/TemperatureController.ino @@ -12,9 +12,9 @@ */ //** CONSTANTS PARAMETERS change for your application **// -const String version = "1.4.0"; // Version of this script. Filename is added before, date of compilation afterwards. +const String version = "2.0.0"; // Version of this script. Filename is added before, date of compilation afterwards. -const int cyclePeriod = 30; //program cycle period in s +const unsigned long cyclePeriod = 1000; //program cycle period in ms const int controlPin = 11; //Pin by which the control unit is controlled (11 or 12) const int secondaryControlPin = -1; // Secondary Pin to control output (or -1) @@ -40,13 +40,15 @@ const int redLedPin = 4; //Pin for a red LED const int errorPin = 7; //Pin for a bright red warning LED // ERROR indicator -const int errorCyclePeriod = 2000; // Interval between two error indicators +const int errorCyclePeriod = 2000; // Interval between two error indicators in ms const int errorOnTime = 100; // How long the output is on (in ms) for a single blink const int errorInterval = 200; // Interval for the error blinks // MISC -const long rolloverThreshold = 4294965000; //After how many milliseconds should we suspend normal operation to await millis()-rollover? -// (Should be at least cyclePeriod+digitalPinSetDelay below the maximum value of an unsigned long of 4.294.967.295) +const unsigned long cycle_period_us = cyclePeriod * 1000; // for the µs counter +const unsigned long max_ulong = -1; // maximum value of unsigned long needed for rollover detection +const float duty_cycle_upper_limit = 1.05; // what the duty cycle should be at most. Should be more than 1 for continuous control +const unsigned long rolloverThreshold = max_ulong - cycle_period_us * duty_cycle_upper_limit * 1.5; // when the rollover protection should kick in. // ******************************************************************************** @@ -88,7 +90,7 @@ float setpoint; // setpoint for the temperature = 36°C float PIDKp; //Wert für die PID Regelung (Proportional-Teil) float PIDKi; //Wert für die PID Regelung (Integral-Teil) float integral; //Wert für die PID Integralteil -float duty_cycle; //Current duty cycle in per mille +float duty_cycle; //Current duty cycle as fraction of cycle period int controller = 1; // controller mode: 0 = off, 1 = on int error = 0; // current error code @@ -118,15 +120,15 @@ void setup() { } EEPROM.get(1 * floatsize, PIDKp); if ( isnan(PIDKp)){ - PIDKp = 1000; + PIDKp = 1; } EEPROM.get(2 * floatsize, PIDKi); if ( isnan(PIDKi)){ - PIDKi = 1; + PIDKi = 0.001; } EEPROM.get(3 * floatsize, integral); - if ( isnan(integral) || integral < 0 || integral > 1000 ){ - integral = 100; + if ( isnan(integral) || integral < 0 || integral > 1 ){ + integral = 0.1; } } @@ -253,7 +255,7 @@ void loop(){ case 'x': // Parameters, name TBD Serial.print("cyclePeriod: "); Serial.print(cyclePeriod); - Serial.print("s, "); + Serial.print("ms, "); Serial.print("controlPin: "); Serial.print(controlPin); Serial.print(", "); @@ -280,15 +282,15 @@ void loop(){ } // Start new pulse, calculating the duty cycle and pulse length - if ( millis() >= nextCycle ){ + if ( micros() >= nextCycle ){ if (controller > 0){ calculatePID(); } - nextCycle += cyclePeriod * 1000; + nextCycle += cycle_period_us; } // stop the pulse, if pulse length elapsed - if ( millis() >= nextOff && nextOff > 0){ + if ( micros() >= nextOff && nextOff > 0){ enable_control(false); } @@ -298,10 +300,10 @@ void loop(){ nextError = millis() + errorCyclePeriod; } - //if we are within 2300ms of rollover of millis counter suspend normal operation - if (millis() > rolloverThreshold){ - nextCycle = cyclePeriod * 1000; //set everything for continuing normal operation after rollover - while (millis() > rolloverThreshold){}; //wait for rollover to happen + //if we are within cycle_period of rollover of counter suspend normal operation + if (micros() > rolloverThreshold){ + while (micros() > rolloverThreshold){}; //wait for rollover to happen + nextCycle = 0; // continue normally after rollover }; } @@ -346,17 +348,21 @@ void calculatePID(){ // Calculate the PID signal and duty cycle, and start a new pulse float error = setpoint - average0.getAverage(); - // calculate integral part, clamp it between 0 and 1000 + // calculate integral part, clamp it between 0 and 1 integral += PIDKi * error; - if (integral > 1000){ - integral = 1000; + if (integral > 1){ + integral = 1; } else if (integral < 0){ integral = 0; } - // caclulate the duty cycle, clamp it between 0 and 1000 + // calculate the duty cycle, clamp it between 0 and 1 duty_cycle = PIDKp * error + integral; + // limit duty cycle against overflow + if (duty_cycle > duty_cycle_upper_limit){ + duty_cycle = duty_cycle_upper_limit; + } if (duty_cycle < 0){ nextOff = 0; duty_cycle = 0; @@ -364,12 +370,9 @@ void calculatePID(){ } else { // start a new pulse and set the pulse length - nextOff = millis() + cyclePeriod * duty_cycle; + nextOff = micros() + cycle_period_us * duty_cycle; enable_control( true ); } - if (duty_cycle > 1000){ - duty_cycle = 1000; - } } void enable_control(const boolean enabled){