PCA9685 모듈의 양 끝에는 6개의 핀이 일렬로 배치되어 있습니다. 이 핀들은 I2C 통신을 주고받고 전원을 공급받기 위한 통로입니다.
보통 모듈의 왼쪽과 오른쪽에 똑같은 구성으로 6개씩 있는데, 이는 여러 개의 PCA9685를 기차놀이처럼 직렬(Daisy Chain)로 연결하기 쉽게 하기 위해서입니다.

핀의 명칭과 역할은 다음과 같습니다.
📍 PCA9685 6핀 인터페이스
| 핀 명칭 | 역할 설명 | 연결 대상 (ESP32-C3 기준) |
| GND | 그라운드 (0V) | ESP32-C3의 GND |
| OE | Output Enable (출력 활성화) | 연결 안 함 (또는 GPIO 연결) |
| SCL | I2C 클럭 신호 | ESP32-C3의 GPIO 1 |
| SDA | I2C 데이터 신호 | ESP32-C3의 GPIO 0 |
| VCC | 로직 전원 (3.3V ~ 5V) | ESP32-C3의 3.3V |
| V+ | 서보 전원 (최대 6V) | 외부 전원(+) 또는 5V |
🔍 핵심 핀 상세 설명
1. OE (Output Enable) – 중요!
- 이 핀은 비상 정지 스위치 같은 역할입니다.
- 기본적으로 내부에서 LOW(0)로 당겨져 있어서 연결하지 않아도 출력이 잘 나옵니다.
- 만약 이 핀을 HIGH(3.3V)로 연결하면, 16개 모든 채널의 PWM 출력이 즉시 차단됩니다. 안전이 중요한 프로젝트에서 제어기에 연결해 사용합니다.
2. VCC vs V+ (전원 구분 필수)
- VCC: PCA9685의 **머리(칩)**를 깨우는 전원입니다. ESP32와 통신하기 위해 ESP32의 3.3V 전원을 씁니다.
- V+: 서보 모터나 LED를 돌리는 힘입니다. 파란색 터미널 블록과 연결되어 있습니다. 모터를 많이 연결한다면 외부 전원(5V 건전지 등)을 여기에 공급해야 ESP32가 타지 않습니다.
3. SCL & SDA
- I2C 통신 라인입니다. 이 두 선만으로 16개의 채널을 제어합니다.
💡 팁: 왜 양쪽에 6개씩 있나요?
PCA9685는 확장성이 장점입니다. 첫 번째 모듈의 오른쪽 6핀과 두 번째 모듈의 왼쪽 6핀을 그대로 이어 붙이면, 선 4가닥(VCC, GND, SCL, SDA)만으로도 32개, 48개… 최대 992개의 서보 모터를 제어할 수 있게 설계되었기 때문입니다.

Python pca9685.py
import time
import ustruct
class PCA9685:
def __init__(self, i2c, address=0x40):
self.i2c = i2c
self.address = address
self.reset()
def _write(self, address, value):
self.i2c.writeto_mem(self.address, address, bytearray([value]))
def _read(self, address):
return self.i2c.readfrom_mem(self.address, address, 1)[0]
def reset(self):
"""모듈 초기화"""
self._write(0x00, 0x00) # MODE1 레지스터 초기화
def freq(self, freq=None):
"""PWM 주파수 설정 (서보 모터는 보통 50Hz 사용)"""
if freq is None:
prescale = self._read(0xFE)
return int(25000000 / (4096 * (prescale + 1)))
prescale = int(25000000 / (4096 * freq) - 0.5)
old_mode = self._read(0x00) # MODE1
self._write(0x00, (old_mode & 0x7F) | 0x10) # Sleep 모드 진입
self._write(0xFE, prescale) # 프레스케일 값 설정
self._write(0x00, old_mode) # 이전 모드로 복귀
time.sleep_ms(5)
self._write(0x00, old_mode | 0xA1) # Restart 및 AI(Auto-Increment) 활성화
def duty(self, index, on=None, off=None):
"""
특정 채널의 듀티비 설정
index: 0-15 채널 번호
on: 0-4095 (신호가 켜지는 시점, 보통 0 사용)
off: 0-4095 (신호가 꺼지는 시점, 듀티비 결정)
"""
if on is None or off is None:
# duty(index, value) 형태로 호출했을 때를 위한 처리
off = on
on = 0
if index < 0 or index > 15:
raise ValueError("채널 번호는 0에서 15 사이여야 합니다.")
# LEDX_ON_L, LEDX_ON_H, LEDX_OFF_L, LEDX_OFF_H 레지스터에 데이터 쓰기
data = ustruct.pack('<HH', on, off)
self.i2c.writeto_mem(self.address, 0x06 + 4 * index, data)
Python test.py
from machine import Pin, I2C
from pca9685 import PCA9685
import time
# 1. I2C 및 PCA9685 설정
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
pca = PCA9685(i2c, address=0x40)
pca.freq(50) # 서보 모터 표준 주파수 50Hz
# 2. 제어할 채널 리스트
servo_channels = [0, 3, 15]
# 3. 서보 설정값 (SG90 기준 가이드)
MIN_DUTY = 150 # 0도 (약 0.5ms)
MAX_DUTY = 600 # 180도 (약 2.5ms)
def set_angle(channel, angle):
"""특정 채널의 서보 각도를 설정하는 함수"""
if angle < 0: angle = 0
if angle > 180: angle = 180
duty = int(MIN_DUTY + (angle / 180) * (MAX_DUTY - MIN_DUTY))
pca.duty(channel, duty)
# 초기 위치 설정 (모두 45도에서 시작)
print("초기화: 모든 서보를 45도로 이동합니다.")
for ch in servo_channels:
set_angle(ch, 45)
time.sleep(1)
# 4. 메인 루프: 하나씩 순차적으로 작동
print("작동 시작: 0번 -> 3번 -> 15번 순서로 왕복합니다.")
try:
while True:
for ch in servo_channels:
print(f"현재 제어 중인 채널: {ch}번")
# 120도로 이동
set_angle(ch, 120)
time.sleep(0.8) # 이동 시간 대기
# 다시 45도로 복귀
set_angle(ch, 45)
time.sleep(0.8) # 이동 시간 대기
print(f"{ch}번 이동 완료. 다음 채널로 넘어갑니다.")
time.sleep(0.5) # 채널 간 전환 대기 시간
except KeyboardInterrupt:
print("프로그램 종료")



micro2iot에 답글 남기기 응답 취소