main/task_driver.c

changeset 102
96e30a3a3980
parent 101
1bc6e9263ada
child 103
1885d0c75c48
equal deleted inserted replaced
101:1bc6e9263ada 102:96e30a3a3980
35 double HLT_Setpoint = 0; ///< HLT setpoint values 35 double HLT_Setpoint = 0; ///< HLT setpoint values
36 int HLT_Output = 0; ///< HLT output value 36 int HLT_Output = 0; ///< HLT output value
37 int HLT_Mode = HLT_MODE_NONE; ///< HLT mode flag 37 int HLT_Mode = HLT_MODE_NONE; ///< HLT mode flag
38 TickType_t MLT_time, HLT_time; 38 TickType_t MLT_time, HLT_time;
39 39
40
41 static const char *MLTTypes[] = { "None", "Bang", "PID", "Off", "Ext" }; 40 static const char *MLTTypes[] = { "None", "Bang", "PID", "Off", "Ext" };
42 static const char *HLTTypes[] = { "None", "Bang", "Off", "On" }; 41 static const char *HLTTypes[] = { "None", "Bang", "Off", "On" };
43 42
44 static const char *TAG = "task_driver"; 43 static const char *TAG = "task_driver";
45 44
60 59
61 /** 60 /**
62 * @brief Turn the Pump on or off. 61 * @brief Turn the Pump on or off.
63 */ 62 */
64 void Pump(int onoff); 63 void Pump(int onoff);
64
65 /**
66 * @brief Calculate and set PWM value.
67 * @param percent Then power percentage, 0..100
68 */
69 void MLT_PWM(int percent);
65 70
66 71
67 72
68 void MLT(int onoff) { 73 void MLT(int onoff) {
69 74
109 Pump_pin = 0; 114 Pump_pin = 0;
110 } 115 }
111 } 116 }
112 117
113 118
119 //int oldval = 200;
120 void MLT_PWM(int percent) {
121 int val;
122 static int oldval = -1;
123
124 if (outEnable) {
125 if (percent < 0) {
126 val = 0;
127 } else if (percent > 100) {
128 val = 1024;
129 } else {
130 val = (percent * 1024) / 100;
131 }
132 } else {
133 val = 0;
134 }
135
136 if (val != oldval) {
137 ESP_LOGI(TAG, "MLT_PWM(%d) val=%d %.0f watt", percent, val, (percent / 100.0) * equipment.MLT_watt);
138 ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 1024 - val);
139 ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
140 }
141 oldval = val;
142 }
143
144
114 145
115 /** 146 /**
116 * @brief Load PID settings from equipment record. 147 * @brief Load PID settings from equipment record.
117 */ 148 */
118 void LoadPIDsettings() { 149 void LoadPIDsettings() {
123 * Initialize the PID 154 * Initialize the PID
124 */ 155 */
125 Output = 0.0; // Reset internal Iterm. 156 Output = 0.0; // Reset internal Iterm.
126 PID_SetMode(PID_MANUAL); 157 PID_SetMode(PID_MANUAL);
127 PID_SetMode(PID_AUTOMATIC); 158 PID_SetMode(PID_AUTOMATIC);
159 }
160
161
162
163 void AllowHLT(void) {
164 if (equipment.SSR2 == SSR2_HLT_SHARE) {
165 if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
166 HLT_Output = 0;
167 if (driver_state->hlt_mode == HLT_MODE_BANG) {
168 HLT_Output = (HLT_Input < HLT_Setpoint) ? 1:0;
169 } else if (driver_state->hlt_mode == HLT_MODE_ON) {
170 HLT_Output = 1;
171 }
172 xSemaphoreGive(xSemaphoreDriver);
173 }
174 HLT(HLT_Output);
175 } else if (equipment.SSR2 == SSR2_ON_IDLE) {
176 HLT_Output = 1;
177 HLT(1);
178 }
128 } 179 }
129 180
130 181
131 182
132 void task_driver(void *pvParameter) 183 void task_driver(void *pvParameter)
144 gpio_set_direction(SSR_MLT, GPIO_MODE_OUTPUT); 195 gpio_set_direction(SSR_MLT, GPIO_MODE_OUTPUT);
145 gpio_pad_select_gpio(SSR_HLT); 196 gpio_pad_select_gpio(SSR_HLT);
146 gpio_set_direction(SSR_HLT, GPIO_MODE_OUTPUT); 197 gpio_set_direction(SSR_HLT, GPIO_MODE_OUTPUT);
147 gpio_pad_select_gpio(SSR_PUMP); 198 gpio_pad_select_gpio(SSR_PUMP);
148 gpio_set_direction(SSR_PUMP, GPIO_MODE_OUTPUT); 199 gpio_set_direction(SSR_PUMP, GPIO_MODE_OUTPUT);
200
201 // Prepare and then apply the LEDC PWM timer configuration
202 ledc_timer_config_t ledc_timer = {
203 .speed_mode = LEDC_LOW_SPEED_MODE, ///< Use low speed
204 .timer_num = LEDC_TIMER_1,
205 .duty_resolution = LEDC_TIMER_10_BIT, ///< 10 bits resolution
206 .freq_hz = 100, ///< 100 Hz
207 .clk_cfg = LEDC_AUTO_CLK ///< Auto select PWM clock
208 };
209 ledc_timer_config(&ledc_timer);
210
211 ledc_channel_config_t pwm_channel = {
212 .channel = LEDC_CHANNEL_0,
213 .duty = 1024, ///< Default 0% (inverted value)
214 .gpio_num = PWM_MLT, ///< MLT pin
215 .speed_mode = LEDC_LOW_SPEED_MODE,
216 .hpoint = 0,
217 .intr_type = LEDC_INTR_DISABLE,
218 .timer_sel = LEDC_TIMER_1
219 };
220 ledc_channel_config(&pwm_channel);
149 221
150 /* 222 /*
151 * Initialize state 223 * Initialize state
152 */ 224 */
153 driver_state = malloc(sizeof(DRIVER_State)); 225 driver_state = malloc(sizeof(DRIVER_State));
166 driver_state->pwm_gpio = PWM_MLT; 238 driver_state->pwm_gpio = PWM_MLT;
167 driver_state->pwm_mlt = false; 239 driver_state->pwm_mlt = false;
168 driver_state->pwm_nohlt = 10; /* Conservative safety value. */ 240 driver_state->pwm_nohlt = 10; /* Conservative safety value. */
169 241
170 PID(&Input, &Output, &Setpoint, 200, 2.0, 1.5, PID_DIRECT); 242 PID(&Input, &Output, &Setpoint, 200, 2.0, 1.5, PID_DIRECT);
171 243
172 /* 244 /*
173 * One loop must complete in 20 mSecs, that is one mains 245 * One loop must complete in 20 mSecs, that is one mains
174 * frequency period cycle in 50 Hz countries. 246 * frequency period cycle in 50 Hz countries.
175 */ 247 */
176 while (1) { 248 while (1) {
239 311
240 if (rc) { 312 if (rc) {
241 w_StartTime = now; 313 w_StartTime = now;
242 } 314 }
243 315
244 if ((int)((Output / 255.0) * RealTime) > (now - w_StartTime)) { 316 if (equipment.Hendi) {
317
318 int PWMout = (int)((Output * 100) / 255.0);
319
320 if ((PID_GetMode() == PID_AUTOMATIC) && (MLT_Mode == MLT_MODE_PID)) {
321 if (PWMout > equipment.MashPower)
322 PWMout = equipment.MashPower;
323 }
324
325 /*
326 * Hendi minimum power is 500 Watt, this is 14%.
327 * So, we turn the cooker on around 10% power.
328 */
329 if (PWMout >= 10) { // Hendi minimum power is 500 Watt, this is 10%
330 if ((((PWMout / 100.0) * equipment.MLT_watt) + equipment.HLT_watt) > equipment.Max_watt) {
331 if (HLT_pin) {
332 ESP_LOGI(TAG, "Power %f %d", ((PWMout / 100.0) * equipment.MLT_watt) + equipment.HLT_watt, equipment.Max_watt);
333 ESP_LOGI(TAG, "Immediate HLT panic shutdown");
334 HLT_Output = 0;
335 HLT(0); // As soon as possible before the Hendi increases power.
336 }
337 } else {
338 AllowHLT(); // TODO: delay this one loop.
339 }
340 MLT_PWM(PWMout);
341 MLT(1);
342 } else {
343 MLT_PWM(0);
344 MLT(0);
345 AllowHLT();
346 }
347 } else if ((int)((Output / 255.0) * RealTime) > (now - w_StartTime)) {
245 MLT(1); 348 MLT(1);
246 if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_ON_IDLE)) { 349 if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_ON_IDLE)) {
247 HLT(0); 350 HLT(0);
248 HLT_Output = 0; 351 HLT_Output = 0;
249 } 352 }
250 } else { 353 } else {
251 MLT(0); 354 MLT(0);
252 if (equipment.SSR2 == SSR2_HLT_SHARE) { 355 AllowHLT();
253 if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
254 HLT_Output = 0;
255 if (driver_state->hlt_mode == HLT_MODE_BANG) {
256 HLT_Output = (HLT_Input < HLT_Setpoint) ? 1:0;
257 } else if (driver_state->hlt_mode == HLT_MODE_ON) {
258 HLT_Output = 1;
259 }
260 xSemaphoreGive(xSemaphoreDriver);
261 }
262 HLT(HLT_Output);
263 } else if (equipment.SSR2 == SSR2_ON_IDLE) {
264 HLT_Output = 1;
265 HLT(1);
266 }
267 } 356 }
268 357
269 /* 358 /*
270 * Independant HLT temperature control 359 * Independant HLT temperature control
271 */ 360 */
307 Input, Output, Setpoint, PID_GetMode() ? "AUTOMATIC" : "MANUAL ", RealTime, 396 Input, Output, Setpoint, PID_GetMode() ? "AUTOMATIC" : "MANUAL ", RealTime,
308 HLT_Input, HLT_Output, HLT_Setpoint); 397 HLT_Input, HLT_Output, HLT_Setpoint);
309 } 398 }
310 #endif 399 #endif
311 400
312 // Not reliable, so do it manually. 401 // Do not use vTaskDelayUntil(), it is not reliable here.
313 //vTaskDelayUntil(&last_wake_time, (1000 / 50) / portTICK_PERIOD_MS);
314 now_tick = xTaskGetTickCount(); 402 now_tick = xTaskGetTickCount();
315 if ((now_tick - last_tick) > (1000 / 50)) { 403 if ((now_tick - last_tick) > (1000 / 50)) {
316 // This happens one or two times during a brew. 404 // This happens one or two times during a brew.
317 wait_ticks = (1000 / 50); 405 wait_ticks = (1000 / 50);
318 } else { 406 } else {

mercurial