main/task_driver.c

changeset 0
b74b0e4902c3
child 1
ad2c8b13eb88
equal deleted inserted replaced
-1:000000000000 0:b74b0e4902c3
1 /**
2 * @file task_driver.c
3 * @brief BrewBoard relays driver. Control the hardware outputs with the
4 * Solid State relays for the Mash/Boil kettle (MLT, the Hot
5 * Liquer Tank (HLT) and the pump. The MLT has a PID controller
6 * during mashing, and a simple bang on/off control during the
7 * boil.
8 * The HLT output can be off, bang on/off, or just on if the MLT
9 * is off, depending on the configuration.
10 * Use SSR modules that switch during zero crossing of the mains
11 * power, so that when one is turned on and on the same time the
12 * other is turned off, they won't be active at the same time.
13 */
14
15 #include "config.h"
16
17
18 #define SSR_MLT CONFIG_SSR_MLT_GPIO
19 #define SSR_HLT CONFIG_SSR_HLT_GPIO
20 #define SSR_PUMP CONFIG_SSR_PUMP_GPIO
21
22
23 bool outEnable = false;
24 DRIVER_State * driver_state;
25 SemaphoreHandle_t xSemaphoreDriver = NULL;
26 int MLT_pin = 0;
27 int HLT_pin = 0;
28 int Pump_pin = 0;
29 double Input = 0, Output = 0, Setpoint = 0;
30 int MLT_Mode = MLT_MODE_NONE;
31 double HLT_Input = 0, HLT_Setpoint = 0;
32 int HLT_Output = 0;
33 int HLT_Mode = HLT_MODE_NONE;
34
35 static const char *TAG = "task_driver";
36
37 extern SemaphoreHandle_t xSemaphoreDS18B20;
38 extern DS18B20_State * ds18b20_state;
39 extern unsigned long lastTime;
40
41
42 /**
43 * @brief Turn the MLT SSR on or off.
44 */
45 void MLT(int onoff);
46
47 /**
48 * @brief Turn the HLT SSR on or off.
49 */
50 void HLT(int onoff);
51
52 /**
53 * @brief Turn the Pump on or off.
54 */
55 void Pump(int onoff);
56
57
58
59 void MLT(int onoff) {
60
61 if (onoff && outEnable) {
62 gpio_set_level(SSR_MLT, 1);
63 MLT_pin = 1;
64 } else {
65 gpio_set_level(SSR_MLT, 0);
66 MLT_pin = 0;
67 }
68 }
69
70
71
72 void HLT(int onoff) {
73
74 if (onoff && outEnable) {
75 gpio_set_level(SSR_HLT, 1);
76 HLT_pin = 1;
77 } else {
78 gpio_set_level(SSR_HLT, 0);
79 HLT_pin = 0;
80 }
81 }
82
83
84
85 void Pump(int onoff) {
86
87 if (onoff && outEnable) {
88 gpio_set_level(SSR_PUMP, 1);
89 Pump_pin = 1;
90 } else {
91 gpio_set_level(SSR_PUMP, 0);
92 Pump_pin = 0;
93 }
94 }
95
96
97
98 void LoadPIDsettings() {
99 PID_SetTunings(equipment.PID_kP, equipment.PID_kI, equipment.PID_kD, equipment.PID_POn);
100 PID_SetSampleTime(equipment.SampleTime);
101
102 /*
103 * Initialize the PID
104 */
105 Output = 0.0; // Reset internal Iterm.
106 PID_SetMode(PID_MANUAL);
107 PID_SetMode(PID_AUTOMATIC);
108 }
109
110
111
112 void task_driver(void *pvParameter)
113 {
114 TickType_t wait_ticks, last_tick, now_tick;
115 bool rc;
116 unsigned long now, RealTime, w_StartTime = 0;
117
118 ESP_LOGI(TAG, "Starting output drivers");
119
120 /*
121 * Configure IOMUX register.
122 */
123 gpio_pad_select_gpio(SSR_MLT);
124 gpio_set_direction(SSR_MLT, GPIO_MODE_OUTPUT);
125 gpio_pad_select_gpio(SSR_HLT);
126 gpio_set_direction(SSR_HLT, GPIO_MODE_OUTPUT);
127 gpio_pad_select_gpio(SSR_PUMP);
128 gpio_set_direction(SSR_PUMP, GPIO_MODE_OUTPUT);
129
130 /*
131 * Initialize state
132 */
133 driver_state = malloc(sizeof(DRIVER_State));
134 driver_state->enable = outEnable = false;
135 driver_state->mlt_gpio = SSR_MLT;
136 driver_state->mlt_mode = MLT_MODE_NONE;
137 driver_state->mlt_sp = driver_state->mlt_pv = 0.0;
138 driver_state->mlt_power = 0;
139 driver_state->hlt_gpio = SSR_HLT;
140 driver_state->hlt_mode = HLT_MODE_NONE;
141 driver_state->hlt_sp = driver_state->hlt_pv = 0.0;
142 driver_state->hlt_power = 0;
143 driver_state->hlt_and_mlt = false;
144 driver_state->pump_gpio = SSR_PUMP;
145 driver_state->pump_run = 0;
146
147 PID(&Input, &Output, &Setpoint, 150, 1.5, 15000, PID_P_ON_E, PID_DIRECT);
148
149 /*
150 * One loop must complete in 20 mSecs, that is one mains
151 * frequency period cycle in 50 Hz countries.
152 */
153 while (1) {
154
155 last_tick = xTaskGetTickCount();
156
157 if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
158 /*
159 * Get the current temperature readings
160 */
161 if (xSemaphoreTake(xSemaphoreDS18B20, 10) == pdTRUE) {
162 if (ds18b20_state->mlt_valid)
163 driver_state->mlt_pv = ds18b20_state->mlt_temperature;
164 if (ds18b20_state->hlt_valid)
165 driver_state->hlt_pv = ds18b20_state->hlt_temperature;
166 xSemaphoreGive(xSemaphoreDS18B20);
167 }
168
169 /*
170 * Other values that we need
171 */
172 Input = driver_state->mlt_pv;
173 Setpoint = driver_state->mlt_sp;
174 if (driver_state->mlt_mode != MLT_Mode) {
175 if (driver_state->mlt_mode == MLT_MODE_BANG) {
176 PID_SetMode(PID_MANUAL);
177 } else if (driver_state->mlt_mode == MLT_MODE_PID) {
178 LoadPIDsettings();
179 }
180 MLT_Mode = driver_state->mlt_mode;
181 ESP_LOGI(TAG, "MLT mode set to %d", MLT_Mode);
182 }
183 if (driver_state->hlt_mode != HLT_Mode) {
184 HLT_Mode = driver_state->hlt_mode;
185 ESP_LOGI(TAG, "HLT mode set to %d", HLT_Mode);
186 }
187 outEnable = driver_state->enable;
188 HLT_Input = driver_state->hlt_pv;
189 HLT_Setpoint = driver_state->hlt_sp;
190 xSemaphoreGive(xSemaphoreDriver);
191 }
192
193 rc = false;
194 now = xTaskGetTickCount() * portTICK_PERIOD_MS;
195
196 if ((PID_GetMode() == PID_AUTOMATIC) && (MLT_Mode == MLT_MODE_PID)) {
197 rc = PID_Compute();
198 RealTime = (equipment.SampleTime * equipment.MashPower) / 100;
199 } else {
200 /*
201 * Schedule the loop ourself.
202 */
203 unsigned long timeChange = (now - lastTime);
204 if (timeChange >= equipment.SampleTime) {
205 lastTime = now;
206 rc = true;
207 }
208 RealTime = equipment.SampleTime;
209 if (driver_state->mlt_mode == MLT_MODE_BANG) {
210 Output = (Input < Setpoint) ? 255:0;
211 }
212 if (driver_state->mlt_mode == MLT_MODE_NONE || driver_state->mlt_mode == MLT_MODE_OFF) {
213 Output = 0;
214 }
215 }
216
217 if (rc) {
218 w_StartTime = now;
219 }
220
221 if ((int)((Output / 255.0) * RealTime) > (now - w_StartTime)) {
222 MLT(1);
223 if ((equipment.SSR2 == SSR2_HLT_SHARE) || (equipment.SSR2 == SSR2_ON_IDLE)) {
224 HLT(0);
225 HLT_Output = 0;
226 }
227 } else {
228 MLT(0);
229 if (equipment.SSR2 == SSR2_HLT_SHARE) {
230 if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
231 HLT_Output = 0;
232 if (driver_state->hlt_mode == HLT_MODE_BANG) {
233 HLT_Output = (HLT_Input < HLT_Setpoint) ? 1:0;
234 } else if (driver_state->hlt_mode == HLT_MODE_ON) {
235 HLT_Output = 1;
236 }
237 xSemaphoreGive(xSemaphoreDriver);
238 }
239 HLT(HLT_Output);
240 } else if (equipment.SSR2 == SSR2_ON_IDLE) {
241 HLT_Output = 1;
242 HLT(1);
243 }
244 }
245
246 /*
247 * Independant HLT temperature control
248 */
249 if (equipment.SSR2 == SSR2_HLT_IND) {
250 if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
251 HLT_Output = 0;
252 if (driver_state->hlt_mode == HLT_MODE_BANG) {
253 HLT_Output = (HLT_Input < HLT_Setpoint) ? 1:0;
254 } else if (driver_state->hlt_mode == HLT_MODE_ON) {
255 HLT_Output = 1;
256 }
257 xSemaphoreGive(xSemaphoreDriver);
258 }
259 HLT(HLT_Output);
260 }
261
262 /*
263 * Update the driver results.
264 */
265 if (xSemaphoreTake(xSemaphoreDriver, 10) == pdTRUE) {
266 driver_state->mlt_power = (int)((Output * 100) / 255.0);
267 if (HLT_Output) {
268 if (equipment.SSR2 == SSR2_HLT_SHARE) {
269 driver_state->hlt_power = 100 - driver_state->mlt_power;
270 } else if (equipment.SSR2 == SSR2_HLT_IND) {
271 driver_state->hlt_power = 100;
272 }
273 } else {
274 driver_state->hlt_power = 0;
275 }
276 if (driver_state->pump_run != Pump_pin)
277 Pump(driver_state->pump_run);
278 xSemaphoreGive(xSemaphoreDriver);
279 }
280
281 #if 0
282 if (rc) {
283 printf("ST: %s MLT[In: %7.3f Out: %3.0f Sp: %6.2f %s RT: %lu] HLT[In: %7.3f Out: %d Sp: %5.1f]\n", outEnable ? "E":"D",
284 Input, Output, Setpoint, PID_GetMode() ? "AUTOMATIC" : "MANUAL ", RealTime,
285 HLT_Input, HLT_Output, HLT_Setpoint);
286 }
287 #endif
288
289 // Not reliable, so do it manually.
290 //vTaskDelayUntil(&last_wake_time, (1000 / 50) / portTICK_PERIOD_MS);
291 now_tick = xTaskGetTickCount();
292 if ((now_tick - last_tick) > (1000 / 50)) {
293 // This happens one or two times during a brew.
294 wait_ticks = (1000 / 50);
295 } else {
296 wait_ticks = (1000 / 50) - (now_tick - last_tick);
297 }
298 if (wait_ticks == 0) {
299 // This is rare, but it happens.
300 wait_ticks = 1;
301 }
302
303 vTaskDelay(wait_ticks);
304 }
305 }
306
307

mercurial