Brew heater controller. Programmed to mash grain and to boil wort
Dependencies: mbed QEI UniGraphic
main.cpp@0:c673d397e9dc, 2022-01-07 (annotated)
- Committer:
- dswood
- Date:
- Fri Jan 07 12:08:12 2022 +0000
- Revision:
- 0:c673d397e9dc
First release. Works but is a little clunky.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dswood | 0:c673d397e9dc | 1 | /** |
dswood | 0:c673d397e9dc | 2 | |
dswood | 0:c673d397e9dc | 3 | Spice modal |
dswood | 0:c673d397e9dc | 4 | .SUBCKT NTCLE203E3103SB0 RN Rp PARAMS: TOLR=0 TOLB=0 |
dswood | 0:c673d397e9dc | 5 | X64 Rn Rp NTC_BASE Params: |
dswood | 0:c673d397e9dc | 6 | + w=-14.6571976 |
dswood | 0:c673d397e9dc | 7 | + x=4798.842 |
dswood | 0:c673d397e9dc | 8 | + y=-115334 |
dswood | 0:c673d397e9dc | 9 | + z=-3730535 |
dswood | 0:c673d397e9dc | 10 | + gth=0.0032 gth1 = 0.0000167 |
dswood | 0:c673d397e9dc | 11 | + cth=0.032 |
dswood | 0:c673d397e9dc | 12 | + a=-14.65719769 |
dswood | 0:c673d397e9dc | 13 | + r25=10000 |
dswood | 0:c673d397e9dc | 14 | + b=4798.842 |
dswood | 0:c673d397e9dc | 15 | + c=-115334 |
dswood | 0:c673d397e9dc | 16 | + d=-3730535 |
dswood | 0:c673d397e9dc | 17 | + T0=273.15 |
dswood | 0:c673d397e9dc | 18 | + TR={1+TOLR/100} |
dswood | 0:c673d397e9dc | 19 | + TB={1+TOLB/100} |
dswood | 0:c673d397e9dc | 20 | .ENDS |
dswood | 0:c673d397e9dc | 21 | |
dswood | 0:c673d397e9dc | 22 | */ |
dswood | 0:c673d397e9dc | 23 | |
dswood | 0:c673d397e9dc | 24 | |
dswood | 0:c673d397e9dc | 25 | /* Includes ------------------------------------------------------------------*/ |
dswood | 0:c673d397e9dc | 26 | |
dswood | 0:c673d397e9dc | 27 | /* mbed specific header files. */ |
dswood | 0:c673d397e9dc | 28 | /* |
dswood | 0:c673d397e9dc | 29 | GPIO_InitTypeDef GPIO_InitStruct; |
dswood | 0:c673d397e9dc | 30 | //Configure GPIO pin : PB14 |
dswood | 0:c673d397e9dc | 31 | GPIO_InitStruct.Pin = GPIO_PIN_14; |
dswood | 0:c673d397e9dc | 32 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // digital Output |
dswood | 0:c673d397e9dc | 33 | GPIO_InitStruct.Speed = GPIO_SPEED_LOW; |
dswood | 0:c673d397e9dc | 34 | HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); |
dswood | 0:c673d397e9dc | 35 | */ |
dswood | 0:c673d397e9dc | 36 | #include "mbed.h" |
dswood | 0:c673d397e9dc | 37 | #include "SSD1306.h" |
dswood | 0:c673d397e9dc | 38 | #include "string" |
dswood | 0:c673d397e9dc | 39 | |
dswood | 0:c673d397e9dc | 40 | #include "MashProfile.h" |
dswood | 0:c673d397e9dc | 41 | #include "MashProfileFull.h" |
dswood | 0:c673d397e9dc | 42 | #include "Boil1.h" |
dswood | 0:c673d397e9dc | 43 | #include "Boil2.h" |
dswood | 0:c673d397e9dc | 44 | #include "Boil3.h" |
dswood | 0:c673d397e9dc | 45 | #ifndef PROFILES |
dswood | 0:c673d397e9dc | 46 | #define PROFILES |
dswood | 0:c673d397e9dc | 47 | #include "Profiles.h" |
dswood | 0:c673d397e9dc | 48 | #endif //Profiles |
dswood | 0:c673d397e9dc | 49 | |
dswood | 0:c673d397e9dc | 50 | #define Height 32 |
dswood | 0:c673d397e9dc | 51 | #define Width 132 |
dswood | 0:c673d397e9dc | 52 | |
dswood | 0:c673d397e9dc | 53 | |
dswood | 0:c673d397e9dc | 54 | |
dswood | 0:c673d397e9dc | 55 | #include "QEI.h" |
dswood | 0:c673d397e9dc | 56 | |
dswood | 0:c673d397e9dc | 57 | //Firing delay in microseconds |
dswood | 0:c673d397e9dc | 58 | #define SyncToZeroCrossingDelayRise 115 |
dswood | 0:c673d397e9dc | 59 | #define SyncToZeroCrossingDelayFall 115 |
dswood | 0:c673d397e9dc | 60 | |
dswood | 0:c673d397e9dc | 61 | #define TriacPulseLength 250 |
dswood | 0:c673d397e9dc | 62 | // Blinking rate in milliseconds |
dswood | 0:c673d397e9dc | 63 | #define BLINKING_RATE_MS 500 |
dswood | 0:c673d397e9dc | 64 | #define Bias_Current 0.261 // Thermistor current in mA |
dswood | 0:c673d397e9dc | 65 | /* |
dswood | 0:c673d397e9dc | 66 | |
dswood | 0:c673d397e9dc | 67 | FIR filter designed with |
dswood | 0:c673d397e9dc | 68 | http://t-filter.appspot.com |
dswood | 0:c673d397e9dc | 69 | |
dswood | 0:c673d397e9dc | 70 | sampling frequency: 2000 Hz |
dswood | 0:c673d397e9dc | 71 | |
dswood | 0:c673d397e9dc | 72 | * 0 Hz - 100 Hz |
dswood | 0:c673d397e9dc | 73 | gain = 1 |
dswood | 0:c673d397e9dc | 74 | desired ripple = 5 dB |
dswood | 0:c673d397e9dc | 75 | actual ripple = 1.0675530446538501 dB |
dswood | 0:c673d397e9dc | 76 | |
dswood | 0:c673d397e9dc | 77 | * 600 Hz - 1000 Hz |
dswood | 0:c673d397e9dc | 78 | gain = 0 |
dswood | 0:c673d397e9dc | 79 | desired attenuation = -60 dB |
dswood | 0:c673d397e9dc | 80 | actual attenuation = -71.5928467318133 dB |
dswood | 0:c673d397e9dc | 81 | |
dswood | 0:c673d397e9dc | 82 | */ |
dswood | 0:c673d397e9dc | 83 | |
dswood | 0:c673d397e9dc | 84 | #define NumberOfTaps 9 |
dswood | 0:c673d397e9dc | 85 | |
dswood | 0:c673d397e9dc | 86 | static double filter_taps[NumberOfTaps] = { |
dswood | 0:c673d397e9dc | 87 | 0.009246906411528302, |
dswood | 0:c673d397e9dc | 88 | 0.0484176527692072, |
dswood | 0:c673d397e9dc | 89 | 0.12764201806827455, |
dswood | 0:c673d397e9dc | 90 | 0.21665898750162413, |
dswood | 0:c673d397e9dc | 91 | 0.25663867508629506, |
dswood | 0:c673d397e9dc | 92 | 0.21665898750162413, |
dswood | 0:c673d397e9dc | 93 | 0.12764201806827455, |
dswood | 0:c673d397e9dc | 94 | 0.0484176527692072, |
dswood | 0:c673d397e9dc | 95 | 0.009246906411528302 |
dswood | 0:c673d397e9dc | 96 | }; |
dswood | 0:c673d397e9dc | 97 | //float PotBuf[NumberOfTaps]; |
dswood | 0:c673d397e9dc | 98 | float TempBuf[NumberOfTaps]; |
dswood | 0:c673d397e9dc | 99 | int CycleCount=0,StartT=0; |
dswood | 0:c673d397e9dc | 100 | bool FireTriac,Boiling,DisplayFlag; |
dswood | 0:c673d397e9dc | 101 | /*------- inputs ---------*/ |
dswood | 0:c673d397e9dc | 102 | InterruptIn FallingEdge(D12); |
dswood | 0:c673d397e9dc | 103 | InterruptIn RisingEdge(D13); |
dswood | 0:c673d397e9dc | 104 | //AnalogIn Potentiometer(A0); |
dswood | 0:c673d397e9dc | 105 | // Thermistor (ntc) with a constant current flowing through it |
dswood | 0:c673d397e9dc | 106 | AnalogIn Thermistor(A1); |
dswood | 0:c673d397e9dc | 107 | //Rotary Encoder for entering values and navigation |
dswood | 0:c673d397e9dc | 108 | QEI wheel (D9, D8, NC, 20); |
dswood | 0:c673d397e9dc | 109 | DigitalIn Button(PC_9); |
dswood | 0:c673d397e9dc | 110 | InterruptIn ButtonPressed(PC_9); |
dswood | 0:c673d397e9dc | 111 | /*------- inputs -end-----*/ |
dswood | 0:c673d397e9dc | 112 | |
dswood | 0:c673d397e9dc | 113 | /*------- outputs ---------*/ |
dswood | 0:c673d397e9dc | 114 | //DigitalOut led(LED1); |
dswood | 0:c673d397e9dc | 115 | // Output to switch on the LED in the opto to fire the triac |
dswood | 0:c673d397e9dc | 116 | DigitalOut Triac(D10),OledReset(D6); |
dswood | 0:c673d397e9dc | 117 | // Test output to see timings and states on a scope |
dswood | 0:c673d397e9dc | 118 | DigitalOut Test(D15); |
dswood | 0:c673d397e9dc | 119 | // The screen |
dswood | 0:c673d397e9dc | 120 | SSD1306 MyOled(SPI_8, 10000000, D4, D5, D3, D2, D6, D7,"MyOled", Width, Height); // Spi 8bit, 10MHz, mosi, miso, sclk, cs, reset, dc |
dswood | 0:c673d397e9dc | 121 | // fixme clock may need to be 5MHz |
dswood | 0:c673d397e9dc | 122 | // 5000000 gives a clock of 3.125MHz (genius) |
dswood | 0:c673d397e9dc | 123 | // 10000000 gives 6.25 |
dswood | 0:c673d397e9dc | 124 | // 12800000 gives 12.8Mhz still works |
dswood | 0:c673d397e9dc | 125 | // 20000000 gives 12.5Mhz |
dswood | 0:c673d397e9dc | 126 | // the nearest i can find to 8MHz is 10000000 |
dswood | 0:c673d397e9dc | 127 | |
dswood | 0:c673d397e9dc | 128 | /*------- outputs -end-----*/ |
dswood | 0:c673d397e9dc | 129 | |
dswood | 0:c673d397e9dc | 130 | |
dswood | 0:c673d397e9dc | 131 | char Buff[3][20]; |
dswood | 0:c673d397e9dc | 132 | Timeout SyncDelay,TriacPulseTimeout,ReadTemperature; |
dswood | 0:c673d397e9dc | 133 | |
dswood | 0:c673d397e9dc | 134 | //float Pot; |
dswood | 0:c673d397e9dc | 135 | int FireCount; |
dswood | 0:c673d397e9dc | 136 | int Demand; |
dswood | 0:c673d397e9dc | 137 | float valT,LastTemp=0,LastError=0,Integrated=0; |
dswood | 0:c673d397e9dc | 138 | bool Rise,MainsOn; |
dswood | 0:c673d397e9dc | 139 | time_t now; |
dswood | 0:c673d397e9dc | 140 | Timer ElapsedTime; |
dswood | 0:c673d397e9dc | 141 | uint64_t LastTime,TempTime,DebounceTime,StartTime,DemandTime,CheckTime,KnobTime,CycleTime; |
dswood | 0:c673d397e9dc | 142 | struct Controls { |
dswood | 0:c673d397e9dc | 143 | float Temperature; |
dswood | 0:c673d397e9dc | 144 | int8_t PercentPower; |
dswood | 0:c673d397e9dc | 145 | int16_t TimeSeconds; |
dswood | 0:c673d397e9dc | 146 | int8_t ProfileNumber; |
dswood | 0:c673d397e9dc | 147 | int8_t ElementNumber; |
dswood | 0:c673d397e9dc | 148 | uint8_t MessageNo; |
dswood | 0:c673d397e9dc | 149 | goal Goal; |
dswood | 0:c673d397e9dc | 150 | char Message[20]; |
dswood | 0:c673d397e9dc | 151 | |
dswood | 0:c673d397e9dc | 152 | }; |
dswood | 0:c673d397e9dc | 153 | struct Controls MyControls= {25.0,50,0}; |
dswood | 0:c673d397e9dc | 154 | struct Profile *ProfileArray[5]= { &MashProfile,&MashProfileFull,&Boil1,&Boil2,&Boil3}; |
dswood | 0:c673d397e9dc | 155 | enum VariableType { Index, TempC, PwrW, TimeS }; |
dswood | 0:c673d397e9dc | 156 | struct MenuType { |
dswood | 0:c673d397e9dc | 157 | int8_t IndexVal; //The current thing pointed to by the cursor |
dswood | 0:c673d397e9dc | 158 | int8_t Number; |
dswood | 0:c673d397e9dc | 159 | int8_t MaxIndex; |
dswood | 0:c673d397e9dc | 160 | int8_t Offset; |
dswood | 0:c673d397e9dc | 161 | VariableType CurrentType; |
dswood | 0:c673d397e9dc | 162 | void EncoderHandler( bool Increment, VariableType ChangeType); |
dswood | 0:c673d397e9dc | 163 | struct Controls *Cntrl; // points to the main loop controls |
dswood | 0:c673d397e9dc | 164 | char *MenuText[8]; //8 lines of menus to start with |
dswood | 0:c673d397e9dc | 165 | void (*NextMenu[8])(); |
dswood | 0:c673d397e9dc | 166 | bool Switch; |
dswood | 0:c673d397e9dc | 167 | }; |
dswood | 0:c673d397e9dc | 168 | |
dswood | 0:c673d397e9dc | 169 | Serial Mypc(USBTX, USBRX, 115200); //for debugging |
dswood | 0:c673d397e9dc | 170 | int64_t DebugValue; |
dswood | 0:c673d397e9dc | 171 | void FiringCounter(int Power); |
dswood | 0:c673d397e9dc | 172 | void PulseTriac(); |
dswood | 0:c673d397e9dc | 173 | void SyncFall(); |
dswood | 0:c673d397e9dc | 174 | void SyncRise(); |
dswood | 0:c673d397e9dc | 175 | //char *Menu[2]={"Manual","Programmed"}; |
dswood | 0:c673d397e9dc | 176 | |
dswood | 0:c673d397e9dc | 177 | int string_length(char* given_string) |
dswood | 0:c673d397e9dc | 178 | { |
dswood | 0:c673d397e9dc | 179 | // variable to store the |
dswood | 0:c673d397e9dc | 180 | // length of the string |
dswood | 0:c673d397e9dc | 181 | int length = 0; |
dswood | 0:c673d397e9dc | 182 | while (*given_string != '\0') { |
dswood | 0:c673d397e9dc | 183 | length++; |
dswood | 0:c673d397e9dc | 184 | given_string++; |
dswood | 0:c673d397e9dc | 185 | } |
dswood | 0:c673d397e9dc | 186 | |
dswood | 0:c673d397e9dc | 187 | return length; |
dswood | 0:c673d397e9dc | 188 | } |
dswood | 0:c673d397e9dc | 189 | void MenuType::EncoderHandler( bool Increment, VariableType ChangeType) |
dswood | 0:c673d397e9dc | 190 | { |
dswood | 0:c673d397e9dc | 191 | int Multiplier=1,t; |
dswood | 0:c673d397e9dc | 192 | t=ElapsedTime.read_ms()-KnobTime; |
dswood | 0:c673d397e9dc | 193 | if (t<50) Multiplier=10; |
dswood | 0:c673d397e9dc | 194 | else if (t<100) Multiplier=5; |
dswood | 0:c673d397e9dc | 195 | else if (t<150) Multiplier=2; |
dswood | 0:c673d397e9dc | 196 | KnobTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 197 | switch (ChangeType) { |
dswood | 0:c673d397e9dc | 198 | case Index: |
dswood | 0:c673d397e9dc | 199 | if (Increment) IndexVal++; |
dswood | 0:c673d397e9dc | 200 | else IndexVal--; |
dswood | 0:c673d397e9dc | 201 | if (IndexVal>MaxIndex) IndexVal=0; |
dswood | 0:c673d397e9dc | 202 | if (IndexVal<0) IndexVal=MaxIndex; |
dswood | 0:c673d397e9dc | 203 | if ((IndexVal-Offset)>2) Offset=IndexVal-2; |
dswood | 0:c673d397e9dc | 204 | if ((IndexVal-Offset)<0) Offset=IndexVal; |
dswood | 0:c673d397e9dc | 205 | break; |
dswood | 0:c673d397e9dc | 206 | case TempC: |
dswood | 0:c673d397e9dc | 207 | if (Increment) Cntrl->Temperature=Cntrl->Temperature+(float)0.1*(float)Multiplier; |
dswood | 0:c673d397e9dc | 208 | else Cntrl->Temperature=Cntrl->Temperature-(float)0.1*(float)Multiplier; |
dswood | 0:c673d397e9dc | 209 | if (Cntrl->Temperature>120)Cntrl->Temperature=120; |
dswood | 0:c673d397e9dc | 210 | if (Cntrl->Temperature<25)Cntrl->Temperature=25; |
dswood | 0:c673d397e9dc | 211 | break; |
dswood | 0:c673d397e9dc | 212 | case PwrW: |
dswood | 0:c673d397e9dc | 213 | if (Increment) Cntrl->PercentPower+=Multiplier; |
dswood | 0:c673d397e9dc | 214 | else Cntrl->PercentPower-=Multiplier; |
dswood | 0:c673d397e9dc | 215 | if (Cntrl->PercentPower>100)Cntrl->PercentPower=100; |
dswood | 0:c673d397e9dc | 216 | if (Cntrl->PercentPower<=0)Cntrl->PercentPower=1; |
dswood | 0:c673d397e9dc | 217 | break; |
dswood | 0:c673d397e9dc | 218 | case TimeS: |
dswood | 0:c673d397e9dc | 219 | Multiplier=Multiplier*Multiplier; |
dswood | 0:c673d397e9dc | 220 | if (Increment) Cntrl->TimeSeconds+=Multiplier; |
dswood | 0:c673d397e9dc | 221 | else Cntrl->TimeSeconds-=Multiplier; |
dswood | 0:c673d397e9dc | 222 | if (Cntrl->TimeSeconds>10800)Cntrl->TimeSeconds=10800; |
dswood | 0:c673d397e9dc | 223 | if (Cntrl->TimeSeconds<0)Cntrl->TimeSeconds=0; |
dswood | 0:c673d397e9dc | 224 | break; |
dswood | 0:c673d397e9dc | 225 | } |
dswood | 0:c673d397e9dc | 226 | } |
dswood | 0:c673d397e9dc | 227 | |
dswood | 0:c673d397e9dc | 228 | struct MenuType MainMenu; |
dswood | 0:c673d397e9dc | 229 | void SetTopLevelMenu(); |
dswood | 0:c673d397e9dc | 230 | void SetProgrammedMenu(); |
dswood | 0:c673d397e9dc | 231 | void SetManualMenu(); |
dswood | 0:c673d397e9dc | 232 | void ShowProgramMenu(); |
dswood | 0:c673d397e9dc | 233 | void StartProfileMenu(); |
dswood | 0:c673d397e9dc | 234 | void DoNothing(); |
dswood | 0:c673d397e9dc | 235 | void AlterDataMenu(); |
dswood | 0:c673d397e9dc | 236 | void LoadProfile(int Prof,int Ele); |
dswood | 0:c673d397e9dc | 237 | void SetProfile(); |
dswood | 0:c673d397e9dc | 238 | void ProfileMenu(); |
dswood | 0:c673d397e9dc | 239 | void GetTemperature(); |
dswood | 0:c673d397e9dc | 240 | void DisplayNow(); |
dswood | 0:c673d397e9dc | 241 | void DisplayMenu(); |
dswood | 0:c673d397e9dc | 242 | void SetOutputSpeed(); |
dswood | 0:c673d397e9dc | 243 | void PulseTriac() |
dswood | 0:c673d397e9dc | 244 | { |
dswood | 0:c673d397e9dc | 245 | if (Triac==1) { |
dswood | 0:c673d397e9dc | 246 | Triac=0; |
dswood | 0:c673d397e9dc | 247 | Test=0; //fixme |
dswood | 0:c673d397e9dc | 248 | } else { |
dswood | 0:c673d397e9dc | 249 | Triac=1;// Fire the triac |
dswood | 0:c673d397e9dc | 250 | Test=1; |
dswood | 0:c673d397e9dc | 251 | TriacPulseTimeout.attach_us(&PulseTriac,TriacPulseLength); |
dswood | 0:c673d397e9dc | 252 | } |
dswood | 0:c673d397e9dc | 253 | } |
dswood | 0:c673d397e9dc | 254 | void MenuSetup() |
dswood | 0:c673d397e9dc | 255 | { |
dswood | 0:c673d397e9dc | 256 | MainMenu.Offset=0; |
dswood | 0:c673d397e9dc | 257 | MainMenu.IndexVal=0; |
dswood | 0:c673d397e9dc | 258 | MainMenu.Cntrl=&MyControls; |
dswood | 0:c673d397e9dc | 259 | SetTopLevelMenu(); |
dswood | 0:c673d397e9dc | 260 | } |
dswood | 0:c673d397e9dc | 261 | void SyncFall() |
dswood | 0:c673d397e9dc | 262 | { |
dswood | 0:c673d397e9dc | 263 | int64_t t; |
dswood | 0:c673d397e9dc | 264 | /* After many attempts to get this right t should be a uint64_t BUT |
dswood | 0:c673d397e9dc | 265 | whan you do a comparison if(uint64_t> 99) it all goes to crap. |
dswood | 0:c673d397e9dc | 266 | I think you end up with an overflow in the math used to evaluate it. |
dswood | 0:c673d397e9dc | 267 | So only do comparicons with signed numbers int or float. |
dswood | 0:c673d397e9dc | 268 | */ |
dswood | 0:c673d397e9dc | 269 | if (!Rise) return; |
dswood | 0:c673d397e9dc | 270 | Rise=false; |
dswood | 0:c673d397e9dc | 271 | t=ElapsedTime.read_us()-CycleTime; |
dswood | 0:c673d397e9dc | 272 | DebugValue=t; |
dswood | 0:c673d397e9dc | 273 | CycleTime=ElapsedTime.read_us(); |
dswood | 0:c673d397e9dc | 274 | if (DisplayFlag) return; |
dswood | 0:c673d397e9dc | 275 | if ((t>20400)||(t<19600)) { |
dswood | 0:c673d397e9dc | 276 | CycleCount=0; |
dswood | 0:c673d397e9dc | 277 | MainsOn=false; |
dswood | 0:c673d397e9dc | 278 | } |
dswood | 0:c673d397e9dc | 279 | if (CycleCount<10) { |
dswood | 0:c673d397e9dc | 280 | CycleCount++; |
dswood | 0:c673d397e9dc | 281 | return; |
dswood | 0:c673d397e9dc | 282 | } |
dswood | 0:c673d397e9dc | 283 | MainsOn=true; |
dswood | 0:c673d397e9dc | 284 | if (FireTriac) SyncDelay.attach_us(&PulseTriac,SyncToZeroCrossingDelayFall); |
dswood | 0:c673d397e9dc | 285 | FiringCounter(Demand); |
dswood | 0:c673d397e9dc | 286 | ReadTemperature.attach_us(&GetTemperature,9000); //read temp if mains on synced |
dswood | 0:c673d397e9dc | 287 | // the noise generated on triac firing upsets the temperature measurment |
dswood | 0:c673d397e9dc | 288 | } |
dswood | 0:c673d397e9dc | 289 | void SyncRise() |
dswood | 0:c673d397e9dc | 290 | { |
dswood | 0:c673d397e9dc | 291 | int64_t t; |
dswood | 0:c673d397e9dc | 292 | Test=1; |
dswood | 0:c673d397e9dc | 293 | if (Rise) return; |
dswood | 0:c673d397e9dc | 294 | Rise=true; |
dswood | 0:c673d397e9dc | 295 | t=ElapsedTime.read_us()-CycleTime; |
dswood | 0:c673d397e9dc | 296 | if (DisplayFlag) return; |
dswood | 0:c673d397e9dc | 297 | if ((t>10200)||(t<9800)) { |
dswood | 0:c673d397e9dc | 298 | CycleCount=0; |
dswood | 0:c673d397e9dc | 299 | MainsOn=false; |
dswood | 0:c673d397e9dc | 300 | } |
dswood | 0:c673d397e9dc | 301 | if (CycleCount<10) { |
dswood | 0:c673d397e9dc | 302 | return; |
dswood | 0:c673d397e9dc | 303 | } |
dswood | 0:c673d397e9dc | 304 | Test=0; |
dswood | 0:c673d397e9dc | 305 | if (FireTriac) SyncDelay.attach_us(&PulseTriac,SyncToZeroCrossingDelayRise); |
dswood | 0:c673d397e9dc | 306 | } |
dswood | 0:c673d397e9dc | 307 | |
dswood | 0:c673d397e9dc | 308 | float ReadResistance() // Read voltage across thermistor |
dswood | 0:c673d397e9dc | 309 | { |
dswood | 0:c673d397e9dc | 310 | |
dswood | 0:c673d397e9dc | 311 | int i,j; |
dswood | 0:c673d397e9dc | 312 | float tmp=0; |
dswood | 0:c673d397e9dc | 313 | j=StartT; |
dswood | 0:c673d397e9dc | 314 | TempBuf[StartT]=Thermistor; |
dswood | 0:c673d397e9dc | 315 | for (i=0; i<NumberOfTaps; i++) { |
dswood | 0:c673d397e9dc | 316 | if (j<0) j+=NumberOfTaps; |
dswood | 0:c673d397e9dc | 317 | tmp+=TempBuf[j]*filter_taps[i]; |
dswood | 0:c673d397e9dc | 318 | j--; |
dswood | 0:c673d397e9dc | 319 | if (j<0) j=NumberOfTaps-1; |
dswood | 0:c673d397e9dc | 320 | } |
dswood | 0:c673d397e9dc | 321 | StartT--; |
dswood | 0:c673d397e9dc | 322 | if (StartT<0) StartT=NumberOfTaps-1; |
dswood | 0:c673d397e9dc | 323 | /* tmp is the fraction 3.3V across thermistor. |
dswood | 0:c673d397e9dc | 324 | Resistance = V/I |
dswood | 0:c673d397e9dc | 325 | Resistance = (tmp*3.3V)/Bias_Current */ |
dswood | 0:c673d397e9dc | 326 | tmp=(tmp*(float)3.3)/(float)Bias_Current; // Answer is in Kohm because current is in mA |
dswood | 0:c673d397e9dc | 327 | return tmp; |
dswood | 0:c673d397e9dc | 328 | } |
dswood | 0:c673d397e9dc | 329 | float ResistanceToTemp(float Res) |
dswood | 0:c673d397e9dc | 330 | { |
dswood | 0:c673d397e9dc | 331 | /* T0 = 25C = 298K |
dswood | 0:c673d397e9dc | 332 | beta =3977 |
dswood | 0:c673d397e9dc | 333 | R0=10000 ohm */ |
dswood | 0:c673d397e9dc | 334 | Res=Res+(float)0.0001; //Res can't be zero |
dswood | 0:c673d397e9dc | 335 | float temp; // temp here is both temperary and temperature |
dswood | 0:c673d397e9dc | 336 | temp=log(Res/(float)10)/(float)3977.0; //beta from datasheet |
dswood | 0:c673d397e9dc | 337 | temp=(float)1/(temp+(float)0.003354); // 1/298.15 |
dswood | 0:c673d397e9dc | 338 | //temp=temp-(float)273.15 ;//kelvin to c conversion |
dswood | 0:c673d397e9dc | 339 | /* ok so the temp is miles off due to things like the sensor being pressed |
dswood | 0:c673d397e9dc | 340 | against the outside of the barrel. Loosing heat to ambient etc. |
dswood | 0:c673d397e9dc | 341 | So lets compensate for that with an offset and a scale factor. */ |
dswood | 0:c673d397e9dc | 342 | temp=(temp*(float)1.09)-(float)22; |
dswood | 0:c673d397e9dc | 343 | temp=temp-(float)273.15 ;//kelvin to c conversion |
dswood | 0:c673d397e9dc | 344 | return temp; |
dswood | 0:c673d397e9dc | 345 | } |
dswood | 0:c673d397e9dc | 346 | void GetTemperature() |
dswood | 0:c673d397e9dc | 347 | { |
dswood | 0:c673d397e9dc | 348 | if (DisplayFlag) return; // The noise generated by the comms to the display causes 0.5C error |
dswood | 0:c673d397e9dc | 349 | valT=ResistanceToTemp(ReadResistance()); |
dswood | 0:c673d397e9dc | 350 | } |
dswood | 0:c673d397e9dc | 351 | void Pressed() |
dswood | 0:c673d397e9dc | 352 | { |
dswood | 0:c673d397e9dc | 353 | int t; |
dswood | 0:c673d397e9dc | 354 | t=ElapsedTime.read_ms()-DebounceTime; |
dswood | 0:c673d397e9dc | 355 | DebounceTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 356 | if (t<250) return; |
dswood | 0:c673d397e9dc | 357 | //Mypc.printf("Index %d \n",MainMenu.IndexVal); |
dswood | 0:c673d397e9dc | 358 | MainMenu.Number=MainMenu.IndexVal; |
dswood | 0:c673d397e9dc | 359 | MainMenu.NextMenu[MainMenu.IndexVal](); |
dswood | 0:c673d397e9dc | 360 | } |
dswood | 0:c673d397e9dc | 361 | void setup() |
dswood | 0:c673d397e9dc | 362 | { |
dswood | 0:c673d397e9dc | 363 | set_time(1256729737); // Set RTC time to Wed, 28 Oct 2009 11:35:37 |
dswood | 0:c673d397e9dc | 364 | now=time(NULL); |
dswood | 0:c673d397e9dc | 365 | // Mypc.printf("Setup"); |
dswood | 0:c673d397e9dc | 366 | Triac=0; // Low to fire |
dswood | 0:c673d397e9dc | 367 | FallingEdge.fall(&SyncFall); //falling mains voltage |
dswood | 0:c673d397e9dc | 368 | RisingEdge.fall(&SyncRise); //rising mains voltage |
dswood | 0:c673d397e9dc | 369 | FireCount=0; |
dswood | 0:c673d397e9dc | 370 | ButtonPressed.fall(&Pressed); |
dswood | 0:c673d397e9dc | 371 | //SetOutputSpeed(); |
dswood | 0:c673d397e9dc | 372 | MyOled.BusEnable(true);//Chip select |
dswood | 0:c673d397e9dc | 373 | MyOled.FastWindow(true); |
dswood | 0:c673d397e9dc | 374 | MyOled.set_orientation(3); |
dswood | 0:c673d397e9dc | 375 | MyOled.locate(0,0); |
dswood | 0:c673d397e9dc | 376 | MyOled.set_font((unsigned char*) Terminal6x8,32,127,false); |
dswood | 0:c673d397e9dc | 377 | MyOled.cls(); |
dswood | 0:c673d397e9dc | 378 | MyOled.BusEnable(false);//Chip select |
dswood | 0:c673d397e9dc | 379 | ButtonPressed.fall(&Pressed); |
dswood | 0:c673d397e9dc | 380 | ElapsedTime.start(); |
dswood | 0:c673d397e9dc | 381 | LastTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 382 | DebounceTime=LastTime; |
dswood | 0:c673d397e9dc | 383 | CycleTime=ElapsedTime.read_us(); |
dswood | 0:c673d397e9dc | 384 | TempTime=LastTime; |
dswood | 0:c673d397e9dc | 385 | CheckTime=LastTime; |
dswood | 0:c673d397e9dc | 386 | DemandTime=LastTime; |
dswood | 0:c673d397e9dc | 387 | KnobTime=LastTime; |
dswood | 0:c673d397e9dc | 388 | MenuSetup(); |
dswood | 0:c673d397e9dc | 389 | } |
dswood | 0:c673d397e9dc | 390 | void SetOutputSpeed() |
dswood | 0:c673d397e9dc | 391 | { |
dswood | 0:c673d397e9dc | 392 | GPIO_InitTypeDef GPIO_InitStruct; |
dswood | 0:c673d397e9dc | 393 | //Configure GPIO pin : PB_3 D3 |
dswood | 0:c673d397e9dc | 394 | GPIO_InitStruct.Pin = GPIO_PIN_3; |
dswood | 0:c673d397e9dc | 395 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // digital Output |
dswood | 0:c673d397e9dc | 396 | GPIO_InitStruct.Speed = GPIO_SPEED_LOW; |
dswood | 0:c673d397e9dc | 397 | HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); |
dswood | 0:c673d397e9dc | 398 | } |
dswood | 0:c673d397e9dc | 399 | |
dswood | 0:c673d397e9dc | 400 | void FiringCounter(int Power) |
dswood | 0:c673d397e9dc | 401 | { |
dswood | 0:c673d397e9dc | 402 | int x; |
dswood | 0:c673d397e9dc | 403 | x=Power; |
dswood | 0:c673d397e9dc | 404 | if (x>100) x=100; |
dswood | 0:c673d397e9dc | 405 | if (x<0) x=0; |
dswood | 0:c673d397e9dc | 406 | if (FireCount<0) { |
dswood | 0:c673d397e9dc | 407 | FireCount+=100-x; |
dswood | 0:c673d397e9dc | 408 | FireTriac=true; |
dswood | 0:c673d397e9dc | 409 | } else { |
dswood | 0:c673d397e9dc | 410 | FireCount-=x; |
dswood | 0:c673d397e9dc | 411 | FireTriac=false; |
dswood | 0:c673d397e9dc | 412 | } |
dswood | 0:c673d397e9dc | 413 | |
dswood | 0:c673d397e9dc | 414 | } |
dswood | 0:c673d397e9dc | 415 | void SetTopLevelMenu() |
dswood | 0:c673d397e9dc | 416 | { |
dswood | 0:c673d397e9dc | 417 | |
dswood | 0:c673d397e9dc | 418 | MainMenu.IndexVal=0; |
dswood | 0:c673d397e9dc | 419 | MainMenu.MaxIndex=2; |
dswood | 0:c673d397e9dc | 420 | MainMenu.Offset=0; |
dswood | 0:c673d397e9dc | 421 | MainMenu.MenuText[0]=TopLevelMenu[0]; |
dswood | 0:c673d397e9dc | 422 | MainMenu.MenuText[1]=TopLevelMenu[1]; |
dswood | 0:c673d397e9dc | 423 | MainMenu.MenuText[2]=TopLevelMenu[2]; |
dswood | 0:c673d397e9dc | 424 | MainMenu.CurrentType=Index; |
dswood | 0:c673d397e9dc | 425 | MainMenu.NextMenu[0]=&SetTopLevelMenu; |
dswood | 0:c673d397e9dc | 426 | MainMenu.NextMenu[1]=&SetManualMenu; |
dswood | 0:c673d397e9dc | 427 | MainMenu.NextMenu[2]=&SetProgrammedMenu; |
dswood | 0:c673d397e9dc | 428 | MainMenu.NextMenu[3]=&SetTopLevelMenu;//Set it to something that is valid |
dswood | 0:c673d397e9dc | 429 | MainMenu.NextMenu[4]=&SetTopLevelMenu; |
dswood | 0:c673d397e9dc | 430 | MainMenu.NextMenu[5]=&SetTopLevelMenu; |
dswood | 0:c673d397e9dc | 431 | MyControls.Temperature= 25.0; |
dswood | 0:c673d397e9dc | 432 | MyControls.PercentPower=1; |
dswood | 0:c673d397e9dc | 433 | MyControls.TimeSeconds=0; |
dswood | 0:c673d397e9dc | 434 | MainMenu.Switch=true; |
dswood | 0:c673d397e9dc | 435 | } |
dswood | 0:c673d397e9dc | 436 | void SetProgrammedMenu() |
dswood | 0:c673d397e9dc | 437 | { |
dswood | 0:c673d397e9dc | 438 | MainMenu.Offset=0; |
dswood | 0:c673d397e9dc | 439 | MainMenu.IndexVal=0; |
dswood | 0:c673d397e9dc | 440 | MainMenu.MaxIndex=5;//12345678901234567890 |
dswood | 0:c673d397e9dc | 441 | MainMenu.MenuText[0]="Previous Menu "; |
dswood | 0:c673d397e9dc | 442 | MainMenu.MenuText[1]=MashProfile.Name; |
dswood | 0:c673d397e9dc | 443 | MainMenu.MenuText[2]=MashProfileFull.Name; |
dswood | 0:c673d397e9dc | 444 | MainMenu.MenuText[3]=Boil1.Name; |
dswood | 0:c673d397e9dc | 445 | MainMenu.MenuText[4]=Boil2.Name; |
dswood | 0:c673d397e9dc | 446 | MainMenu.MenuText[5]=Boil3.Name; |
dswood | 0:c673d397e9dc | 447 | |
dswood | 0:c673d397e9dc | 448 | MainMenu.NextMenu[0]=&SetTopLevelMenu; |
dswood | 0:c673d397e9dc | 449 | MainMenu.NextMenu[1]=&SetProfile; |
dswood | 0:c673d397e9dc | 450 | MainMenu.NextMenu[2]=&SetProfile; |
dswood | 0:c673d397e9dc | 451 | MainMenu.NextMenu[3]=&SetProfile; |
dswood | 0:c673d397e9dc | 452 | MainMenu.NextMenu[4]=&SetProfile; |
dswood | 0:c673d397e9dc | 453 | MainMenu.NextMenu[5]=&SetProfile; |
dswood | 0:c673d397e9dc | 454 | |
dswood | 0:c673d397e9dc | 455 | MainMenu.CurrentType=Index; |
dswood | 0:c673d397e9dc | 456 | MainMenu.Switch=true; |
dswood | 0:c673d397e9dc | 457 | } |
dswood | 0:c673d397e9dc | 458 | void SetManualMenu() |
dswood | 0:c673d397e9dc | 459 | { |
dswood | 0:c673d397e9dc | 460 | MainMenu.IndexVal=0; |
dswood | 0:c673d397e9dc | 461 | MainMenu.MaxIndex=3; |
dswood | 0:c673d397e9dc | 462 | MainMenu.Offset=0; // 1234567890123456789 |
dswood | 0:c673d397e9dc | 463 | MainMenu.MenuText[0]="Manual Menu "; |
dswood | 0:c673d397e9dc | 464 | MainMenu.MenuText[1]="Temperature"; |
dswood | 0:c673d397e9dc | 465 | MainMenu.MenuText[2]="Power Level"; |
dswood | 0:c673d397e9dc | 466 | MainMenu.MenuText[3]="Time "; |
dswood | 0:c673d397e9dc | 467 | MainMenu.NextMenu[0]=&SetTopLevelMenu; |
dswood | 0:c673d397e9dc | 468 | MainMenu.NextMenu[1]=&AlterDataMenu; |
dswood | 0:c673d397e9dc | 469 | MainMenu.NextMenu[2]=&AlterDataMenu; |
dswood | 0:c673d397e9dc | 470 | MainMenu.NextMenu[3]=&AlterDataMenu; |
dswood | 0:c673d397e9dc | 471 | MainMenu.NextMenu[4]=&DoNothing; |
dswood | 0:c673d397e9dc | 472 | MainMenu.Switch=false; |
dswood | 0:c673d397e9dc | 473 | } |
dswood | 0:c673d397e9dc | 474 | void ShowProgramMenu() |
dswood | 0:c673d397e9dc | 475 | { |
dswood | 0:c673d397e9dc | 476 | MainMenu.Offset=0; |
dswood | 0:c673d397e9dc | 477 | MainMenu.IndexVal=0; |
dswood | 0:c673d397e9dc | 478 | MainMenu.MaxIndex=2; |
dswood | 0:c673d397e9dc | 479 | MainMenu.MenuText[0]="Previous Menu "; |
dswood | 0:c673d397e9dc | 480 | MainMenu.MenuText[1]=ProfileArray[MyControls.ProfileNumber]->Name; |
dswood | 0:c673d397e9dc | 481 | MainMenu.MenuText[2]="Start "; |
dswood | 0:c673d397e9dc | 482 | |
dswood | 0:c673d397e9dc | 483 | if (MyControls.Goal==Null) { |
dswood | 0:c673d397e9dc | 484 | MainMenu.MenuText[3]=""; |
dswood | 0:c673d397e9dc | 485 | MainMenu.NextMenu[3]=&SetProgrammedMenu; |
dswood | 0:c673d397e9dc | 486 | } else {//profile loaded |
dswood | 0:c673d397e9dc | 487 | MainMenu.MenuText[3]="Current Profile "; |
dswood | 0:c673d397e9dc | 488 | // 1234567890123456789 |
dswood | 0:c673d397e9dc | 489 | MainMenu.NextMenu[3]=&ProfileMenu; |
dswood | 0:c673d397e9dc | 490 | MainMenu.MaxIndex=3; |
dswood | 0:c673d397e9dc | 491 | } |
dswood | 0:c673d397e9dc | 492 | MainMenu.MenuText[4]=""; |
dswood | 0:c673d397e9dc | 493 | MainMenu.MenuText[5]=""; |
dswood | 0:c673d397e9dc | 494 | MainMenu.NextMenu[0]=&SetProgrammedMenu; |
dswood | 0:c673d397e9dc | 495 | MainMenu.NextMenu[1]=&DoNothing; |
dswood | 0:c673d397e9dc | 496 | MainMenu.NextMenu[2]=&StartProfileMenu; |
dswood | 0:c673d397e9dc | 497 | |
dswood | 0:c673d397e9dc | 498 | MainMenu.NextMenu[4]=&SetProgrammedMenu; |
dswood | 0:c673d397e9dc | 499 | MainMenu.NextMenu[5]=&SetProgrammedMenu; |
dswood | 0:c673d397e9dc | 500 | MainMenu.CurrentType=Index; |
dswood | 0:c673d397e9dc | 501 | MainMenu.Switch=true; |
dswood | 0:c673d397e9dc | 502 | |
dswood | 0:c673d397e9dc | 503 | } |
dswood | 0:c673d397e9dc | 504 | void StartProfileMenu() |
dswood | 0:c673d397e9dc | 505 | { |
dswood | 0:c673d397e9dc | 506 | LoadProfile(MyControls.ProfileNumber,0); //load the first element of the selected profile |
dswood | 0:c673d397e9dc | 507 | ProfileMenu(); |
dswood | 0:c673d397e9dc | 508 | } |
dswood | 0:c673d397e9dc | 509 | void ProfileMenu() |
dswood | 0:c673d397e9dc | 510 | { |
dswood | 0:c673d397e9dc | 511 | MainMenu.IndexVal=0; |
dswood | 0:c673d397e9dc | 512 | MainMenu.MaxIndex=3; |
dswood | 0:c673d397e9dc | 513 | MainMenu.Offset=0; // |
dswood | 0:c673d397e9dc | 514 | MainMenu.MenuText[0]=MyControls.Message; |
dswood | 0:c673d397e9dc | 515 | MainMenu.MenuText[1]="Temperature"; |
dswood | 0:c673d397e9dc | 516 | MainMenu.MenuText[2]="Power Level"; |
dswood | 0:c673d397e9dc | 517 | MainMenu.MenuText[3]="Time "; |
dswood | 0:c673d397e9dc | 518 | MainMenu.NextMenu[0]=&ShowProgramMenu; |
dswood | 0:c673d397e9dc | 519 | MainMenu.NextMenu[1]=&AlterDataMenu; |
dswood | 0:c673d397e9dc | 520 | MainMenu.NextMenu[2]=&AlterDataMenu; |
dswood | 0:c673d397e9dc | 521 | MainMenu.NextMenu[3]=&AlterDataMenu; |
dswood | 0:c673d397e9dc | 522 | MainMenu.NextMenu[4]=&DoNothing; |
dswood | 0:c673d397e9dc | 523 | MainMenu.Switch=false; |
dswood | 0:c673d397e9dc | 524 | } |
dswood | 0:c673d397e9dc | 525 | void AlterDataMenu() |
dswood | 0:c673d397e9dc | 526 | { |
dswood | 0:c673d397e9dc | 527 | if (MainMenu.CurrentType==Index) switch (MainMenu.IndexVal) { |
dswood | 0:c673d397e9dc | 528 | case 1: |
dswood | 0:c673d397e9dc | 529 | MainMenu.CurrentType=TempC; |
dswood | 0:c673d397e9dc | 530 | break; |
dswood | 0:c673d397e9dc | 531 | case 2: |
dswood | 0:c673d397e9dc | 532 | MainMenu.CurrentType=PwrW; |
dswood | 0:c673d397e9dc | 533 | break; |
dswood | 0:c673d397e9dc | 534 | case 3: |
dswood | 0:c673d397e9dc | 535 | MainMenu.CurrentType=TimeS; |
dswood | 0:c673d397e9dc | 536 | break; |
dswood | 0:c673d397e9dc | 537 | default: |
dswood | 0:c673d397e9dc | 538 | MainMenu.CurrentType=Index; |
dswood | 0:c673d397e9dc | 539 | } else MainMenu.CurrentType=Index; |
dswood | 0:c673d397e9dc | 540 | } |
dswood | 0:c673d397e9dc | 541 | void DoNothing() //The purpose of this function is assign a function pointer to it rather than something wrong or a crash |
dswood | 0:c673d397e9dc | 542 | { |
dswood | 0:c673d397e9dc | 543 | } |
dswood | 0:c673d397e9dc | 544 | void SetProfile() |
dswood | 0:c673d397e9dc | 545 | { |
dswood | 0:c673d397e9dc | 546 | int i=MainMenu.Number-1; |
dswood | 0:c673d397e9dc | 547 | if (i<0)i=0; |
dswood | 0:c673d397e9dc | 548 | if (i>4)i=4;//sanitize |
dswood | 0:c673d397e9dc | 549 | MyControls.ProfileNumber=i; |
dswood | 0:c673d397e9dc | 550 | strncpy(MyControls.Message,ProfileArray[i]->Name,20); |
dswood | 0:c673d397e9dc | 551 | MyControls.Goal=Null; |
dswood | 0:c673d397e9dc | 552 | ShowProgramMenu(); |
dswood | 0:c673d397e9dc | 553 | |
dswood | 0:c673d397e9dc | 554 | |
dswood | 0:c673d397e9dc | 555 | } |
dswood | 0:c673d397e9dc | 556 | void LoadProfile(int Prof,int Ele) |
dswood | 0:c673d397e9dc | 557 | { |
dswood | 0:c673d397e9dc | 558 | MyControls.Temperature= ProfileArray[Prof]->Element[Ele].Temp; |
dswood | 0:c673d397e9dc | 559 | MyControls.PercentPower=ProfileArray[Prof]->Element[Ele].Power; |
dswood | 0:c673d397e9dc | 560 | MyControls.TimeSeconds=ProfileArray[Prof]->Element[Ele].Seconds; |
dswood | 0:c673d397e9dc | 561 | MyControls.Goal=ProfileArray[Prof]->Element[Ele].GoalType; |
dswood | 0:c673d397e9dc | 562 | MyControls.ProfileNumber=Prof; |
dswood | 0:c673d397e9dc | 563 | MyControls.ElementNumber=Ele; |
dswood | 0:c673d397e9dc | 564 | MyControls.MessageNo=ProfileArray[Prof]->Element[Ele].MessageNo; |
dswood | 0:c673d397e9dc | 565 | StartTime=ElapsedTime.read(); |
dswood | 0:c673d397e9dc | 566 | /*Mypc.printf("T %.1f P %d Sec %d Prof %d Ele %d\n", |
dswood | 0:c673d397e9dc | 567 | MyControls.Temperature, |
dswood | 0:c673d397e9dc | 568 | MyControls.PercentPower, |
dswood | 0:c673d397e9dc | 569 | MyControls.TimeSeconds, |
dswood | 0:c673d397e9dc | 570 | MyControls.ProfileNumber, |
dswood | 0:c673d397e9dc | 571 | MyControls.ElementNumber); |
dswood | 0:c673d397e9dc | 572 | */ |
dswood | 0:c673d397e9dc | 573 | } |
dswood | 0:c673d397e9dc | 574 | |
dswood | 0:c673d397e9dc | 575 | void DisplayMenu() |
dswood | 0:c673d397e9dc | 576 | { |
dswood | 0:c673d397e9dc | 577 | DisplayFlag=true; //This flag is used to stop generating new interupts |
dswood | 0:c673d397e9dc | 578 | wait_us(SyncToZeroCrossingDelayRise+TriacPulseLength+25); //wait for interupts to finish |
dswood | 0:c673d397e9dc | 579 | MyOled.BusEnable(true);//Chip select |
dswood | 0:c673d397e9dc | 580 | bool Highlight=false; |
dswood | 0:c673d397e9dc | 581 | //We have a 32 pixecl height and 9 pixcel font. 3 lines 10 spacing |
dswood | 0:c673d397e9dc | 582 | if (MainMenu.Switch) { |
dswood | 0:c673d397e9dc | 583 | for (int i=0; i<3 ; i++) { |
dswood | 0:c673d397e9dc | 584 | MyOled.locate(6,(i*10)+1); |
dswood | 0:c673d397e9dc | 585 | if (MainMenu.IndexVal==(i+MainMenu.Offset)) { |
dswood | 0:c673d397e9dc | 586 | MyOled.background(White); |
dswood | 0:c673d397e9dc | 587 | MyOled.foreground(Black); |
dswood | 0:c673d397e9dc | 588 | } else { |
dswood | 0:c673d397e9dc | 589 | MyOled.background(Black); |
dswood | 0:c673d397e9dc | 590 | MyOled.foreground(White); |
dswood | 0:c673d397e9dc | 591 | } |
dswood | 0:c673d397e9dc | 592 | MyOled.printf(MainMenu.MenuText[i+MainMenu.Offset]); |
dswood | 0:c673d397e9dc | 593 | MyOled.background(Black); |
dswood | 0:c673d397e9dc | 594 | MyOled.foreground(White); |
dswood | 0:c673d397e9dc | 595 | } |
dswood | 0:c673d397e9dc | 596 | } else { |
dswood | 0:c673d397e9dc | 597 | time_t t; |
dswood | 0:c673d397e9dc | 598 | if (MainMenu.CurrentType==TempC)sprintf(Buff[0]," %6.1f ",MyControls.Temperature); |
dswood | 0:c673d397e9dc | 599 | else sprintf(Buff[0]," %6.1f ",valT); |
dswood | 0:c673d397e9dc | 600 | if (MainMenu.CurrentType==PwrW)sprintf(Buff[1]," %5d%c ",MyControls.PercentPower,38); |
dswood | 0:c673d397e9dc | 601 | else sprintf(Buff[1]," %5d%c ",Demand,38); |
dswood | 0:c673d397e9dc | 602 | if (MainMenu.CurrentType==TimeS) { |
dswood | 0:c673d397e9dc | 603 | t=MyControls.TimeSeconds; |
dswood | 0:c673d397e9dc | 604 | strftime(Buff[2],10,"%T ",localtime(&t)); |
dswood | 0:c673d397e9dc | 605 | } else { |
dswood | 0:c673d397e9dc | 606 | t=(int)ElapsedTime.read()-StartTime; |
dswood | 0:c673d397e9dc | 607 | strftime(Buff[2],10,"%T ",localtime(&t)); |
dswood | 0:c673d397e9dc | 608 | } |
dswood | 0:c673d397e9dc | 609 | for (int i=0; i<3 ; i++) { |
dswood | 0:c673d397e9dc | 610 | MyOled.locate(6,(i*10)+1); |
dswood | 0:c673d397e9dc | 611 | if (MainMenu.IndexVal==(i+MainMenu.Offset)) { |
dswood | 0:c673d397e9dc | 612 | Highlight=true; |
dswood | 0:c673d397e9dc | 613 | } else { |
dswood | 0:c673d397e9dc | 614 | Highlight=false; |
dswood | 0:c673d397e9dc | 615 | } |
dswood | 0:c673d397e9dc | 616 | if (Highlight&&MainMenu.CurrentType==Index) { |
dswood | 0:c673d397e9dc | 617 | MyOled.background(White); |
dswood | 0:c673d397e9dc | 618 | MyOled.foreground(Black); |
dswood | 0:c673d397e9dc | 619 | MyOled.printf(MainMenu.MenuText[i+MainMenu.Offset]); |
dswood | 0:c673d397e9dc | 620 | } else { |
dswood | 0:c673d397e9dc | 621 | MyOled.background(Black); |
dswood | 0:c673d397e9dc | 622 | MyOled.foreground(White); |
dswood | 0:c673d397e9dc | 623 | MyOled.printf(MainMenu.MenuText[i+MainMenu.Offset]); |
dswood | 0:c673d397e9dc | 624 | } |
dswood | 0:c673d397e9dc | 625 | if (Highlight&&MainMenu.CurrentType!=Index) { |
dswood | 0:c673d397e9dc | 626 | MyOled.background(White); |
dswood | 0:c673d397e9dc | 627 | MyOled.foreground(Black); |
dswood | 0:c673d397e9dc | 628 | if ((i+MainMenu.Offset>=1)&&(i+MainMenu.Offset<=3))MyOled.printf(Buff[i+MainMenu.Offset-1]); |
dswood | 0:c673d397e9dc | 629 | } else { |
dswood | 0:c673d397e9dc | 630 | MyOled.background(Black); |
dswood | 0:c673d397e9dc | 631 | MyOled.foreground(White); |
dswood | 0:c673d397e9dc | 632 | if ((i+MainMenu.Offset>=1)&&(i+MainMenu.Offset<=3))MyOled.printf(Buff[i+MainMenu.Offset-1]); |
dswood | 0:c673d397e9dc | 633 | } |
dswood | 0:c673d397e9dc | 634 | } |
dswood | 0:c673d397e9dc | 635 | } |
dswood | 0:c673d397e9dc | 636 | MyOled.BusEnable(false);//Chip select |
dswood | 0:c673d397e9dc | 637 | DisplayFlag=false; |
dswood | 0:c673d397e9dc | 638 | } |
dswood | 0:c673d397e9dc | 639 | int CalcDemand() //return percent power |
dswood | 0:c673d397e9dc | 640 | { |
dswood | 0:c673d397e9dc | 641 | float ErrorSignal, Differential; |
dswood | 0:c673d397e9dc | 642 | int power; |
dswood | 0:c673d397e9dc | 643 | ErrorSignal=MyControls.Temperature-valT; |
dswood | 0:c673d397e9dc | 644 | if (abs(ErrorSignal)<1)Integrated+=ErrorSignal; |
dswood | 0:c673d397e9dc | 645 | else Integrated=0; |
dswood | 0:c673d397e9dc | 646 | if (Integrated>20)Integrated=(float)20; |
dswood | 0:c673d397e9dc | 647 | if (Integrated<-1)Integrated=(float)-1; |
dswood | 0:c673d397e9dc | 648 | Differential=ErrorSignal-LastError; |
dswood | 0:c673d397e9dc | 649 | LastError=ErrorSignal; |
dswood | 0:c673d397e9dc | 650 | power=(int)(((float)70*ErrorSignal)+((float)0.6*Integrated)+(45*Differential)); |
dswood | 0:c673d397e9dc | 651 | // Mypc.printf("Error %.2f Int %.2f Dif %.2f\n\r", ErrorSignal,Integrated,Differential); |
dswood | 0:c673d397e9dc | 652 | MainsOn ? Mypc.printf("Mains On\n\r") : Mypc.printf("Mains Off\n\r"); |
dswood | 0:c673d397e9dc | 653 | Mypc.printf("DebugValue %d\n\r",DebugValue); |
dswood | 0:c673d397e9dc | 654 | Mypc.printf("Elapsed time %d\n\r",ElapsedTime.read_us()); |
dswood | 0:c673d397e9dc | 655 | |
dswood | 0:c673d397e9dc | 656 | if (power<0)power=0; |
dswood | 0:c673d397e9dc | 657 | if (power>MyControls.PercentPower)power=MyControls.PercentPower; |
dswood | 0:c673d397e9dc | 658 | return power; |
dswood | 0:c673d397e9dc | 659 | } |
dswood | 0:c673d397e9dc | 660 | void DisplayMessage() |
dswood | 0:c673d397e9dc | 661 | { |
dswood | 0:c673d397e9dc | 662 | int x,y,z; |
dswood | 0:c673d397e9dc | 663 | z=MyControls.MessageNo; //convert to int before compare |
dswood | 0:c673d397e9dc | 664 | if (z>7)MyControls.MessageNo=0; |
dswood | 0:c673d397e9dc | 665 | if (z==0) { |
dswood | 0:c673d397e9dc | 666 | strncpy(MyControls.Message,ProfileArray[MyControls.ProfileNumber]->Name,20); |
dswood | 0:c673d397e9dc | 667 | } else { |
dswood | 0:c673d397e9dc | 668 | y=string_length(Message[MyControls.MessageNo]) ; |
dswood | 0:c673d397e9dc | 669 | for (x=0; x<18; x++) { |
dswood | 0:c673d397e9dc | 670 | if (x<y)MainMenu.MenuText[0][x]=Message[MyControls.MessageNo][x]; |
dswood | 0:c673d397e9dc | 671 | else MainMenu.MenuText[0][x]=' '; |
dswood | 0:c673d397e9dc | 672 | } |
dswood | 0:c673d397e9dc | 673 | MainMenu.MenuText[0][19]='\0'; |
dswood | 0:c673d397e9dc | 674 | } |
dswood | 0:c673d397e9dc | 675 | } |
dswood | 0:c673d397e9dc | 676 | int main() |
dswood | 0:c673d397e9dc | 677 | { |
dswood | 0:c673d397e9dc | 678 | Mypc.printf("Starting Main\n\r"); |
dswood | 0:c673d397e9dc | 679 | setup(); |
dswood | 0:c673d397e9dc | 680 | int Position=wheel.getPulses(); |
dswood | 0:c673d397e9dc | 681 | int UpdateTime=750; |
dswood | 0:c673d397e9dc | 682 | uint64_t TempTime=0; |
dswood | 0:c673d397e9dc | 683 | int64_t t;// time is uint64_t but int64_t used for comparison in if statement |
dswood | 0:c673d397e9dc | 684 | while (true) { //main loop |
dswood | 0:c673d397e9dc | 685 | if (Position!=wheel.getPulses()) { |
dswood | 0:c673d397e9dc | 686 | MainMenu.EncoderHandler( Position<wheel.getPulses(), MainMenu.CurrentType); |
dswood | 0:c673d397e9dc | 687 | Position=wheel.getPulses(); |
dswood | 0:c673d397e9dc | 688 | UpdateTime=250; //Quick display refresh when knob moved |
dswood | 0:c673d397e9dc | 689 | //Mypc.printf("Pos %d \n",Position); |
dswood | 0:c673d397e9dc | 690 | //DisplayMenu(); |
dswood | 0:c673d397e9dc | 691 | } |
dswood | 0:c673d397e9dc | 692 | /*Had a problem where mains detection was dropping out here. |
dswood | 0:c673d397e9dc | 693 | The sum ElapsedTime.read_ms()-CycleTime was sometimes =0. |
dswood | 0:c673d397e9dc | 694 | But 0>75 is true. eg if ((ElapsedTime.read_ms()-CycleTime)>75) would be true |
dswood | 0:c673d397e9dc | 695 | if the sum result was 0. Doing the sum first was ok. Had the same problem with Debounce. |
dswood | 0:c673d397e9dc | 696 | */ |
dswood | 0:c673d397e9dc | 697 | t=ElapsedTime.read_us()-CycleTime; |
dswood | 0:c673d397e9dc | 698 | if (t>75000) { //mains not proven. Read temp. When mains is on this is done synced to mains |
dswood | 0:c673d397e9dc | 699 | CycleCount=0; |
dswood | 0:c673d397e9dc | 700 | MainsOn=false; |
dswood | 0:c673d397e9dc | 701 | GetTemperature(); |
dswood | 0:c673d397e9dc | 702 | } |
dswood | 0:c673d397e9dc | 703 | t=ElapsedTime.read_ms()-LastTime; |
dswood | 0:c673d397e9dc | 704 | if (t>UpdateTime) { |
dswood | 0:c673d397e9dc | 705 | LastTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 706 | UpdateTime=750; |
dswood | 0:c673d397e9dc | 707 | DisplayMenu(); |
dswood | 0:c673d397e9dc | 708 | } |
dswood | 0:c673d397e9dc | 709 | t=ElapsedTime.read_ms()-TempTime; |
dswood | 0:c673d397e9dc | 710 | if (t>15000) { //upped to 15s which will give a smaller temp rise by averaging over a longer period |
dswood | 0:c673d397e9dc | 711 | if (valT>99.0f) { |
dswood | 0:c673d397e9dc | 712 | if (valT-LastTemp<0.15f)Boiling=true; |
dswood | 0:c673d397e9dc | 713 | else Boiling=false; // still rising |
dswood | 0:c673d397e9dc | 714 | } else Boiling=false; //too cold |
dswood | 0:c673d397e9dc | 715 | LastTemp=valT; |
dswood | 0:c673d397e9dc | 716 | TempTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 717 | } |
dswood | 0:c673d397e9dc | 718 | t=ElapsedTime.read_ms()-DemandTime; |
dswood | 0:c673d397e9dc | 719 | if (t>3000) { |
dswood | 0:c673d397e9dc | 720 | Demand=CalcDemand(); |
dswood | 0:c673d397e9dc | 721 | DemandTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 722 | } |
dswood | 0:c673d397e9dc | 723 | t=ElapsedTime.read_ms()-CheckTime; |
dswood | 0:c673d397e9dc | 724 | if (t>3000) { |
dswood | 0:c673d397e9dc | 725 | CheckTime=ElapsedTime.read_ms(); |
dswood | 0:c673d397e9dc | 726 | switch (MyControls.Goal) { |
dswood | 0:c673d397e9dc | 727 | //enum goal { Null,Boil, Temp, Time}; |
dswood | 0:c673d397e9dc | 728 | case Boil: |
dswood | 0:c673d397e9dc | 729 | if (Boiling ) { |
dswood | 0:c673d397e9dc | 730 | DisplayMessage(); |
dswood | 0:c673d397e9dc | 731 | if (MyControls.ElementNumber<5) { |
dswood | 0:c673d397e9dc | 732 | MyControls.ElementNumber++; |
dswood | 0:c673d397e9dc | 733 | LoadProfile(MyControls.ProfileNumber,MyControls.ElementNumber); |
dswood | 0:c673d397e9dc | 734 | } else { |
dswood | 0:c673d397e9dc | 735 | MyControls.Temperature=25.0; |
dswood | 0:c673d397e9dc | 736 | MyControls.PercentPower=0; |
dswood | 0:c673d397e9dc | 737 | MyControls.TimeSeconds=0; |
dswood | 0:c673d397e9dc | 738 | } |
dswood | 0:c673d397e9dc | 739 | } |
dswood | 0:c673d397e9dc | 740 | break; |
dswood | 0:c673d397e9dc | 741 | case Temp: |
dswood | 0:c673d397e9dc | 742 | if (abs(valT-MyControls.Temperature)<(float)0.25) { |
dswood | 0:c673d397e9dc | 743 | DisplayMessage(); |
dswood | 0:c673d397e9dc | 744 | if (MyControls.ElementNumber<5) { |
dswood | 0:c673d397e9dc | 745 | MyControls.ElementNumber++; |
dswood | 0:c673d397e9dc | 746 | LoadProfile(MyControls.ProfileNumber,MyControls.ElementNumber); |
dswood | 0:c673d397e9dc | 747 | } else { |
dswood | 0:c673d397e9dc | 748 | MyControls.Temperature=25.0; |
dswood | 0:c673d397e9dc | 749 | MyControls.PercentPower=0; |
dswood | 0:c673d397e9dc | 750 | MyControls.TimeSeconds=0; |
dswood | 0:c673d397e9dc | 751 | } |
dswood | 0:c673d397e9dc | 752 | } |
dswood | 0:c673d397e9dc | 753 | break; |
dswood | 0:c673d397e9dc | 754 | case Time: |
dswood | 0:c673d397e9dc | 755 | t=ElapsedTime.read()-StartTime; |
dswood | 0:c673d397e9dc | 756 | if (t>MyControls.TimeSeconds) { |
dswood | 0:c673d397e9dc | 757 | DisplayMessage(); |
dswood | 0:c673d397e9dc | 758 | if(MyControls.ElementNumber<5) { |
dswood | 0:c673d397e9dc | 759 | MyControls.ElementNumber++; |
dswood | 0:c673d397e9dc | 760 | LoadProfile(MyControls.ProfileNumber,MyControls.ElementNumber); |
dswood | 0:c673d397e9dc | 761 | } else { |
dswood | 0:c673d397e9dc | 762 | MyControls.Temperature=25.0; |
dswood | 0:c673d397e9dc | 763 | MyControls.PercentPower=0; |
dswood | 0:c673d397e9dc | 764 | MyControls.TimeSeconds=0; |
dswood | 0:c673d397e9dc | 765 | } |
dswood | 0:c673d397e9dc | 766 | } |
dswood | 0:c673d397e9dc | 767 | break; |
dswood | 0:c673d397e9dc | 768 | } |
dswood | 0:c673d397e9dc | 769 | }//goal test |
dswood | 0:c673d397e9dc | 770 | } |
dswood | 0:c673d397e9dc | 771 | } |