Finished experimental code to drive the German HendiControl board. Added BoilPower and RampPower buttons during the while boil process. RampPower (going to boil power) is now adjustable. Added PWM driver code to the driver task.

Mon, 21 Jun 2021 19:04:10 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 21 Jun 2021 19:04:10 +0200
changeset 102
96e30a3a3980
parent 101
1bc6e9263ada
child 103
1885d0c75c48

Finished experimental code to drive the German HendiControl board. Added BoilPower and RampPower buttons during the while boil process. RampPower (going to boil power) is now adjustable. Added PWM driver code to the driver task.

main/automation.c file | annotate | diff | comparison | revisions
main/config.h file | annotate | diff | comparison | revisions
main/task_driver.c file | annotate | diff | comparison | revisions
--- a/main/automation.c	Sat Jun 19 20:46:42 2021 +0200
+++ b/main/automation.c	Mon Jun 21 19:04:10 2021 +0200
@@ -6,6 +6,7 @@
 #include "config.h"
 
 int	    			BoilPower = 100;		///< Boil power 0..100%
+int				RampPower = 100;		///< Boil ramp power 0..100%
 int				LastMashStep = 0;		///< Last valid mash step
 char        			temp_buf[64];			///< Temporary buffer
 char				logline[128];			///< Log line buffer
@@ -269,11 +270,14 @@
                 runtime.StageResume = Main_Screen;
                 updateRuntime = true;
 		TempReached = false;
+		RampPower = equipment.RampPower;
 
                 TopMessage((char *)"Naar koken");
                 MLT_info(71, 26, false);
-                Buttons_Add(  5,  30, 60, 40, (char *)"+sp",  0);
-                Buttons_Add(255,  30, 60, 40, (char *)"-sp",  1);
+                Buttons_Add(  5,  30, 60, 40, (char *)"+sp", 0);
+                Buttons_Add(255,  30, 60, 40, (char *)"-sp", 1);
+		Buttons_Add(  3, 110, 60, 40, (char *)"+%",  2);
+                Buttons_Add(257, 110, 60, 40, (char *)"-%",  3);
                 Buttons_Show();
                 log_msg(TAG, "Mash done, going to boil.");
 		Sub_Screen = 0;
@@ -300,10 +304,12 @@
                 updateRuntime = true;
                 TopMessage((char *)"Koken");
                 MLT_info(71, 26, false);
-                Buttons_Add(  3,  30, 60, 40, (char *)"+sp",  0);
-                Buttons_Add(257,  30, 60, 40, (char *)"-sp",  1);
-                Buttons_Add(  3, 190, 60, 40, (char *)"+1m",  2);
-                Buttons_Add(257, 190, 60, 40, (char *)"-1m",  3);
+                Buttons_Add(  3,  30, 60, 40, (char *)"+sp", 0);
+                Buttons_Add(257,  30, 60, 40, (char *)"-sp", 1);
+		Buttons_Add(  3, 110, 60, 40, (char *)"+%",  2);
+		Buttons_Add(257, 110, 60, 40, (char *)"-%",  3);
+                Buttons_Add(  3, 190, 60, 40, (char *)"+1m", 4);
+                Buttons_Add(257, 190, 60, 40, (char *)"-1m", 5);
                 Buttons_Show();
                 log_msg(TAG, "Boil temperature reached, boil %d minutes", (TimeLeft / 60) -1);
 		log_annotation(ANNOTATION_STAGE, (char *)"Koken");
@@ -1003,7 +1009,7 @@
                 break;
 
 	case MAIN_AUTO_TOBOIL:
-                Output = 255;
+                Output = (int)((RampPower * 255.0) / 100.0);
                 /*
                  * Go to the boil temperature and wait until it is steady.
                  */
@@ -1032,6 +1038,16 @@
 				}
                                 break;
 
+		    case 2:	if (RampPower < 100)
+				    RampPower++;
+				log_msg(TAG, "Increase ramppower to %d%%", RampPower);
+				break;
+
+		    case 3:	if (RampPower > 0)
+				    RampPower--;
+				log_msg(TAG, "Decrease ramppower to %d%%", RampPower);
+				break;
+
                     default:    break;
                 }
 		if (Resume)
@@ -1063,19 +1079,8 @@
                     Output = 0;
                 } else if (driver_state->mlt_pv >= stageTemp) {
                     Output = (int)((BoilPower * 255.0) / 100.0);
-                    if (Buttons[4].x == -1) {
-                        Buttons_Add(  3,110, 60, 40, (char *)"+%", 4);
-                        Buttons_Add(257,110, 60, 40, (char *)"-%", 5);
-                        Buttons_Show();
-                    }
                 } else {
-                    Output = 255;
-                    if (Buttons[4].x != -1) {
-                        Buttons[4].x = Buttons[5].x = -1;
-                        Buttons_Show();
-                        TFT_fillRect(  3,110, 60, 40, TFT_BLACK);
-                        TFT_fillRect(257,110, 60, 40, TFT_BLACK);
-                    }
+                    Output = (int)((RampPower * 255.0) / 100.0);;
                 }
 
                 MLT_info(71, 26, true);
@@ -1092,20 +1097,32 @@
 				}
                                 break;
 
-                    case 2:     change_tl(21600);
+                    case 4:     change_tl(21600);
                                 break;
 
-                    case 3:     change_tl(0);
+                    case 5:     change_tl(0);
                                 break;
 
-                    case 4:     if (BoilPower < 100)
-                                    BoilPower++;
-				log_msg(TAG, "Increase boilpower to %d%%", BoilPower);
+                    case 2:     if (driver_state->mlt_pv >= stageTemp) {
+				    if (BoilPower < 100)
+                                    	BoilPower++;
+				    log_msg(TAG, "Increase boilpower to %d%%", BoilPower);
+				} else {
+				    if (RampPower < 100)
+					RampPower++;
+				    log_msg(TAG, "Increase ramppower to %d%%", RampPower);
+				}
                                 break;
 
-                    case 5:     if (BoilPower > 0)
-                                    BoilPower--;
-				log_msg(TAG, "Decrease boilpower to %d%%", BoilPower);
+                    case 3:     if (driver_state->mlt_pv >= stageTemp) {
+				    if (BoilPower > 0)
+                                    	BoilPower--;
+				    log_msg(TAG, "Decrease boilpower to %d%%", BoilPower);
+				} else {
+				    if (RampPower > 0)
+					RampPower--;
+				    log_msg(TAG, "Decrease ramppower to %d%%", RampPower);
+				}
                                 break;
 
                     default:    break;
--- a/main/config.h	Sat Jun 19 20:46:42 2021 +0200
+++ b/main/config.h	Mon Jun 21 19:04:10 2021 +0200
@@ -25,6 +25,7 @@
 #include "freertos/event_groups.h"
 #include "freertos/queue.h"
 #include "driver/i2c.h"
+#include "driver/ledc.h"
 #include "esp_log.h"
 #include "esp_spiffs.h"
 #include "esp_event.h"
--- a/main/task_driver.c	Sat Jun 19 20:46:42 2021 +0200
+++ b/main/task_driver.c	Mon Jun 21 19:04:10 2021 +0200
@@ -37,7 +37,6 @@
 int			HLT_Mode = HLT_MODE_NONE;		///< HLT mode flag
 TickType_t		MLT_time, HLT_time;
 
-
 static const char	*MLTTypes[] = { "None", "Bang", "PID", "Off", "Ext" };
 static const char	*HLTTypes[] = { "None", "Bang", "Off", "On" };
 
@@ -63,6 +62,12 @@
  */
 void Pump(int onoff);
 
+/**
+ * @brief Calculate and set PWM value.
+ * @param percent Then power percentage, 0..100
+ */
+void MLT_PWM(int percent);
+
 
 
 void MLT(int onoff) {
@@ -111,6 +116,32 @@
 }
 
 
+//int oldval = 200;
+void MLT_PWM(int percent) {
+    int		val;
+    static int	oldval = -1;
+
+    if (outEnable) {
+	if (percent < 0) {
+	    val = 0;
+	} else if (percent > 100) {
+	    val = 1024;
+	} else {
+    	    val = (percent * 1024) / 100;
+	}
+    } else {
+	val = 0;
+    }
+
+    if (val != oldval) {
+    	ESP_LOGI(TAG, "MLT_PWM(%d) val=%d %.0f watt", percent, val, (percent / 100.0) * equipment.MLT_watt);
+    	ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 1024 - val);
+    	ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
+    }
+    oldval = val;
+}
+
+
 
 /**
  * @brief Load PID settings from equipment record.
@@ -129,6 +160,26 @@
 
 
 
+void AllowHLT(void) {
+    if (equipment.SSR2 == SSR2_HLT_SHARE) {
+	if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
+	    HLT_Output = 0;
+	    if (driver_state->hlt_mode == HLT_MODE_BANG) {
+		HLT_Output = (HLT_Input < HLT_Setpoint) ? 1:0;
+	    } else if (driver_state->hlt_mode == HLT_MODE_ON) {
+		HLT_Output = 1;
+	    }
+	    xSemaphoreGive(xSemaphoreDriver);
+	}
+	HLT(HLT_Output);
+    } else if (equipment.SSR2 == SSR2_ON_IDLE) {
+	HLT_Output = 1;
+	HLT(1);
+    }
+}
+
+
+
 void task_driver(void *pvParameter)
 {
     TickType_t		wait_ticks, last_tick, now_tick;
@@ -147,6 +198,27 @@
     gpio_pad_select_gpio(SSR_PUMP);
     gpio_set_direction(SSR_PUMP, GPIO_MODE_OUTPUT);
 
+    // Prepare and then apply the LEDC PWM timer configuration
+    ledc_timer_config_t ledc_timer = {
+	.speed_mode = LEDC_LOW_SPEED_MODE,		///< Use low speed
+	.timer_num = LEDC_TIMER_1,
+	.duty_resolution = LEDC_TIMER_10_BIT,		///< 10 bits resolution
+	.freq_hz = 100,					///< 100 Hz
+	.clk_cfg = LEDC_AUTO_CLK			///< Auto select PWM clock
+    };
+    ledc_timer_config(&ledc_timer);
+
+    ledc_channel_config_t pwm_channel = {
+	.channel    = LEDC_CHANNEL_0,
+	.duty       = 1024,				///< Default 0% (inverted value)
+	.gpio_num   = PWM_MLT,				///< MLT pin
+	.speed_mode = LEDC_LOW_SPEED_MODE,
+	.hpoint     = 0,
+	.intr_type  = LEDC_INTR_DISABLE,
+	.timer_sel  = LEDC_TIMER_1
+    };
+    ledc_channel_config(&pwm_channel);
+
     /*
      * Initialize state
      */
@@ -168,7 +240,7 @@
     driver_state->pwm_nohlt = 10;	/* Conservative safety value. */
 
     PID(&Input, &Output, &Setpoint, 200, 2.0, 1.5, PID_DIRECT);
-    
+
     /*
      * One loop must complete in 20 mSecs, that is one mains
      * frequency period cycle in 50 Hz countries.
@@ -241,7 +313,38 @@
 	    w_StartTime = now;
 	}
 
-	if ((int)((Output / 255.0) * RealTime) > (now - w_StartTime)) {
+	if (equipment.Hendi) {
+
+	    int PWMout = (int)((Output * 100) / 255.0);
+
+	    if ((PID_GetMode() == PID_AUTOMATIC) && (MLT_Mode == MLT_MODE_PID)) {
+		if (PWMout > equipment.MashPower)
+		    PWMout = equipment.MashPower;
+	    }
+
+	    /*
+	     * Hendi minimum power is 500 Watt, this is 14%.
+	     * So, we turn the cooker on around 10% power.
+	     */
+	    if (PWMout >= 10) {	// Hendi minimum power is 500 Watt, this is 10%
+		if ((((PWMout / 100.0) * equipment.MLT_watt) + equipment.HLT_watt) > equipment.Max_watt) {
+		    if (HLT_pin) {
+		    	ESP_LOGI(TAG, "Power %f  %d", ((PWMout / 100.0) * equipment.MLT_watt) + equipment.HLT_watt, equipment.Max_watt);
+		    	ESP_LOGI(TAG, "Immediate HLT panic shutdown");
+		    	HLT_Output = 0;
+		    	HLT(0);		// As soon as possible before the Hendi increases power.
+		    }
+		} else {
+		    AllowHLT();		// TODO: delay this one loop.
+		}
+		MLT_PWM(PWMout);
+                MLT(1);
+	    } else {
+		MLT_PWM(0);
+		MLT(0);
+		AllowHLT();
+	    }
+	} else if ((int)((Output / 255.0) * RealTime) > (now - w_StartTime)) {
 	    MLT(1);
 	    if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_ON_IDLE)) {
 	    	HLT(0);
@@ -249,21 +352,7 @@
 	    }
 	} else {
 	    MLT(0);
-	    if (equipment.SSR2 == SSR2_HLT_SHARE) {
-	    	if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
-		    HLT_Output = 0;
-	    	    if (driver_state->hlt_mode == HLT_MODE_BANG) {
-		    	HLT_Output = (HLT_Input < HLT_Setpoint) ? 1:0;
-	    	    } else if (driver_state->hlt_mode == HLT_MODE_ON) {
-		    	HLT_Output = 1;
-	    	    }
-		    xSemaphoreGive(xSemaphoreDriver);
-	    	}
-	    	HLT(HLT_Output);
-	    } else if (equipment.SSR2 == SSR2_ON_IDLE) {
-		HLT_Output = 1;
-		HLT(1);
-	    }
+	    AllowHLT();
 	}
 
 	/*
@@ -309,8 +398,7 @@
 	}
 #endif
 
-	// Not reliable, so do it manually.
-	//vTaskDelayUntil(&last_wake_time, (1000 / 50) / portTICK_PERIOD_MS);
+	// Do not use vTaskDelayUntil(), it is not reliable here.
 	now_tick = xTaskGetTickCount();
 	if ((now_tick - last_tick) > (1000 / 50)) {
 	    // This happens one or two times during a brew.

mercurial