Build a Temperature and/or Humidity Controlled Fan with a Picaxe 08M2 Microcontroller

September 25, 2017 by Raymond Genovese

A Picaxe 08M2 microcontroller and an HIH6030 sensor team up to easily control a ventilation fan using temperature or humidity or both.

A Picaxe 08M2 microcontroller and an HIH6030 sensor team up to easily control a ventilation fan using temperature or humidity or both.

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.

Circuit Schematic

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.


Project BOM

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 *
D1 1N4001 diode *
D2 1N914 diode *
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


Power Supply

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.


Fan Tachometer

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.


Piezoelectric Buzzer

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 & 000000   ; get status bits
054		let B1=B1 & 111111	; 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
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.

Closing Thoughts

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.