diff --git a/README.md b/README.md index d126b3e..bbf85c0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,15 @@ DShanMCU-Yat_ESP32 +UART2 +- TX: GPIO17 +- RX: GPIO16 +- RTS: SD_D0 GPIO07 +- CTS: SD_D1 GPIO08 +``` +idf.py add-dependency esp-modbus +``` ## How to use example We encourage the users to use the example as a template for the new projects. diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 7b5b7c9..da0d7e3 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -2,5 +2,7 @@ idf_component_register( SRCS main.cpp console_settings.h console_settings.c + modbus_params.h modbus_params.c + Modbus.h Modbus.cpp INCLUDE_DIRS "." ) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index f9af9ed..1da7024 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -16,4 +16,101 @@ menu "Dual Led Controller Configuration" ignore empty lines (the example would continue), or break on empty lines (the example would stop after an empty line). + + config MB_UART_PORT_ONE + bool + default y + depends on (ESP_CONSOLE_UART_NUM !=1) && (SOC_UART_NUM > 1) + + config MB_UART_PORT_TWO + bool + default y + depends on (ESP_CONSOLE_UART_NUM !=2) && (SOC_UART_NUM > 2) + + config MB_UART_PORT_NUM + int "UART port number" + range 0 2 if MB_UART_PORT_TWO + default 2 if MB_UART_PORT_TWO + range 0 1 if MB_UART_PORT_ONE + default 1 if MB_UART_PORT_ONE + help + UART communication port number for Modbus example. + + config MB_UART_BAUD_RATE + int "UART communication speed" + range 1200 115200 + default 115200 + help + UART communication speed for Modbus example. + + config MB_UART_RXD + int "UART RXD pin number" + range 0 34 if IDF_TARGET_ESP32 + range 0 23 if IDF_TARGET_ESP32C6 + range 0 56 if IDF_TARGET_ESP32P4 + default 22 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32P4 + range 0 46 if IDF_TARGET_ESP32S2 + range 0 47 if IDF_TARGET_ESP32S3 + range 0 19 if IDF_TARGET_ESP32C3 + range 0 20 if IDF_TARGET_ESP32C2 + range 0 27 if IDF_TARGET_ESP32H2 + default 8 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 8 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2 + help + GPIO number for UART RX pin. See UART documentation for more information + about available pin numbers for UART. + + config MB_UART_TXD + int "UART TXD pin number" + range 0 34 if IDF_TARGET_ESP32 + range 0 23 if IDF_TARGET_ESP32C6 + range 0 56 if IDF_TARGET_ESP32P4 + default 23 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32P4 + range 0 46 if IDF_TARGET_ESP32S2 + range 0 47 if IDF_TARGET_ESP32S3 + range 0 19 if IDF_TARGET_ESP32C3 + range 0 20 if IDF_TARGET_ESP32C2 + range 0 27 if IDF_TARGET_ESP32H2 + default 9 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 9 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2 + help + GPIO number for UART TX pin. See UART documentation for more information + about available pin numbers for UART. + + config MB_UART_RTS + int "UART RTS pin number" + range 0 34 if IDF_TARGET_ESP32 + range 0 56 if IDF_TARGET_ESP32P4 + range 0 23 if IDF_TARGET_ESP32C6 + default 18 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C6 + default 20 if IDF_TARGET_ESP32P4 + range 0 46 if IDF_TARGET_ESP32S2 + range 0 47 if IDF_TARGET_ESP32S3 + range 0 19 if IDF_TARGET_ESP32C3 + range 0 20 if IDF_TARGET_ESP32C2 + range 0 27 if IDF_TARGET_ESP32H2 + default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 10 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2 + help + GPIO number for UART RTS pin. This pin is connected to + ~RE/DE pin of RS485 transceiver to switch direction. + See UART documentation for more information about available pin + numbers for UART. + + choice MB_COMM_MODE + prompt "Modbus communication mode" + default MB_COMM_MODE_RTU if CONFIG_FMB_COMM_MODE_RTU_EN + help + Selection of Modbus communication mode option for Modbus. + + config MB_COMM_MODE_RTU + bool "RTU mode" + depends on FMB_COMM_MODE_RTU_EN + + config MB_COMM_MODE_ASCII + bool "ASCII mode" + depends on FMB_COMM_MODE_ASCII_EN + + endchoice + endmenu diff --git a/main/Modbus.cpp b/main/Modbus.cpp new file mode 100644 index 0000000..56e5379 --- /dev/null +++ b/main/Modbus.cpp @@ -0,0 +1,233 @@ +#include "Modbus.h" +#include "modbus_params.h" +#include "sdkconfig.h" +#include +#include + +static const char *TAG = "modbus"; + +#define MB_PORT_NUM (CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection +#define MB_DEV_SPEED (CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART + +static void *master_handle = NULL; + +// Enumeration of all supported CIDs for device (used in parameter definition table) +enum { + CID_INP_DATA_0 = 0, + CID_HOLD_DATA_0, + CID_INP_DATA_1, + CID_HOLD_DATA_1, + CID_INP_DATA_2, + CID_HOLD_DATA_2, + CID_HOLD_TEST_REG, + CID_RELAY_P1, + CID_RELAY_P2, + CID_DISCR_P1, +#if CONFIG_FMB_EXT_TYPE_SUPPORT + CID_HOLD_U8_A, + CID_HOLD_U8_B, + CID_HOLD_U16_AB, + CID_HOLD_U16_BA, + CID_HOLD_UINT32_ABCD, + CID_HOLD_UINT32_CDAB, + CID_HOLD_UINT32_BADC, + CID_HOLD_UINT32_DCBA, + CID_HOLD_FLOAT_ABCD, + CID_HOLD_FLOAT_CDAB, + CID_HOLD_FLOAT_BADC, + CID_HOLD_FLOAT_DCBA, + CID_HOLD_DOUBLE_ABCDEFGH, + CID_HOLD_DOUBLE_HGFEDCBA, + CID_HOLD_DOUBLE_GHEFCDAB, + CID_HOLD_DOUBLE_BADCFEHG, +#endif + CID_COUNT +}; + +// Enumeration of modbus device addresses accessed by master device +enum { + MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here) +}; + +#define STR(fieldname) ((const char *)(fieldname)) + +// The macro to get offset for parameter in the appropriate structure +#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1)) +#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1)) +#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1)) +// Discrete offset macro +#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1)) + +#define TEST_INPUT_REG_START(field) (INPUT_OFFSET(field) >> 1) +#define TEST_INPUT_REG_SIZE(field) (sizeof(((input_reg_params_t *)0)->field) >> 1) +// Example Data (Object) Dictionary for Modbus parameters: +// The CID field in the table must be unique. +// Modbus Slave Addr field defines slave address of the device with correspond parameter. +// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such). +// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the +// characteristic accordingly. The Instance Offset defines offset in the appropriate parameter structure that will be +// used as instance to save parameter value. Data Type, Data Size specify type of the characteristic and its data size. +// Parameter Options field specifies the options that can be used to process parameter value (limits or masks). +// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, +// factory mode values and etc). +const mb_parameter_descriptor_t device_parameters[] = { + // { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, + // Data Size, Parameter Options, Access Mode} + {CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, + TEST_INPUT_REG_START(input_data0), TEST_INPUT_REG_SIZE(input_data0), INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, + 4, OPTS(TEST_TEMP_MIN, TEST_TEMP_MAX, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_data0), TEST_HOLD_REG_SIZE(holding_data0), HOLD_OFFSET(holding_data0), + PARAM_TYPE_FLOAT, 4, OPTS(TEST_HUMI_MIN, TEST_HUMI_MAX, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, TEST_INPUT_REG_START(input_data1), + TEST_INPUT_REG_SIZE(input_data1), INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, + OPTS(TEST_TEMP_MIN, TEST_TEMP_MAX, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_data1), TEST_HOLD_REG_SIZE(holding_data1), HOLD_OFFSET(holding_data1), + PARAM_TYPE_FLOAT, 4, OPTS(TEST_HUMI_MIN, TEST_HUMI_MAX, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, TEST_INPUT_REG_START(input_data2), + TEST_INPUT_REG_SIZE(input_data2), INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, + OPTS(TEST_TEMP_MIN, TEST_TEMP_MAX, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_data2), TEST_HOLD_REG_SIZE(holding_data2), HOLD_OFFSET(holding_data2), + PARAM_TYPE_FLOAT, 4, OPTS(TEST_HUMI_MIN, TEST_HUMI_MAX, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TEST_HOLD_REG_START(test_regs), + TEST_ARR_REG_SZ, HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, (TEST_ARR_REG_SZ * 2), + OPTS(TEST_TEMP_MIN, TEST_TEMP_MAX, TEST_ASCII_BIN), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 2, 6, COIL_OFFSET(coils_port0), + PARAM_TYPE_U8, 1, OPTS(0xAA, 0x15, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 10, 6, COIL_OFFSET(coils_port1), + PARAM_TYPE_U8, 1, OPTS(0x55, 0x2A, 0), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_DISCR_P1, STR("DiscreteInpP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_DISCRETE, 2, 7, + DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1, OPTS(0xAA, 0x15, 0), PAR_PERMS_READ_WRITE_TRIGGER}, +#if CONFIG_FMB_EXT_TYPE_SUPPORT + {CID_HOLD_U8_A, STR("U8_A"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TEST_HOLD_REG_START(holding_u8_a), + TEST_HOLD_REG_SIZE(holding_u8_a), HOLD_OFFSET(holding_u8_a), PARAM_TYPE_U8_A, + (TEST_HOLD_REG_SIZE(holding_u8_a) << 1), OPTS(CHAR_MIN, 0x0055, 0x0055), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_U8_B, STR("U8_B"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TEST_HOLD_REG_START(holding_u8_b), + TEST_HOLD_REG_SIZE(holding_u8_b), HOLD_OFFSET(holding_u8_b), PARAM_TYPE_U8_B, + (TEST_HOLD_REG_SIZE(holding_u8_b) << 1), OPTS(0, 0x5500, 0x5500), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_U16_AB, STR("U16_AB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TEST_HOLD_REG_START(holding_u16_ab), + TEST_HOLD_REG_SIZE(holding_u16_ab), HOLD_OFFSET(holding_u16_ab), PARAM_TYPE_U16_AB, + (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_U16_BA, STR("U16_BA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TEST_HOLD_REG_START(holding_u16_ba), + TEST_HOLD_REG_SIZE(holding_u16_ba), HOLD_OFFSET(holding_u16_ba), PARAM_TYPE_U16_BA, + (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_UINT32_ABCD, STR("UINT32_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_uint32_abcd), TEST_HOLD_REG_SIZE(holding_uint32_abcd), + HOLD_OFFSET(holding_uint32_abcd), PARAM_TYPE_U32_ABCD, (TEST_HOLD_REG_SIZE(holding_uint32_abcd) << 1), + OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_UINT32_CDAB, STR("UINT32_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_uint32_cdab), TEST_HOLD_REG_SIZE(holding_uint32_cdab), + HOLD_OFFSET(holding_uint32_cdab), PARAM_TYPE_U32_CDAB, (TEST_HOLD_REG_SIZE(holding_uint32_cdab) << 1), + OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_UINT32_BADC, STR("UINT32_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_uint32_badc), TEST_HOLD_REG_SIZE(holding_uint32_badc), + HOLD_OFFSET(holding_uint32_badc), PARAM_TYPE_U32_BADC, (TEST_HOLD_REG_SIZE(holding_uint32_badc) << 1), + OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_UINT32_DCBA, STR("UINT32_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_uint32_dcba), TEST_HOLD_REG_SIZE(holding_uint32_dcba), + HOLD_OFFSET(holding_uint32_dcba), PARAM_TYPE_U32_DCBA, (TEST_HOLD_REG_SIZE(holding_uint32_dcba) << 1), + OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_FLOAT_ABCD, STR("FLOAT_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_float_abcd), TEST_HOLD_REG_SIZE(holding_float_abcd), HOLD_OFFSET(holding_float_abcd), + PARAM_TYPE_FLOAT_ABCD, (TEST_HOLD_REG_SIZE(holding_float_abcd) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), + PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_FLOAT_CDAB, STR("FLOAT_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_float_cdab), TEST_HOLD_REG_SIZE(holding_float_cdab), HOLD_OFFSET(holding_float_cdab), + PARAM_TYPE_FLOAT_CDAB, (TEST_HOLD_REG_SIZE(holding_float_cdab) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), + PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_FLOAT_BADC, STR("FLOAT_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_float_badc), TEST_HOLD_REG_SIZE(holding_float_badc), HOLD_OFFSET(holding_float_badc), + PARAM_TYPE_FLOAT_BADC, (TEST_HOLD_REG_SIZE(holding_float_badc) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), + PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_FLOAT_DCBA, STR("FLOAT_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_float_dcba), TEST_HOLD_REG_SIZE(holding_float_dcba), HOLD_OFFSET(holding_float_dcba), + PARAM_TYPE_FLOAT_DCBA, (TEST_HOLD_REG_SIZE(holding_float_dcba) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), + PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DOUBLE_ABCDEFGH, STR("DOUBLE_ABCDEFGH"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_double_abcdefgh), TEST_HOLD_REG_SIZE(holding_double_abcdefgh), + HOLD_OFFSET(holding_double_abcdefgh), PARAM_TYPE_DOUBLE_ABCDEFGH, + (TEST_HOLD_REG_SIZE(holding_double_abcdefgh) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DOUBLE_HGFEDCBA, STR("DOUBLE_HGFEDCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_double_hgfedcba), TEST_HOLD_REG_SIZE(holding_double_hgfedcba), + HOLD_OFFSET(holding_double_hgfedcba), PARAM_TYPE_DOUBLE_HGFEDCBA, + (TEST_HOLD_REG_SIZE(holding_double_hgfedcba) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DOUBLE_GHEFCDAB, STR("DOUBLE_GHEFCDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_double_ghefcdab), TEST_HOLD_REG_SIZE(holding_double_ghefcdab), + HOLD_OFFSET(holding_double_ghefcdab), PARAM_TYPE_DOUBLE_GHEFCDAB, + (TEST_HOLD_REG_SIZE(holding_double_ghefcdab) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER}, + {CID_HOLD_DOUBLE_BADCFEHG, STR("DOUBLE_BADCFEHG"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, + TEST_HOLD_REG_START(holding_double_badcfehg), TEST_HOLD_REG_SIZE(holding_double_badcfehg), + HOLD_OFFSET(holding_double_badcfehg), PARAM_TYPE_DOUBLE_BADCFEHG, + (TEST_HOLD_REG_SIZE(holding_double_badcfehg) << 1), OPTS(0, TEST_VALUE, TEST_VALUE), PAR_PERMS_READ_WRITE_TRIGGER} +#endif +}; + +// Modbus master initialization +static esp_err_t master_init(void) { + // Initialize Modbus controller + mb_communication_info_t comm; + comm.ser_opts.port = MB_PORT_NUM; +#if CONFIG_MB_COMM_MODE_ASCII + comm.ser_opts.mode = MB_ASCII; +#elif CONFIG_MB_COMM_MODE_RTU + comm.ser_opts.mode = MB_RTU; +#endif + + comm.ser_opts.baudrate = MB_DEV_SPEED; + comm.ser_opts.parity = MB_PARITY_NONE; + comm.ser_opts.uid = 0; + comm.ser_opts.response_tout_ms = 1000; + comm.ser_opts.data_bits = UART_DATA_8_BITS; + comm.ser_opts.stop_bits = UART_STOP_BITS_1; + + esp_err_t err = mbc_master_create_serial(&comm, &master_handle); + MB_RETURN_ON_FALSE((master_handle != NULL), ESP_ERR_INVALID_STATE, TAG, "mb controller initialization fail."); + MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, "mb controller initialization fail, returns(0x%x).", + (int)err); + + // Set UART pin numbers + err = uart_set_pin(static_cast(MB_PORT_NUM), CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD, + CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE); + MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, + "mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err); + + err = mbc_master_start(master_handle); + MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, "mb controller start fail, returned (0x%x).", + (int)err); + + // Set driver mode to Half Duplex + err = uart_set_mode(static_cast(MB_PORT_NUM), UART_MODE_RS485_HALF_DUPLEX); + MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, + "mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err); + + vTaskDelay(5); + err = mbc_master_set_descriptor(master_handle, &device_parameters[0], num_device_parameters); + MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, "mb controller set descriptor fail, returns(0x%x).", + (int)err); + ESP_LOGI(TAG, "Modbus master stack initialized..."); + return err; +} + +Modbus::Modbus() { + const uart_port_t uart_num = UART_NUM_2; + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, + .rx_flow_ctrl_thresh = 122, + }; + // Configure UART parameters + ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config)); + + ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, 17, 16, 7, 8)); + + // Setup UART buffered IO with event queue + const int uart_buffer_size = (1024 * 2); + QueueHandle_t uart_queue; + // Install UART driver using an event queue here + ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, uart_buffer_size, uart_buffer_size, 10, &uart_queue, 0)); +} diff --git a/main/Modbus.h b/main/Modbus.h new file mode 100644 index 0000000..b0e9b43 --- /dev/null +++ b/main/Modbus.h @@ -0,0 +1,9 @@ +#ifndef __MODBUS_H__ +#define __MODBUS_H__ + +class Modbus { +public: + Modbus(); +}; + +#endif // __MODBUS_H__ \ No newline at end of file diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..e3ec552 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,17 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: '>=4.1.0' + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true + espressif/esp-modbus: '*' diff --git a/main/modbus_params.c b/main/modbus_params.c new file mode 100644 index 0000000..8a5bbd4 --- /dev/null +++ b/main/modbus_params.c @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/*===================================================================================== + * Description: + * C file to define parameter storage instances + *====================================================================================*/ +#include +#include "modbus_params.h" + +// Here are the user defined instances for device parameters packed by 1 byte +// These are keep the values that can be accessed from Modbus master +holding_reg_params_t holding_reg_params = { 0 }; + +input_reg_params_t input_reg_params = { 0 }; + +coil_reg_params_t coil_reg_params = { 0 }; + +discrete_reg_params_t discrete_reg_params = { 0 }; diff --git a/main/modbus_params.h b/main/modbus_params.h new file mode 100644 index 0000000..fd19f92 --- /dev/null +++ b/main/modbus_params.h @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/*===================================================================================== + * Description: + * The Modbus parameter structures used to define Modbus instances that + * can be addressed by Modbus protocol. Define these structures per your needs in + * your application. Below is just an example of possible parameters. + *====================================================================================*/ +#ifndef _DEVICE_PARAMS +#define _DEVICE_PARAMS + +#include +#include "sdkconfig.h" + +// This file defines structure of modbus parameters which reflect correspond modbus address space +// for each modbus register type (coils, discreet inputs, holding registers, input registers) +#pragma pack(push, 1) +typedef struct +{ + uint8_t discrete_input0:1; + uint8_t discrete_input1:1; + uint8_t discrete_input2:1; + uint8_t discrete_input3:1; + uint8_t discrete_input4:1; + uint8_t discrete_input5:1; + uint8_t discrete_input6:1; + uint8_t discrete_input7:1; + uint8_t discrete_input_port1; + uint8_t discrete_input_port2; +} discrete_reg_params_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct +{ + uint8_t coils_port0; + uint8_t coils_port1; + uint8_t coils_port2; +} coil_reg_params_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct +{ + float input_data0; // 0 + float input_data1; // 2 + float input_data2; // 4 + float input_data3; // 6 + uint16_t data[150]; // 8 + 150 = 158 + float input_data4; // 158 + float input_data5; + float input_data6; + float input_data7; + uint16_t data_block1[150]; +} input_reg_params_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct +{ +#if CONFIG_FMB_EXT_TYPE_SUPPORT + uint16_t holding_u8_a[2]; + uint16_t holding_u8_b[2]; + uint16_t holding_u16_ab[2]; + uint16_t holding_u16_ba[2]; + uint32_t holding_uint32_abcd[2]; + uint32_t holding_uint32_cdab[2]; + uint32_t holding_uint32_badc[2]; + uint32_t holding_uint32_dcba[2]; + float holding_float_abcd[2]; + float holding_float_cdab[2]; + float holding_float_badc[2]; + float holding_float_dcba[2]; + double holding_double_abcdefgh[2]; + double holding_double_hgfedcba[2]; + double holding_double_ghefcdab[2]; + double holding_double_badcfehg[2]; + uint32_t holding_area2_end; +#endif + float holding_data0; + float holding_data1; + float holding_data2; + float holding_data3; + uint16_t test_regs[150]; + float holding_data4; + float holding_data5; + float holding_data6; + float holding_data7; + uint32_t holding_area1_end; +} holding_reg_params_t; +#pragma pack(pop) + +extern holding_reg_params_t holding_reg_params; +extern input_reg_params_t input_reg_params; +extern coil_reg_params_t coil_reg_params; +extern discrete_reg_params_t discrete_reg_params; + +#endif // !defined(_DEVICE_PARAMS)