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