Maintenance: Project Hub will be unavailable on Monday 24 (9AM to 6PM CET) while we deploy critical improvements
Components and supplies
IRF520 MOSFET module
12V 40mm TEC
12V 40mm high power fan
12V 10A power supply
Arduino UNO
3 mm LED: Yellow
BTS7960 motor driver
OPT101 light sensor
SparkFun Humidity and Temperature Sensor Breakout - Si7021
40mm heat sink
Thermally conductive adhesive
Thermal paste
DS18B20 Programmable Resolution 1-Wire Digital Thermometer
small mirror
Tools and machines
Hot glue gun (generic)
Apps and platforms
Arduino IDE
Project description
Code
Chilled Mirror Hygrometer
c_cpp
Arduino code
1#include <math.h> 2#include <avr/wdt.h> //Watchdog crash detection 3 4//These are custom libraries. 5#include "Si7021.h" //humidity sensor with heater 6#include <OneWire.h> //DS18B20 temp sensor 7#include <DallasTemperature.h> //DS18B20 temp sensor 8 9//Timer library: https://github.com/brunocalou/Timer 10#include "timer.h" 11#include "timerManager.h" 12 13//Define the hardware pins on the Arduino board. 14#define coolingPWM 6 15#define heatingPWM 5 16#define coolingEnable 13 17#define heatingEnable 12 18#define tecFan 7 19#define opticalSensor 0 //Analog in 20#define oneWireBus A3 //DS18B20 temp sensor 21 22//The state of the TEC. 23#define COOLING 0 24#define HEATING 1 25#define OFF 2 26 27//Timers 28Timer timerMainLoop; 29Timer timerTecCooling; 30Timer timerSampleNoise; 31 32//Temperature sensor (humidity not used). 33Si7021 si7021; 34 35//DS18B20 temp sensor 36OneWire oneWire(oneWireBus); 37DallasTemperature sensors(&oneWire); 38 39float humidity = 0; 40float ambientTemp = 0; 41float opticalDewpoint = 0; 42 43//Set these to an initial higher value to get the Serial Plotter range correct. 44float mirrorTemp = 30; 45float optical = 30; 46float dewPoint = 15; //initial value must be lower than the mirror temp. 47float relativeHumidity = 30; 48 49int tecState = OFF; 50bool cooling = false; 51 52int intervalTecCooling = 200; //How often the TEC timer is updated in ms. 53float opticalThreshold = 0.5f; //0.5 //The amount of degrees C the optical reading has to drop below the reference in order to flag condensation detection. This must be a bigger number than the signal noise. 54int pwmIncrement = 1; 55int startPwm = 100; 56int maxPwm = 255; 57int intervalMainLoop = 200; 58int tecPwm = 0; 59int noiseSampleIndex = 0; 60int noiseSampleAmount = 10; 61float noiseSampleHighest = 0; 62float noiseSampleLowest = 10000; 63bool noiseSampling = false; 64 65 66 67float calculateHumidity(float TD, float T){ 68 69 //The dew point cannot be higher than the temperature. 70 if(TD > T){ 71 72 TD = T; 73 } 74 75 //August-Roche-Magnus approximation. 76 float rh = 100*(exp((17.625*TD)/(243.04+TD))/exp((17.625*T)/(243.04+T))); 77 78 return rh; 79} 80 81 82//Set the TEC to heating, cooling, or off. 83void SetTEC(int state, int amount){ 84 85 tecState = state; 86 87 //Note that for both heating and cooling, the heating AND cooling pin need to be set to high. Ask the PCB designer why. 88 //Driver used to control the TEC: BTS7960 motor driver board. Note that PWM to drive a TEC is not efficient and it is better to use a variable current source. 89 switch(state) 90 { 91 case COOLING: 92 digitalWrite(heatingEnable, HIGH); 93 analogWrite(heatingPWM, 0); 94 digitalWrite(coolingEnable, HIGH); 95 analogWrite(coolingPWM, amount); 96 break; 97 98 case HEATING: 99 digitalWrite(coolingEnable, HIGH); 100 analogWrite(coolingPWM, 0); 101 digitalWrite(heatingEnable, HIGH); 102 analogWrite(heatingPWM, amount); 103 break; 104 105 case OFF: 106 digitalWrite(coolingEnable, LOW); 107 analogWrite(coolingPWM, 0); 108 digitalWrite(heatingEnable, LOW); 109 analogWrite(heatingPWM, 0); 110 break; 111 112 default: 113 digitalWrite(coolingEnable, LOW); 114 analogWrite(coolingPWM, 0); 115 digitalWrite(heatingEnable, LOW); 116 analogWrite(heatingPWM, 0); 117 } 118} 119 120void setup() { 121 122 //Watchdog crash detection. This is for safety because you don't want the TEC to be stuck in heating mode. 123 wdt_enable(WDTO_2S); //WDTO_500MS //WDTO_1S 124 125 Serial.begin(9600); //9600 //57600 126 127 pinMode(coolingPWM, OUTPUT); 128 pinMode(heatingPWM, OUTPUT); 129 pinMode(coolingEnable, OUTPUT); 130 pinMode(heatingEnable, OUTPUT); 131 pinMode(tecFan, OUTPUT); 132 pinMode(opticalSensor, INPUT); 133 134 //Setup the timers 135 timerMainLoop.setInterval(intervalMainLoop); 136 timerMainLoop.setCallback(mainLoop); 137 timerMainLoop.start(); 138 139 timerTecCooling.setInterval(intervalTecCooling); 140 timerTecCooling.setCallback(tecCoolingCallback); 141 142 timerSampleNoise.setInterval(intervalTecCooling); 143 timerSampleNoise.setCallback(sampleNoiseCallback); 144 145 //si7021 temp sensor setup. 146 uint64_t serialNumber = 0ULL; 147 si7021.begin(); 148 serialNumber = si7021.getSerialNumber(); 149 150 //DS18B20 onewire temperature sensor 151 sensors.begin(); 152 153 //Disable the temp sensor debug logging in order to get the graph to work correctly. 154 /* 155 Serial.print("Si7021 serial number: "); 156 Serial.print((uint32_t)(serialNumber >> 32), HEX); 157 Serial.println((uint32_t)(serialNumber), HEX); 158 //Firware version 159 Serial.print("Si7021 firmware version: "); 160 Serial.println(si7021.getFirmwareVersion(), HEX); 161 */ 162 163 startNoiseSampling(); 164 165} 166 167//Get the optical sensor reading. 168float getOptical(){ 169 170 int opt = analogRead(opticalSensor); 171 float optFactored = (float)opt / 30.0f; 172 173 return optFactored; 174} 175 176//Timer callback. 177void tecCoolingCallback(){ 178 179 digitalWrite(tecFan, HIGH); 180 181 //Slowly increase the power of the TEC. 182 tecPwm += pwmIncrement; 183 184 //Clamp 185 if(tecPwm > maxPwm){ 186 187 tecPwm = maxPwm; 188 } 189 190 //Set the TEC cooling amount 191 SetTEC(COOLING, tecPwm); 192 193 //Is condensation detected? 194 if(optical <= (noiseSampleLowest - opticalThreshold)){ 195 196 //Log the dew point; 197 dewPoint = mirrorTemp; 198 opticalDewpoint = optical; 199 200 stopTec(); 201 } 202} 203 204void startNoiseSampling(){ 205 206 noiseSampling = true; 207 noiseSampleHighest = 0; 208 noiseSampleLowest = 10000; 209 timerSampleNoise.start(); 210} 211 212void sampleNoiseReset(){ 213 214 timerSampleNoise.stop(); 215 noiseSampleIndex = 0; 216 noiseSampling = false; 217} 218 219void sampleNoiseCallback(){ 220 221 222 if(noiseSampleIndex > noiseSampleAmount){ 223 224 sampleNoiseReset(); 225 startTecCooling(); 226 } 227 228 else{ 229 230 if(optical > noiseSampleHighest){ 231 232 noiseSampleHighest = optical; 233 } 234 235 if(optical < noiseSampleLowest){ 236 237 noiseSampleLowest = optical; 238 } 239 } 240 241 noiseSampleIndex++; 242} 243 244 245void startTecCooling(){ 246 247 cooling = true; 248 249 digitalWrite(tecFan, HIGH); 250 251 tecPwm = startPwm; 252 253 //Start the TEC counter callback. 254 timerTecCooling.start(); 255} 256 257void stopTec(){ 258 259 cooling = false; 260 261 //Turn the TEC fan off. 262 digitalWrite(tecFan, LOW); 263 264 timerTecCooling.stop(); 265 266 //No cooling, no heating 267 SetTEC(OFF, 0); 268} 269 270 271//Non blocking timer. 272void mainLoop(){ 273 274 //DS18B20 temp sensor for ambient temperature. 275 sensors.setResolution(10); //has to be done before each temperature measurement. Note that a higher resolution is slower. 276 sensors.requestTemperatures(); 277 ambientTemp = sensors.getTempCByIndex(0); 278 279 //si7021 temps sensor for mirror. 280 mirrorTemp = si7021.measureTemperature(); 281 282 //Get the optical sensor reading. 283 optical = getOptical(); 284 285 relativeHumidity = calculateHumidity(dewPoint, ambientTemp); 286 287/* 288 //Readable format 289 Serial.print("dewPoint: "); 290 Serial.println(dewPoint, 2); 291 Serial.print("mirrorTemp: "); 292 Serial.println(mirrorTemp, 2); 293 Serial.print("ambientTemp: "); 294 Serial.println(ambientTemp, 2); 295 Serial.print("relativeHumidity: "); 296 Serial.println(relativeHumidity, 2); 297 298*/ 299 300 //For the Serial Plotter 301 Serial.print(mirrorTemp, 2); 302 Serial.print(" "); 303 Serial.print(optical, 2); 304 Serial.print(" "); 305 Serial.println(dewPoint, 2); 306 // Serial.print(" "); 307 // Serial.println(relativeHumidity, 2); 308 309 310 311 312 //Wait for the condensation to disappear 313 if(!cooling && !noiseSampling && (optical >= noiseSampleLowest)){ 314 315 startNoiseSampling(); 316 } 317} 318 319void loop() { 320 321 //Watchdog crash detection 322 wdt_reset(); 323 324 //Update all timers. 325 TimerManager::instance().update(); 326}
Downloadable files
Chilled Mirror Hygrometer schematic
Chilled Mirror Hygrometer schematic
Chilled Mirror Hygrometer schematic
Chilled Mirror Hygrometer schematic
Comments
Only logged in users can leave comments