09-09-2025, 02:49 AM
Code:
/*
* ----------------------------------------------------------------------------
* Copyright (c) 2025 KinCony IoT
*
* ----------------------------------------------------------------------------
*/
#include <Adafruit_PCF8575.h>
#include <HardwareSerial.h>
// Define Modbus RTU frame format constants
#define MODBUS_READ_COILS 0x01
#define MODBUS_READ_REGISTERS 0x03
#define MODBUS_WRITE_SINGLE_REGISTER 0x06
#define MODBUS_WRITE_MULTIPLE_REGISTERS 0x10
/* Example for 16 input buttons that are connected from the GPIO expander pins to ground.
* Note: The buttons must be connected with the other side of the switch to GROUND.
* There is a built-in pull-up resistor on each input, but no pull-down resistor capability.
*/
#define SDA_PIN 8
#define SCL_PIN 18
#define ADDRESS_PCF8575 0x22
#define ST_RX 4 //// ESP32 receive pin
#define ST_TX 6 //// ESP32 send pin
typedef enum {KEY_RELEASE=0, KEY_SHORT_PRESSED, KEY_LONG_PRESSED} KEY_STATUS;
typedef struct {
uint8_t key_index;
KEY_STATUS key_status;
long key_time_start;
long key_time_rec;
long key_press_time;
int16_t key_press_cnt; //// Send serial data every 100ms
int16_t key_press_cnt_old;
float current_light; /// Percentage of 0-4095
} KEY_PRESS_PROP;
KEY_PRESS_PROP key_press_prop[16] = {0};
Adafruit_PCF8575 pcf;
HardwareSerial myst_serial(1);
TwoWire myI2c = TwoWire(0);
// Modbus CRC16 calculation function
uint16_t modbus_crc16(uint8_t *data, uint16_t length) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
return crc;
}
/**
* Send Modbus RTU frame
*
* @param serial HardwareSerial object
* @param address Slave address (1-247)
* @param function Function code
* @param data Data section
* @param dataLen Data length
*/
void send_modbus_frame(HardwareSerial &serial, uint8_t address, uint8_t function,
const uint8_t *data, uint16_t dataLen) {
// Create send buffer
uint16_t totalLen = 1 + 1 + dataLen + 2; // Address + Function code + Data + CRC
uint8_t buffer[totalLen];
// Fill address and function code
buffer[0] = address;
buffer[1] = function;
// Copy data
memcpy(&buffer[2], data, dataLen);
// Calculate CRC (excluding CRC section)
uint16_t crc = modbus_crc16(buffer, 2 + dataLen);
// Add CRC (little-endian: low byte first)
buffer[2 + dataLen] = crc & 0xFF; // CRC low byte
buffer[3 + dataLen] = (crc >> 8) & 0xFF; // CRC high byte
// Send complete frame
for (uint16_t i = 0; i < totalLen; i++) {
serial.write(buffer[i]);
}
// Flush send buffer to ensure all data is sent
serial.flush();
}
// Encapsulation of common Modbus functions
/**
* Send "Read Holding Registers" request
*
* @param serial HardwareSerial object
* @param address Slave address
* @param startReg Start register address
* @param numRegs Number of registers to read
*/
void modbus_read_registers(HardwareSerial &serial, uint8_t address,
uint16_t startReg, uint16_t numRegs) {
uint8_t data[4];
// Fill register address and quantity in big-endian
data[0] = (startReg >> 8) & 0x
1-dac-16ch.zip (Size: 1.47 KB / Downloads: 176)
BIN file (you can use esp32 download tool download to ESP32-S3 with address 0x0 then directly to use) download:
1-dac-16ch.ino.merged.zip (Size: 205.57 KB / Downloads: 174)
YouTube: https://www.youtube.com/c/KinCony
Online Store: https://shop.kincony.com
Alibaba Store: https://kincony.en.alibaba.com/
Online Store: https://shop.kincony.com
Alibaba Store: https://kincony.en.alibaba.com/

