
1. Introduction
Implement motor control: Connect to an external microcontroller via the I2C interface, use the PCA9685 chip to output PWM signals, and control the speed and other parameters of the four-channel MOC PF motor.8PIN Interface: Provides 8 pin interfaces, which can be used to connect sensors, other controllers, or expand more functions, facilitating further expansion and integration of the system.
Power management: It usually integrates power interfaces to provide the appropriate power for the connected motors and the chips themselves.Part of the expansion board also has reverse connection protection circuit, preventing damage to the circuit due to reversed positive and negative poles of the power supply.
2. Schematic
PCA9685-I2C-quad MOC-PF motor-8PIN-expansion board-HS-F27-LClick to view
Module Parameters
Pin Name | description |
|---|---|
G | GND (Negative Power Input) |
V | VCC (Positive Power Input) |
SDA | Data pin |
SCL | clock pin |
Supply voltage: 3.3V-5V
Connection method: PH2.0 4P terminal wire
Installation method: Lego assembly
4, Circuit Board Size

5 of Arduino IDE example program
Attention: If prompted with an error message about the library file during program upload, please import the library file first!
Arduino IDE Library Download and Import Tutorial:Click to view
Example program (UNO development board):
#include "Wire.h"
#include "Adafruit_PWMServoDriver.h"
Adafruit_PWMServoDriver PWM = Adafruit_PWMServoDriver(0x40);
void setup(){
PWM.begin();
PWM.setPWMFreq(85);
}
void loop(){
PWM.setPWM(0,0,0);
PWM.setPWM(1,0,2048);
PWM.setPWM(2,0,0);
PWM.setPWM(3,0,2048);
PWM.setPWM(4,0,0);
PWM.setPWM(5,0,2048);
PWM.setPWM(6,0,0);
PWM.setPWM(7,0,2048);
for (int i = 0; i <= 180; i = i + (1)) {
PWM.setPWM(8,0,(map(i, 0, 180, 140, 680)));
PWM.setPWM(9,0,(map(i, 0, 180, 140, 680)));
PWM.setPWM(10,0,(map(i, 0, 180, 140, 680)));
PWM.setPWM(11,0,(map(i, 0, 180, 140, 680)));
delay(50);
}
}6, ESP32 Python Example (for Mixly IDE/Misashi)
Choose the development board Python ESP32 [ESP32 Generic(4MB)] and upload in code mode
Attention: If prompted with an error message about the library file during program upload, please import the library file first!
Download and import tutorial for Mixly IDE ESP32 library:Click to view
Example program (ESP32-Python):
from machine import I2C, Pin
import time
from mixpy import math_map
PCA9685_MODE1 = 0x00
PCA9685_MODE2 = 0x01
PCA9685_LED0_ON_L = 0x06
PCA9685_LED0_ON_H = 0x07
PCA9685_LED0_OFF_L = 0x08
PCA9685_LED0_OFF_H = 0x09
PCA9685_ALLLED_ON_L = 0xFA
PCA9685_ALLLED_ON_H = 0xFB
PCA9685_ALLLED_OFF_L = 0xFC
PCA9685_ALLLED_OFF_H = 0xFD
PCA9685_PRESCALE = 0xFE
MODE1_ALLCAL = 0x01
MODE1_SUB3 = 0x02
MODE1_SUB2 = 0x04
MODE1_SUB1 = 0x08
MODE1_SLEEP = 0x10
MODE1_AI = 0x20
MODE1_EXTCLK = 0x40
MODE1_RESTART = 0x80
MODE2_OUTNE_0 = 0x01
MODE2_OUTNE_1 = 0x02
MODE2_OUTDRV = 0x04
MODE2_OCH = 0x08
MODE2_INVRT = 0x10
PCA9685_I2C_ADDRESS = 0x40
FREQUENCY_OSCILLATOR_HZ = 25_000_000
PRESCALE_MIN = 3
PRESCALE_MAX = 255
class PCA9685:
def __init__(self, i2c: I2C, addr: int = PCA9685_I2C_ADDRESS):
self.i2c = i2c
self.addr = addr
self._oscillator_freq = FREQUENCY_OSCILLATOR_HZ
def _write8(self, reg: int, val: int):
self.i2c.writeto_mem(self.addr, reg, bytes([val & 0xFF]))
def _read8(self, reg: int) -> int:
return self.i2c.readfrom_mem(self.addr, reg, 1)[0]
def _write4(self, base_reg: int, on: int, off: int):
buf = bytearray(4)
buf[0] = on & 0xFF
buf[1] = (on >> 8) & 0x0F
buf[2] = off & 0xFF
buf[3] = (off >> 8) & 0x0F
self.i2c.writeto_mem(self.addr, base_reg, buf)
def begin(self):
self.reset()
mode1 = self._read8(PCA9685_MODE1)
self._write8(PCA9685_MODE1, mode1 | MODE1_AI)
self.set_output_mode(True)
def reset(self):
self._write8(PCA9685_MODE1, MODE1_RESTART) # ๅ RESTART
time.sleep_ms(10)
def sleep(self):
m1 = self._read8(PCA9685_MODE1)
self._write8(PCA9685_MODE1, m1 | MODE1_SLEEP)
time.sleep_ms(5)
def wakeup(self):
m1 = self._read8(PCA9685_MODE1)
self._write8(PCA9685_MODE1, m1 & (~MODE1_SLEEP))
time.sleep_ms(5)
def set_output_mode(self, totempole: bool = True):
m2 = self._read8(PCA9685_MODE2)
if totempole:
m2 |= MODE2_OUTDRV
else:
m2 &= ~MODE2_OUTDRV
self._write8(PCA9685_MODE2, m2)
def set_oscillator_frequency(self, freq_hz: int):
self._oscillator_freq = int(freq_hz)
def get_oscillator_frequency(self) -> int:
return self._oscillator_freq
def set_pwm_freq(self, freq_hz: float):
if freq_hz < 1.0:
freq_hz = 1.0
if freq_hz > 3500.0:
freq_hz = 3500.0
prescaleval = ((self._oscillator_freq / (freq_hz * 4096.0)) + 0.5) - 1.0
if prescaleval < PRESCALE_MIN:
prescaleval = PRESCALE_MIN
if prescaleval > PRESCALE_MAX:
prescaleval = PRESCALE_MAX
prescale = int(prescaleval)
oldmode = self._read8(PCA9685_MODE1)
newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP
self._write8(PCA9685_MODE1, newmode)
self._write8(PCA9685_PRESCALE, prescale)
self._write8(PCA9685_MODE1, oldmode)
time.sleep_ms(5)
self._write8(PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI)
def read_prescale(self) -> int:
return self._read8(PCA9685_PRESCALE)
def set_pwm(self, ch: int, on: int, off: int):
base = PCA9685_LED0_ON_L + 4 * ch
self._write4(base, on & 0x1FFF, off & 0x1FFF)
def set_pin(self, ch: int, val: int, invert: bool = False):
if val < 0:
val = 0
if val > 4095:
val = 4095
if invert:
if val == 0:
self.set_pwm(ch, 4096, 0) # fully ON
elif val == 4095:
self.set_pwm(ch, 0, 4096) # fully OFF
else:
self.set_pwm(ch, 0, 4095 - val)
else:
if val == 4095:
self.set_pwm(ch, 4096, 0) # fully ON
elif val == 0:
self.set_pwm(ch, 0, 4096) # fully OFF
else:
self.set_pwm(ch, 0, val)
def write_microseconds(self, ch: int, us: int):
prescale = self.read_prescale() + 1
us_per_bit = (1_000_000.0 * prescale) / float(self._oscillator_freq)
ticks = int(us / us_per_bit + 0.5)
if ticks < 0:
ticks = 0
if ticks > 4095:
ticks = 4095
self.set_pwm(ch, 0, ticks)
i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000)
PWM = PCA9685(i2c, addr=0x40)
PWM.begin()
PWM.set_pwm_freq(50)
while True:
PWM.set_pwm(0,1,4095)
PWM.set_pwm(1,1,2000)
PWM.set_pwm(2,1,4095)
PWM.set_pwm(3,1,2000)
PWM.set_pwm(4,1,4095)
PWM.set_pwm(5,1,2000)
PWM.set_pwm(6,1,4095)
PWM.set_pwm(7,1,2000)
PWM.set_pwm(8, 0, int(math_map(90, 0, 180, 140, 680)))
time.sleep(5)
PWM.set_pwm(0,1,2000)
PWM.set_pwm(1,1,2000)
PWM.set_pwm(2,1,2000)
PWM.set_pwm(3,1,2000)
PWM.set_pwm(4,1,2000)
PWM.set_pwm(5,1,2000)
PWM.set_pwm(6,1,2000)
PWM.set_pwm(7,1,2000)
PWM.set_pwm(8, 0, int(math_map(0, 0, 180, 140, 680)))
time.sleep(5)7, Mixly example program (graphical language)
Example program (UNO development board):Click to download
Attention: If prompted with an error message about the library file during program upload, please import the library file first!
Download and import tutorial of Mixly IDE Arduino library:Click to view

Example Program (ESP32 Development Board):Click to download
Attention: If prompted with an error message about the library file during program upload, please import the library file first!
Download and import tutorial for Mixly IDE ESP32 library:Click to view

8. Setting up the Test Environment
Arduino UNO Test Environment Setup
Prepare Components:
UNO-R3 Development Board *1
UNO-R3 Expansion Board *1
USB TYPE-C DATA CABLE *1
HS-F27 4-channel motor 8-channel servo expansion board*1
PH2.0 4P Double Head Terminal Line *1
6-9V battery box*1
LEGO motor*4
Servo*4
Circuit wiring diagram:

ESP32 Test Environment Setup
Prepare Components:Pending update...
Circuit wiring diagram:Pending update...
9, Video tutorial
Arduino UNO video tutorial:Click to view
ESP32 Python Video Tutorial:Click to view
10, Test results
Arduino UNO test results:
Insert the code, connect the corresponding module, after powering on, the motor and servo will rotate simultaneously.
