We use a ventilation fan when we want to move air. Sometimes we want to move air for exhaust (such as a kitchen fan clearing cooking odors away) or to bring in cooler air (such as a PC fan to reduce internal component temperatures) or to move moist air away (such as a bathroom fan).
Fans can be controlled manually with a simple on/off switch and we can also automate their use. In this project, we build an automated fan that is controlled by a user temperature setting, a user humidity setting, or both.
To build the project, we construct a circuit that uses a Picaxe 08M2 microcontroller to read a Honeywell HIH6030 temperature and humidity sensor. Based on a comparison between the user-defined values programmed into the Picaxe nonvolatile memory and the values read from the sensor, a decision is made to switch the fan on or off.
If a sensor error occurs, it turns the fan off and sounds an alarm. The circuit also monitors the speed of the fan and if it is not moving when it should be, or if it is moving when it shouldn't be, it will sound an alarm.
The complete circuit for the project is shown in the schematic below.
Schematic for the project. Click to enlarge.
|Component||Description||Source / Price|
|M1 (Fan)||Thermaltake Pure 20||Newegg $19.95|
|U1||78L05 5 volt regulator (100 mA)||Digi-Key $0.38|
|U2||Picaxe 08M2 microcontroller||RobotShop $2.89|
|U3||HIH6030-021-001 hum/tem sensor||Digi-Key $8.61|
|Q1||IRL540 MOSFET N-CH TO-220AB||Digi-Key $1.87|
|SG1||Piezoelectric buzzer 5 volt||Banggood ~$0.55|
|C1||1.0 µF polarized capacitor||*|
|C2,C3,C5||0.1 µF nonpolarized capacitor||*|
|C4||0.22 µF nonpolarized capacitor||*|
|R1||10 kΩ resistor||*|
|R2||33 kΩ resistor||*|
|R3||4.7 kΩ resistor||*|
|R4,R5||2.2 kΩ resistor||*|
|R6||150 Ω resistor||*|
*Note: Sources and prices for common components (capacitors, diodes, resistors) vary.
The Picaxe 08M2 microcontroller (left) and HIH6030 sensor on a carrier board (right).
The “brain” for the project is a Picaxe 08M2 microcontroller programmed using the Picaxe BASIC language. The 8-pin device features 2048 bytes of program memory (up to 1800 program lines), 128 bytes of RAM, and six port pins (C.0 through C.4 are I/O, C.5 is input only).
For the project, the port pins are dedicated to the following functions (details follow):
- C.0 – Operates a piezoelectric buzzer to provide an alarm.
- C.1 – I2C, SCL.
- C.2 – I2C, SDA.
- C.3 – Reads fan tachometer signal.
- C.4 – Turns fan on/off using the MOSFET (Q1) switch.
- C.5 – Not used (tied to ground through R3).
Humidity and Temperature Sensor
The project uses a Honeywell HIH6030 to monitor temperature and relative humidity. The chip has a supply voltage range of 1.8V-5.5V and uses an I2C interface to communicate with a microcontroller. R4 and R5 are the recommended pullup resistors. Capacitors C4 and C5 also follow the values recommended by Honeywell.
The device comes in a surface mount package (SOIC-8) and, for the project, is soldered onto a carrier board making it usable as a DIP-8 package.
Power supply for the project
A regulated 12V power supply (model F1650) that previously served as a power supply for a laptop is used for the project. The unit is fused and is rated to provide 12V at up to 3.5A – plenty of power for this application. This model is still readily available (e.g., on eBay) and can be obtained on the used surplus market as well. Of course, not all model F1650 power supplies are necessarily equivalent and you should check the output details of whichever power supply that you use.
The 12V supply is used to operate the fan and also provide 5V power. To implement the 5V supply, I used the venerable 78L05 (U1) 5V regulator along with capacitors C1 and C2. The 5V supply powers the Picaxe controller (U2), the HIH6030 sensor (U3), and the piezoelectric buzzer (SG1).
I used this fan from Thermaltake. The 200 × 200 × 30 mm fan’s specifications include 12V operation and ~130 CFM. D1 is a “flyback” diode used to suppress voltage spikes that occur across the inductive load presented by M1, the fan’s motor.
The fan used has three connections on the cable: Vcc (+12V), ground, and tachometer out. On the unit I used, the wires were color coded as red, black, and yellow, respectively. The tachometer signal comes from a Hall effect sensor internal to the fan. Additionally, there are two magnets internal to the fan. Normally the tachometer signal is at 12V. When a magnet passes the Hall effect sensor, the signal switches to ground. It is configured as an open collector output with a pullup resistor to 12V internal to the fan.
We want the 08M2 input port C.3 to read the tachometer signal, but at 5V, not 12V. To accomplish this, we use R3 pulled up to 5V and diode D2 to prevent the 12V from reaching the 08M2 while preserving the pulses that correlate with the RPM of the fan. Note also that, because there are two magnets, there are two pulses per revolution.
Not all fans with a “third wire” tachometer signal work the same. I have seen ones where there was no internal pullup resistor and I have even seen ones where there was no internal connection at all! It's a good idea to test the functionality of the tachometer signal before using it in the project.
Piezoelectric buzzer (left) and IRL540 MOSFET (right)
Fan Control Switch
The fan is operated by a 08M2 output bit (C.4) connected to the gate of Q1, an IRL540 N-channel power MOSFET. Q1 is used in a "low side" driver configuration such that it will sink the fan’s current when the voltage of the gate, relative to its source pin, which is at ground, is increased by just a few volts.
The IRL540 is well-suited for the application because when the gate is near +5V (relative to the source), the device’s resistance is rated to be only 0.077Ω, and it is able to sink a much greater amount of current than the rated 0.23A of the fan. Thus, when the Picaxe output pin is set to a logic level “high” (~5V), the fan turns on and when the output pin is at a logic level “low” (<0.6V), the fan is off.
R1 is used to pull down the voltage at the gate of Q1 when the Picaxe output port is in a high impedance state, such as during power up.
SG1 is a generic 5V buzzer. I measured the current drawn by the device at 5V as 24mA. Since that amount is near the Picaxe port's maximum output current, current-limiting resistor R6 is used. SG1 is connected to Picaxe output C.0 and functions as a notification/alarm buzzer. Even with R6, it is suitably loud.
The project circuit on a breadboard: 12V components (left) and 5V components (right).
Before presenting the program code listing, some explanation of the basic tasks that the software must perform is in order.
Reading Humidity and Temperature Values
To thoroughly understand how to use the HIH6030 sensor, it is advisable to become familiar with a technical note from Honeywell detailing I2C communications with the sensor (PDF here).
The default I2C address of the sensor is 0x27, and Picaxe BASIC wants the 8-bit left-shifted value of 0x4E. When the device powers up, it will accept a data byte of 0xA0 to put it into “command mode”, if one is received within 10 milliseconds. Command mode can be used to set alarms, read EEPROM and even configure the default I2C address. There is a Honeywell technical note on command mode if you want to know more (PDF here). We are not, however, using command mode at all for the project and explicitly execute a software delay on power up to prevent the possibility of entering command mode.
We can read the sensor's temperature and relative humidity values by first sending the device a measurement request. To do this, we simply issue a write to the slave address. The sensor responds with an acknowledge (ACK), and the Master device then generates a “STOP” condition. For Picaxe BASIC, we have to send a data byte along with the initial write command to complete the transaction. Thus, we send a “dummy” data byte of 0xFF, which is always ignored by the sensor.
After issuing a measurement request and waiting a short time (~37 milliseconds) for the measurements to complete, we can read the sensor's values by retrieving four bytes of data as illustrated below.
Data stream read from the HIH6030 sensor (figure courtesy of Honeywell). Click to enlarge.
The data stream contains status, humidity, and temperature values. Status values can be 0b00 = normal, 0b01 = stale data, 0b10 = in command mode, and 0b11 = not defined. See the technical note for a full explanation of the status codes. In our project, the status value must be equal to 0b00 indicating a normal transaction. Any other received status value indicates a sensor or transmission error and will result in an alarm sounding in an infinite loop.
The Picaxe will read the four values and store the 14-bit humidity value (after masking the status bits) in one variable and the 14-bit temperature value (after dividing the value by 4 to shift the bits right two places) into another variable.
These raw humidity and temperature values will be compared to the high and low humidity and temperature values that the user has set in the program to decide whether to turn the fan on or off. While it is the raw values that the program uses, it is necessary to understand the relationship between the raw values and the RH percentage and degrees (C) that they represent.
That relationship for percent relative humidity is given by the formula below, where "Humcount" is the 14-bit raw humidity value.
For temperature, the relationship is given by the formula below, where "Temcount" is the 14-bit raw temperature value.
Configuring the Fan’s On and Off Thresholds
For both humidity and temperature, the program uses an “on” threshold and an “off” threshold. If the sensor value equals or exceeds the “on” value, the fan will turn on. If the fan is on and the value drops to the “off” value, the fan will turn off. By separating the threshold values, we prevent the fan from rapidly oscillating around one value. This is referred to as hysteresis.
To set the threshold values in the program, we convert RH percentage and degrees (C) to raw values that the program uses in the variables HumH (high humidity threshold), HumL (low humidity threshold), TemH (high temperature threshold), and TemL (low temperature threshold).
For humidity: raw value = RH(%)/0.0061.Thus, if you want to set the high RH threshold to 82% RH and the low threshold to 74% RH:
- 82/0.0061 = 13442.62, set HumH = 13443
- 74/0.0061 = 12131.15, set HumL = 12131
For temperature: raw value = (degrees (C) + 40)/0.01007. Thus, if you want to set the high temperature threshold to 29 degrees (C) and the low threshold to 27.5 degrees (C):
- (29+40)/0.01007 = 6852.04, set TemH=6852
- (27.5+40)/0.01007 = 6703.08, set TemL=6703
Fan Operating Modes
The operating mode of the fan is set in firmware by the user setting the symbol UMODE, which sets the value of the program variable, MODE, in the Picaxe code. Only values of 1, 2, or 3 are functional. The fan will not operate with other values.
- When MODE is set to 1, the fan will operate based on the sensor temperature value. When temperature, in sensor counts, equals or is greater than the value set in the variable "TemH", the fan will be switched on. When temperature, in sensor counts, equals or is lower than the value set in the variable "TemL", the fan will be switched off.
- When MODE is set to 2, the fan will operate based on the sensor RH value. When RH, in sensor counts, equals or is greater than the value set in the variable "HumH", the fan will be switched on. When RH, in sensor counts, equals or is lower than the value set in the variable "HumL", the fan will be switched off.
- When MODE is set to 3, sensor values for both temperature and humidity are used to control the fan. That is, when either temperature or humidity measures are at, or exceed, the upper limits (TemH or HumH), the fan turns on. The decision to turn the fan off in mode 3 is more complicated and is detailed below.
For Mode 3, if the fan has been turned on as a result of only temperature rising to the upper limit, then when temperature decreases to the lower limit, the fan turns off. Similarly, if the fan turns on as a result of only humidity reaching the upper limit, then when humidity decreases to the lower limit, the fan turns off. The procedures are just like those in modes 1 and 2, respectively.
When the temperature and humidity have both risen to or beyond their respective upper limits, however, we will turn the fan off only if both lower limits have been met. To accomplish this, we track the two measures independently. That is, we track the characteristic (temperature and humidity) that caused the fan to turn on using bits in the program variable FMODE.
For example, if temperature rises to the upper limit, FMODE bit 0 is set and the fan is turned on. If humidity subsequently rises to the upper limit, FMODE bit 1 is set (the fan is already on). Now, suppose that temperature, but not humidity, falls to the lower limit. In this case, we clear FMODE bit 0, but the fan remains on because FMODE bit 1 is still set. When humidity falls to the lower limit, we clear FMODE bit 1. Now, the fan is turned off because both bits 0 and 1 of FMODE are cleared.
Checking RPM of the Fan
The fan speed for the unit that I used is stated as 800 RPM in the specifications. I measured the fan RPM for my unit, using two different frequency counters, and the result was about 900 RPM. As mentioned in the fan documentation, “Specifications are subject to change without notice”. I believe that this is such a case.
To measure the RPM in the project code, I used the Picaxe BASIC “count” command. The command counts the number of low-to-high transitions on a Picaxe input port bit (the project schematic uses port bit C.3). For a 5-second period, the count was at 151 ± a few counts. That comes out to 30.2 pulses per second or 1812 pulses per minute (at 4MHz, the speed of the 08M2). The fan has two magnets that pass by the Hall effect sensor, so we need to divide the number of pulses by 2 to get RPM. Doing so gives a value of 906 RPM, which is acceptably close to my other measurements that indicated an RPM of ~900.
The program uses this feature to detect whether the fan is actually turning when it is switched on. That is, the program samples the fan RPM and compares the number to a programmed minimum value that is set in firmware using the variable mRPM. The default for mRPM is 100, but the value can be changed by the user. Thus, if RPM is less than mRPM after the fan is switched on, we assume a fan error.
We also use this feature to detect if the fan is turning when it is switched off. That is, if RPM is greater than mRPM after the fan is switched off, we assume a fan error.
The fan does not have a brake; when it is switched off, RPM values will decline over a few seconds before reaching a value of 0. Additionally, when first switched on, a small amount of time is required before RPM reaches the normal peak value. We have a 5-second delay in software before we measure RPM for an additional 5 seconds. Thus, we can overlook start-up and shut-down RPM values, while checking temperature and humidity every 10 seconds.
The code for the project is given below, and the file can be downloaded at the end of the article.
001 ; AxeFan.bas-PICAXE code to accompany the article - 002 ; "Build a temperature and/or humidity controlled fan" 003 ; 004 ; *** This software is offered stricly as-is with no warranties 005 ; whatsoever. Use it at your own risk. *** 006 init: 007 ;-------------------------------- 008 ; User sets the following turn on and turn off values for temperature 009 ; and humidity as 16 bit sensor counts in decimal 010 SYMBOL TemH=6852 ;29 degrees (C) 011 SYMBOL TemL=6703 ;27.5 degrees (C) 012 SYMBOL HumH=13443 ;82 % RH 013 SYMBOL HumL=12131 ;74 % RH 014 SYMBOL mRPM=100 ;151=~900 RPM full on 015 ; User sets the mode to 1=temperature only, 2=humidity only, 3=both 016 SYMBOL UMode=3 017 ;-------------------------------- 018 ; The SYMBOLS below are for program variable use 019 SYMBOL HUM=W0 ; 16 bit humidity 020 SYMBOL TEMP=W1 ; 16 bit temperature 021 SYMBOL status=B4 ; HIH status (must be 0) 022 SYMBOL Fstatus=B5 ; fan bit status (0=off, 1=on) 023 SYMBOL MODE=B6 ; fan mode 024 SYMBOL FMODE=B7 ; to track which (T or H) or both turned the Fan on 025 ; FMODE bit 0=T and bit 1=H 026 SYMBOL RPM=W4 ; to measure Fan RPM 027 ; Note: Fan=4=MOSFET G on C.4 028 SYMBOL Fan=4; 029 ; Note: Buzzer=0=piezo on C.0 030 SYMBOL Buzzer=0; 031 ; Note: RPMin=3=Fan tach on C.3 032 SYMBOL RPMin=3 033 ;-------------------------------- 034 let MODE=UMode 035 ; get fan bit status, Fstatus=1 if fan GPIO is on 036 Fstatus=pinc.4 037 gosub FanOff ; should boot up off but switch it to be sure 038 let Fstatus=0 039 ; I2C address is $27 shifted=$4e 040 hi2csetup I2CMASTER, $4E, i2cslow, i2cbyte 041 let B5=$ff ; dummy arg 042 pause 30 ; wait past command window 043 gosub PU_tone 044 ;-------------------------------- 045 ; main loop 046 main: ;get temperature and humidity 047 hi2cout (B5) ; wake up kick to start measurement cycle 048 pause 60 ; wait for measurement cycle (nominally 36.65 ms) 049 hi2cin (B1) ; Hum hi 050 hi2cin (B0) ; Hum low 051 hi2cin (B3) ; Tem hi 052 hi2cin (B2) ; Tem lo 053 let status=B1 & %11000000 ; get status bits 054 let B1=B1 & %00111111 ; mask status 055 let W1=W1/4 ; shift temperature 056 ; if status is not 0, we have a read error indicating either a 057 ; transmission error or a sensor error. 058 ; ** This results in an error trap. ** 059 if status<>0 then 060 goto TerrorS 061 endif 062 ; handle fan on/off depending on the operating mode 063 MODE1: 064 ; mode 1 is temperature only 065 if MODE = 1 then 066 if TEMP >=TemH then 067 gosub FanOn 068 endif 069 if TEMP <=TemL then 070 gosub FanOff 071 endif 072 endif 073 MODE2: 074 ; mode 2 is humidity only 075 if MODE=2 then 076 if HUM >=HumH then 077 gosub FanOn 078 endif 079 if HUM<=HumL then 080 gosub FanOff 081 endif 082 endif 083 MODE3: 084 ; mode 3 is both humidity and temperature 085 if MODE=3 then 086 ; If fan is off, should we turn it on? 087 if Fstatus=0 then 088 if TEMP >=TemH then 089 FMODE=FMODE|1 ;set b0 090 gosub FanON 091 endif 092 if HUM >=Humh then 093 FMODE=FMODE|2 ;set b1 094 gosub FanOn 095 endif 096 elseif Fstatus=1 then 097 ;else 098 ; if fan is on should we turn it off? 099 if TEMP <=TemL then 100 FMODE=FMODE&2 ;reset b0 101 endif 102 if HUM <=HumL then 103 FMODE=FMODE&1 ;reset b1 104 endif 105 if FMODE=0 then 106 gosub FanOff 107 endif 108 endif 109 endif 110 111 next1: 112 ; get fan bit status, Fstatus=1 if fan GPIO is on 113 Fstatus=pinc.4 114 ; delay for 10 seconds before looping 115 pause 5000; 116 ; check fan RPM as part of the 10 sec delay 117 count RPMin,5000,RPM 118 if Fstatus=1 then 119 if RPM < mRPM then 120 goto TerrorF ; fan error - RPM too low! 121 endif 122 elseif Fstatus=0 then 123 ;else 124 if RPM >= mRPM then 125 goto TerrorF ; fan error - RPM too high! 126 endif 127 endif 128 goto main 129 ;-------------------------------- 130 ; Error Traps (infinite loops) 131 ; sensor or transmission error - give continuous fast beeps 132 TerrorS: 133 switchon Buzzer 134 pause 35 135 switchoff Buzzer 136 pause 100 137 goto TerrorS 138 ; Fan RPM eror - give continuous slow beeps 139 TerrorF: 140 switchon Buzzer 141 pause 75 142 switchoff Buzzer 143 pause 300 144 goto TerrorF 145 ;-------------------------------- 146 ; subroutines 147 FanOn: 148 if pinc.4=0 then switchon Fan endif 149 return 150 FanOff: 151 if pinc.4=1 then switchoff Fan endif 152 return 153 PU_tone: 154 ; power up - three beeps 155 switchon Buzzer 156 pause 100 157 switchoff Buzzer 158 pause 100 159 switchon Buzzer 160 pause 100 161 switchoff Buzzer 162 pause 100 163 switchon Buzzer 164 pause 100 165 switchoff Buzzer 166 return
Program Structure Comments
Lines 8-16: User-defined values for symbols to set program variables that control the fan.
- TemH, TemL, HumH, HumL are the high and low raw-data values for controlling the fan on/off set points.
- mRPM is the RPM value used to determine if the fan is turning when on and not turning when off.
- UMODE sets the operation mode for the fan (1 = temperature only, 2 = humidity only, 3 = both).
Lines 17-32: Symbol definitions for program variables.
Lines 33-43: Initialization.
- Initialization of the I2C interface.
- Issue starting tone (three beeps).
Lines 44-128: Main loop.
- Lines 47-61: Read HIH3060 sensor; evaluate status bits and store humidity and temperature raw-data values.
- Lines 62-111: Decide on whether to turn the fan on or off for the current operating mode.
- Lines 116-127: Check for acceptable fan RPM depending upon on/off status.
Lines 129-144: Error alarm traps (infinite loops).
- Lines 132-137: Error alarm (fast beeps) if status byte does not equal 0 (transmission or sensor error).
- Lines 139-144: Error alarm (slow beeps) if RPM is below mRPM when fan is on or above RPM when fan is off.
Lines 145-166: Utility subroutines.
This project presents an economical and relatively simple example of automating the control of a fan. The implementation can be accomplished with just a few ICs, primarily because the sensor and the microcontroller are highly integrated devices. The system is flexible in that it can be configured to be controlled by temperature or humidity or the combination of both temperature and humidity. Additionally, the user can easily configure the characteristics of the control parameters, changing them to suit a variety of applications.
The source code for the project can be downloaded by clicking the link below:
Give this project a try for yourself! Get the BOM.