Code:
/*
* Made by KinCony IoT: https://www.kincony.com
*
* This program reads inputs from two XL9535 I/O expander chips (I2C addresses 0x24 and 0x25)
* and one PCF8574 I/O expander (I2C address 0x23) via I2C using an ESP32-S3.
* The state of all inputs is printed in binary format to the serial monitor every second.
*
* - The XL9535 chips read inputs from channels 1-32.
* - The PCF8574 chip reads inputs from channels 33-40.
*
* I2C is initialized on GPIO 11 (SDA) and GPIO 10 (SCL) with a frequency of 40kHz.
*/
#include <stdio.h>
#include "driver/i2c.h"
#include "esp_log.h"
// I2C communication settings
#define I2C_MASTER_SCL_IO 10 // GPIO number for I2C clock line (SCL)
#define I2C_MASTER_SDA_IO 11 // GPIO number for I2C data line (SDA)
#define I2C_MASTER_FREQ_HZ 40000 // I2C frequency set to 40kHz
#define I2C_MASTER_PORT I2C_NUM_0 // I2C port number used in this program
// I2C addresses for XL9535 chips and PCF8574
#define XL9535_ADDR_1 0x24 // Address for XL9535 (channels 1-16)
#define XL9535_ADDR_2 0x25 // Address for XL9535 (channels 17-32)
#define PCF8574_ADDR 0x23 // Address for PCF8574 (channels 33-40)
// XL9535 registers for input ports
#define XL9535_INPUT_PORT_0 0x00 // Input register for port 0 (channels 1-8)
#define XL9535_INPUT_PORT_1 0x01 // Input register for port 1 (channels 9-16)
// Function prototypes
esp_err_t i2c_master_init();
esp_err_t xl9535_read_inputs(uint8_t device_addr, uint8_t *data);
esp_err_t pcf8574_read_inputs(uint8_t *data);
void read_and_print_inputs();
void app_main() {
// Initialize I2C master
ESP_ERROR_CHECK(i2c_master_init());
// Main loop to read and print input states every second
while (1) {
read_and_print_inputs();
vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait for 1 second
}
}
// Initialize I2C master interface
esp_err_t i2c_master_init() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER, // Set I2C mode to master
.sda_io_num = I2C_MASTER_SDA_IO, // SDA GPIO pin
.scl_io_num = I2C_MASTER_SCL_IO, // SCL GPIO pin
.sda_pullup_en = GPIO_PULLUP_ENABLE, // Enable internal pull-up for SDA line
.scl_pullup_en = GPIO_PULLUP_ENABLE, // Enable internal pull-up for SCL line
.master.clk_speed = I2C_MASTER_FREQ_HZ, // Set I2C clock frequency to 40kHz
};
i2c_param_config(I2C_MASTER_PORT, &conf);
return i2c_driver_install(I2C_MASTER_PORT, conf.mode, 0, 0, 0);
}
// Read inputs from XL9535 I/O expander
esp_err_t xl9535_read_inputs(uint8_t device_addr, uint8_t *data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, XL9535_INPUT_PORT_0, true);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (device_addr << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &data[0], I2C_MASTER_ACK); // Read port 0 (channels 1-8 or 17-24)
i2c_master_read_byte(cmd, &data[1], I2C_MASTER_NACK); // Read port 1 (channels 9-16 or 25-32)
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
// Read inputs from PCF8574 I/O expander
esp_err_t pcf8574_read_inputs(uint8_t *data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (PCF8574_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, data, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_PORT, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
// Function to read and print the state of inputs from XL9535 and PCF8574 chips
void read_and_print_inputs() {
uint8_t xl9535_data_1[2]; // Data buffer for XL9535 (channels 1-16)
uint8_t xl9535_data_2[2]; // Data buffer for XL9535 (channels 17-32)
uint8_t pcf8574_data; // Data buffer for PCF8574 (channels 33-40)
// Read inputs from the first XL9535 (channels 1-16)
if (xl9535_read_inputs(XL9535_ADDR_1, xl9535_data_1) == ESP_OK) {
printf("1-16 input states: %02X%02X\n", xl9535_data_1[1], xl9535_data_1[0]); // Print in binary
} else {
printf("Error reading from XL9535 (channels 1-16)\n");
}
// Read inputs from the second XL9535 (channels 17-32)
if (xl9535_read_inputs(XL9535_ADDR_2, xl9535_data_2) == ESP_OK) {
printf("17-32 input states: %02X%02X\n", xl9535_data_2[1], xl9535_data_2[0]); // Print in binary
} else {
printf("Error reading from XL9535 (channels 17-32)\n");
}
// Read inputs from the PCF8574 (channels 33-40)
if (pcf8574_read_inputs(&pcf8574_data) == ESP_OK) {
printf("33-40 input states: %02X\n", pcf8574_data); // Print in binary
} else {
printf("Error reading from PCF8574 (channels 33-40)\n");
}
}