Compare commits

10 Commits

Author SHA1 Message Date
Razvalyaev
0264ccd54e Фиксы табуляции 2025-11-06 18:15:42 +03:00
Razvalyaev
82cbdfe883 Документация отладки rs_message 2025-11-06 18:15:27 +03:00
Razvalyaev
920ceb1a3d Рефакторинг modbus_core енумов и структур 2025-11-06 17:53:37 +03:00
Razvalyaev
f7ab05d097 оптимизированы пользовательские объекты 2025-11-06 13:45:14 +03:00
Razvalyaev
8a2e7398e1 Перенос заглушек в modbus_compat и заготовки для TCP 2025-11-06 12:48:37 +03:00
Razvalyaev
510e8aec50 фикс чтения коилов в мастере 2025-11-06 10:18:18 +03:00
Razvalyaev
b71b799566 Добавлен протокол TCP, но не проверен 2025-11-05 18:18:55 +03:00
Razvalyaev
52143ce07c Мастер: коллбек вызывается и при таймауте
В коллбеке можно понять статус реквеста по hmodbus->RS_STATUS
2025-11-05 16:36:44 +03:00
Razvalyaev
5bbbbde3e6 Data Access API расширено функциями для чтения/записи регистров 2025-11-05 13:11:25 +03:00
Razvalyaev
fdf22949ed API для реквестов MB_RespGet.. перенесено в modbus_master 2025-11-05 12:49:05 +03:00
28 changed files with 468 additions and 1004 deletions

View File

@@ -1,71 +1,18 @@
/** /**
******************************************************************************* **************************************************************************
* @file __modbus_compat.h * @file __modbus_compat.h
* @brief Модуль для совместимости библиотеки MODBUS. * @brief Модуль для совместимости библиотеки MODBUS.
******************************************************************************* **************************************************************************
* @details Файл содержит API старых функций, а также заглушки для отключенных модулей: * @details Файл содержит API старых функций, а также заглушки для отключенных модулей:
******************************************************************************/ *************************************************************************/
#ifndef __MODBUS_COMPAT_H_ #include "modbus.h"
#define __MODBUS_COMPAT_H_
#include "modbus_core.h"
#define CREATE_DEPRECATED_ALIAS(old_name, new_name, type) \
__attribute__((deprecated("Use " #new_name " instead"))) \
static const type old_name = new_name;
// Для функций
#define CREATE_DEPRECATED_FUNCTION(old_name, new_name, return_type, ...) \
__attribute__((deprecated("Use " #new_name " instead"))) \
return_type old_name(__VA_ARGS__) { \
return new_name(__VA_ARGS__); \
}
/** @addtogroup MODBUS_LEGACY_API Legacy API /** @addtogroup MODBUS_LEGACY_API Legacy API
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief Старые API функций, сохранённые для обратной совместимости.
* @note Не используйте эти функции в новом коде. Они будут удалены в будущих версиях.
* Вместо них используйте актуальные API, приведенные в втором столбце.
* @{ * @{
*/ */
// Устаревшие enum //Старый замените на // Новый
// | // |
// v // v
CREATE_DEPRECATED_ALIAS(NO_ERRORS, ET_NO_ERRORS, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(ILLEGAL_FUNCTION, ET_ILLEGAL_FUNCTION, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(ILLEGAL_DATA_ADDRESS, ET_ILLEGAL_DATA_ADDRESS, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(ILLEGAL_DATA_VALUE, ET_ILLEGAL_DATA_VALUE, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(SLAVE_DEVICE_FAILURE, ET_SLAVE_DEVICE_FAILURE, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_COILS, FC_R_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_DISC_IN, FC_R_DISC_IN, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_HOLD_REGS, FC_R_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_IN_REGS, FC_R_IN_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_COIL, FC_W_COIL, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_HOLD_REG, FC_W_HOLD_REG, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_COILS, FC_W_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_HOLD_REGS, FC_W_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_DIAGNOSTICS, FC_R_DIAGNOSTICS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_DEVICE_ID, FC_R_DEVICE_ID, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_COILS, FC_ERR_R_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_DISC_IN, FC_ERR_R_DISC_IN, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_IN_REGS, FC_ERR_R_IN_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_HOLD_REGS, FC_ERR_R_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_COIL, FC_ERR_W_COIL, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_HOLD_REG, FC_ERR_W_HOLD_REG, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_COILS, FC_ERR_W_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_HOLD_REGS, FC_ERR_W_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_DIAGNOSTIC, FC_ERR_R_DIAGNOSTIC, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_DEVICE_INFO, FC_ERR_R_DEVICE_INFO, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_BASIC_IDENTIFICATIONS, RID_BASIC_IDENTIFICATIONS, MB_ReadDevId);
CREATE_DEPRECATED_ALIAS(MB_REGULAR_IDENTIFICATIONS, RID_REGULAR_IDENTIFICATIONS, MB_ReadDevId);
CREATE_DEPRECATED_ALIAS(MB_EXTENDED_IDENTIFICATIONS, RID_EXTENDED_IDENTIFICATIONS, MB_ReadDevId);
CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIONS, MB_ReadDevId);
#define MbAddr DeviceAddr
/** MODBUS_LEGACY_API /** MODBUS_LEGACY_API
@@ -117,7 +64,7 @@ CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIO
#define MB_Diagnostics_SlaveNoResponseCnt() #define MB_Diagnostics_SlaveNoResponseCnt()
#define MB_Diagnostics_SlaveNAKCnt() #define MB_Diagnostics_SlaveNAKCnt()
#define MB_Diagnostics_SlaveBusyCnt() #define MB_Diagnostics_SlaveBusyCnt()
#define MB_GetDeviceMode() MODBUS_NORMAL_MODE #define MB_GetDeviceMode(void) MODBUS_NORMAL_MODE
#endif #endif
@@ -164,5 +111,5 @@ CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIO
#define MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR #define MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
#define MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR #define MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
#endif #endif
/** @endcond */ /** @endcond */
#endif //__MODBUS_COMPAT_H_

View File

@@ -1,22 +1,20 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus.h * @file modbus.h
* @brief Главный заголовочный файл Modbus библиотеки * @brief Главный заголовочный файл Modbus библиотеки
******************************************************************************* ******************************************************************************
@addtogroup MODBUS Modbus tools @addtogroup MODBUS Modbus tools
@brief Библиотека реализующая протокол Modbus ******************************************************************************
*******************************************************************************
@addtogroup MODBUS_FUNCTIONS Main API for Modbus Library @addtogroup MODBUS_FUNCTIONS Main API for Modbus Library
@ingroup MODBUS @ingroup MODBUS
@brief Публичные функции библиотеки
@{ @{
******************************************************************************* ******************************************************************************
* @details * @details
Объединяющий файл для подключения всей функциональности Modbus. Объединяющий файл для подключения всей функциональности Modbus.
Подключает все необходимые модули: Подключает все необходимые модули:
@section Start Инструкция по подключению @section init Инструкция по подключению
Для корректной работы надо: Для корректной работы надо:
- Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие - Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие
низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика
@@ -25,36 +23,31 @@
- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1 - Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1
- После для запуска Modbus: - После для запуска Modbus:
@code @verbatim
//----------------Слейв модбас----------------// //----------------Слейв модбас----------------//
#include "modbus.h" #include "modbus.h"
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3, NULL); // NULL, если управление RE/DE не нужно MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
MODBUS_SlaveStart(&hmodbus1, NULL); MODBUS_SlaveStart(&hmodbus1, NULL);
@endcode @endverbatim
@code @verbatim
//----------------Мастер модбас----------------// //----------------Мастер модбас----------------//
#include "modbus.h" #include "modbus.h"
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3, NULL); // NULL, если управление RE/DE не нужно MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER);
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
// При получении ответа вызовется функция callback_func()
RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func);
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
// MB_RespGet_... Чтобы достать нужные данные из ответа // MB_RespGet_... Чтобы достать нужные данные из ответа
if(hmodbus->RS_STATUS == RS_OK)
if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок
{ {
for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++) for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
{ {
// Запись регистров из ответа в массив
uint16_t value; uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
{ {
@@ -62,14 +55,11 @@
} }
} }
} }
else // Ответ получен с ошибкой или не получен вовсе
{
}
} }
@endcode @endverbatim
@section modules Подключаемые модули: @section Подключаемые модули:
- rs_message.h - работа с uart - rs_message.h - работа с uart
- modbus_core.h - базовые определения - modbus_core.h - базовые определения
- modbus_coils.h - работа с дискретными выходами - modbus_coils.h - работа с дискретными выходами
@@ -79,7 +69,7 @@
- modbus_diag.h - диагностика modbus - modbus_diag.h - диагностика modbus
@section data Структура данных Modbus @section Структура данных Modbus
#### Holding/Input Registers: #### Holding/Input Registers:
- Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель. - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
@@ -115,18 +105,14 @@
#ifdef MODBUS_ENABLE_DIAGNOSTICS #ifdef MODBUS_ENABLE_DIAGNOSTICS
#include "modbus_diag.h" #include "modbus_diag.h"
#endif #endif
#ifdef MODBUS_ENABLE_OSCIL
#include "modbus_oscil.h"
#endif
#include "modbus_data.h"
#ifdef MODBUS_ENABLE_MASTER #ifdef MODBUS_ENABLE_MASTER
#define MODBUS_MODE_MASTER 1 ///< Псевдо-enum: Режим мастер #define MODBUS_MODE_MASTER 1
#endif #endif
#ifdef MODBUS_ENABLE_SLAVE #ifdef MODBUS_ENABLE_SLAVE
#define MODBUS_MODE_SLAVE 0 ///< Псевдо-enum: Режим слейв #define MODBUS_MODE_SLAVE 0
#endif #endif
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -136,7 +122,7 @@
//----------------FUNCTIONS FOR USER---------------- //----------------FUNCTIONS FOR USER----------------
/* Инициализация периферии модбас. */ /* Инициализация периферии модбас. */
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)); HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
/* Программная конфигурация модбас. */ /* Программная конфигурация модбас. */
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master); HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
/* Запуск слейв устройства */ /* Запуск слейв устройства */

View File

@@ -1,27 +1,23 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_coils.h * @file modbus_coils.h
* @brief Работа с коилами Modbus * @brief Работа с коилами Modbus
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_COILS Coils Tools @addtogroup MODBUS_COILS Coils Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с коилами ******************************************************************************
*******************************************************************************
* @details * @details
Модуль для доступа к coils внутри программы:
- Функции для доступа к coils по глобальным адресам
- Макросы для доступа к coils по локальным адресам
Модуль предоставляет функции и макросы для работы с битовыми данными: Модуль предоставляет функции и макросы для работы с битовыми данными:
- Чтение coils (0x01) Упаковка битов в байты - Чтение coils (0x01) Упаковка битов в байты
- Запись одиночного coil (0x05) Установка/сброс бита - Запись одиночного coil (0x05) Установка/сброс бита
- Запись множественных coils (0x0F) - распаковка байтов в биты - Запись множественных coils (0x0F) - распаковка байтов в биты
- Макросы для локального доступа к coils
@section cbits Организация битовых данных: @section Организация битовых данных:
Coils упакованы в 16-битные слова для эффективного использования памяти. Coils упакованы в 16-битные слова для эффективного использования памяти.
Биты нумеруются от младшего к старшему внутри каждого слова. Биты нумеруются от младшего к старшему внутри каждого слова.
@section caddr Адресация: @section Адресация:
- Глобальная - абсолютный адрес в пространстве Modbus - Глобальная - абсолютный адрес в пространстве Modbus
- Локальная - относительный адрес внутри массива coils - Локальная - относительный адрес внутри массива coils
- Макросы автоматически вычисляют смещения и маски - Макросы автоматически вычисляют смещения и маски
@@ -30,7 +26,6 @@ Coils упакованы в 16-битные слова для эффективн
#ifndef __MODBUS_COILS_H_ #ifndef __MODBUS_COILS_H_
#define __MODBUS_COILS_H_ #define __MODBUS_COILS_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_COILS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---//////////////////// ////////////////////---MODBUS FUNCTION DEFINES---////////////////////
@@ -49,7 +44,7 @@ Coils упакованы в 16-битные слова для эффективн
/** /**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief API для доступа к данным модбас внутри программы * @brief Функции для доступа к данным модбас
* @{ * @{
*/ */
@@ -106,7 +101,7 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @{ @{
*/ */
/* Обработать функцию Read Coils (01 - 0x01) */ /* Обработать функцию Read Coils (01 - 0x01) */
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg); uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg);
@@ -119,5 +114,5 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
* @} * @}
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_COILS
#endif //__MODBUS_COILS_H_ #endif //__MODBUS_COILS_H_

View File

@@ -1,13 +1,12 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_core.h * @file modbus_core.h
* @brief Ядро Modbus протокола - определения и структуры * @brief Ядро Modbus протокола - определения и структуры
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_INTERNAL Modbus Internal Tools @addtogroup MODBUS_INTERNAL Modbus Internal Tools
@ingroup MODBUS @ingroup MODBUS
@brief Внутренние штуки библиотеки
@{ @{
******************************************************************************* ******************************************************************************
* @details * @details
Базовые определения для реализации Modbus RTU устройства: Базовые определения для реализации Modbus RTU устройства:
- Структуры сообщений Modbus - Структуры сообщений Modbus
@@ -15,7 +14,7 @@
Константы размеров полей Константы размеров полей
Вспомогательные макросы Вспомогательные макросы
@section msg Структура сообщения: @section Структура сообщения:
[ADDR][FUNC][DATA...][CRC] [ADDR][FUNC][DATA...][CRC]
- Адрес: 1 байт - Адрес: 1 байт
- Функция: 1 байт - Функция: 1 байт
@@ -27,44 +26,45 @@
#define __MODBUS_CORE_H_ #define __MODBUS_CORE_H_
#include "modbus_config.h" #include "modbus_config.h"
#include "modbus_data.h"
#include "__crc_algs.h" #include "__crc_algs.h"
/** /**
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools * @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
* @ingroup MODBUS * @ingroup MODBUS
* @brief Определения протокола модбас * @brief Определения протокола модбас
* @{ @{
*/ */
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
//-------------DEFINES FOR STRUCTURE---------------- //-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */ /* defines for structure of modbus message */
#define MbTransactionID_size 2 ///< size of (Transaction ID) #define TransactionID_size 2 ///< size of (Transaction ID)
#define MbProtocolID_size 2 ///< size of (Protocol ID) #define ProtocolID_size 2 ///< size of (Protocol ID)
#define MbPDULength_size 2 ///< size of (PDU Length) #define PDULength_size 2 ///< size of (PDU Length)
#define MbDeviceAddr_size 1 ///< size of (Slave Addr) #define MbAddr_SIZE 1 ///< size of (Slave Addr)
#define MbFuncCode_size 1 ///< size of (Function Code) #define Func_Code_SIZE 1 ///< size of (Function Code)
#define MbAddr_size 2 ///< size of (Address) #define Addr_SIZE 2 ///< size of (Address)
#define MbQnt_size 2 ///< size of (Quantity) #define Qnt_SIZE 2 ///< size of (Quantity)
#define MbByteCnt_size 1 ///< size of (Byte Count) #define ByteCnt_SIZE 1 ///< size of (Byte Count)
#define MbData_size 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) #define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE)
#define MbCRC_size 2 ///< size of (MbCRC) in bytes #define CRC_SIZE 2 ///< size of (MbCRC) in bytes
#ifndef MODBUS_PROTOCOL_TCP #ifndef MODBUS_PROTOCOL_TCP
/** @brief Size of whole RTU message */ /** @brief Size of whole RTU message */
#define RS_INFO_SIZE_MAX (MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size+MbByteCnt_size) #define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE)
#else #else
/** @brief Size of whole TCP message */ /** @brief Size of whole TCP message */
#define RS_INFO_SIZE_MAX (MbTransactionID_size+MbProtocolID_size+MbPDULength_size+MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size) #define INFO_SIZE_MAX (TransactionID_size+ProtocolID_size+PDULength_size+MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE)
#endif #endif
/** @brief Size of first part of message that will be received /** @brief Size of first part of message that will be received
first receive info part of message, than defines size of rest message*/ first receive info part of message, than defines size of rest message*/
#define RS_RX_FIRST_PART_SIZE RS_INFO_SIZE_MAX #define RX_FIRST_PART_SIZE INFO_SIZE_MAX
/** @brief Size of buffer: max size of whole message */ /** @brief Size of buffer: max size of whole message */
#define RS_MSG_SIZE_MAX (RS_INFO_SIZE_MAX + MbData_size*2 + MbCRC_size) // max possible size of message #define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message
/** /**
* @brief Enum for modbus exception codes * @brief Enum for modbus exception codes
@@ -72,17 +72,15 @@ first receive info part of message, than defines size of rest message*/
*/ */
typedef enum //MB_ExceptionTypeDef typedef enum //MB_ExceptionTypeDef
{ {
/* Регулярные коды ошибок, которые определены конкретной программой */ // reading
ET_NO_ERRORS = 0x00, ///< no errors ET_NO_ERRORS = 0x00, ///< no errors
ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
// ET_ACKNOWLEDGE = 0x05, ///< idk
/* Специальные коды ошибок, которые определены конкретной программой */ // ET_SLAVE_DEVICE_BUSY = 0x06, ///< idk
ET_ACKNOWLEDGE = 0x05, ///< Устройство приняло запрос, но на обработку требуется время. Нужно чтобы не было Timeout ошибки // ET_MEMORY_PARITY_ERROR = 0x08, ///< idk
ET_SLAVE_DEVICE_BUSY = 0x06, ///< Устройство занято обработкой комманды
ET_MEMORY_PARITY_ERROR = 0x08, ///< Ошибка внешней памяти
}MB_ExceptionTypeDef; }MB_ExceptionTypeDef;
#define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes #define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes
@@ -95,7 +93,7 @@ typedef enum //MB_FunctonTypeDef
/* COMMANDS */ /* COMMANDS */
// reading // reading
FC_R_COILS = 0x01, ///< Чтение битовых ячеек 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 #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
FC_R_HOLD_REGS = 0x03, ///< Чтение входных регистров FC_R_HOLD_REGS = 0x03, ///< Чтение входных регистров
FC_R_IN_REGS = 0x04, ///< Чтение регистров хранения FC_R_IN_REGS = 0x04, ///< Чтение регистров хранения
@@ -116,7 +114,7 @@ typedef enum //MB_FunctonTypeDef
/* ERRORS */ /* ERRORS */
// error reading // error reading
FC_ERR_R_COILS = FC_R_COILS + FC_ERR_VALUES_START, ///< Ошибка чтения битовых ячеек 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_IN_REGS = FC_R_IN_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения регистров хранения
FC_ERR_R_HOLD_REGS = FC_R_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения входных регистров FC_ERR_R_HOLD_REGS = FC_R_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения входных регистров
@@ -126,13 +124,11 @@ typedef enum //MB_FunctonTypeDef
FC_ERR_W_COILS = FC_W_COILS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек 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_W_HOLD_REGS = FC_W_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких регистров
FC_ERR_R_DIAGNOSTIC = FC_R_DIAGNOSTICS + 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_FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве
}MB_FunctonTypeDef; }MB_FunctonTypeDef;
/** /** @brief Enum for MEI func codes */
* @brief Enum for MEI func codes
*/
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
MEI_DEVICE_IDENTIFICATIONS = 0x0E, MEI_DEVICE_IDENTIFICATIONS = 0x0E,
@@ -160,13 +156,13 @@ typedef enum //MB_FunctonTypeDef
RID_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications. RID_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications.
@details The device provides one specific identifications object. */ @details The device provides one specific identifications object. */
}MB_ReadDevId; }ReadDevId;
/** @brief Structure for device identifications message type */ /** @brief Structure for device identifications message type */
typedef struct typedef struct
{ {
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface
MB_ReadDevId ReadDevId; ReadDevId ReadDevId;
uint8_t Conformity; ///< Identification conformity level of the device and type of supported access @ref MODBUS_DEVICE_CONFORMITY uint8_t Conformity; ///< Identification conformity level of the device and type of supported access @ref MODBUS_DEVICE_CONFORMITY
uint8_t MoreFollows; uint8_t MoreFollows;
uint8_t NextObjId; uint8_t NextObjId;
@@ -183,14 +179,14 @@ typedef struct // RS_MsgTypeDef
uint16_t PDULength; ///< Modbus TCP: PDU Length uint16_t PDULength; ///< Modbus TCP: PDU Length
#endif #endif
uint8_t DeviceAddr; ///< Modbus Slave Address uint8_t MbAddr; ///< Modbus Slave Address
MB_FunctonTypeDef FuncCode; ///< Modbus Function Code MB_FunctonTypeDef FuncCode; ///< Modbus Function Code
MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct
uint16_t Addr; ///< Modbus Address of data uint16_t Addr; ///< Modbus Address of data
uint16_t Qnt; ///< Quantity of modbus data uint16_t Qnt; ///< Quantity of modbus data
uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive
uint16_t MbData[MbData_size]; ///< Modbus Data uint16_t MbData[DATA_SIZE]; ///< Modbus Data
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
uint16_t MbCRC; ///< Modbus CRC uint16_t MbCRC; ///< Modbus CRC
@@ -221,7 +217,7 @@ extern RS_MsgTypeDef MODBUS_MSG;
* @param _parr_ - массив коилов. * @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Mask * @note Используется вместе с @ref MB_Set_Coil_Mask
@code Пояснение выражений @verbatim Пояснение выражений
- (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_ - (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_
Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0) Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0)
@@ -229,14 +225,14 @@ extern RS_MsgTypeDef MODBUS_MSG;
|register[0]----| |register[1]----| |register[0]----| |register[1]----|
|skip this------| |get this-------| |skip this------| |get this-------|
|shift to 14 bit| |shift to 14 bit|
@endcode @endverbatim
*/ */
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) #define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
/** /**
* @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра * @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра
* @param _coil_ - Номер коила от начала массива _arr_. * @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
@code Пояснение выражений @verbatim Пояснение выражений
- (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра - (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра
- _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре - _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре
@@ -248,7 +244,7 @@ extern RS_MsgTypeDef MODBUS_MSG;
|register[0]----| |register[1]----| |register[0]----| |register[1]----|
|skip this------| |get this-------| |skip this------| |get this-------|
|shift to 14 bit| |shift to 14 bit|
@endcode @endverbatim
*/ */
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) #define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
@@ -293,7 +289,7 @@ extern RS_MsgTypeDef MODBUS_MSG;
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @{ @{
*/ */
/* Реализация этих функций лежит в modbus_data.c */ /* Реализация этих функций лежит в modbus_data.c */
@@ -301,17 +297,17 @@ extern RS_MsgTypeDef MODBUS_MSG;
/* Check is address valid for certain array */ /* Check is address valid for certain array */
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB); MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB);
/* Define Address Origin for Input/Holding Registers */ /* Define Address Origin for Input/Holding Registers */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag); MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType);
/* Define Address Origin for coils */ /* Define Address Origin for coils */
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag); MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag);
/** MODBUS_CMD_PROCESS_FUNCTIONS /** MODBUS_CMD_PROCESS_FUNCTIONS
* @} * @}
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#include "__modbus_compat.h"
#endif //__MODBUS_CORE_H_ #endif //__MODBUS_CORE_H_
/** MODBUS_INTERNAL /** MODBUS_INTERNAL
* @} * @}
*/ */

View File

@@ -1,19 +1,18 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_devid.h * @file modbus_devid.h
* @brief Идентификаторы устройства Modbus * @brief Идентификаторы устройства Modbus
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_DEVID Device Identifications Tools @addtogroup MODBUS_DEVID Device Identifications Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с идентификаторами устройства ******************************************************************************
*******************************************************************************
* @details * @details
Модуль реализации функции Read Device Identifications (0x2B): Модуль реализации функции Read Device Identifications (0x2B):
- Базовая идентификация (Vendor, Product, Revision) - Базовая идентификация (Vendor, Product, Revision)
- Расширенная идентификация (URL, Model, User fields) - Расширенная идентификация (URL, Model, User fields)
- Поддержка потоковой передачи больших объектов - Поддержка потоковой передачи больших объектов
@section devobj Объекты идентификации: @section Объекты идентификации:
- VendorName, ProductCode, Revision - обязательные - VendorName, ProductCode, Revision - обязательные
- VendorUrl, ProductName, ModelName - опциональные - VendorUrl, ProductName, ModelName - опциональные
- User objects - пользовательские поля - User objects - пользовательские поля
@@ -22,7 +21,6 @@
#ifndef __MODBUS_DEVID_H_ #ifndef __MODBUS_DEVID_H_
#define __MODBUS_DEVID_H_ #define __MODBUS_DEVID_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -110,7 +108,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj);
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @{ @{
*/ */
/* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */ /* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */
@@ -120,6 +118,5 @@ uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg);
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#endif //__MODBUS_DEVID_H_ #endif //__MODBUS_DEVID_H_

View File

@@ -1,23 +1,21 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_diag.h * @file modbus_diag.h
* @brief Диагностика устройства Modbus * @brief Диагностика устройства Modbus
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_DIAG Diagnostics Tools @addtogroup MODBUS_DIAG Diagnostics Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с диагностикой ******************************************************************************
*******************************************************************************
* @details * @details
Модуль реализации Diagnostics (Serial Line only) (0x08): Модуль реализации Diagnostics (Serial Line only) (0x08):
- Полная поддержка всех подфункций диагностики - Полная поддержка всех подфункций диагностики
- Возможность выставить/сбросить любой бит в диагностическом регистре - Возможность выставить/сбросить любой бит в диагностическом регистре
- Сбор статистики работы устройства - Сбор статистики работы устройства
- Управление режимами работы - Управление режимами работы
******************************************************************************/ ****************************************** ************************************/
#ifndef __MODBUS_DIAG_H_ #ifndef __MODBUS_DIAG_H_
#define __MODBUS_DIAG_H_ #define __MODBUS_DIAG_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_DIAGNOSTICS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////---DEVICE DIAGNOSTICS DEFINES---//////////////////// /////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
@@ -102,7 +100,7 @@ void MB_Diagnostics_SlaveBusyCnt(void);
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @{ @{
*/ */
/* Обработка команды диагностики (0x08) */ /* Обработка команды диагностики (0x08) */
@@ -117,7 +115,6 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg);
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_DIAGNOSTICS
#endif //__MODBUS_DIAG_H_ #endif //__MODBUS_DIAG_H_
/** MODBUS_DIAG /** MODBUS_DIAG

View File

@@ -1,29 +1,24 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_holdregs.h * @file modbus_holdregs.h
* @brief Работа с регистрами хранения Modbus * @brief Работа с регистрами хранения Modbus
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_HOLD Holding Registers Tools @addtogroup MODBUS_INS Input Register Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с регистрами хранения ******************************************************************************
*******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к регистрам хранения по глобальным адресам
Модуль обработки команд для регистров хранения (Holding Registers): Модуль обработки команд для регистров хранения (Holding Registers):
- Чтение множества регистров (0x03) - Чтение множества регистров (0x03)
- Запись одиночного регистра (0x06) - Запись одиночного регистра (0x06)
- Запись множества регистров (0x10) - Запись множества регистров (0x10)
@section hold Регистры хранения: @section Регистры хранения:
- Read/Write доступ - Read/Write доступ
- 16-битные значения (uint16_t) - 16-битные значения (uint16_t)
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_HOLDREGS_H_ #ifndef __MODBUS_HOLDREGS_H_
#define __MODBUS_HOLDREGS_H_ #define __MODBUS_HOLDREGS_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_HOLDINGS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
@@ -46,7 +41,7 @@ uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @{ @{
*/ */
/* Обработать функцию Read Holding Registers (03 - 0x03) */ /* Обработать функцию Read Holding Registers (03 - 0x03) */
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
@@ -60,5 +55,4 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_HOLDINGS
#endif //__MODBUS_HOLDREGS_H_ #endif //__MODBUS_HOLDREGS_H_

View File

@@ -1,27 +1,22 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_inputregs.h * @file modbus_inputregs.h
* @brief Работа с входными регистрами Modbus * @brief Работа с входными регистрами Modbus
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_INS Input Register Tools @addtogroup MODBUS_HOLD Holding Registers Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с входными регистрами ******************************************************************************
*******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к входным регистрам по глобальным адресам
Модуль обработки команд для входных регистров (Input Registers): Модуль обработки команд для входных регистров (Input Registers):
- Чтение множества регистров (0x04) - Чтение множества регистров (0x04)
@section in Входные регистры: @section Входные регистры:
- Read-Only доступ - Read-Only доступ
- 16-битные значения - 16-битные значения
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_INPUTREGS_H_ #ifndef __MODBUS_INPUTREGS_H_
#define __MODBUS_INPUTREGS_H_ #define __MODBUS_INPUTREGS_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_INPUTS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
@@ -45,7 +40,7 @@ uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions
* @ingroup MODBUS_INTERNAL * @ingroup MODBUS_INTERNAL
* @brief Функции обработки запросов модбас * @brief Функции обработки запросов модбас
* @{ @{
*/ */
/* Обработать функцию Read Input Registers (04 - 0x04) */ /* Обработать функцию Read Input Registers (04 - 0x04) */
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
@@ -55,5 +50,4 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_INPUTS
#endif //__MODBUS_INPUTREGS_H_ #endif //__MODBUS_INPUTREGS_H_

View File

@@ -1,24 +1,23 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_master.h * @file modbus_master.h
* @brief Главный заголовочный файл Modbus библиотеки * @brief Главный заголовочный файл Modbus библиотеки
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_MASTER Modbus master funtions @addtogroup MODBUS_MASTER Modbus master funtions
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS @ingroup MODBUS_CMD_PROCESS_FUNCTIONS
@brief Функции для работы в режиме Master ******************************************************************************
*******************************************************************************
* @details * @details
Модуль реализации Modbus в режиме мастер Модуль реализации обработки UART сообщение в режиме мастер
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_MASTER_H_ #ifndef __MODBUS_MASTER_H_
#define __MODBUS_MASTER_H_ #define __MODBUS_MASTER_H_
#include "rs_message.h" #include "rs_message.h"
#ifdef MODBUS_ENABLE_MASTER
/** /**
* @addtogroup MODBUS_REQUEST_MSG API for Master Requests * @addtogroup MODBUS_REQUEST_MSG API for Master Requests
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief API для формирования фрейма-запроса в режиме мастер * @brief Макросы для создания запросов в режиме мастер
* @details Примеры использования: * @details Примеры использования:
* @code * @code
* // Чтение 10 holding registers начиная с адреса 0 * // Чтение 10 holding registers начиная с адреса 0
@@ -81,20 +80,24 @@ RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t obj
* @code * @code
* // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105 * // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105
* uint16_t reg_value; * uint16_t reg_value;
* if(MB_RespGet_RegisterValue(modbus_msg, 105, &reg_value)) * if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, &reg_value))
* { * {
* printf("Register 105 value: %d\n", reg_value); * printf("Register 105 value: %d\n", reg_value);
* } * }
* *
* // Пример: Получить все запрошенные регистры * // Пример: Получить все запрошенные регистры
* uint16_t reg_value[125]; * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
* MB_RespGet_RegisterAll(modbus_msg) * {
* uint16_t value;
* if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
* {
* printf("Register %d: %d\n", addr, value);
* }
* }
* @endcode * @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); int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value);
@@ -112,16 +115,16 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1
* @code * @code
* // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25 * // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25
* int coil_state; * 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"); * printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF");
* } * }
* *
* // Пример: Получить состояние всех запрошенных coils * // Пример: Получить состояние всех запрошенных coils
* for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++) * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
* { * {
* int state; * 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"); * printf("Coil %d: %s\n", addr, state ? "ON" : "OFF");
* } * }
@@ -129,9 +132,7 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1
* @endcode * @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); int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state);
/** MODBUS_REQ_COILS_API /** MODBUS_REQ_COILS_API
@@ -149,7 +150,7 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi
* // Пример 1: Получить VendorName (ID = 0x00) * // Пример 1: Получить VendorName (ID = 0x00)
* uint8_t length; * uint8_t length;
* char vendor_name[64]; * char vendor_name[64];
* if(MB_RespGet_ObjectById(modbus_msg, 0x00, vendor_name, &length)) * if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length))
* { * {
* // получено * // получено
* } * }
@@ -158,12 +159,12 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi
* uint8_t obj_id, obj_length; * uint8_t obj_id, obj_length;
* char obj_data[256]; * 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); * printf("Total objects: %d\n", obj_count);
* *
* for(int i = 0; i < obj_count; i++) * 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))
* { * {
* // получено * // получено
* } * }
@@ -195,7 +196,7 @@ int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_
* @code * @code
* // Получить данные диагностики (значение счетчика) * // Получить данные диагностики (значение счетчика)
* uint16_t counter_value; * 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); * printf("Counter value: %d\n", counter_value);
* } * }
@@ -203,7 +204,6 @@ int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_
* @{ * @{
*/ */
/* Получить */
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data); int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data);
/** MODBUS_REQ_DIAG_API /** MODBUS_REQ_DIAG_API
@@ -228,5 +228,4 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
* @} * @}
*/ */
#endif //MODBUS_ENABLE_MASTER
#endif //__MODBUS_MASTER_H_ #endif //__MODBUS_MASTER_H_

View File

@@ -1,111 +0,0 @@
/**
*******************************************************************************
* @file modbus_oscil.h
* @brief Заголовочный файл модуля осциллографа через MODBUS.
*******************************************************************************
* @addtogroup MODBUS_OSCIL Modbus Oscilloscope
* @ingroup MODBUS
* @brief Модуль для сбора и хранения данных осциллографа
* @details
* Реализует кольцевой буфер для хранения данных с нескольких каналов
* с возможностью чтения через Modbus. Данные 8-битные, упаковываются
* по 2 сэмпла в 16-битный регистр Modbus.
*
* Карта Modbus регистров (адрес относительный):
* | Адрес | Биты | Назначение | Диапазон | Описание |
* |--------|------|------------|----------|----------|
* | 0x0000 | 0-3 | channels | 1-16 | Количество каналов |
* | | 4-7 | reserved | 0 | Зарезервировано |
* | | 8-15 | buffer_size| 1-125 | Размер буфера в регистрах |
* | 0x0001 | 0-7 | tail | 0-124 | Начало новых данных |
* | | 8-15 | head | 0-124 | Конец новых данных |
* | 0x0002...| 0-15| data | - | Буфер данных |
* @{
******************************************************************************/
#ifndef __MODBUS_OSCIL_H_
#define __MODBUS_OSCIL_H_
#include "modbus_core.h"
#ifdef MODBUS_ENABLE_OSCIL
/**
* @brief Структура конфигурации осциллографа
*/
typedef struct
{
/* Адрес 0 */
uint16_t Overrun:1; ///< Overrun
uint16_t NumbOfChannels:4; ///< Количество каналов (1-16)
uint16_t BufferSize:7; ///< Размер буфера в регистрах (1-125)
uint16_t SampleTime; ///< Адрес 1: Время между сэмплами в мкс/мс
uint16_t reserved[2]; ///< Резерв
uint32_t LastTick; ///< Адрес 4-5: Время последнего добавления (uint32_t)
} MB_ConfigTypeDef;
/**
* @brief Структура указателей буфера
*/
typedef struct
{
uint16_t Head:8; ///< Указатель на последний записанный байт
uint16_t Tail:8; ///< Указатель на начало непрочитанных данных (байты)
} MB_PreambleTypeDef;
/**
* @brief Основная структура осциллографа
*/
typedef struct
{
MB_ConfigTypeDef Config; /*!< @brief Отн. Адрес 0-6: Конфигурация */
uint16_t User[4]; /*!< @brief Отн. Адрес 6-9: Пользовательские регистры */
MB_PreambleTypeDef Preamble; /*!< @brief Отн. Адрес 10: Указатели head и tail буфера */
uint8_t Data[MbData_size*2-1]; ///< /*!< @brief Отн. Адрес 11-131: Буфер данных (в байтах) */
} MB_OscilTypeDef;
/**
* @addtogroup MODBUS_OSCIL_API API for Oscilloscope
* @ingroup MODBUS_OSCIL
* @brief API для работы с буфером осциллографа
* @details Примеры использования:
* @code
* MB_OscilTypeDef oscil;
*
* // Инициализация осциллографа
* MB_Oscil_Init(&oscil, 120, 4, 1000);
*
* // В цикле сбора данных
* uint8_t ch_data[4] = {adc1, adc2, adc3, adc4};
* MB_Oscil_Add(&oscil, ch_data);
*
* // После чтения данных через Modbus
* MB_Oscil_UpdateTail(&oscil);
* @endcode
* @{
*/
/* Инициализация структуры осциллографа */
HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime);
/* Добавление данных всех каналов в буфер */
HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data);
/* Обновление указателя Tail */
HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil);
/** MODBUS_OSCIL_API
* @}
*/
#endif //MODBUS_ENABLE_OSCIL
#endif //__MODBUS_OSCIL_H_
/** MODBUS_OSCIL
* @}
*/

View File

@@ -1,19 +1,18 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_slave.h * @file modbus_slave.h
* @brief Главный заголовочный файл Modbus библиотеки * @brief Главный заголовочный файл Modbus библиотеки
******************************************************************************* ******************************************************************************
@addtogroup MODBUS_SLAVE Modbus slave funtions @addtogroup MODBUS_SLAVE Modbus slave funtions
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS @ingroup MODBUS_CMD_PROCESS_FUNCTIONS
@brief Функции для работы в режиме Slave ******************************************************************************
*******************************************************************************
* @details * @details
Модуль реализации Modbus в режиме слейв Модуль реализации обработки UART сообщение в режиме слейв
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_SLAVE_H_ #ifndef __MODBUS_SLAVE_H_
#define __MODBUS_SLAVE_H_ #define __MODBUS_SLAVE_H_
#include "rs_message.h" #include "rs_message.h"
#ifdef MODBUS_ENABLE_SLAVE
/** /**
@@ -21,10 +20,6 @@
* @{ * @{
*/ */
/* Ответить позже, не в прерывании */
HAL_StatusTypeDef MB_Slave_ResponseLater(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode);
/* Ответить на запрос */
HAL_StatusTypeDef MB_Slave_SendResponse(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode, MB_ExceptionTypeDef error);
/* Ответ на сообщение в режиме слейва */ /* Ответ на сообщение в режиме слейва */
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */ /* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
@@ -35,7 +30,4 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
/** MODBUS_SLAVE /** MODBUS_SLAVE
* @} * @}
*/ */
#endif //MODBUS_ENABLE_SLAVE
#endif //__MODBUS_SLAVE_H_ #endif //__MODBUS_SLAVE_H_

View File

@@ -1,30 +1,30 @@
/** /**
******************************************************************************* ******************************************************************************
* @file rs_message.h * @file rs_message.h
* @brief Библиотека обмена сообщениями по RS-интерфейсу * @brief Библиотека обмена сообщениями по RS-интерфейсу
******************************************************************************* ******************************************************************************
@defgroup RS_TOOLS RS Tools @defgroup RS_TOOLS RS Tools
@brief Всякое для работы по UART/RS @brief Всякое для работы по UART/RS
@{ @{
******************************************************************************* ******************************************************************************
* @details * @details
Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom) Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom)
через UART в режиме прерываний с поддержкой таймаутов. через UART в режиме прерываний с поддержкой таймаутов.
@section posibility Основные возможности: @section Основные возможности:
- Прием/передача в прерываниях - Прием/передача в прерываниях
- Обработка IDLE линии для определения конца фрейма - Обработка IDLE линии для определения конца фрейма
- Таймауты приема через TIM - Таймауты приема через TIM
- Гибкая настройка размера сообщений - Гибкая настройка размера сообщений
@section usage Использование: @section Использование:
1. Определить структуру сообщения и размеры буфера 1. Определить структуру сообщения и размеры буфера
2. Реализовать weak-функции обработки сообщений 2. Реализовать weak-функции обработки сообщений
3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания 3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания
4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT() 4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT()
@section features Особенности: @section Особенности:
- Буфер: RS_Buffer[RS_MSG_SIZE_MAX] Общий для приема/передачи - Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи
- Состояния: отслеживается через флаги в RS_HandleTypeDef - Состояния: отслеживается через флаги в RS_HandleTypeDef
- Таймауты: контролируют максимальное время ожидания фрейма - Таймауты: контролируют максимальное время ожидания фрейма
******************************************************************************/ ******************************************************************************/
@@ -36,8 +36,8 @@
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---//////////////////////////// ////////////////////////////---DEFINES---////////////////////////////
/* Check that all defines required by RS are defined */ /* Check that all defines required by RS are defined */
#ifndef RS_MSG_SIZE_MAX #ifndef MSG_SIZE_MAX
#error Define RS_MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. #error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
#endif #endif
/** /**
@@ -45,7 +45,7 @@
*/ */
/* Clear message-uart buffer */ /* Clear message-uart buffer */
#define RS_Clear_Buff(_buff_) for(int i=0; i<RS_MSG_SIZE_MAX;i++) _buff_[i] = NULL #define RS_Clear_Buff(_buff_) for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL
/* Set/Reset flags */ /* Set/Reset flags */
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0 #define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
@@ -68,7 +68,7 @@
#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) #define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_)
/* Clear all RS stuff */ /* Clear all RS stuff */
#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->BufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_); #define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_);
//#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX) //#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX)
//#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) //#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX)
@@ -89,7 +89,6 @@
/** /**
* @addtogroup RS_DEBUG Tools for debug RS/UART/TIM * @addtogroup RS_DEBUG Tools for debug RS/UART/TIM
* @ingroup RS_TOOLS * @ingroup RS_TOOLS
* @brief Дефайны для отладки периферии
* @{ * @{
*/ */
@@ -97,25 +96,17 @@
#define RS_USER_VARS_NUMB 0 ///< Количество переменных в @ref TrackerTypeDef #define RS_USER_VARS_NUMB 0 ///< Количество переменных в @ref TrackerTypeDef
#endif #endif
#ifndef TrackerTypeDef
/** /**
* @brief Тип структуры для счетчиков-переменных * @brief Тип структуры для счетчиков-переменных
* @param num_user_vars Есть возмоность добавления num_user_vars количества пользовательскиъх переменных * @param num_user_vars Есть возмоность добавления num_user_vars количества пользовательскиъх переменных
*/ */
#define TrackerTypeDef(num_user_vars) void * #define TrackerTypeDef(num_user_vars) void *
#endif
#ifndef TrackerCnt_Ok
/** @brief Инкрементировать переменную - успешных событий */ /** @brief Инкрементировать переменную - успешных событий */
#define TrackerCnt_Ok(_cntstruct_) #define TrackerCnt_Ok(_cntstruct_)
#endif
#ifndef TrackerCnt_Err
/** @brief Инкрементировать переменную - ошибок */ /** @brief Инкрементировать переменную - ошибок */
#define TrackerCnt_Err(_cntstruct_) #define TrackerCnt_Err(_cntstruct_)
#endif
#ifndef TrackerCnt_Warn
/** @brief Инкрементировать переменную - предупреждений */ /** @brief Инкрементировать переменную - предупреждений */
#define TrackerCnt_Warn(_cntstruct_) #define TrackerCnt_Warn(_cntstruct_)
#endif
@@ -219,13 +210,11 @@ typedef struct
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
// Выставление следующие флагов определяет пользователь // Выставление следующие флагов определяет пользователь
unsigned RX_Continue:1; ///< 1 - Продолжить принимать, 0 - Начать прием сначала unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
unsigned DataUpdated:1; ///< 1 - Данные были обновлены: unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании
unsigned DeviceBusy:1; ///< 1 - Устройство занято (важно! не rs а именно устрройство) unsigned DataUpdated:1; ///< 1 - Данные были обновлены
unsigned DeferredResponse:8; ///< >0 - Не начинать передачу в IT, 0 - Ответить в прерывании
}RS_FlagsTypeDef; }RS_FlagsTypeDef;
@@ -239,7 +228,7 @@ typedef struct // RS_HandleTypeDef
/* MESSAGE */ /* MESSAGE */
uint8_t ID; ///< ID хендла uint8_t ID; ///< ID хендла
RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола
uint8_t BufferPtr[RS_MSG_SIZE_MAX]; ///< Указатеь на буфер UART uint8_t *pBufferPtr; ///< Указатеь на буфер UART
int32_t RS_Message_Size; ///< size of whole message, not only data int32_t RS_Message_Size; ///< size of whole message, not only data
/* HANDLERS and SETTINGS */ /* HANDLERS and SETTINGS */
@@ -247,7 +236,6 @@ typedef struct // RS_HandleTypeDef
TIM_HandleTypeDef *htim; ///< Хендл TIM TIM_HandleTypeDef *htim; ///< Хендл TIM
RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef
uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера
void (*pSetDirection)(int Tx); ///< Указатель на функцию: смена направления
void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер
/* FLAGS */ /* FLAGS */
@@ -291,7 +279,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Инициалазация структуры @ref RS_HandleTypeDef */ /* Инициалазация структуры @ref RS_HandleTypeDef */
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)); RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr);
/* Отменить прием/передачу RS/UART */ /* Отменить прием/передачу RS/UART */
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);

398
README.md
View File

@@ -6,29 +6,24 @@
*Note: Файлы начинающиеся с `__` и которых **нет** в этом дереве являются **внутренними/непротестированными/недокументированными*** *Note: Файлы начинающиеся с `__` и которых **нет** в этом дереве являются **внутренними/непротестированными/недокументированными***
``` ```
Modbus/ Иерархия модулей: Modbus/ Иерархия модулей:
│ inc/ modbus │ inc/ modbus
│ ├── modbus.h # Главный заголовочный файл modbus_slave │ ├── modbus.h # Главный заголовочный файл modbus_slave
│ ├── modbus_core.h # Базовые определения и структуры modbus_master │ ├── modbus_core.h # Базовые определения и структуры modbus_master
│ ├── modbus_coils.h # Работа с дискретными коилами ├── modbus_coils │ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils
│ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs │ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs
│ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs │ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs
│ ├── modbus_devid.h # Идентификаторы устройства ├── modbus_devid │ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid
│ ├── modbus_master.h # Заголовочный файл Master режима ├── modbus_diag │ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag
│ ├── modbus_slave.h # Заголовочный файл Slave режима ├── modbus_oscil ├── src/ └── rs_message
│ ├── modbus_diag.h # Диагностика Modbus └── rs_message │ ├── modbus.c # Основная логика Modbus │
│ ├── modbus_oscil.h # Осциллографирование данных │ │ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро)
── rs_message.h # Драйвер обмена по RS/UART └── modbus_core (единое ядро) ── modbus_master.c # Основная логика Master Modbus ├── modbus_config
├── src/ ├── modbus_config │ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data
│ ├── modbus.c # Основная логика Modbus ├── modbus_data │ ├── modbus_holdregs.c # Реализация регистров хранения └── __crc_algs
│ ├── modbus_slave.c # Основная логика Slave Modbus └── __crc_algs
│ ├── modbus_master.c # Основная логика Master Modbus
│ ├── modbus_coils.c # Реализация работы с coils
│ ├── modbus_holdregs.c # Реализация регистров хранения
│ ├── modbus_inputregs.c # Реализация входных регистров │ ├── modbus_inputregs.c # Реализация входных регистров
│ ├── modbus_devid.c # Реализация идентификации устройства │ ├── modbus_devid.c # Реализация идентификации устройства
│ ├── modbus_diag.c # Диагностические функции и счетчики ошибок │ ├── modbus_data.c # Функции доступа к данным
│ ├── modbus_oscil.c # Сбор и хранение осциллограмм
│ └── rs_message.c # Реализация драйвера RS │ └── rs_message.c # Реализация драйвера RS
├── __modbus_config.h # Конфигурация Modbus (надо заменить) ├── __modbus_config.h # Конфигурация Modbus (надо заменить)
├── __modbus_data.h # Структуры данных (надо заменить) ├── __modbus_data.h # Структуры данных (надо заменить)
@@ -37,14 +32,14 @@ Modbus/
## Инструкция по подключению ## Инструкция по подключению
### 1. **Склонируйте субмодуль** в ваш проект: 1. **Склонируйте субмодуль** в ваш проект:
```bash ```bash
git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus
git submodule update --init --recursive git submodule update --init --recursive
``` ```
### 2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов: 2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов:
``` ```
ProjectRoot/ ProjectRoot/
@@ -52,226 +47,219 @@ ProjectRoot/
│ ├── modbus_config.h # скопировать из __modbus_config.h │ ├── modbus_config.h # скопировать из __modbus_config.h
│ ├── modbus_data.h # скопировать из __modbus_data.h │ ├── modbus_data.h # скопировать из __modbus_data.h
│ └── modbus_data.c # скопировать из __modbus_data.c │ └── modbus_data.c # скопировать из __modbus_data.c
└── Modbus/ # Субмодуль └── Modbus/ # Субмодуль
``` ```
### 3. **Настройте конфигурацию** под ваш проект: 3. **Настройте конфигурацию** под ваш проект:
#### 3.1. Настройка периферии
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1 3.1. Настройка периферии
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
- **Включите прерывания** для UART и TIM
#### 3.2. Подключение обработчиков прерываний - **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
- **Включите прерывания** для UART и TIM
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков: 3.2. Подключение обработчиков прерываний
```c
#include "modbus.h"
void USARTx_IRQHandler(void) Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
{
RS_UART_Handler(&hmodbus1);
return;
HAL_UART_IRQHandler(&huart);
}
void TIMx_IRQHandler(void) ```c
{ #include "modbus.h"
RS_TIM_Handler(&hmodbus1);
return;
HAL_TIM_IRQHandler(&htim);
}
```
#### 3.3. В `modbus_config.h` укажите параметры устройства
#### 3.4. Инициализация в коде void USARTx_IRQHandler(void)
{
RS_UART_Handler(&hmodbus1);
return;
HAL_UART_IRQHandler(&huart);
}
Чтобы настроить Slave-режим `main()` после инициализации HAL: void TIMx_IRQHandler(void)
{
RS_TIM_Handler(&hmodbus1);
return;
HAL_TIM_IRQHandler(&htim);
}
```
```c 3.3. В `modbus_config.h` укажите параметры устройства
#include "modbus.h"
// TxEnable: 1 - передача, 0 - прием 3.4. Инициализация в коде
void SetTxDirectionFunc(int TxEnable)
{
HAL_GPIO_WritePin(SCIDE1_GPIO_Port, SCIDE1_Pin, !TxEnable);
}
int main(void) Чтобы настроить Slave-режим `main()` после инициализации HAL:
{
// Инициализация HAL
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
// Инициализация Modbus ```c
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, &SetTxDirectionFunc); #include "modbus.h"
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
// Запуск приема Modbus int main(void)
MODBUS_SlaveStart(&hmodbus1, NULL); {
// Инициализация HAL
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
while (1) // Инициализация Modbus
{ MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
// Основной цикл MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
}
}
```
Чтобы настроить Master-режим `main()` после инициализации HAL:
```c // Запуск приема Modbus
#include "modbus.h" MODBUS_SlaveStart(&hmodbus1, NULL);
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук while (1)
// При получении ответа вызовется функция callback_func() {
RS_MsgTypeDef read_hold_cmd = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); // Основной цикл
}
}
```
// коллбек, вызовется при получении ответа от слейва Чтобы настроить Master-режим `main()` после инициализации HAL:
uint16_t read_hold[10];
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{
// MB_RespGet_... Чтобы достать нужные данные из ответа
if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок ```c
{ #include "modbus.h"
for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++) // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
{ RS_MsgTypeDef read_hold_cmd = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
// Запись регистров из ответа в массив // коллбек, вызовется при получении ответа от слейва
uint16_t value; read_hold[10];
if(MB_RespGet_RegisterValue(modbus_msg, addr, &value)) 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++)
{ {
read_hold[i] = value; uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
{
read_hold[i] = value;
}
} }
} }
// Или так }
MB_RespGet_RegisterAll(modbus_msg, read_hold); // копирует все принятые регистр из modbus_msg в read_hold в количестве Qnt int main(void)
} {
else // Ответ получен с ошибкой или не получен вовсе // Инициализация HAL
{ HAL_Init();
} SystemClock_Config();
} MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
int main(void) // Инициализация Modbus
{ MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
// Инициализация HAL MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
// Инициализация Modbus // Запрос по Modbus
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func);
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
// Запрос по Modbus }
MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func); ```
3.5. Настройка карты данных
} В `modbus_data.h` настройте регистры и coils под ваше устройство:
```
#### 3.5. Настройка карты данных (только для режима Slave)
В `modbus_data.h` настройте регистры и coils под ваше устройство: **Input Registers (только чтение)**
```c
typedef struct
{
uint16_t Temperature; // Адрес 0
uint16_t Humidity; // Адрес 1
uint16_t Pressure; // Адрес 2
uint16_t Voltage; // Адрес 3
} MB_DataInRegsTypeDef;
**Input Registers (только чтение)** #define R_INPUT_ADDR 0 // Начальный адрес Input регистров
```c #define R_INPUT_QNT 4 // Количество Input регистров
typedef struct ```
{
uint16_t Temperature; // Адрес 0
uint16_t Humidity; // Адрес 1
uint16_t Pressure; // Адрес 2
uint16_t Voltage; // Адрес 3
} MB_DataInRegsTypeDef;
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров **Holding Registers (чтение/запись)**
#define R_INPUT_QNT 4 // Количество Input регистров ```c
``` typedef struct
**Holding Registers (чтение/запись)** {
```c uint16_t SetpointTemp; // Адрес 0
typedef struct uint16_t SetpointHumidity; // Адрес 1
{ uint16_t ControlMode; // Адрес 2
uint16_t SetpointTemp; // Адрес 0 } MB_DataHoldRegsTypeDef;
uint16_t SetpointHumidity; // Адрес 1
uint16_t ControlMode; // Адрес 2
} MB_DataHoldRegsTypeDef;
#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров #define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров
#define R_HOLDING_QNT 3 // Количество 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 C_COILS_ADDR 0 // Начальный адрес Coils **Coils (1-битные)**
#define C_COILS_QNT 4 // Количество Coils ```c
``` typedef struct
#### 3.6. Доступ к данным в коде {
unsigned Relay1 : 1; // Адрес 0
unsigned Relay2 : 1; // Адрес 1
unsigned Pump : 1; // Адрес 2
unsigned Heater : 1; // Адрес 3
unsigned reserved : 12; // Резерв (выравнивание до 16 бит)
} MB_DataCoilsTypeDef;
В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля #define C_COILS_ADDR 0 // Начальный адрес Coils
```c #define C_COILS_QNT 4 // Количество Coils
// Чтение входных регистров ```
uint16_t temp = MB_DATA.InRegs.Temperature;
// Запись в регистры хранения 3.6. Доступ к данным в коде
MB_DATA.HoldRegs.SetpointTemp = 2500;
// Управление coils
MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить 0 бит в Coils
MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить 1 бит в Coils
// Чтение coil В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) { ```c
// Pump включен // Чтение входных регистров
} uint16_t temp = MB_DATA.InRegs.Temperature;
```
В режиме **мастера** есть функции для получения информации из ответа `MB_RespGet_...()`
```c
// Чтение регистров: Получить запрошенные регистры
uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, &reg_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]; MB_DATA.HoldRegs.SetpointTemp = 2500;
if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, 0x00, &obj_id, obj_data, &obj_length))
{ // Управление coils
printf("First object - ID: 0x%02X, Data: %s\n", obj_id, obj_data); 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, &reg_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);
}
```
### 5. **Обновление библиотеки**: 5. **Обновление библиотеки**:
После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся: После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся:
```bash ```bash

View File

@@ -1,7 +1,8 @@
/** /**
******************************************************************************* **************************************************************************
* @file __modbus_compat.c * @file __modbus_compat.c
* @brief Модуль для совместимости библиотеки MODBUS. * @brief Модуль для совместимости библиотеки MODBUS.
******************************************************************************* **************************************************************************
* @details Файл содержит API старых функций, а также заглушки для отключенных модулей:
******************************************************************************/ ******************************************************************************/
#include "modbus.h" #include "modbus.h"

View File

@@ -1,12 +1,12 @@
/** /**
******************************************************************************* **************************************************************************
* @file modbus.c * @file modbus.c
* @brief Модуль для реализации MODBUS. * @brief Модуль для реализации MODBUS.
******************************************************************************* **************************************************************************
* @details * @details
Файл содержит реализацию функций работы с Modbus. Файл содержит реализацию функций работы с Modbus.
@section mbapi Функции и макросы @section Функции и макросы
### Инициализация: ### Инициализация:
- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM) - MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM)
@@ -24,6 +24,8 @@
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
@@ -34,11 +36,10 @@ static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_
* @param hmodbus Указатель на хендлер RS * @param hmodbus Указатель на хендлер RS
* @param huart Указатель на хендлер UART * @param huart Указатель на хендлер UART
* @param htim Указатель на хендлер TIM * @param htim Указатель на хендлер TIM
* @param pSetDirection Указатель на функцию для смены направления RS485
* @details Подключает хендлы периферии к hmodbus * @details Подключает хендлы периферии к hmodbus
* Конфигурация выставляется по умолчанию из modbus_config.h * Конфигурация выставляется по умолчанию из modbus_config.h
*/ */
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)) HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
{ {
if((hmodbus == NULL) || (huart == NULL)) if((hmodbus == NULL) || (huart == NULL))
{ {
@@ -52,10 +53,9 @@ HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT; hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
// INIT // INIT
hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, pSetDirection); hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
if(hmodbus->pSetDirection) RS_EnableReceive();
hmodbus->pSetDirection(0);
if(hmodbus->RS_STATUS == RS_OK) if(hmodbus->RS_STATUS == RS_OK)
return HAL_OK; return HAL_OK;
@@ -164,15 +164,9 @@ HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
return HAL_ERROR; return HAL_ERROR;
} }
//-------------------------------------------------------------------
//-----------------------------INTERNAL------------------------------
/**
* @brief Дефолтный коллбек для мастера.
* @param hmodbus Указатель на хендлер RS
* @param modbus_msg Указатель на структуру сообщения
* @details В этот коллбек попадут все запросы, с NULL-коллбеком
*/
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
__NOP(); __NOP();

View File

@@ -1,22 +1,14 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_coils.c * @file modbus_coils.c
* @brief Реализация работы с коилами Modbus * @brief Реализация работы с коилами Modbus
******************************************************************************* ******************************************************************************
* @details * @details
Модуль для доступа к coils внутри программы:
- Функции для доступа к coils по глобальным адресам
- Макросы для доступа к coils по локальным адресам
Модуль обработки команд для coils (битовых данных): Модуль обработки команд для coils (битовых данных):
- Чтение coils (0x01) - упаковка битов в байты для передачи - Чтение coils (0x01) - упаковка битов в байты для передачи
- Запись одиночного coil (0x05) - установка/сброс бита - Запись одиночного coil (0x05) - установка/сброс бита
- Запись множественных coils (0x0F) - распаковка битов из байтов - Запись множественных coils (0x0F) - распаковка битов из байтов
@section cvalid Валидация данных:
- Проверка соответствия количества байт и регистров
- Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах
******************************************************************************/ ******************************************************************************/
#include "modbus_coils.h" #include "modbus_coils.h"

View File

@@ -1,8 +1,8 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_core.c * @file modbus_core.c
* @brief Базовая реализация ядра Modbus * @brief Базовая реализация ядра Modbus
******************************************************************************* ******************************************************************************
* @details * @details
В текущей реализации этот файл служит заглушкой для будущего расширения В текущей реализации этот файл служит заглушкой для будущего расширения
функциональности ядра Modbus протокола. функциональности ядра Modbus протокола.

View File

@@ -1,15 +1,15 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_devid.c * @file modbus_devid.c
* @brief Реализация идентификаторов устройства Modbus * @brief Реализация идентификаторов устройства Modbus
******************************************************************************* ******************************************************************************
* @details * @details
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E: Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
- Формирование иерархии объектов идентификации - Формирование иерархии объектов идентификации
- Поддержка потоковой передачи при большом количестве объектов - Поддержка потоковой передачи при большом количестве объектов
- Автоматический расчет MoreFollows флагов - Автоматический расчет MoreFollows флагов
@section stream Потоковая передача: @section Потоковая передача:
При большом количестве объектов идентификация разбивается на несколько При большом количестве объектов идентификация разбивается на несколько
сообщений с установкой флага MoreFollows и указанием NextObjId для сообщений с установкой флага MoreFollows и указанием NextObjId для
продолжения чтения в следующем запросе. продолжения чтения в следующем запросе.
@@ -51,7 +51,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
/* Define number of object in one message */ /* Define number of object in one message */
unsigned lastobjid = 0; unsigned lastobjid = 0;
for(int i = 0; i < MbData_size*2;) for(int i = 0; i < DATA_SIZE*2;)
{ {
/* Если объект за пределами допутимого - выходим из цикла */ /* Если объект за пределами допутимого - выходим из цикла */
if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS) if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS)
@@ -60,7 +60,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
i += 2; i += 2;
i += obj[objidtmp].length; i += obj[objidtmp].length;
/* Если все еще помещается в массив переходим на следующий объект */ /* Если все еще помещается в массив переходим на следующий объект */
if(i < MbData_size*2) if(i < DATA_SIZE*2)
{ {
objidtmp++; objidtmp++;
} }

View File

@@ -1,8 +1,8 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_diag.c * @file modbus_diag.c
* @brief Реализация диагностики устройства Modbus * @brief Реализация диагностики устройства Modbus
******************************************************************************* ******************************************************************************
* @details * @details
Модуль обработки запросов диагностической информации (0x08): Модуль обработки запросов диагностической информации (0x08):
- Полная поддержка всех подфункций диагностики согласно спецификации Modbus - Полная поддержка всех подфункций диагностики согласно спецификации Modbus

View File

@@ -1,21 +1,22 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_holdregs.c * @file modbus_holdregs.c
* @brief Реализация работы с регистрами хранения Modbus * @brief Реализация работы с регистрами хранения Modbus
******************************************************************************* ******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к регистрам хранения по глобальным адресам
Модуль обработки команд для holding registers (регистров хранения): Модуль обработки команд для holding registers (регистров хранения):
- Чтение множественных регистров (0x03) - копирование данных в буфер ответа - Чтение множественных регистров (0x03) - копирование данных в буфер ответа
- Запись одиночного регистра (0x06) - прямая запись значения - Запись одиночного регистра (0x06) - прямая запись значения
- Запись множественных регистров (0x10) - пакетная запись из буфера - Запись множественных регистров (0x10) - пакетная запись из буфера
@section hvalid Валидация данных: @section Валидация данных:
- Проверка соответствия количества байт и регистров - Проверка соответствия количества байт и регистров
- Валидация адресов через MB_DefineRegistersAddress() Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах - Обработка исключений при некорректных запросах
@section Echo-ответы:
При успешной записи формируется echo-ответ с теми же данными,
что были в запросе (для функций 0x05, 0x06, 0x0F, 0x10).
******************************************************************************/ ******************************************************************************/
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
@@ -40,7 +41,7 @@ MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal)
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
//------------WRITE COIL------------- //------------WRITE COIL-------------
Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 1); Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding);
if(Exception == ET_NO_ERRORS) if(Exception == ET_NO_ERRORS)
{ {
*(pHoldRegs) = WriteVal; *(pHoldRegs) = WriteVal;
@@ -66,7 +67,7 @@ uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
//------------READ COIL-------------- //------------READ COIL--------------
Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 0); Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding);
if(Exception) // if exception is not given to func fill it if(Exception) // if exception is not given to func fill it
*Exception = Exception_tmp; *Exception = Exception_tmp;
@@ -94,7 +95,7 @@ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 0); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -121,7 +122,7 @@ uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
{ {
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding, 1); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -146,7 +147,7 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
} }
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 1); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;

View File

@@ -1,18 +1,13 @@
/** /**
******************************************************************************* ******************************************************************************
* @file modbus_inputregs.c * @file modbus_inputregs.c
* @brief Реализация работы с входными регистрами Modbus * @brief Реализация работы с входными регистрами Modbus
******************************************************************************* ******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к входным регистрам по глобальным адресам
Модуль обработки команды чтения input registers (0x04): Модуль обработки команды чтения input registers (0x04):
- Чтение множественных входных регистров
@section ivalid Валидация данных: Копирование данных из структур устройства в буфер ответа
- Проверка соответствия количества байт и регистров - Поддержка знаковых и беззнаковых значений
- Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах
******************************************************************************/ ******************************************************************************/
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
@@ -36,7 +31,7 @@ MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal)
uint16_t *pInRegs; uint16_t *pInRegs;
//------------WRITE COIL------------- //------------WRITE COIL-------------
Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 1); Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input);
if(Exception == ET_NO_ERRORS) if(Exception == ET_NO_ERRORS)
{ {
*(pInRegs) = WriteVal; *(pInRegs) = WriteVal;
@@ -62,7 +57,7 @@ uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
uint16_t *pInRegs; uint16_t *pInRegs;
//------------READ COIL-------------- //------------READ COIL--------------
Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 0); Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input);
if(Exception) // if exception is not given to func fill it if(Exception) // if exception is not given to func fill it
*Exception = Exception_tmp; *Exception = Exception_tmp;
@@ -89,7 +84,7 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
// get origin address for data // get origin address for data
uint16_t *pInRegs; uint16_t *pInRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input, 0); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;

View File

@@ -1,22 +1,12 @@
/** /**
******************************************************************************* **************************************************************************
* @file modbus_master.c * @file modbus_master.c
* @brief Модуль для реализации мастера MODBUS. * @brief Модуль для реализации мастера MODBUS.
******************************************************************************* **************************************************************************
* @details * @details
Файл содержит реализацию функций для работы Modbus в режиме мастера. Файл содержит реализацию функций для работы Modbus в режиме мастера.
@section mast Функции и макросы @section Функции и макросы
- 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_Collect_Message() — Сбор сообщения в режиме мастера
- MB_Master_Parse_Message() — Парс сообщения в режиме мастера - MB_Master_Parse_Message() — Парс сообщения в режиме мастера
@@ -26,35 +16,8 @@
#ifdef MODBUS_ENABLE_MASTER #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, &reg_arr[i]))
{
read_cnt++;
}
i++;
}
return read_cnt;
}
/**
* @brief Получить значение регистра в ответе по его адресу
* @param modbus_msg Указатель на структуру сообщения * @param modbus_msg Указатель на структуру сообщения
* @param reg_addr Адрес регистра, значение которого нужно получить * @param reg_addr Адрес регистра, значение которого нужно получить
* @param reg_value Указатель для значения регистра * @param reg_value Указатель для значения регистра
@@ -92,31 +55,6 @@ 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 в ответе по его адресу * @brief Получить состояние coil в ответе по его адресу
* @param modbus_msg Указатель на структуру сообщения * @param modbus_msg Указатель на структуру сообщения
@@ -155,7 +93,7 @@ int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coi
if(bit_index < 8) if(bit_index < 8)
*coil_state = (modbus_msg->MbData[data_index] >> (bit_index+8)) & 0x01; *coil_state = (modbus_msg->MbData[data_index] >> (bit_index+8)) & 0x01;
else 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; return 1;
@@ -312,10 +250,6 @@ int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data)
} }
//-------------------------------------------------------------------
//-----------------------------INTERNAL------------------------------
/** /**
* @brief Определить размер модбас запроса (МАСТЕР версия). * @brief Определить размер модбас запроса (МАСТЕР версия).
* @param hRS Указатель на хендлер RS. * @param hRS Указатель на хендлер RS.
@@ -374,7 +308,7 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
} }
} }
mb_func_size = RS_RX_FIRST_PART_SIZE + mb_func_size; // size of whole message mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
return mb_func_size; return mb_func_size;
} }
@@ -392,7 +326,7 @@ RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgType
//------INFO ABOUT DATA/MESSAGE------ //------INFO ABOUT DATA/MESSAGE------
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of slave device // set ID of slave device
modbus_uart_buff[ind++] = modbus_msg->DeviceAddr; modbus_uart_buff[ind++] = modbus_msg->MbAddr;
// set function code // set function code
modbus_uart_buff[ind++] = modbus_msg->FuncCode; modbus_uart_buff[ind++] = modbus_msg->FuncCode;
@@ -472,7 +406,7 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
int expected_size = 0; int expected_size = 0;
// get ID of slave device // get ID of slave device
modbus_msg->DeviceAddr = modbus_uart_buff[ind++]; modbus_msg->MbAddr = modbus_uart_buff[ind++];
// get function code (check if error response) // get function code (check if error response)
modbus_msg->FuncCode = modbus_uart_buff[ind++]; modbus_msg->FuncCode = modbus_uart_buff[ind++];
@@ -633,7 +567,7 @@ RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start
// Copy coil data to message MbData array // Copy coil data to message MbData array
for(int i = 0; i < byte_count; i++) { for(int i = 0; i < byte_count; i++) {
if(i < MbData_size) { if(i < DATA_SIZE) {
msg.MbData[i] = coils_data[i]; msg.MbData[i] = coils_data[i];
} }
} }
@@ -649,7 +583,7 @@ RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_
msg.ByteCnt = quantity * 2; // Each register is 2 bytes msg.ByteCnt = quantity * 2; // Each register is 2 bytes
// Copy register data to message MbData array // Copy register data to message MbData array
for(int i = 0; i < quantity && i < MbData_size; i++) { for(int i = 0; i < quantity && i < DATA_SIZE; i++) {
msg.MbData[i] = regs_data[i]; msg.MbData[i] = regs_data[i];
} }

View File

@@ -1,145 +0,0 @@
/**
*******************************************************************************
* @file modbus_oscil.c
* @brief Модуль для реализации осциллографа через MODBUS.
*******************************************************************************
* @details
* Файл содержит реализацию функций для работы с буфером осциллографа.
*
* @section oscil_functions Функции
* - MB_Oscil_Init() — Инициализация структуры осциллографа
* - MB_Oscil_Add() — Добавление данных в буфер
* - MB_Oscil_UpdateTail() — Обновление указателя Tail
******************************************************************************/
#include "modbus_oscil.h"
#ifdef MODBUS_ENABLE_OSCIL
/**
* @brief Инициализация структуры осциллографа
* @param oscil Указатель на структуру осциллографа
* @param BufferSize Размер буфера в Modbus регистрах (max 125)
* @param NumbOfChannels Количество каналов (должно быть четным)
* @param SampleTime Период дискретизации
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime)
{
if(!oscil || (BufferSize >= MbData_size) || (NumbOfChannels > 15) || !SampleTime)
return HAL_ERROR;
if(NumbOfChannels % 2 != 0)
return HAL_ERROR;
oscil->Config.BufferSize = BufferSize;
oscil->Config.NumbOfChannels = NumbOfChannels;
oscil->Config.SampleTime = SampleTime;
oscil->Config.LastTick = 0;
oscil->Preamble.Head = 0;
oscil->Preamble.Tail = 0;
oscil->Config.Overrun = 0;
return HAL_OK;
}
/**
* @brief Инициализация структуры осциллографа
* @param oscil Указатель на структуру осциллографа
* @param BufferSize Размер буфера в Modbus регистрах (max 125)
* @param NumbOfChannels Количество каналов (должно быть четным)
* @param SampleTime Период дискретизации
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Set_SampleTime(MB_OscilTypeDef *oscil, uint16_t SampleTime)
{
if(!oscil || !SampleTime)
return HAL_ERROR;
oscil->Config.SampleTime = SampleTime;
return HAL_OK;
}
/**
* @brief Добавление данных всех каналов в буфер
* @param oscil Указатель на структуру осциллографа
* @param Data Массив с данными каналов (длина = NumbOfChannels)
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data)
{
if(!oscil || !Data)
return HAL_ERROR;
if(local_time() - oscil->Config.LastTick < oscil->Config.SampleTime)
return HAL_BUSY;
oscil->Config.LastTick = local_time();
uint8_t head_max = oscil->Config.BufferSize * 2;
uint8_t start_pos = oscil->Preamble.Head;
uint8_t channels = oscil->Config.NumbOfChannels;
uint8_t tail = oscil->Preamble.Tail;
// Пишем данные
for(uint8_t i = 0; i < channels; i++)
{
uint8_t write_pos = (start_pos + i) % head_max;
oscil->Data[write_pos] = Data[i];
}
// Новое положение Head
uint8_t new_head = (start_pos + channels) % head_max;
// Проверяем, есть ли непрочитанные данные (Tail != Head)
// if(tail != start_pos) {
// Если есть непрочитанные данные, проверяем не перетерли ли мы их
if(start_pos < new_head) {
// Линейный случай
if(tail > start_pos && tail <= new_head) {
oscil->Preamble.Tail = (new_head + 1) % head_max;
oscil->Config.Overrun = 1;
}
} else if(start_pos > new_head) {
// Кольцевой случай (было переполнение)
if(tail > start_pos || tail <= new_head) {
oscil->Preamble.Tail = (new_head + 1) % head_max;
oscil->Config.Overrun = 1;
}
}
// }
oscil->Preamble.Head = new_head;
return HAL_OK;
}
/**
* @brief Обновление указателя Tail
* @param oscil Указатель на структуру осциллографа
* @return HAL Status
*
* @details Вызывается после того, как данные были прочитаны через Modbus.
* Tail устанавливается на следующий байт за Head.
*/
HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil)
{
if(!oscil)
return HAL_ERROR;
// Сдвигаем Tail на следующий байт за Head
uint8_t head_max = oscil->Config.BufferSize * 2;
oscil->Preamble.Tail = oscil->Preamble.Head;
if(oscil->Preamble.Tail >= head_max)
oscil->Preamble.Tail = 0;
oscil->Config.Overrun = 0;
return HAL_OK;
}
#endif //MODBUS_ENABLE_OSCIL

View File

@@ -1,14 +1,12 @@
/** /**
******************************************************************************* **************************************************************************
* @file modbus_slave.c * @file modbus_slave.c
* @brief Модуль для реализации слейв MODBUS. * @brief Модуль для реализации слейв MODBUS.
******************************************************************************* **************************************************************************
* @details * @details
Файл содержит реализацию функций для работы Modbus в режиме слейва. Файл содержит реализацию функций для работы Modbus в режиме слейва.
@section slave Функции и макросы @section Функции и макросы
- MB_Slave_ResponseLater() — Выставить флаг на ответ вне прерывания
- MB_Slave_SendResponse() — Ответить на запрос
- MB_Slave_Response() — Ответ на запрос - MB_Slave_Response() — Ответ на запрос
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва. - MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
@@ -17,66 +15,6 @@
#include "modbus.h" #include "modbus.h"
#ifdef MODBUS_ENABLE_SLAVE #ifdef MODBUS_ENABLE_SLAVE
/**
* @brief Ответить позже, не в прерывании.
* @param hmodbus Указатель на хендлер RS.
* @param ResponseCode Код запроса на который надо ответить.
* @return HAL Status.
* @details Отменяет ответ в прерывании на запрос.
Используется вместе с @ref MB_Slave_SendResponse
*/
HAL_StatusTypeDef MB_Slave_ResponseLater(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode)
{
hmodbus->f.DeferredResponse = ResponseCode;
return HAL_OK;
}
/**
* @brief Ответить на запрос.
* @param hmodbus Указатель на хендлер RS.
* @param ResponseCode Код запроса на который надо ответить.
* @param error Тип ошибки или её отсутствия в ответе.
* @return HAL Status.
* @details Ответить на запрос вне прерывания.
Используется вместе с @ref MB_Slave_ResponseLater
*/
HAL_StatusTypeDef MB_Slave_SendResponse(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode, MB_ExceptionTypeDef error)
{
RS_StatusTypeDef MB_RES = 0;
if(hmodbus->f.DeferredResponse == ResponseCode)
{
hmodbus->f.DeferredResponse = 0;
switch(error)
{
case ET_NO_ERRORS:
break;
case ET_ACKNOWLEDGE:
MB_Diagnostics_SlaveNAKCnt();
break;
case ET_SLAVE_DEVICE_BUSY:
MB_Diagnostics_SlaveBusyCnt();
break;
default:
break;
}
if(error != ET_NO_ERRORS)
{
MB_Diagnostics_ExceptionErrorCnt();
TrackerCnt_Warn(hmodbus->rs_err);
hmodbus->pMessagePtr->FuncCode |= FC_ERR_VALUES_START;
hmodbus->pMessagePtr->Except_Code = error;
}
hmodbus->RS_STATUS = RS_Handle_Transmit_Start(hmodbus, hmodbus->pMessagePtr);
}
return HAL_OK;
}
/** /**
* @brief Ответ на сообщение в режиме слейва. * @brief Ответ на сообщение в режиме слейва.
* @param hmodbus Указатель на хендлер RS. * @param hmodbus Указатель на хендлер RS.
@@ -91,7 +29,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
MB_Diagnostics_BusMessageCnt(); MB_Diagnostics_BusMessageCnt();
if(hmodbus->ID == 0 || modbus_msg->DeviceAddr == 0) if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0)
{ {
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
hmodbus->RS_STATUS = RS_SKIP; hmodbus->RS_STATUS = RS_SKIP;
@@ -111,11 +49,6 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
// Read Hodling Registers // Read Hodling Registers
case FC_R_HOLD_REGS: case FC_R_HOLD_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
#ifdef MODBUS_ENABLE_OSCIL
int is_oscil_data_register = ((hmodbus->pMessagePtr->Addr >= R_HOLDING_OSCIL_ADDR+4) && (hmodbus->pMessagePtr->Addr + hmodbus->pMessagePtr->Qnt <= (R_HOLDING_OSCIL_ADDR+5+(sizeof(MB_OscilTypeDef)/2))));
if(is_oscil_data_register)
MB_Oscil_UpdateTail(&MB_INTERNAL.oscil);
#endif
break; break;
case FC_R_IN_REGS: case FC_R_IN_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);
@@ -179,6 +112,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
} }
// Проверяем режим устройства - если Listen Only, не обрабатываем команды // Проверяем режим устройства - если Listen Only, не обрабатываем команды
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE) if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
{ {
@@ -213,8 +147,8 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
} }
else else
{ {
// RS_Handle_Receive_Start(hmodbus, modbus_msg); RS_Handle_Receive_Start(hmodbus, modbus_msg);
// hmodbus->f.DeferredResponse = 0; hmodbus->f.DeferredResponse = 0;
} }
hmodbus->RS_STATUS = MB_RES; hmodbus->RS_STATUS = MB_RES;
@@ -234,7 +168,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
{ {
int ind = 0; // ind for modbus-uart buffer int ind = 0; // ind for modbus-uart buffer
if(hmodbus->f.EchoResponse && (modbus_msg->Except_Code == ET_NO_ERRORS)) // if echo response need if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
ind = hmodbus->RS_Message_Size; ind = hmodbus->RS_Message_Size;
else else
{ {
@@ -251,7 +185,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
#endif #endif
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of message/user // set ID of message/user
modbus_uart_buff[ind++] = modbus_msg->DeviceAddr; modbus_uart_buff[ind++] = modbus_msg->MbAddr;
// set dat or err response // set dat or err response
modbus_uart_buff[ind++] = modbus_msg->FuncCode; modbus_uart_buff[ind++] = modbus_msg->FuncCode;
@@ -270,7 +204,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId; modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj; modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj;
if (modbus_msg->ByteCnt > MbData_size*2) // if ByteCnt less than MbData_size if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
{ {
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
return RS_COLLECT_MSG_ERR; return RS_COLLECT_MSG_ERR;
@@ -301,7 +235,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
else // modbus data header else // modbus data header
{ {
// set size of received data // set size of received data
if (modbus_msg->ByteCnt <= MbData_size*2) // if ByteCnt less than MbData_size if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
modbus_uart_buff[ind++] = modbus_msg->ByteCnt; modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
else // otherwise return data_size err else // otherwise return data_size err
{ {
@@ -380,7 +314,7 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
} }
mb_func_size = RS_RX_FIRST_PART_SIZE + mb_func_size; // size of whole message mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
return mb_func_size; return mb_func_size;
} }
@@ -414,12 +348,12 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
// get ID of message/user // get ID of message/user
if(modbus_uart_buff[ind] != hmodbus->ID) if(modbus_uart_buff[ind] != hmodbus->ID)
{ {
modbus_msg->DeviceAddr = 0; modbus_msg->MbAddr = 0;
ind++; ind++;
} }
else else
{ {
modbus_msg->DeviceAddr = modbus_uart_buff[ind++]; modbus_msg->MbAddr = modbus_uart_buff[ind++];
} }
// get func code // get func code
@@ -427,7 +361,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // явная херня if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // явная херня
{ {
MB_Diagnostics_SlaveNAKCnt(); MB_Diagnostics_SlaveNAKCnt();
modbus_msg->DeviceAddr = 0; modbus_msg->MbAddr = 0;
return RS_SKIP; return RS_SKIP;
} }
@@ -490,7 +424,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
if (modbus_msg->ByteCnt != 0) if (modbus_msg->ByteCnt != 0)
{ {
//check that data size is correct //check that data size is correct
if (modbus_msg->ByteCnt > MbData_size*2) if (modbus_msg->ByteCnt > DATA_SIZE*2)
{ {
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
modbus_msg->FuncCode |= FC_ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;

View File

@@ -1,8 +1,8 @@
/** /**
******************************************************************************* ******************************************************************************
* @file rs_message.c * @file rs_message.c
* @brief Реализация протоколов обмена по RS/UART * @brief Реализация протоколов обмена по RS/UART
******************************************************************************* ******************************************************************************
* @details * @details
Модуль реализует асинхронный обмен сообщениями через UART с использованием: Модуль реализует асинхронный обмен сообщениями через UART с использованием:
- Прерываний по приему/передаче - Прерываний по приему/передаче
@@ -10,21 +10,23 @@
- Таймаутов через таймер - Таймаутов через таймер
- Двухстадийного приема (заголовок + данные) - Двухстадийного приема (заголовок + данные)
@section arch Архитектура: @section Архитектура:
В режиме слейв: В режиме слейв:
- Инициализация приема с сообщения с максимальным размером RS_MSG_SIZE_MAX - Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX
- При срабатывании прерывания IDLE - обработка полученного сообщения - При срабатывании прерывания IDLE - обработка полученного сообщения
В режиме мастер (пока не реализовано): В режиме мастер (пока не реализовано):
- Отправка запроса и переход в режим приема сообщения с максимальным размером RS_MSG_SIZE_MAX - Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX
- При срабатывании прерывания IDLE - обработка полученного ответа - При срабатывании прерывания IDLE - обработка полученного ответа
@section ithandler Необходимые обработчики: @section Необходимые обработчики:
- RS_UART_Handler() в UARTx_IRQHandler вместо HAL_UART_IRQHandler() - RS_UART_Handler() в UARTx_IRQHandler вместо HAL_UART_IRQHandler()
- RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler() - RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler()
******************************************************************************/ ******************************************************************************/
#include "rs_message.h" #include "rs_message.h"
#include "modbus_diag.h" #include "modbus_diag.h"
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
extern void RS_UART_Init(void); extern void RS_UART_Init(void);
extern void RS_UART_DeInit(UART_HandleTypeDef *huart); extern void RS_UART_DeInit(UART_HandleTypeDef *huart);
extern void RS_TIM_Init(void); extern void RS_TIM_Init(void);
@@ -50,8 +52,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
//-----------INITIALIZE RECEIVE------------- //-----------INITIALIZE RECEIVE-------------
// if all OK: start receiving // if all OK: start receiving
if(hRS->pSetDirection) RS_EnableReceive();
hRS->pSetDirection(0);
RS_Set_Busy(hRS); // set RS busy RS_Set_Busy(hRS); // set RS busy
RS_Set_RX_Flags(hRS); // initialize flags for receive RS_Set_RX_Flags(hRS); // initialize flags for receive
hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions
@@ -60,7 +61,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
// start receiving // start receiving
__HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE); __HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE);
uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->BufferPtr[hRS->RS_Message_Size], RS_MSG_SIZE_MAX); // receive until ByteCnt+1 byte, uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte,
// then in Callback restart receive for rest bytes // then in Callback restart receive for rest bytes
// if receive isnt started - abort RS // if receive isnt started - abort RS
@@ -100,7 +101,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
//------------COLLECT MESSAGE--------------- //------------COLLECT MESSAGE---------------
RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->BufferPtr); RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr);
if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES
{// need collect message status, so doesnt write abort to RS_RES {// need collect message status, so doesnt write abort to RS_RES
RS_Abort(hRS, ABORT_RS); RS_Abort(hRS, ABORT_RS);
@@ -110,8 +111,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
//----------INITIALIZE TRANSMIT------------- //----------INITIALIZE TRANSMIT-------------
if(hRS->pSetDirection) RS_EnableTransmit();
hRS->pSetDirection(1);
RS_Set_Busy(hRS); // set RS busy RS_Set_Busy(hRS); // set RS busy
RS_Set_TX_Flags(hRS); // initialize flags for transmit IT RS_Set_TX_Flags(hRS); // initialize flags for transmit IT
@@ -123,7 +123,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
return RS_ERR; return RS_ERR;
} }
// if all OK: start transmitting // if all OK: start transmitting
uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->BufferPtr, hRS->RS_Message_Size); uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size);
// if transmit isnt started - abort RS // if transmit isnt started - abort RS
if(uart_res != HAL_OK) if(uart_res != HAL_OK)
{ {
@@ -153,7 +153,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
* @return RS_RES Статус о состоянии RS после инициализации. * @return RS_RES Статус о состоянии RS после инициализации.
* @details Инициализация перефирии и структуры для приема-передачи по RS. * @details Инициализация перефирии и структуры для приема-передачи по RS.
*/ */
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)) RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr)
{ {
// check that hRS is defined // check that hRS is defined
if (hRS == NULL) if (hRS == NULL)
@@ -166,7 +166,13 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
hRS->htim = htim; hRS->htim = htim;
hRS->pSetDirection = pSetDirection; // check that buffer is defined
if (hRS->pBufferPtr == NULL)
{
hRS->pBufferPtr = RS_Buffer; // if no - set default
}
else
hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user
return RS_OK; return RS_OK;
} }
@@ -343,7 +349,7 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
RS_Set_RX_End(hRS); RS_Set_RX_End(hRS);
// Парсим наше сообщение // Парсим наше сообщение
hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->BufferPtr); hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr);
// Если сообещине принято корректно // Если сообещине принято корректно
if(hRS->RS_STATUS == RS_OK) if(hRS->RS_STATUS == RS_OK)
@@ -439,7 +445,7 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
hRS->RS_STATUS = RS_TIMEOUT; hRS->RS_STATUS = RS_TIMEOUT;
if(hRS->sRS_Mode < RS_MASTER_MODE_START) if(hRS->sRS_Mode < RS_MASTER_MODE_START)
if(hRS->pMessagePtr->DeviceAddr == hRS->ID) // ошибка если таймаут по нашему сообщению if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
TrackerCnt_Err(hRS->rs_err); TrackerCnt_Err(hRS->rs_err);
if(hRS->sRS_Mode >= RS_MASTER_MODE_START) if(hRS->sRS_Mode >= RS_MASTER_MODE_START)

View File

@@ -5,7 +5,6 @@
****************************************************************************** ******************************************************************************
@addtogroup MODBUS_CONFIGS Modbus configs @addtogroup MODBUS_CONFIGS Modbus configs
@ingroup MODBUS @ingroup MODBUS
@brief Конфигурация библиотеки
@{ @{
****************************************************************************** ******************************************************************************
* @details * @details
@@ -40,6 +39,8 @@
// Периферия (опционально) // Периферия (опционально)
#define mb_huart huart1 ///< Удобный дефайн для модбасовского uart #define mb_huart huart1 ///< Удобный дефайн для модбасовского uart
#define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера #define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера
//#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
//#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
// Модули modbus // Модули modbus
@@ -52,12 +53,10 @@
#define MODBUS_ENABLE_DEVICE_IDENTIFICATIONS ///< Включить обработку идентификаторы устройства #define MODBUS_ENABLE_DEVICE_IDENTIFICATIONS ///< Включить обработку идентификаторы устройства
#define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас #define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас
#define MODBUS_ENABLE_OSCIL ///< Включить осциллограф Modbus
//#define MODBUS_PROTOCOL_TCP ///< Включить TCP-протокол, иначе - RTU //#define MODBUS_PROTOCOL_TCP ///< Включить TCP-протокол, иначе - RTU
/** /**
* @brief Поменять комманды 0x03 и 0x04 местами * @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей)
* @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS * @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS
* Поэтому чтобы считывать Input Regs - надо поменять их местами. * Поэтому чтобы считывать Input Regs - надо поменять их местами.
*/ */

View File

@@ -22,8 +22,6 @@
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
#include "modbus_devid.h" #include "modbus_devid.h"
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = { 0 }; ///< Coils & Registers
/** /**
* @brief Check is address valid for certain array. * @brief Check is address valid for certain array.
@@ -65,10 +63,10 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16
* @details Определение адреса начального регистра. * @details Определение адреса начального регистра.
* @note WriteFlag пока не используется. * @note WriteFlag пока не используется.
*/ */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag) MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType)
{ {
/* check quantity error */ /* check quantity error */
if (Qnt > MbData_size) if (Qnt > DATA_SIZE)
{ {
return ET_ILLEGAL_DATA_VALUE; // return exception code return ET_ILLEGAL_DATA_VALUE; // return exception code
} }
@@ -80,13 +78,6 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
{ {
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр
} }
#if defined(MODBUS_ENABLE_OSCIL) && defined(R_HOLDING_OSCIL_ADDR) && defined(R_HOLDING_OSCIL_QNT)
else if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_OSCIL_ADDR, R_HOLDING_OSCIL_QNT) == ET_NO_ERRORS)
{
local_addr = Addr - R_HOLDING_OSCIL_ADDR;
*pRegs = MB_Set_Register_Ptr(&MB_INTERNAL.oscil , local_addr); // указатель на выбранный по Addr регистр
}
#endif
// if address doesnt match any array - return illegal data address response // if address doesnt match any array - return illegal data address response
else else
{ {

View File

@@ -3,7 +3,7 @@
* @file modbus_data.h * @file modbus_data.h
* @brief Определения структур данных Modbus устройства * @brief Определения структур данных Modbus устройства
****************************************************************************** ******************************************************************************
@defgroup MODBUS_DATA Modbus Registers Map @defgroup MODBUS_DATA Modbus Data Tools
@ingroup MODBUS @ingroup MODBUS
@brief Определение карты регистров и коилов @brief Определение карты регистров и коилов
****************************************************************************** ******************************************************************************
@@ -13,7 +13,7 @@
- Input Registers (R/O) - входные регистры - Input Registers (R/O) - входные регистры
- Coils (R/W) - дискретные выходы - Coils (R/W) - дискретные выходы
@section datinit Базовая настройка под устройство: @section Базовая настройка под устройство:
1. Настроить диапазоны адресов 1. Настроить диапазоны адресов
- @ref R_INPUT_ADDR и @ref R_INPUT_QNT для входных регистров - @ref R_INPUT_ADDR и @ref R_INPUT_QNT для входных регистров
- @ref R_HOLDING_ADDR и @ref R_HOLDING_QNT для регистров хранения - @ref R_HOLDING_ADDR и @ref R_HOLDING_QNT для регистров хранения
@@ -24,7 +24,7 @@
- @ref MB_DataCoilsTypeDef - @ref MB_DataCoilsTypeDef
@section datexpert Расширенная настройка под устройство: @section Расширенная настройка под устройство:
1. Добавить новый массив с нужными данными. 1. Добавить новый массив с нужными данными.
2. Добавить дефайны для определения его начального адреса и количества элементов 2. Добавить дефайны для определения его начального адреса и количества элементов
3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress. 3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress.
@@ -75,11 +75,11 @@
* @addtogroup MODBUS_DATA_RERISTERS_DEFINES Registers structures * @addtogroup MODBUS_DATA_RERISTERS_DEFINES Registers structures
* @ingroup MODBUS_DATA * @ingroup MODBUS_DATA
* @brief Стуруктура регистров (входных и хранения) * @brief Стуруктура регистров (входных и хранения)
@code @verbatim
Для массивов регистров: Для массивов регистров:
R_<NAME_ARRAY>_ADDR - модбас адресс первого регистра в массиве R_<NAME_ARRAY>_ADDR - модбас адресс первого регистра в массиве
R_<NAME_ARRAY>_QNT - количество регистров в массиве R_<NAME_ARRAY>_QNT - количество регистров в массиве
@endcode @endverbatim
* @{ * @{
*/ */
@@ -111,12 +111,12 @@ typedef struct //MB_DataInRegsTypeDef
* @addtogroup MODBUS_DATA_COILS_DEFINES Coils Structure * @addtogroup MODBUS_DATA_COILS_DEFINES Coils Structure
* @ingroup MODBUS_DATA * @ingroup MODBUS_DATA
* @brief Структура коилов * @brief Структура коилов
@code @verbatim
Структура дефайна Структура дефайна
Для массивов коилов: Для массивов коилов:
C_<NAME_ARRAY>_ADDR - модбас адресс первого коила в массиве C_<NAME_ARRAY>_ADDR - модбас адресс первого коила в массиве
C_<NAME_ARRAY>_QNT - количество коилов в массиве (минимум 16) C_<NAME_ARRAY>_QNT - количество коилов в массиве (минимум 16)
@endcode @endverbatim
* @{ * @{
*/ */