From 040a5ff654ffd3378f959bb7547e303aaf3ba97f Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Thu, 6 Nov 2025 19:37:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=BF=D0=BE=20=D1=81=D0=B8=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D0=BA=D1=81=D0=B8=D1=81=D1=83=20=D0=B8=20doxygen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Inc/__modbus_compat.h | 15 +- Inc/modbus.h | 30 +-- Inc/modbus_coils.h | 20 +- Inc/modbus_core.h | 30 +-- Inc/modbus_devid.h | 11 +- Inc/modbus_diag.h | 11 +- Inc/modbus_holdregs.h | 14 +- Inc/modbus_inputregs.h | 14 +- Inc/modbus_master.h | 44 ++--- Inc/modbus_slave.h | 9 +- Inc/rs_message.h | 13 +- README.md | 413 ++++++++++++++++++++--------------------- Src/__modbus_compat.c | 9 +- Src/modbus.c | 20 +- Src/modbus_coils.c | 12 +- Src/modbus_core.c | 4 +- Src/modbus_devid.c | 6 +- Src/modbus_diag.c | 4 +- Src/modbus_holdregs.c | 15 +- Src/modbus_inputregs.c | 15 +- Src/modbus_master.c | 80 +++++++- Src/modbus_slave.c | 10 +- Src/rs_message.c | 8 +- __modbus_config.h | 1 + __modbus_data.h | 14 +- 25 files changed, 460 insertions(+), 362 deletions(-) diff --git a/Inc/__modbus_compat.h b/Inc/__modbus_compat.h index 67e1c6e..5b7a95c 100644 --- a/Inc/__modbus_compat.h +++ b/Inc/__modbus_compat.h @@ -1,15 +1,18 @@ /** -************************************************************************** -* @file __modbus_compat.h -* @brief Модуль для совместимости библиотеки MODBUS. -************************************************************************** +******************************************************************************* +* @file __modbus_compat.h +* @brief Модуль для совместимости библиотеки MODBUS. +******************************************************************************* * @details Файл содержит API старых функций, а также заглушки для отключенных модулей: -*************************************************************************/ -#include "modbus.h" +******************************************************************************/ +#include "modbus_core.h" /** @addtogroup MODBUS_LEGACY_API Legacy API * @ingroup MODBUS_FUNCTIONS + * @brief Старые API функций, сохранённые для обратной совместимости. + * @note Не используйте эти функции в новом коде. Они могут быть удалены в будущих версиях. + * Вместо них используйте функции из основных групп MODBUS API. * @{ */ diff --git a/Inc/modbus.h b/Inc/modbus.h index c8714da..121630c 100644 --- a/Inc/modbus.h +++ b/Inc/modbus.h @@ -1,20 +1,22 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus.h * @brief Главный заголовочный файл Modbus библиотеки -****************************************************************************** +******************************************************************************* @addtogroup MODBUS Modbus tools -****************************************************************************** +@brief Библиотека реализующая протокол Modbus +******************************************************************************* @addtogroup MODBUS_FUNCTIONS Main API for Modbus Library @ingroup MODBUS +@brief Публичные функции библиотеки @{ -****************************************************************************** +******************************************************************************* * @details Объединяющий файл для подключения всей функциональности Modbus. Подключает все необходимые модули: -@section init Инструкция по подключению +@section Start Инструкция по подключению Для корректной работы надо: - Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика @@ -23,20 +25,20 @@ - Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1 - После для запуска Modbus: - @verbatim + @code //----------------Слейв модбас----------------// #include "modbus.h" MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); MODBUS_SlaveStart(&hmodbus1, NULL); - @endverbatim - @verbatim + @endcode + @code //----------------Мастер модбас----------------// #include "modbus.h" MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); - MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER); + MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); @@ -56,10 +58,10 @@ } } } - @endverbatim + @endcode -@section Подключаемые модули: +@section modules Подключаемые модули: - rs_message.h - работа с uart - modbus_core.h - базовые определения - modbus_coils.h - работа с дискретными выходами @@ -69,7 +71,7 @@ - modbus_diag.h - диагностика modbus -@section Структура данных Modbus +@section data Структура данных Modbus #### Holding/Input Registers: - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель. @@ -108,11 +110,11 @@ #ifdef MODBUS_ENABLE_MASTER -#define MODBUS_MODE_MASTER 1 +#define MODBUS_MODE_MASTER 1 ///< Псевдо-enum: Режим мастер #endif #ifdef MODBUS_ENABLE_SLAVE -#define MODBUS_MODE_SLAVE 0 +#define MODBUS_MODE_SLAVE 0 ///< Псевдо-enum: Режим слейв #endif ///////////////////////////////////////////////////////////////////// diff --git a/Inc/modbus_coils.h b/Inc/modbus_coils.h index 6dc0c19..f01cafd 100644 --- a/Inc/modbus_coils.h +++ b/Inc/modbus_coils.h @@ -1,23 +1,27 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_coils.h * @brief Работа с коилами Modbus -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_COILS Coils Tools @ingroup MODBUS_INTERNAL -****************************************************************************** +@brief Функции для работы с коилами +******************************************************************************* * @details +Модуль для доступа к coils внутри программы: +- Функции для доступа к coils по глобальным адресам +- Макросы для доступа к coils по локальным адресам + Модуль предоставляет функции и макросы для работы с битовыми данными: - Чтение coils (0x01) Упаковка битов в байты - Запись одиночного coil (0x05) Установка/сброс бита - Запись множественных coils (0x0F) - распаковка байтов в биты -- Макросы для локального доступа к coils -@section Организация битовых данных: +@section cbits Организация битовых данных: Coils упакованы в 16-битные слова для эффективного использования памяти. Биты нумеруются от младшего к старшему внутри каждого слова. -@section Адресация: +@section caddr Адресация: - Глобальная - абсолютный адрес в пространстве Modbus - Локальная - относительный адрес внутри массива coils - Макросы автоматически вычисляют смещения и маски @@ -44,7 +48,7 @@ Coils упакованы в 16-битные слова для эффективн /** * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access * @ingroup MODBUS_FUNCTIONS - * @brief Функции для доступа к данным модбас + * @brief API для доступа к данным модбас внутри программы * @{ */ @@ -101,7 +105,7 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS - @{ + * @{ */ /* Обработать функцию Read Coils (01 - 0x01) */ uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg); diff --git a/Inc/modbus_core.h b/Inc/modbus_core.h index 1e14879..ef7e25e 100644 --- a/Inc/modbus_core.h +++ b/Inc/modbus_core.h @@ -1,12 +1,13 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_core.h * @brief Ядро Modbus протокола - определения и структуры -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_INTERNAL Modbus Internal Tools @ingroup MODBUS +@brief Внутренние штуки библиотеки @{ -****************************************************************************** +******************************************************************************* * @details Базовые определения для реализации Modbus RTU устройства: - Структуры сообщений Modbus @@ -14,7 +15,7 @@ Константы размеров полей Вспомогательные макросы -@section Структура сообщения: +@section msg Структура сообщения: [ADDR][FUNC][DATA...][CRC] - Адрес: 1 байт - Функция: 1 байт @@ -28,12 +29,13 @@ #include "modbus_config.h" #include "modbus_data.h" #include "__crc_algs.h" +#include "__modbus_compat.h" /** * @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools * @ingroup MODBUS * @brief Определения протокола модбас - @{ + * @{ */ ///////////////////////////////////////////////////////////////////// @@ -93,7 +95,7 @@ typedef enum //MB_FunctonTypeDef /* COMMANDS */ // reading FC_R_COILS = 0x01, ///< Чтение битовых ячеек - //FC_R_DISC_IN = 0x02, ///< Чтение дискретных входов + FC_R_DISC_IN = 0x02, ///< Чтение дискретных входов #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS FC_R_HOLD_REGS = 0x03, ///< Чтение входных регистров FC_R_IN_REGS = 0x04, ///< Чтение регистров хранения @@ -114,7 +116,7 @@ typedef enum //MB_FunctonTypeDef /* ERRORS */ // error reading FC_ERR_R_COILS = FC_R_COILS + FC_ERR_VALUES_START, ///< Ошибка чтения битовых ячеек - //FC_ERR_R_DISC_IN = FC_R_DISC_IN + FC_ERR_VALUES_START, ///< Ошибка чтения дискретных входов + FC_ERR_R_DISC_IN = FC_R_DISC_IN + FC_ERR_VALUES_START, ///< Ошибка чтения дискретных входов FC_ERR_R_IN_REGS = FC_R_IN_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения регистров хранения FC_ERR_R_HOLD_REGS = FC_R_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения входных регистров @@ -124,8 +126,8 @@ typedef enum //MB_FunctonTypeDef FC_ERR_W_COILS = FC_W_COILS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек FC_ERR_W_HOLD_REGS = FC_W_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких регистров - FC_ERR_R_DIAGNOSTIC = FC_R_DIAGNOSTICS + FC_ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства - MB_FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве + FC_ERR_R_DIAGNOSTIC = FC_R_DIAGNOSTICS + FC_ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства + FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве }MB_FunctonTypeDef; /** @brief Enum for MEI func codes */ @@ -217,7 +219,7 @@ extern RS_MsgTypeDef MODBUS_MSG; * @param _parr_ - массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @note Используется вместе с @ref MB_Set_Coil_Mask - @verbatim Пояснение выражений + @code Пояснение выражений - (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_ Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0) @@ -225,14 +227,14 @@ extern RS_MsgTypeDef MODBUS_MSG; |register[0]----| |register[1]----| |skip this------| |get this-------| |shift to 14 bit| - @endverbatim + @endcode */ #define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) /** * @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра * @param _coil_ - Номер коила от начала массива _arr_. * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr - @verbatim Пояснение выражений + @code Пояснение выражений - (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра - _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре @@ -244,7 +246,7 @@ extern RS_MsgTypeDef MODBUS_MSG; |register[0]----| |register[1]----| |skip this------| |get this-------| |shift to 14 bit| - @endverbatim + @endcode */ #define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) @@ -289,7 +291,7 @@ extern RS_MsgTypeDef MODBUS_MSG; /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS - @{ + * @{ */ /* Реализация этих функций лежит в modbus_data.c */ diff --git a/Inc/modbus_devid.h b/Inc/modbus_devid.h index 4928222..b232e3d 100644 --- a/Inc/modbus_devid.h +++ b/Inc/modbus_devid.h @@ -1,18 +1,19 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_devid.h * @brief Идентификаторы устройства Modbus -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_DEVID Device Identifications Tools @ingroup MODBUS_INTERNAL -****************************************************************************** +@brief Функции для работы с идентификаторами устройства +******************************************************************************* * @details Модуль реализации функции Read Device Identifications (0x2B): - Базовая идентификация (Vendor, Product, Revision) - Расширенная идентификация (URL, Model, User fields) - Поддержка потоковой передачи больших объектов -@section Объекты идентификации: +@section devobj Объекты идентификации: - VendorName, ProductCode, Revision - обязательные - VendorUrl, ProductName, ModelName - опциональные - User objects - пользовательские поля @@ -108,7 +109,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj); /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS - @{ + * @{ */ /* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */ diff --git a/Inc/modbus_diag.h b/Inc/modbus_diag.h index 4d8671a..94b0349 100644 --- a/Inc/modbus_diag.h +++ b/Inc/modbus_diag.h @@ -1,18 +1,19 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_diag.h * @brief Диагностика устройства Modbus -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_DIAG Diagnostics Tools @ingroup MODBUS_INTERNAL -****************************************************************************** +@brief Функции для работы с диагностикой +******************************************************************************* * @details Модуль реализации Diagnostics (Serial Line only) (0x08): - Полная поддержка всех подфункций диагностики - Возможность выставить/сбросить любой бит в диагностическом регистре - Сбор статистики работы устройства - Управление режимами работы -****************************************** ************************************/ +******************************************************************************/ #ifndef __MODBUS_DIAG_H_ #define __MODBUS_DIAG_H_ #include "modbus_core.h" @@ -100,7 +101,7 @@ void MB_Diagnostics_SlaveBusyCnt(void); /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS - @{ + * @{ */ /* Обработка команды диагностики (0x08) */ diff --git a/Inc/modbus_holdregs.h b/Inc/modbus_holdregs.h index 7ab4e67..98f6bef 100644 --- a/Inc/modbus_holdregs.h +++ b/Inc/modbus_holdregs.h @@ -1,18 +1,22 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_holdregs.h * @brief Работа с регистрами хранения Modbus -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_INS Input Register Tools @ingroup MODBUS_INTERNAL -****************************************************************************** +@brief Функции для работы с входными регистрами +******************************************************************************* * @details +Модуль для доступа к регистрам внутри программы: +- Функции для доступа к регистрам хранения по глобальным адресам + Модуль обработки команд для регистров хранения (Holding Registers): - Чтение множества регистров (0x03) - Запись одиночного регистра (0x06) - Запись множества регистров (0x10) -@section Регистры хранения: +@section hold Регистры хранения: - Read/Write доступ - 16-битные значения (uint16_t) ******************************************************************************/ @@ -41,7 +45,7 @@ uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS - @{ + * @{ */ /* Обработать функцию Read Holding Registers (03 - 0x03) */ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); diff --git a/Inc/modbus_inputregs.h b/Inc/modbus_inputregs.h index 7912553..ff3f9d1 100644 --- a/Inc/modbus_inputregs.h +++ b/Inc/modbus_inputregs.h @@ -1,16 +1,20 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_inputregs.h * @brief Работа с входными регистрами Modbus -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_HOLD Holding Registers Tools @ingroup MODBUS_INTERNAL -****************************************************************************** +@brief Функции для работы с регистрами хранения +******************************************************************************* * @details +Модуль для доступа к регистрам внутри программы: +- Функции для доступа к входным регистрам по глобальным адресам + Модуль обработки команд для входных регистров (Input Registers): - Чтение множества регистров (0x04) -@section Входные регистры: +@section in Входные регистры: - Read-Only доступ - 16-битные значения ******************************************************************************/ @@ -40,7 +44,7 @@ uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions * @ingroup MODBUS_INTERNAL * @brief Функции обработки запросов модбас - @{ + * @{ */ /* Обработать функцию Read Input Registers (04 - 0x04) */ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); diff --git a/Inc/modbus_master.h b/Inc/modbus_master.h index 60df97f..84cf4ea 100644 --- a/Inc/modbus_master.h +++ b/Inc/modbus_master.h @@ -1,13 +1,14 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_master.h * @brief Главный заголовочный файл Modbus библиотеки -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_MASTER Modbus master funtions @ingroup MODBUS_CMD_PROCESS_FUNCTIONS -****************************************************************************** +@brief Функции для работы в режиме Master +******************************************************************************* * @details -Модуль реализации обработки UART сообщение в режиме мастер +Модуль реализации Modbus в режиме мастер ******************************************************************************/ #ifndef __MODBUS_MASTER_H_ #define __MODBUS_MASTER_H_ @@ -17,7 +18,7 @@ /** * @addtogroup MODBUS_REQUEST_MSG API for Master Requests * @ingroup MODBUS_FUNCTIONS - * @brief Макросы для создания запросов в режиме мастер + * @brief API для формирования фрейма-запроса в режиме мастер * @details Примеры использования: * @code * // Чтение 10 holding registers начиная с адреса 0 @@ -80,24 +81,20 @@ RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t obj * @code * // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105 * uint16_t reg_value; - * if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, ®_value)) + * if(MB_RespGet_RegisterValue(modbus_msg, 105, ®_value)) * { * printf("Register 105 value: %d\n", reg_value); * } * * // Пример: Получить все запрошенные регистры - * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) - * { - * uint16_t value; - * if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) - * { - * printf("Register %d: %d\n", addr, value); - * } - * } + * uint16_t reg_value[125]; + * MB_RespGet_RegisterAll(modbus_msg) * @endcode * @{ */ - +/* Получить значение ВСЕХ регистров в ответе */ +int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr); +/* Получить значение регистра в ответе по его адресу */ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value); @@ -115,7 +112,7 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1 * @code * // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25 * int coil_state; - * if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state)) + * if(MB_RespGet_CoilState(modbus_msg, 25, &coil_state)) * { * printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF"); * } @@ -124,7 +121,7 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1 * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) * { * int state; - * if(MB_RespGet_CoilState(&MODBUS_MSG, addr, &state)) + * if(MB_RespGet_CoilState(modbus_msg, addr, &state)) * { * printf("Coil %d: %s\n", addr, state ? "ON" : "OFF"); * } @@ -132,7 +129,9 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1 * @endcode * @{ */ - +/* Получить состояние ВСЕХ coil в ответе */ +int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr); +/* Получить состояние coil в ответе по его адресу */ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state); /** MODBUS_REQ_COILS_API @@ -150,7 +149,7 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi * // Пример 1: Получить VendorName (ID = 0x00) * uint8_t length; * char vendor_name[64]; - * if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length)) + * if(MB_RespGet_ObjectById(modbus_msg, 0x00, vendor_name, &length)) * { * // получено * } @@ -159,12 +158,12 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi * uint8_t obj_id, obj_length; * char obj_data[256]; * - * int obj_count = MB_RespGet_NumberOfObjects(&MODBUS_MSG); + * int obj_count = MB_RespGet_NumberOfObjects(modbus_msg); * printf("Total objects: %d\n", obj_count); * * for(int i = 0; i < obj_count; i++) * { - * if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, i, &obj_id, obj_data, &obj_length)) + * if(MB_RespGet_ObjectByIndex(modbus_msg, i, &obj_id, obj_data, &obj_length)) * { * // получено * } @@ -196,7 +195,7 @@ int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_ * @code * // Получить данные диагностики (значение счетчика) * uint16_t counter_value; - * if(MB_RespGet_Diagnostic(&MODBUS_MSG, &counter_value)) + * if(MB_RespGet_Diagnostic(modbus_msg, &counter_value)) * { * printf("Counter value: %d\n", counter_value); * } @@ -204,6 +203,7 @@ int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_ * @{ */ +/* Получить */ int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data); /** MODBUS_REQ_DIAG_API diff --git a/Inc/modbus_slave.h b/Inc/modbus_slave.h index 9db55a4..9320c6b 100644 --- a/Inc/modbus_slave.h +++ b/Inc/modbus_slave.h @@ -1,13 +1,14 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_slave.h * @brief Главный заголовочный файл Modbus библиотеки -****************************************************************************** +******************************************************************************* @addtogroup MODBUS_SLAVE Modbus slave funtions @ingroup MODBUS_CMD_PROCESS_FUNCTIONS -****************************************************************************** +@brief Функции для работы в режиме Slave +******************************************************************************* * @details -Модуль реализации обработки UART сообщение в режиме слейв +Модуль реализации Modbus в режиме слейв ******************************************************************************/ #ifndef __MODBUS_SLAVE_H_ #define __MODBUS_SLAVE_H_ diff --git a/Inc/rs_message.h b/Inc/rs_message.h index 4920966..8723a98 100644 --- a/Inc/rs_message.h +++ b/Inc/rs_message.h @@ -1,29 +1,29 @@ /** -****************************************************************************** +******************************************************************************* * @file rs_message.h * @brief Библиотека обмена сообщениями по RS-интерфейсу -****************************************************************************** +******************************************************************************* @defgroup RS_TOOLS RS Tools @brief Всякое для работы по UART/RS @{ -****************************************************************************** +******************************************************************************* * @details Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom) через UART в режиме прерываний с поддержкой таймаутов. -@section Основные возможности: +@section posibility Основные возможности: - Прием/передача в прерываниях - Обработка IDLE линии для определения конца фрейма - Таймауты приема через TIM - Гибкая настройка размера сообщений -@section Использование: +@section usage Использование: 1. Определить структуру сообщения и размеры буфера 2. Реализовать weak-функции обработки сообщений 3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания 4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT() -@section Особенности: +@section features Особенности: - Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи - Состояния: отслеживается через флаги в RS_HandleTypeDef - Таймауты: контролируют максимальное время ожидания фрейма @@ -89,6 +89,7 @@ /** * @addtogroup RS_DEBUG Tools for debug RS/UART/TIM * @ingroup RS_TOOLS + * @brief Дефайны для отладки периферии * @{ */ diff --git a/README.md b/README.md index 6fcb33e..b20d31b 100644 --- a/README.md +++ b/README.md @@ -6,40 +6,40 @@ *Note: Файлы начинающиеся с `__` и которых **нет** в этом дереве являются **внутренними/непротестированными/недокументированными*** ``` -Modbus/ Иерархия модулей: -│ inc/ modbus -│ ├── modbus.h # Главный заголовочный файл modbus_slave -│ ├── modbus_core.h # Базовые определения и структуры modbus_master -│ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils -│ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs -│ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs -│ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid -│ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag -├── src/ └── rs_message -│ ├── modbus.c # Основная логика Modbus │ -│ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро) -│ ├── modbus_master.c # Основная логика Master Modbus ├── modbus_config -│ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data -│ ├── modbus_holdregs.c # Реализация регистров хранения └── __crc_algs -│ ├── modbus_inputregs.c # Реализация входных регистров -│ ├── modbus_devid.c # Реализация идентификации устройства -│ ├── modbus_data.c # Функции доступа к данным -│ └── rs_message.c # Реализация драйвера RS -├── __modbus_config.h # Конфигурация Modbus (надо заменить) -├── __modbus_data.h # Структуры данных (надо заменить) -└── __modbus_data.c # Функции доступа (надо заменить) +Modbus/ Иерархия модулей: +│ inc/ modbus +│ ├── modbus.h # Главный заголовочный файл modbus_slave +│ ├── modbus_core.h # Базовые определения и структуры modbus_master +│ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils +│ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs +│ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs +│ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid +│ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag +├── src/ └── rs_message +│ ├── modbus.c # Основная логика Modbus │ +│ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро) +│ ├── modbus_master.c # Основная логика Master Modbus ├── modbus_config +│ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data +│ ├── modbus_holdregs.c # Реализация регистров хранения └── __crc_algs +│ ├── modbus_inputregs.c # Реализация входных регистров +│ ├── modbus_devid.c # Реализация идентификации устройства +│ ├── modbus_data.c # Функции доступа к данным +│ └── rs_message.c # Реализация драйвера RS +├── __modbus_config.h # Конфигурация Modbus (надо заменить) +├── __modbus_data.h # Структуры данных (надо заменить) +└── __modbus_data.c # Функции доступа (надо заменить) ``` ## Инструкция по подключению -1. **Склонируйте субмодуль** в ваш проект: +### 1. **Склонируйте субмодуль** в ваш проект: ```bash git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus git submodule update --init --recursive ``` -2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов: +### 2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов: ``` ProjectRoot/ @@ -47,219 +47,210 @@ ProjectRoot/ │ ├── modbus_config.h # скопировать из __modbus_config.h │ ├── modbus_data.h # скопировать из __modbus_data.h │ └── modbus_data.c # скопировать из __modbus_data.c -└── Modbus/ # Субмодуль +└── Modbus/ # Субмодуль ``` -3. **Настройте конфигурацию** под ваш проект: - - 3.1. Настройка периферии +### 3. **Настройте конфигурацию** под ваш проект: + #### 3.1. Настройка периферии - - **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1 - - **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick) - - **Включите прерывания** для UART и TIM + - **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1 + - **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick) + - **Включите прерывания** для UART и TIM - 3.2. Подключение обработчиков прерываний + #### 3.2. Подключение обработчиков прерываний - Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков: + Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков: - ```c - #include "modbus.h" +```c +#include "modbus.h" - void USARTx_IRQHandler(void) - { - RS_UART_Handler(&hmodbus1); - return; - HAL_UART_IRQHandler(&huart); - } +void USARTx_IRQHandler(void) +{ + RS_UART_Handler(&hmodbus1); + return; + HAL_UART_IRQHandler(&huart); +} - void TIMx_IRQHandler(void) - { - RS_TIM_Handler(&hmodbus1); - return; - HAL_TIM_IRQHandler(&htim); - } - ``` +void TIMx_IRQHandler(void) +{ + RS_TIM_Handler(&hmodbus1); + return; + HAL_TIM_IRQHandler(&htim); +} +``` + #### 3.3. В `modbus_config.h` укажите параметры устройства - 3.3. В `modbus_config.h` укажите параметры устройства + #### 3.4. Инициализация в коде + + Чтобы настроить Slave-режим `main()` после инициализации HAL: - 3.4. Инициализация в коде - - Чтобы настроить Slave-режим `main()` после инициализации HAL: +```c +#include "modbus.h" - ```c - #include "modbus.h" +int main(void) +{ + // Инициализация HAL + HAL_Init(); + SystemClock_Config(); + MX_GPIO_Init(); + MX_USART1_UART_Init(); + MX_TIM3_Init(); + + // Инициализация Modbus + MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); + MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); + + // Запуск приема Modbus + MODBUS_SlaveStart(&hmodbus1, NULL); + + while (1) + { + // Основной цикл + } +} +``` + Чтобы настроить Master-режим `main()` после инициализации HAL: - int main(void) - { - // Инициализация HAL - HAL_Init(); - SystemClock_Config(); - MX_GPIO_Init(); - MX_USART1_UART_Init(); - MX_TIM3_Init(); - - // Инициализация Modbus - MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); - MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); - - // Запуск приема Modbus - MODBUS_SlaveStart(&hmodbus1, NULL); - - while (1) - { - // Основной цикл - } - } - ``` +```c +#include "modbus.h" +// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук +RS_MsgTypeDef read_hold_cmd = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); +// коллбек, вызовется при получении ответа от слейва +read_hold[10]; +void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) +{ + // MB_RespGet_... Чтобы достать нужные данные из ответа + if(hmodbus->RS_STATUS == RS_OK) + { + for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) + { + uint16_t value; + if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) + { + read_hold[i] = value; + } + } + } +} +int main(void) +{ + // Инициализация HAL + HAL_Init(); + SystemClock_Config(); + MX_GPIO_Init(); + MX_USART1_UART_Init(); + MX_TIM3_Init(); + + // Инициализация Modbus + MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); + MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); + + // Запрос по Modbus + MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func); - Чтобы настроить Master-режим `main()` после инициализации HAL: +} +``` + #### 3.5. Настройка карты данных - ```c - #include "modbus.h" - // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук - RS_MsgTypeDef read_hold_cmd = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); - // коллбек, вызовется при получении ответа от слейва - read_hold[10]; - void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) - { - // MB_RespGet_... Чтобы достать нужные данные из ответа - if(hmodbus->RS_STATUS == RS_OK) - { - for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) - { - uint16_t value; - if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) - { - read_hold[i] = value; - } - } - } - } - int main(void) - { - // Инициализация HAL - HAL_Init(); - SystemClock_Config(); - MX_GPIO_Init(); - MX_USART1_UART_Init(); - MX_TIM3_Init(); - - // Инициализация Modbus - MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); - MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); - - // Запрос по Modbus - MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func); + В `modbus_data.h` настройте регистры и coils под ваше устройство: - } - ``` - 3.5. Настройка карты данных + **Input Registers (только чтение)** +```c +typedef struct +{ + uint16_t Temperature; // Адрес 0 + uint16_t Humidity; // Адрес 1 + uint16_t Pressure; // Адрес 2 + uint16_t Voltage; // Адрес 3 +} MB_DataInRegsTypeDef; - В `modbus_data.h` настройте регистры и coils под ваше устройство: +#define R_INPUT_ADDR 0 // Начальный адрес Input регистров +#define R_INPUT_QNT 4 // Количество Input регистров +``` + **Holding Registers (чтение/запись)** +```c +typedef struct +{ + uint16_t SetpointTemp; // Адрес 0 + uint16_t SetpointHumidity; // Адрес 1 + uint16_t ControlMode; // Адрес 2 +} MB_DataHoldRegsTypeDef; - **Input Registers (только чтение)** - ```c - typedef struct - { - uint16_t Temperature; // Адрес 0 - uint16_t Humidity; // Адрес 1 - uint16_t Pressure; // Адрес 2 - uint16_t Voltage; // Адрес 3 - } MB_DataInRegsTypeDef; +#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров +#define R_HOLDING_QNT 3 // Количество Holding регистров +``` + **Coils (1-битные)** +```c +typedef struct +{ + unsigned Relay1 : 1; // Адрес 0 + unsigned Relay2 : 1; // Адрес 1 + unsigned Pump : 1; // Адрес 2 + unsigned Heater : 1; // Адрес 3 + unsigned reserved : 12; // Резерв (выравнивание до 16 бит) +} MB_DataCoilsTypeDef; - #define R_INPUT_ADDR 0 // Начальный адрес Input регистров - #define R_INPUT_QNT 4 // Количество Input регистров - ``` +#define C_COILS_ADDR 0 // Начальный адрес Coils +#define C_COILS_QNT 4 // Количество Coils +``` + #### 3.6. Доступ к данным в коде - **Holding Registers (чтение/запись)** - ```c - typedef struct - { - uint16_t SetpointTemp; // Адрес 0 - uint16_t SetpointHumidity; // Адрес 1 - uint16_t ControlMode; // Адрес 2 - } MB_DataHoldRegsTypeDef; + В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля +```c +// Чтение входных регистров +uint16_t temp = MB_DATA.InRegs.Temperature; - #define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров - #define R_HOLDING_QNT 3 // Количество Holding регистров - ``` +// Запись в регистры хранения +MB_DATA.HoldRegs.SetpointTemp = 2500; - **Coils (1-битные)** - ```c - typedef struct - { - unsigned Relay1 : 1; // Адрес 0 - unsigned Relay2 : 1; // Адрес 1 - unsigned Pump : 1; // Адрес 2 - unsigned Heater : 1; // Адрес 3 - unsigned reserved : 12; // Резерв (выравнивание до 16 бит) - } MB_DataCoilsTypeDef; +// Управление coils +MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить Relay1 +MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2 - #define C_COILS_ADDR 0 // Начальный адрес Coils - #define C_COILS_QNT 4 // Количество Coils - ``` +// Чтение coil +if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) { + // Pump включен +} +``` + В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()` +```c +// Чтение регистров: Получить запрошенные регистры +uint16_t value; +if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, ®_value)) +{ + printf("Register 105 value: %d\n", reg_value); +} +// Чтение коилов: Получить запрошенные коилы +int state; +if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state)) +{ + printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF"); +} +// Чтение диагностики: Получить запрошенныую диагностику +uint16_t counter_value; +if(MB_RespGet_DiagnosticResponse(&MODBUS_MSG, &counter_value)) +{ + printf("Counter value: %d\n", counter_value); +} +// Чтение идентификаторов: Получить запрошенные идентификаторы +uint8_t length; +char vendor_name[64]; +if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length)) +{ + printf("Vendor Name: %s (length: %d)\n", vendor_name, length); +} - 3.6. Доступ к данным в коде - - - В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля - ```c - // Чтение входных регистров - uint16_t temp = MB_DATA.InRegs.Temperature; - - // Запись в регистры хранения - MB_DATA.HoldRegs.SetpointTemp = 2500; - - // Управление coils - MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить Relay1 - MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2 - - // Чтение coil - if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) { - // Pump включен - } - ``` - - В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()` - ```c - // Чтение регистров: Получить запрошенные регистры - uint16_t value; - if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, ®_value)) - { - printf("Register 105 value: %d\n", reg_value); - } - // Чтение коилов: Получить запрошенные коилы - int state; - if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state)) - { - printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF"); - } - // Чтение диагностики: Получить запрошенныую диагностику - uint16_t counter_value; - if(MB_RespGet_DiagnosticResponse(&MODBUS_MSG, &counter_value)) - { - printf("Counter value: %d\n", counter_value); - } - // Чтение идентификаторов: Получить запрошенные идентификаторы - uint8_t length; - char vendor_name[64]; - if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length)) - { - printf("Vendor Name: %s (length: %d)\n", vendor_name, length); - } - - uint8_t obj_id, obj_length; - char obj_data[64]; - if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, 0x00, &obj_id, obj_data, &obj_length)) - { - printf("First object - ID: 0x%02X, Data: %s\n", obj_id, obj_data); - } - ``` +uint8_t obj_id, obj_length; +char obj_data[64]; +if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, 0x00, &obj_id, obj_data, &obj_length)) +{ + printf("First object - ID: 0x%02X, Data: %s\n", obj_id, obj_data); +} +``` -5. **Обновление библиотеки**: - +### 5. **Обновление библиотеки**: После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся: ```bash diff --git a/Src/__modbus_compat.c b/Src/__modbus_compat.c index 2c8e730..3f2cf3f 100644 --- a/Src/__modbus_compat.c +++ b/Src/__modbus_compat.c @@ -1,8 +1,7 @@ /** -************************************************************************** -* @file __modbus_compat.c -* @brief Модуль для совместимости библиотеки MODBUS. -************************************************************************** -* @details Файл содержит API старых функций, а также заглушки для отключенных модулей: +******************************************************************************* +* @file __modbus_compat.c +* @brief Модуль для совместимости библиотеки MODBUS. +******************************************************************************* ******************************************************************************/ #include "modbus.h" diff --git a/Src/modbus.c b/Src/modbus.c index d360350..3973261 100644 --- a/Src/modbus.c +++ b/Src/modbus.c @@ -1,12 +1,12 @@ /** -************************************************************************** -* @file modbus.c -* @brief Модуль для реализации MODBUS. -************************************************************************** +******************************************************************************* +* @file modbus.c +* @brief Модуль для реализации MODBUS. +******************************************************************************* * @details Файл содержит реализацию функций работы с Modbus. -@section Функции и макросы +@section mbapi Функции и макросы ### Инициализация: - MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM) @@ -164,9 +164,15 @@ HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef return HAL_ERROR; } +//------------------------------------------------------------------- +//-----------------------------INTERNAL------------------------------ - - +/** + * @brief Дефолтный коллбек для мастера. + * @param hmodbus Указатель на хендлер RS + * @param modbus_msg Указатель на структуру сообщения + * @details В этот коллбек попадут все запросы, с NULL-коллбеком + */ static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { __NOP(); diff --git a/Src/modbus_coils.c b/Src/modbus_coils.c index 0e4e9e6..6c3430e 100644 --- a/Src/modbus_coils.c +++ b/Src/modbus_coils.c @@ -1,14 +1,22 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_coils.c * @brief Реализация работы с коилами Modbus -****************************************************************************** +******************************************************************************* * @details +Модуль для доступа к coils внутри программы: +- Функции для доступа к coils по глобальным адресам +- Макросы для доступа к coils по локальным адресам + Модуль обработки команд для coils (битовых данных): - Чтение coils (0x01) - упаковка битов в байты для передачи - Запись одиночного coil (0x05) - установка/сброс бита - Запись множественных coils (0x0F) - распаковка битов из байтов +@section cvalid Валидация данных: +- Проверка соответствия количества байт и регистров +- Валидация адресов через MB_DefineRegistersAddress() +- Обработка исключений при некорректных запросах ******************************************************************************/ #include "modbus_coils.h" diff --git a/Src/modbus_core.c b/Src/modbus_core.c index ed9c0ff..9e9dfcc 100644 --- a/Src/modbus_core.c +++ b/Src/modbus_core.c @@ -1,8 +1,8 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_core.c * @brief Базовая реализация ядра Modbus -****************************************************************************** +******************************************************************************* * @details В текущей реализации этот файл служит заглушкой для будущего расширения функциональности ядра Modbus протокола. diff --git a/Src/modbus_devid.c b/Src/modbus_devid.c index 06a4336..45453b7 100644 --- a/Src/modbus_devid.c +++ b/Src/modbus_devid.c @@ -1,15 +1,15 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_devid.c * @brief Реализация идентификаторов устройства Modbus -****************************************************************************** +******************************************************************************* * @details Модуль обработки запросов идентификации устройства через MEI-тип 0x0E: - Формирование иерархии объектов идентификации - Поддержка потоковой передачи при большом количестве объектов - Автоматический расчет MoreFollows флагов -@section Потоковая передача: +@section stream Потоковая передача: При большом количестве объектов идентификация разбивается на несколько сообщений с установкой флага MoreFollows и указанием NextObjId для продолжения чтения в следующем запросе. diff --git a/Src/modbus_diag.c b/Src/modbus_diag.c index c7b74c6..2a6967a 100644 --- a/Src/modbus_diag.c +++ b/Src/modbus_diag.c @@ -1,8 +1,8 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_diag.c * @brief Реализация диагностики устройства Modbus -****************************************************************************** +******************************************************************************* * @details Модуль обработки запросов диагностической информации (0x08): - Полная поддержка всех подфункций диагностики согласно спецификации Modbus diff --git a/Src/modbus_holdregs.c b/Src/modbus_holdregs.c index fe6a161..88ab7f7 100644 --- a/Src/modbus_holdregs.c +++ b/Src/modbus_holdregs.c @@ -1,22 +1,21 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_holdregs.c * @brief Реализация работы с регистрами хранения Modbus -****************************************************************************** +******************************************************************************* * @details +Модуль для доступа к регистрам внутри программы: +- Функции для доступа к регистрам хранения по глобальным адресам + Модуль обработки команд для holding registers (регистров хранения): - Чтение множественных регистров (0x03) - копирование данных в буфер ответа - Запись одиночного регистра (0x06) - прямая запись значения - Запись множественных регистров (0x10) - пакетная запись из буфера -@section Валидация данных: +@section hvalid Валидация данных: - Проверка соответствия количества байт и регистров -Валидация адресов через MB_DefineRegistersAddress() +- Валидация адресов через MB_DefineRegistersAddress() - Обработка исключений при некорректных запросах - -@section Echo-ответы: -При успешной записи формируется echo-ответ с теми же данными, -что были в запросе (для функций 0x05, 0x06, 0x0F, 0x10). ******************************************************************************/ #include "modbus_inputregs.h" diff --git a/Src/modbus_inputregs.c b/Src/modbus_inputregs.c index 24e4ee4..41081d6 100644 --- a/Src/modbus_inputregs.c +++ b/Src/modbus_inputregs.c @@ -1,13 +1,18 @@ /** -****************************************************************************** +******************************************************************************* * @file modbus_inputregs.c * @brief Реализация работы с входными регистрами Modbus -****************************************************************************** +******************************************************************************* * @details +Модуль для доступа к регистрам внутри программы: +- Функции для доступа к входным регистрам по глобальным адресам + Модуль обработки команды чтения input registers (0x04): -- Чтение множественных входных регистров -Копирование данных из структур устройства в буфер ответа -- Поддержка знаковых и беззнаковых значений + +@section ivalid Валидация данных: +- Проверка соответствия количества байт и регистров +- Валидация адресов через MB_DefineRegistersAddress() +- Обработка исключений при некорректных запросах ******************************************************************************/ #include "modbus_inputregs.h" diff --git a/Src/modbus_master.c b/Src/modbus_master.c index 672f5ac..e5305ad 100644 --- a/Src/modbus_master.c +++ b/Src/modbus_master.c @@ -1,12 +1,22 @@ /** -************************************************************************** -* @file modbus_master.c -* @brief Модуль для реализации мастера MODBUS. -************************************************************************** +******************************************************************************* +* @file modbus_master.c +* @brief Модуль для реализации мастера MODBUS. +******************************************************************************* * @details Файл содержит реализацию функций для работы Modbus в режиме мастера. -@section Функции и макросы +@section mast Функции и макросы +- MB_RespGet_RegisterAll() — Считать все регистра из ответа +- MB_RespGet_RegisterValue() — Считать один регистр из ответа +- MB_RespGet_CoilAll() — Считать все коилы из ответа +- MB_RespGet_CoilState() — Считать один коил из ответа +- MB_RespGet_NumberOfObjects() — Считать количество принятых объектов идентификатора +- MB_RespGet_ObjectById() — Считать объект идентификатора по + его ID +- MB_RespGet_ObjectByIndex() — Считать объект идентификатора по + порядковому номеру в сообщении +- MB_RespGet_Diagnostic() — Считать запрошенный диагностический счетчик - MB_Master_Collect_Message() — Сбор сообщения в режиме мастера - MB_Master_Parse_Message() — Парс сообщения в режиме мастера @@ -16,8 +26,35 @@ #ifdef MODBUS_ENABLE_MASTER +//------------------------------------------------------------------- +//-----------------------------FOR USER------------------------------ /** - * @brief Получить значение регистра из ответа по его адресу + * @brief Получить значение ВСЕХ регистров в ответе + * @param modbus_msg Указатель на структуру сообщения + * @param reg_addr Адрес регистра, значение которого нужно получить + * @param reg_arr Указатель для массив для сохранения значений регистров + * @return количество считанных регистров, 0 - ошибка + */ +int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr) +{ + if(modbus_msg == NULL || reg_arr == NULL) + return 0; + int read_cnt = 0; + int i = 0; + for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++) + { + if(MB_RespGet_RegisterValue(modbus_msg, addr, ®_arr[i])) + { + read_cnt++; + } + i++; + } + + return read_cnt; +} + +/** + * @brief Получить значение регистра в ответе по его адресу * @param modbus_msg Указатель на структуру сообщения * @param reg_addr Адрес регистра, значение которого нужно получить * @param reg_value Указатель для значения регистра @@ -55,6 +92,31 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1 +/** + * @brief Получить состояние ВСЕХ coil в ответе + * @param modbus_msg Указатель на структуру сообщения + * @param coil_arr Указатель для массив доя сохранения состояний coil (1 - ON, 0 - OFF) + * @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса + */ +int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr) +{ + if(modbus_msg == NULL || coil_arr == NULL) + return 0; + + int read_cnt = 0; + int i = 0; + for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++) + { + if(MB_RespGet_CoilState(modbus_msg, addr, &coil_arr[i])) + { + read_cnt++; + } + i++; + } + + return 1; +} + /** * @brief Получить состояние coil в ответе по его адресу * @param modbus_msg Указатель на структуру сообщения @@ -93,7 +155,7 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi if(bit_index < 8) *coil_state = (modbus_msg->MbData[data_index] >> (bit_index+8)) & 0x01; else - *coil_state = ((modbus_msg->MbData[data_index]&0xFF) >> bit_index-8) & 0x01; + *coil_state = ((modbus_msg->MbData[data_index]&0xFF) >> (bit_index-8)) & 0x01; return 1; @@ -250,6 +312,10 @@ int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data) } + + +//------------------------------------------------------------------- +//-----------------------------INTERNAL------------------------------ /** * @brief Определить размер модбас запроса (МАСТЕР версия). * @param hRS Указатель на хендлер RS. diff --git a/Src/modbus_slave.c b/Src/modbus_slave.c index 67ae099..77fa6fb 100644 --- a/Src/modbus_slave.c +++ b/Src/modbus_slave.c @@ -1,12 +1,12 @@ /** -************************************************************************** -* @file modbus_slave.c -* @brief Модуль для реализации слейв MODBUS. -************************************************************************** +******************************************************************************* +* @file modbus_slave.c +* @brief Модуль для реализации слейв MODBUS. +******************************************************************************* * @details Файл содержит реализацию функций для работы Modbus в режиме слейва. -@section Функции и макросы +@section slave Функции и макросы - MB_Slave_Response() — Ответ на запрос - MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва. diff --git a/Src/rs_message.c b/Src/rs_message.c index 9b2d90b..ed5d801 100644 --- a/Src/rs_message.c +++ b/Src/rs_message.c @@ -1,8 +1,8 @@ /** -****************************************************************************** +******************************************************************************* * @file rs_message.c * @brief Реализация протоколов обмена по RS/UART -****************************************************************************** +******************************************************************************* * @details Модуль реализует асинхронный обмен сообщениями через UART с использованием: - Прерываний по приему/передаче @@ -10,7 +10,7 @@ - Таймаутов через таймер - Двухстадийного приема (заголовок + данные) -@section Архитектура: +@section arch Архитектура: В режиме слейв: - Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX - При срабатывании прерывания IDLE - обработка полученного сообщения @@ -18,7 +18,7 @@ - Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX - При срабатывании прерывания IDLE - обработка полученного ответа -@section Необходимые обработчики: +@section ithandler Необходимые обработчики: - RS_UART_Handler() в UARTx_IRQHandler вместо HAL_UART_IRQHandler() - RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler() ******************************************************************************/ diff --git a/__modbus_config.h b/__modbus_config.h index fba9dff..9f65c31 100644 --- a/__modbus_config.h +++ b/__modbus_config.h @@ -5,6 +5,7 @@ ****************************************************************************** @addtogroup MODBUS_CONFIGS Modbus configs @ingroup MODBUS +@brief Конфигурация библиотеки @{ ****************************************************************************** * @details diff --git a/__modbus_data.h b/__modbus_data.h index e2b7bad..848006b 100644 --- a/__modbus_data.h +++ b/__modbus_data.h @@ -3,7 +3,7 @@ * @file modbus_data.h * @brief Определения структур данных Modbus устройства ****************************************************************************** -@defgroup MODBUS_DATA Modbus Data Tools +@defgroup MODBUS_DATA Modbus Registers Map @ingroup MODBUS @brief Определение карты регистров и коилов ****************************************************************************** @@ -13,7 +13,7 @@ - Input Registers (R/O) - входные регистры - Coils (R/W) - дискретные выходы -@section Базовая настройка под устройство: +@section datinit Базовая настройка под устройство: 1. Настроить диапазоны адресов - @ref R_INPUT_ADDR и @ref R_INPUT_QNT для входных регистров - @ref R_HOLDING_ADDR и @ref R_HOLDING_QNT для регистров хранения @@ -24,7 +24,7 @@ - @ref MB_DataCoilsTypeDef -@section Расширенная настройка под устройство: +@section datexpert Расширенная настройка под устройство: 1. Добавить новый массив с нужными данными. 2. Добавить дефайны для определения его начального адреса и количества элементов 3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress. @@ -75,11 +75,11 @@ * @addtogroup MODBUS_DATA_RERISTERS_DEFINES Registers structures * @ingroup MODBUS_DATA * @brief Стуруктура регистров (входных и хранения) - @verbatim + @code Для массивов регистров: R__ADDR - модбас адресс первого регистра в массиве R__QNT - количество регистров в массиве - @endverbatim + @endcode * @{ */ @@ -111,12 +111,12 @@ typedef struct //MB_DataInRegsTypeDef * @addtogroup MODBUS_DATA_COILS_DEFINES Coils Structure * @ingroup MODBUS_DATA * @brief Структура коилов - @verbatim + @code Структура дефайна Для массивов коилов: C__ADDR - модбас адресс первого коила в массиве C__QNT - количество коилов в массиве (минимум 16) - @endverbatim + @endcode * @{ */