From a880f46a56fe4a802e44b8131085c056949043c3 Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Fri, 20 Feb 2026 10:41:31 +0300 Subject: [PATCH] release 0.5 (*API CHANGED) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - чуть переделаны некоторые дефайны для универсализации - смена направления сделана через указател на функцию, а не глобальный дефайн - добавлен бета осцилограф модбас - некоторый рефакторинг --- Inc/__modbus_compat.h | 3 + Inc/modbus.h | 20 ++++-- Inc/modbus_core.h | 39 +++++------ Inc/modbus_holdregs.h | 4 +- Inc/modbus_inputregs.h | 4 +- Inc/modbus_oscil.h | 111 +++++++++++++++++++++++++++++++ Inc/rs_message.h | 15 +++-- README.md | 72 ++++++++++++-------- Src/modbus.c | 10 +-- Src/modbus_devid.c | 4 +- Src/modbus_holdregs.c | 12 ++-- Src/modbus_inputregs.c | 6 +- Src/modbus_master.c | 10 +-- Src/modbus_oscil.c | 145 +++++++++++++++++++++++++++++++++++++++++ Src/modbus_slave.c | 23 ++++--- Src/rs_message.c | 32 ++++----- __modbus_config.h | 6 +- __modbus_data.c | 13 +++- 18 files changed, 415 insertions(+), 114 deletions(-) create mode 100644 Inc/modbus_oscil.h create mode 100644 Src/modbus_oscil.c diff --git a/Inc/__modbus_compat.h b/Inc/__modbus_compat.h index f1a00a8..1526622 100644 --- a/Inc/__modbus_compat.h +++ b/Inc/__modbus_compat.h @@ -65,6 +65,9 @@ CREATE_DEPRECATED_ALIAS(MB_EXTENDED_IDENTIFICATIONS, RID_EXTENDED_IDENTIFICATIO CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIONS, MB_ReadDevId); +#define MbAddr DeviceAddr + + /** MODBUS_LEGACY_API * @} */ diff --git a/Inc/modbus.h b/Inc/modbus.h index 121630c..329474e 100644 --- a/Inc/modbus.h +++ b/Inc/modbus.h @@ -29,7 +29,7 @@ //----------------Слейв модбас----------------// #include "modbus.h" - MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); + MODBUS_FirstInit(&hmodbus1, &huart1, &htim3, NULL); // NULL, если управление RE/DE не нужно MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); MODBUS_SlaveStart(&hmodbus1, NULL); @endcode @@ -37,19 +37,24 @@ //----------------Мастер модбас----------------// #include "modbus.h" - MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); + MODBUS_FirstInit(&hmodbus1, &huart1, &htim3, NULL); // NULL, если управление RE/DE не нужно MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); + // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук + // При получении ответа вызовется функция callback_func() RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { // 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++) { + // Запись регистров из ответа в массив uint16_t value; if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) { @@ -57,6 +62,9 @@ } } } + else // Ответ получен с ошибкой или не получен вовсе + { + } } @endcode @@ -107,6 +115,10 @@ #ifdef MODBUS_ENABLE_DIAGNOSTICS #include "modbus_diag.h" #endif +#ifdef MODBUS_ENABLE_OSCIL +#include "modbus_oscil.h" +#endif +#include "modbus_data.h" #ifdef MODBUS_ENABLE_MASTER @@ -124,7 +136,7 @@ //----------------FUNCTIONS FOR USER---------------- /* Инициализация периферии модбас. */ -HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim); +HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)); /* Программная конфигурация модбас. */ HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master); /* Запуск слейв устройства */ diff --git a/Inc/modbus_core.h b/Inc/modbus_core.h index 8b26730..48f32b4 100644 --- a/Inc/modbus_core.h +++ b/Inc/modbus_core.h @@ -27,7 +27,6 @@ #define __MODBUS_CORE_H_ #include "modbus_config.h" -#include "modbus_data.h" #include "__crc_algs.h" /** @@ -41,31 +40,31 @@ ////////////////////---MODBUS MESSAGE DEFINES---///////////////////// //-------------DEFINES FOR STRUCTURE---------------- /* defines for structure of modbus message */ -#define TransactionID_size 2 ///< size of (Transaction ID) -#define ProtocolID_size 2 ///< size of (Protocol ID) -#define PDULength_size 2 ///< size of (PDU Length) -#define MbAddr_SIZE 1 ///< size of (Slave Addr) -#define Func_Code_SIZE 1 ///< size of (Function Code) -#define Addr_SIZE 2 ///< size of (Address) -#define Qnt_SIZE 2 ///< size of (Quantity) -#define ByteCnt_SIZE 1 ///< size of (Byte Count) -#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) -#define CRC_SIZE 2 ///< size of (MbCRC) in bytes +#define MbTransactionID_size 2 ///< size of (Transaction ID) +#define MbProtocolID_size 2 ///< size of (Protocol ID) +#define MbPDULength_size 2 ///< size of (PDU Length) +#define MbDeviceAddr_size 1 ///< size of (Slave Addr) +#define MbFuncCode_size 1 ///< size of (Function Code) +#define MbAddr_size 2 ///< size of (Address) +#define MbQnt_size 2 ///< size of (Quantity) +#define MbByteCnt_size 1 ///< size of (Byte Count) +#define MbData_size 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) +#define MbCRC_size 2 ///< size of (MbCRC) in bytes #ifndef MODBUS_PROTOCOL_TCP /** @brief Size of whole RTU message */ -#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE) +#define RS_INFO_SIZE_MAX (MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size+MbByteCnt_size) #else /** @brief Size of whole TCP message */ -#define INFO_SIZE_MAX (TransactionID_size+ProtocolID_size+PDULength_size+MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE) +#define RS_INFO_SIZE_MAX (MbTransactionID_size+MbProtocolID_size+MbPDULength_size+MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size) #endif /** @brief Size of first part of message that will be received first receive info part of message, than defines size of rest message*/ -#define RX_FIRST_PART_SIZE INFO_SIZE_MAX +#define RS_RX_FIRST_PART_SIZE RS_INFO_SIZE_MAX /** @brief Size of buffer: max size of whole message */ -#define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message +#define RS_MSG_SIZE_MAX (RS_INFO_SIZE_MAX + MbData_size*2 + MbCRC_size) // max possible size of message /** * @brief Enum for modbus exception codes @@ -129,7 +128,9 @@ typedef enum //MB_FunctonTypeDef FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве }MB_FunctonTypeDef; -/** @brief Enum for MEI func codes */ +/** + * @brief Enum for MEI func codes + */ typedef enum //MB_FunctonTypeDef { MEI_DEVICE_IDENTIFICATIONS = 0x0E, @@ -180,14 +181,14 @@ typedef struct // RS_MsgTypeDef uint16_t PDULength; ///< Modbus TCP: PDU Length #endif - uint8_t MbAddr; ///< Modbus Slave Address + uint8_t DeviceAddr; ///< Modbus Slave Address MB_FunctonTypeDef FuncCode; ///< Modbus Function Code MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct uint16_t Addr; ///< Modbus Address of data uint16_t Qnt; ///< Quantity of modbus data uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive - uint16_t MbData[DATA_SIZE]; ///< Modbus Data + uint16_t MbData[MbData_size]; ///< Modbus Data MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command uint16_t MbCRC; ///< Modbus CRC @@ -298,7 +299,7 @@ extern RS_MsgTypeDef MODBUS_MSG; /* 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); /* Define Address Origin for Input/Holding Registers */ -MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType); +MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag); /* 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); /** MODBUS_CMD_PROCESS_FUNCTIONS diff --git a/Inc/modbus_holdregs.h b/Inc/modbus_holdregs.h index 45cf0ad..d631422 100644 --- a/Inc/modbus_holdregs.h +++ b/Inc/modbus_holdregs.h @@ -3,9 +3,9 @@ * @file modbus_holdregs.h * @brief Работа с регистрами хранения Modbus ******************************************************************************* -@addtogroup MODBUS_INS Input Register Tools +@addtogroup MODBUS_HOLD Holding Registers Tools @ingroup MODBUS_INTERNAL -@brief Функции для работы с входными регистрами +@brief Функции для работы с регистрами хранения ******************************************************************************* * @details Модуль для доступа к регистрам внутри программы: diff --git a/Inc/modbus_inputregs.h b/Inc/modbus_inputregs.h index bcfcd22..a0e9fc1 100644 --- a/Inc/modbus_inputregs.h +++ b/Inc/modbus_inputregs.h @@ -3,9 +3,9 @@ * @file modbus_inputregs.h * @brief Работа с входными регистрами Modbus ******************************************************************************* -@addtogroup MODBUS_HOLD Holding Registers Tools +@addtogroup MODBUS_INS Input Register Tools @ingroup MODBUS_INTERNAL -@brief Функции для работы с регистрами хранения +@brief Функции для работы с входными регистрами ******************************************************************************* * @details Модуль для доступа к регистрам внутри программы: diff --git a/Inc/modbus_oscil.h b/Inc/modbus_oscil.h new file mode 100644 index 0000000..34291f9 --- /dev/null +++ b/Inc/modbus_oscil.h @@ -0,0 +1,111 @@ +/** +******************************************************************************* +* @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 + * @} + */ + \ No newline at end of file diff --git a/Inc/rs_message.h b/Inc/rs_message.h index faaf00b..4734766 100644 --- a/Inc/rs_message.h +++ b/Inc/rs_message.h @@ -24,7 +24,7 @@ 4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT() @section features Особенности: -- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи +- Буфер: RS_Buffer[RS_MSG_SIZE_MAX] Общий для приема/передачи - Состояния: отслеживается через флаги в RS_HandleTypeDef - Таймауты: контролируют максимальное время ожидания фрейма ******************************************************************************/ @@ -36,8 +36,8 @@ ///////////////////////////////////////////////////////////////////// ////////////////////////////---DEFINES---//////////////////////////// /* Check that all defines required by RS are defined */ -#ifndef MSG_SIZE_MAX -#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. +#ifndef RS_MSG_SIZE_MAX +#error Define RS_MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. #endif /** @@ -45,7 +45,7 @@ */ /* Clear message-uart buffer */ -#define RS_Clear_Buff(_buff_) for(int i=0; if.RS_Busy = 0 @@ -68,7 +68,7 @@ #define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) /* Clear all RS stuff */ -#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_); +#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->BufferPtr); 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_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) @@ -237,7 +237,7 @@ typedef struct // RS_HandleTypeDef /* MESSAGE */ uint8_t ID; ///< ID хендла RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола - uint8_t *pBufferPtr; ///< Указатеь на буфер UART + uint8_t BufferPtr[RS_MSG_SIZE_MAX]; ///< Указатеь на буфер UART int32_t RS_Message_Size; ///< size of whole message, not only data /* HANDLERS and SETTINGS */ @@ -245,6 +245,7 @@ typedef struct // RS_HandleTypeDef TIM_HandleTypeDef *htim; ///< Хендл TIM RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера + void (*pSetDirection)(int Tx); ///< Указатель на функцию: смена направления void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер /* FLAGS */ @@ -288,7 +289,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); /* Инициалазация структуры @ref RS_HandleTypeDef */ -RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr); +RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)); /* Отменить прием/передачу RS/UART */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); diff --git a/README.md b/README.md index b20d31b..ca03f7e 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,29 @@ Modbus/ │ inc/ modbus │ ├── modbus.h # Главный заголовочный файл modbus_slave │ ├── modbus_core.h # Базовые определения и структуры modbus_master -│ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils +│ ├── modbus_coils.h # Работа с дискретными коилами ├── modbus_coils │ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs │ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs -│ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid -│ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag -├── src/ └── rs_message -│ ├── modbus.c # Основная логика Modbus │ -│ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро) -│ ├── modbus_master.c # Основная логика Master Modbus ├── modbus_config -│ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data -│ ├── modbus_holdregs.c # Реализация регистров хранения └── __crc_algs -│ ├── modbus_inputregs.c # Реализация входных регистров -│ ├── modbus_devid.c # Реализация идентификации устройства -│ ├── modbus_data.c # Функции доступа к данным +│ ├── modbus_devid.h # Идентификаторы устройства ├── modbus_devid +│ ├── modbus_master.h # Заголовочный файл Master режима ├── modbus_diag +│ ├── modbus_slave.h # Заголовочный файл Slave режима ├── modbus_oscil +│ ├── modbus_diag.h # Диагностика Modbus └── rs_message +│ ├── modbus_oscil.h # Осциллографирование данных │ +│ └── rs_message.h # Драйвер обмена по RS/UART └── modbus_core (единое ядро) +├── src/ ├── modbus_config +│ ├── modbus.c # Основная логика Modbus ├── modbus_data +│ ├── modbus_slave.c # Основная логика Slave Modbus └── __crc_algs +│ ├── modbus_master.c # Основная логика Master Modbus +│ ├── modbus_coils.c # Реализация работы с coils +│ ├── modbus_holdregs.c # Реализация регистров хранения +│ ├── modbus_inputregs.c # Реализация входных регистров +│ ├── modbus_devid.c # Реализация идентификации устройства +│ ├── modbus_diag.c # Диагностические функции и счетчики ошибок +│ ├── modbus_oscil.c # Сбор и хранение осциллограмм │ └── rs_message.c # Реализация драйвера RS ├── __modbus_config.h # Конфигурация Modbus (надо заменить) ├── __modbus_data.h # Структуры данных (надо заменить) -└── __modbus_data.c # Функции доступа (надо заменить) +└── __modbus_data.c # Функции доступа (надо заменить) ``` ## Инструкция по подключению @@ -97,7 +102,7 @@ int main(void) MX_TIM3_Init(); // Инициализация Modbus - MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); + MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, SetTxDirectionFunc); MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); // Запуск приема Modbus @@ -113,25 +118,40 @@ int main(void) ```c #include "modbus.h" + +// Инициализация Modbus +MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, SetTxDirectionFunc); +MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); + + // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук -RS_MsgTypeDef read_hold_cmd = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); +// При получении ответа вызовется функция callback_func() +RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); +MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); + // коллбек, вызовется при получении ответа от слейва read_hold[10]; void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { // 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++) { - uint16_t value; - if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) - { - read_hold[i] = value; - } + // Запись регистров из ответа в массив + uint16_t value; + if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) + { + read_hold[i] = value; + } } } + else // Ответ получен с ошибкой или не получен вовсе + { + } } + int main(void) { // Инициализация HAL @@ -150,7 +170,7 @@ int main(void) } ``` - #### 3.5. Настройка карты данных + #### 3.5. Настройка карты данных (только для режима Slave) В `modbus_data.h` настройте регистры и coils под ваше устройство: @@ -195,7 +215,7 @@ typedef struct ``` #### 3.6. Доступ к данным в коде - В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля + В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля ```c // Чтение входных регистров uint16_t temp = MB_DATA.InRegs.Temperature; @@ -204,15 +224,15 @@ uint16_t temp = MB_DATA.InRegs.Temperature; MB_DATA.HoldRegs.SetpointTemp = 2500; // Управление coils -MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить Relay1 -MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2 +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)) { // Pump включен } ``` - В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()` + В режиме **мастера** есть функции для получения информации из ответа `MB_RespGet_...()` ```c // Чтение регистров: Получить запрошенные регистры uint16_t value; diff --git a/Src/modbus.c b/Src/modbus.c index 3973261..d4670d8 100644 --- a/Src/modbus.c +++ b/Src/modbus.c @@ -24,8 +24,6 @@ RS_HandleTypeDef hmodbus1; ///< Default Handle 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); @@ -36,10 +34,11 @@ static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ * @param hmodbus Указатель на хендлер RS * @param huart Указатель на хендлер UART * @param htim Указатель на хендлер TIM + * @param pSetDirection Указатель на функцию для смены направления RS485 * @details Подключает хендлы периферии к hmodbus * Конфигурация выставляется по умолчанию из modbus_config.h */ -HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim) +HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)) { if((hmodbus == NULL) || (huart == NULL)) { @@ -53,9 +52,10 @@ HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT; // INIT - hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0); + hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, pSetDirection); - RS_EnableReceive(); + if(hmodbus->pSetDirection) + hmodbus->pSetDirection(0); if(hmodbus->RS_STATUS == RS_OK) return HAL_OK; diff --git a/Src/modbus_devid.c b/Src/modbus_devid.c index 45453b7..92d435a 100644 --- a/Src/modbus_devid.c +++ b/Src/modbus_devid.c @@ -51,7 +51,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) /* Define number of object in one message */ unsigned lastobjid = 0; - for(int i = 0; i < DATA_SIZE*2;) + for(int i = 0; i < MbData_size*2;) { /* Если объект за пределами допутимого - выходим из цикла */ if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS) @@ -60,7 +60,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) i += 2; i += obj[objidtmp].length; /* Если все еще помещается в массив переходим на следующий объект */ - if(i < DATA_SIZE*2) + if(i < MbData_size*2) { objidtmp++; } diff --git a/Src/modbus_holdregs.c b/Src/modbus_holdregs.c index 88ab7f7..c7f0174 100644 --- a/Src/modbus_holdregs.c +++ b/Src/modbus_holdregs.c @@ -40,7 +40,7 @@ MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal) uint16_t *pHoldRegs; //------------WRITE COIL------------- - Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding); + Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 1); if(Exception == ET_NO_ERRORS) { *(pHoldRegs) = WriteVal; @@ -66,7 +66,7 @@ uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) uint16_t *pHoldRegs; //------------READ COIL-------------- - Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding); + Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 0); if(Exception) // if exception is not given to func fill it *Exception = Exception_tmp; @@ -94,7 +94,7 @@ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) //---------CHECK FOR ERRORS---------- // get origin address for data uint16_t *pHoldRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 0); // определение адреса регистров if(modbus_msg->Except_Code != ET_NO_ERRORS) return 0; @@ -107,7 +107,7 @@ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) for (i = 0; iQnt; i++) { modbus_msg->MbData[i] = *(pHoldRegs++); - } + } return 1; } @@ -121,7 +121,7 @@ uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) { // get origin address for data uint16_t *pHoldRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding, 1); // определение адреса регистров if(modbus_msg->Except_Code != ET_NO_ERRORS) return 0; @@ -146,7 +146,7 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) } // get origin address for data uint16_t *pHoldRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 1); // определение адреса регистров if(modbus_msg->Except_Code != ET_NO_ERRORS) return 0; diff --git a/Src/modbus_inputregs.c b/Src/modbus_inputregs.c index 41081d6..4218323 100644 --- a/Src/modbus_inputregs.c +++ b/Src/modbus_inputregs.c @@ -36,7 +36,7 @@ MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal) uint16_t *pInRegs; //------------WRITE COIL------------- - Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input); + Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 1); if(Exception == ET_NO_ERRORS) { *(pInRegs) = WriteVal; @@ -62,7 +62,7 @@ uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) uint16_t *pInRegs; //------------READ COIL-------------- - Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input); + Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 0); if(Exception) // if exception is not given to func fill it *Exception = Exception_tmp; @@ -89,7 +89,7 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) //---------CHECK FOR ERRORS---------- // get origin address for data uint16_t *pInRegs; - modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров + modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input, 0); // определение адреса регистров if(modbus_msg->Except_Code != ET_NO_ERRORS) return 0; diff --git a/Src/modbus_master.c b/Src/modbus_master.c index e5305ad..71c72ea 100644 --- a/Src/modbus_master.c +++ b/Src/modbus_master.c @@ -374,7 +374,7 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef * } } - mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message + mb_func_size = RS_RX_FIRST_PART_SIZE + mb_func_size; // size of whole message return mb_func_size; } @@ -392,7 +392,7 @@ RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgType //------INFO ABOUT DATA/MESSAGE------ //-----------[first bytes]----------- // set ID of slave device - modbus_uart_buff[ind++] = modbus_msg->MbAddr; + modbus_uart_buff[ind++] = modbus_msg->DeviceAddr; // set function code modbus_uart_buff[ind++] = modbus_msg->FuncCode; @@ -472,7 +472,7 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe int expected_size = 0; // get ID of slave device - modbus_msg->MbAddr = modbus_uart_buff[ind++]; + modbus_msg->DeviceAddr = modbus_uart_buff[ind++]; // get function code (check if error response) modbus_msg->FuncCode = modbus_uart_buff[ind++]; @@ -633,7 +633,7 @@ RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start // Copy coil data to message MbData array for(int i = 0; i < byte_count; i++) { - if(i < DATA_SIZE) { + if(i < MbData_size) { msg.MbData[i] = coils_data[i]; } } @@ -649,7 +649,7 @@ RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_ msg.ByteCnt = quantity * 2; // Each register is 2 bytes // Copy register data to message MbData array - for(int i = 0; i < quantity && i < DATA_SIZE; i++) { + for(int i = 0; i < quantity && i < MbData_size; i++) { msg.MbData[i] = regs_data[i]; } diff --git a/Src/modbus_oscil.c b/Src/modbus_oscil.c new file mode 100644 index 0000000..330a7d7 --- /dev/null +++ b/Src/modbus_oscil.c @@ -0,0 +1,145 @@ +/** +******************************************************************************* +* @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 \ No newline at end of file diff --git a/Src/modbus_slave.c b/Src/modbus_slave.c index 77fa6fb..310abf6 100644 --- a/Src/modbus_slave.c +++ b/Src/modbus_slave.c @@ -29,7 +29,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit MB_Diagnostics_BusMessageCnt(); - if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0) + if(hmodbus->ID == 0 || modbus_msg->DeviceAddr == 0) { MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения hmodbus->RS_STATUS = RS_SKIP; @@ -49,6 +49,11 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod // Read Hodling Registers case FC_R_HOLD_REGS: 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; case FC_R_IN_REGS: hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr); @@ -185,7 +190,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD #endif //-----------[first bytes]----------- // set ID of message/user - modbus_uart_buff[ind++] = modbus_msg->MbAddr; + modbus_uart_buff[ind++] = modbus_msg->DeviceAddr; // set dat or err response modbus_uart_buff[ind++] = modbus_msg->FuncCode; @@ -204,7 +209,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.NumbOfObj; - if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE + if (modbus_msg->ByteCnt > MbData_size*2) // if ByteCnt less than MbData_size { TrackerCnt_Err(hmodbus->rs_err); return RS_COLLECT_MSG_ERR; @@ -235,7 +240,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD else // modbus data header { // set size of received data - if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE + if (modbus_msg->ByteCnt <= MbData_size*2) // if ByteCnt less than MbData_size modbus_uart_buff[ind++] = modbus_msg->ByteCnt; else // otherwise return data_size err { @@ -314,7 +319,7 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef * } - mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message + mb_func_size = RS_RX_FIRST_PART_SIZE + mb_func_size; // size of whole message return mb_func_size; } @@ -348,12 +353,12 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef // get ID of message/user if(modbus_uart_buff[ind] != hmodbus->ID) { - modbus_msg->MbAddr = 0; + modbus_msg->DeviceAddr = 0; ind++; } else { - modbus_msg->MbAddr = modbus_uart_buff[ind++]; + modbus_msg->DeviceAddr = modbus_uart_buff[ind++]; } // get func code @@ -361,7 +366,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // явная херня { MB_Diagnostics_SlaveNAKCnt(); - modbus_msg->MbAddr = 0; + modbus_msg->DeviceAddr = 0; return RS_SKIP; } @@ -424,7 +429,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef if (modbus_msg->ByteCnt != 0) { //check that data size is correct - if (modbus_msg->ByteCnt > DATA_SIZE*2) + if (modbus_msg->ByteCnt > MbData_size*2) { TrackerCnt_Err(hmodbus->rs_err); modbus_msg->FuncCode |= FC_ERR_VALUES_START; diff --git a/Src/rs_message.c b/Src/rs_message.c index ed5d801..29c0bb9 100644 --- a/Src/rs_message.c +++ b/Src/rs_message.c @@ -12,10 +12,10 @@ @section arch Архитектура: В режиме слейв: - - Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX + - Инициализация приема с сообщения с максимальным размером RS_MSG_SIZE_MAX - При срабатывании прерывания IDLE - обработка полученного сообщения В режиме мастер (пока не реализовано): - - Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX + - Отправка запроса и переход в режим приема сообщения с максимальным размером RS_MSG_SIZE_MAX - При срабатывании прерывания IDLE - обработка полученного ответа @section ithandler Необходимые обработчики: @@ -25,8 +25,6 @@ #include "rs_message.h" #include "modbus_diag.h" -uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer - extern void RS_UART_Init(void); extern void RS_UART_DeInit(UART_HandleTypeDef *huart); extern void RS_TIM_Init(void); @@ -52,7 +50,8 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) //-----------INITIALIZE RECEIVE------------- // if all OK: start receiving - RS_EnableReceive(); + if(hRS->pSetDirection) + hRS->pSetDirection(0); RS_Set_Busy(hRS); // set RS busy RS_Set_RX_Flags(hRS); // initialize flags for receive hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions @@ -61,7 +60,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) // start receiving __HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE); - uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte, + uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->BufferPtr[hRS->RS_Message_Size], RS_MSG_SIZE_MAX); // receive until ByteCnt+1 byte, // then in Callback restart receive for rest bytes // if receive isnt started - abort RS @@ -101,7 +100,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) //------------COLLECT MESSAGE--------------- - RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); + RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->BufferPtr); 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 RS_Abort(hRS, ABORT_RS); @@ -111,7 +110,8 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { //----------INITIALIZE TRANSMIT------------- - RS_EnableTransmit(); + if(hRS->pSetDirection) + hRS->pSetDirection(1); RS_Set_Busy(hRS); // set RS busy 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; } // if all OK: start transmitting - uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size); + uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->BufferPtr, hRS->RS_Message_Size); // if transmit isnt started - abort RS 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 после инициализации. * @details Инициализация перефирии и структуры для приема-передачи по RS. */ -RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr) +RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx)) { // check that hRS is defined if (hRS == NULL) @@ -166,13 +166,7 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H hRS->htim = htim; - // 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 + hRS->pSetDirection = pSetDirection; return RS_OK; } @@ -349,7 +343,7 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) RS_Set_RX_End(hRS); // Парсим наше сообщение - hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); + hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->BufferPtr); // Если сообещине принято корректно if(hRS->RS_STATUS == RS_OK) @@ -445,7 +439,7 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS) hRS->RS_STATUS = RS_TIMEOUT; if(hRS->sRS_Mode < RS_MASTER_MODE_START) - if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению + if(hRS->pMessagePtr->DeviceAddr == hRS->ID) // ошибка если таймаут по нашему сообщению TrackerCnt_Err(hRS->rs_err); if(hRS->sRS_Mode >= RS_MASTER_MODE_START) diff --git a/__modbus_config.h b/__modbus_config.h index 9f65c31..a5c2450 100644 --- a/__modbus_config.h +++ b/__modbus_config.h @@ -40,8 +40,6 @@ // Периферия (опционально) #define mb_huart huart1 ///< Удобный дефайн для модбасовского uart #define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера -//#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485 -//#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485 // Модули modbus @@ -54,10 +52,12 @@ #define MODBUS_ENABLE_DEVICE_IDENTIFICATIONS ///< Включить обработку идентификаторы устройства #define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас + +#define MODBUS_ENABLE_OSCIL ///< Включить осциллограф Modbus //#define MODBUS_PROTOCOL_TCP ///< Включить TCP-протокол, иначе - RTU /** - * @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей) + * @brief Поменять комманды 0x03 и 0x04 местами * @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS * Поэтому чтобы считывать Input Regs - надо поменять их местами. */ diff --git a/__modbus_data.c b/__modbus_data.c index 1626ce8..5f1d2ca 100644 --- a/__modbus_data.c +++ b/__modbus_data.c @@ -22,6 +22,8 @@ #include "modbus_inputregs.h" #include "modbus_devid.h" +/* DEFINE DATA FOR MODBUS */ +MB_DataStructureTypeDef MB_DATA = { 0 }; ///< Coils & Registers /** * @brief Check is address valid for certain array. @@ -63,10 +65,10 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16 * @details Определение адреса начального регистра. * @note WriteFlag пока не используется. */ -MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType) +MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag) { /* check quantity error */ - if (Qnt > DATA_SIZE) + if (Qnt > MbData_size) { return ET_ILLEGAL_DATA_VALUE; // return exception code } @@ -78,6 +80,13 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u { *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 else {