Code:
import smbus2
import time
# MCP23017 Register definitions
IODIRA = 0x00 # Direction register for Port A
IODIRB = 0x01 # Direction register for Port B
OLATA = 0x14 # Output latch register for Port A
OLATB = 0x15 # Output latch register for Port B
# I2C Device Address
MCP23017_ADDRESS = 0x22
# Initialize I2C bus
bus = smbus2.SMBus(1) # Raspberry Pi CM4 typically uses I2C bus 1
def setup_mcp23017():
# Set Port A and Port B to output mode
bus.write_byte_data(MCP23017_ADDRESS, IODIRA, 0x00) # Set Port A to output
bus.write_byte_data(MCP23017_ADDRESS, IODIRB, 0x00) # Set Port B to output
# Turn off all relays initially
bus.write_byte_data(MCP23017_ADDRESS, OLATA, 0x00) # Turn off all relays on Port A
bus.write_byte_data(MCP23017_ADDRESS, OLATB, 0x00) # Turn off all relays on Port B
def set_relay(relay_num, state):
"""
Controls a specific relay
relay_num: 1-16, corresponding to the 16 relays
state: 1 to turn on, 0 to turn off
"""
if relay_num < 1 or relay_num > 16:
raise ValueError("Relay number must be between 1 and 16")
if relay_num <= 8:
# Control relays 1-8 on Port A
current_state = bus.read_byte_data(MCP23017_ADDRESS, OLATA)
if state == 1:
current_state |= (1 << (relay_num - 1)) # Turn on the relay
else:
current_state &= ~(1 << (relay_num - 1)) # Turn off the relay
bus.write_byte_data(MCP23017_ADDRESS, OLATA, current_state)
else:
# Control relays 9-16 on Port B
relay_num -= 8
current_state = bus.read_byte_data(MCP23017_ADDRESS, OLATB)
if state == 1:
current_state |= (1 << (relay_num - 1)) # Turn on the relay
else:
current_state &= ~(1 << (relay_num - 1)) # Turn off the relay
bus.write_byte_data(MCP23017_ADDRESS, OLATB, current_state)
def test_relays():
# Sequentially turn on and off each relay with a 1-second delay
for i in range(1, 17):
print(f"Turning on relay {i}")
set_relay(i, 1)
time.sleep(1)
print(f"Turning off relay {i}")
set_relay(i, 0)
time.sleep(1)
if __name__ == "__main__":
setup_mcp23017()
test_relays() # Test relays
Before running the script, install the smbus2 library: