This project is based on a 4-pin
PWM fan, for testing I have used a Noctua NF-A14 PWM fan,
powered at 12 volts - the power must be supplied via an external power supply. We are going to manage this fan in such a way as to be able to turn it on/off or to change its speed.
For ease we are going to use the FTDI FT232H development board (of which there is a dedicated page on this site) and the
NXP PCA9685 development board (of which there is a dedicated page on this site).
This project is divided into two parts, the second part is simply a variation of the first part and includes two switches that are used to change the fan speed.
This fan must be partially connected to the NXP PCA9685 development board. The connection connectors are listed below:
Image | Board FT232H | Board PCA9685 | Fan |
---|---|---|---|
AD0 | SCL | ------ | |
AD1 + AD2 | SDA | ------ | |
+5V | VCC | ------ | |
GND | GND | ------ | |
------ | Channel 0 - PWM | PWM signal | |
------ | ------ | RPM signal (not used) | |
------ | ------ | VCC (power supply) | |
------ | ------ | GND (power supply) |
To use this project, the presence of the "PCA9685_FTDI" library is required. The Python code is the following:
import time import pca9685_ftdi """ Blue = PWM signal Green = RPM speed signal Yellow = +VCC Black = GND """ # Create library object using our FTDI I2C port pwm = pca9685_ftdi.PCA9685_FTDI() MIN = 300 STEP = 5 SLEEP = 0.025 CHANNEL = 0 try: while True: print("\nFAN off") pwm.setPWM(CHANNEL, 0, 0) time.sleep(10) print("\nFAN full speed") pwm.setPWM(CHANNEL, 0, 4095) time.sleep(10) print("\nIncreasing FAN speed") for fadeValue in range(MIN, 4096, STEP): pwm.setPWM(CHANNEL, 0, fadeValue) time.sleep(SLEEP) print("\nDecreasing FAN speed") for fadeValue in range(4095, MIN - STEP, -STEP): pwm.setPWM(CHANNEL, 0, fadeValue) time.sleep(SLEEP) time.sleep(2) except KeyboardInterrupt: # Capture keyboard ^C to exit the program print('\nYou terminated the program. The program ends!') #pwm.clearAllPins() pwm.set_all_pwm(0, 0) pwm.close()
This fan must be partially connected to the NXP PCA9685 development board, while the two switches must be connected to FTDI FT232H development board. The connection connectors are listed below:
Image | Board FT232H | Board PCA9685 | Fan | Switch 1 | Switch 2 |
---|---|---|---|---|---|
AD0 | SCL | ------ | ------ | ------ | |
AD1 + AD2 | SDA | ------ | ------ | ------ | |
+3.3V | VCC | ------ | ------ | ------ | |
GND | GND | ------ | ------ | ------ | |
------ | Channel 0 - PWM | PWM signal | ------ | ------ | |
------ | ------ | RPM signal (not used) | ------ | ------ | |
------ | ------ | VCC (power supply) | ------ | ------ | |
------ | ------ | GND (power supply) | ------ | ------ | |
+5V | ------ | ------ | Pin 1 | Pin 1 | |
AD3 | ------ | ------ | Pin 2 | ------ | |
AD4 | ------ | ------ | ------ | Pin 2 |
To use this project, the presence of the "PCA9685_FTDI" library is required. The Python code is the following:
import time import pca9685_ftdi """ Blue = PWM signal Green = RPM speed signal Yellow = +VCC Black = GND """ GPIO_IN_OFFSET = 3 # FT232H GPIO inputs are AD3-AD4 (AD0-AD2 are reserved to I2C) MIN = 0 MAX = 4096 STEP = 256 SLEEP = 0.25 CURRENTVALUE = MIN CHANNEL = 0 # Create library object using our FTDI I2C port pwm = pca9685_ftdi.PCA9685_FTDI() pwm._i2c.set_retry_count(16) gpio = pwm._i2c.get_gpio() # We set the two GPIO pins to write mode as we need to set them to 0 before reading the values # (otherwise, if we set them to read mode, the values will be always 1). gpio.set_direction(0b11000, 0b11000) gpio.write(0b000000) pwm.setPWM(CHANNEL, 0, 0) print(CURRENTVALUE) try: while True: din = (gpio.read(True) >> GPIO_IN_OFFSET) & 0b11 if (din == 1 or din == 2): if (din == 1): CURRENTVALUE = CURRENTVALUE + STEP if (din == 2): CURRENTVALUE = CURRENTVALUE - STEP if (CURRENTVALUE < MIN): CURRENTVALUE = MAX if (CURRENTVALUE > MAX): CURRENTVALUE = MIN print(CURRENTVALUE) pwm.setPWM(CHANNEL, 0, CURRENTVALUE) time.sleep(SLEEP) except KeyboardInterrupt: # Capture keyboard ^C to exit the program print('\nYou terminated the program. The program ends!') #pwm.clearAllPins() pwm.set_all_pwm(0, 0) pwm.close()