Compare commits
8 Commits
d136394d23
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
279dc4cee7 | ||
|
|
7870a749c2 | ||
|
|
4116d9edb5 | ||
|
|
c4c8024512 | ||
|
|
f03ffd5bfc | ||
|
|
df3f71cdff | ||
|
|
e0ce0e6dbf | ||
|
|
c5c9ed7ab2 |
@@ -5,17 +5,67 @@
|
||||
*******************************************************************************
|
||||
* @details Файл содержит API старых функций, а также заглушки для отключенных модулей:
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_COMPAT_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
|
||||
* @ingroup MODBUS_FUNCTIONS
|
||||
* @brief Старые API функций, сохранённые для обратной совместимости.
|
||||
* @note Не используйте эти функции в новом коде. Они могут быть удалены в будущих версиях.
|
||||
* Вместо них используйте функции из основных групп MODBUS 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
|
||||
@@ -114,5 +164,5 @@
|
||||
#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
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
#endif //__MODBUS_COMPAT_H_
|
||||
20
Inc/modbus.h
20
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);
|
||||
/* Запуск слейв устройства */
|
||||
|
||||
@@ -30,6 +30,7 @@ Coils упакованы в 16-битные слова для эффективн
|
||||
#ifndef __MODBUS_COILS_H_
|
||||
#define __MODBUS_COILS_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_COILS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
||||
@@ -118,5 +119,5 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_COILS
|
||||
#endif //__MODBUS_COILS_H_
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
#define __MODBUS_CORE_H_
|
||||
|
||||
#include "modbus_config.h"
|
||||
#include "modbus_data.h"
|
||||
#include "__crc_algs.h"
|
||||
#include "__modbus_compat.h"
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
|
||||
@@ -42,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
|
||||
@@ -74,15 +72,17 @@ first receive info part of message, than defines size of rest message*/
|
||||
*/
|
||||
typedef enum //MB_ExceptionTypeDef
|
||||
{
|
||||
// reading
|
||||
/* Регулярные коды ошибок, которые определены конкретной программой */
|
||||
ET_NO_ERRORS = 0x00, ///< no errors
|
||||
ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
|
||||
ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
|
||||
ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
|
||||
ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
|
||||
// ET_ACKNOWLEDGE = 0x05, ///< idk
|
||||
// ET_SLAVE_DEVICE_BUSY = 0x06, ///< idk
|
||||
// ET_MEMORY_PARITY_ERROR = 0x08, ///< idk
|
||||
|
||||
/* Специальные коды ошибок, которые определены конкретной программой */
|
||||
ET_ACKNOWLEDGE = 0x05, ///< Устройство приняло запрос, но на обработку требуется время. Нужно чтобы не было Timeout ошибки
|
||||
ET_SLAVE_DEVICE_BUSY = 0x06, ///< Устройство занято обработкой комманды
|
||||
ET_MEMORY_PARITY_ERROR = 0x08, ///< Ошибка внешней памяти
|
||||
}MB_ExceptionTypeDef;
|
||||
|
||||
#define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes
|
||||
@@ -130,7 +130,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,
|
||||
@@ -181,14 +183,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
|
||||
@@ -299,17 +301,17 @@ 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
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
#include "__modbus_compat.h"
|
||||
#endif //__MODBUS_CORE_H_
|
||||
/** MODBUS_INTERNAL
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#ifndef __MODBUS_DEVID_H_
|
||||
#define __MODBUS_DEVID_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@@ -119,5 +120,6 @@ uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg);
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#endif //__MODBUS_DEVID_H_
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef __MODBUS_DIAG_H_
|
||||
#define __MODBUS_DIAG_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
|
||||
@@ -116,6 +117,7 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg);
|
||||
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
#endif //__MODBUS_DIAG_H_
|
||||
|
||||
/** MODBUS_DIAG
|
||||
|
||||
@@ -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
|
||||
Модуль для доступа к регистрам внутри программы:
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifndef __MODBUS_HOLDREGS_H_
|
||||
#define __MODBUS_HOLDREGS_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_HOLDINGS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
@@ -59,4 +60,5 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_HOLDINGS
|
||||
#endif //__MODBUS_HOLDREGS_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
|
||||
Модуль для доступа к регистрам внутри программы:
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef __MODBUS_INPUTREGS_H_
|
||||
#define __MODBUS_INPUTREGS_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_INPUTS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
@@ -54,4 +55,5 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_INPUTS
|
||||
#endif //__MODBUS_INPUTREGS_H_
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_MASTER_H_
|
||||
#define __MODBUS_MASTER_H_
|
||||
|
||||
#include "rs_message.h"
|
||||
#ifdef MODBUS_ENABLE_MASTER
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_REQUEST_MSG API for Master Requests
|
||||
@@ -228,4 +228,5 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif //MODBUS_ENABLE_MASTER
|
||||
#endif //__MODBUS_MASTER_H_
|
||||
|
||||
111
Inc/modbus_oscil.h
Normal file
111
Inc/modbus_oscil.h
Normal file
@@ -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
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_SLAVE_H_
|
||||
#define __MODBUS_SLAVE_H_
|
||||
|
||||
#include "rs_message.h"
|
||||
#ifdef MODBUS_ENABLE_SLAVE
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,6 +21,10 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Ответить позже, не в прерывании */
|
||||
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);
|
||||
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
|
||||
@@ -31,4 +35,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
|
||||
/** MODBUS_SLAVE
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#endif //MODBUS_ENABLE_SLAVE
|
||||
#endif //__MODBUS_SLAVE_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; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL
|
||||
#define RS_Clear_Buff(_buff_) for(int i=0; i<RS_MSG_SIZE_MAX;i++) _buff_[i] = NULL
|
||||
|
||||
/* Set/Reset flags */
|
||||
#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_)
|
||||
|
||||
/* 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)
|
||||
@@ -211,11 +211,13 @@ typedef struct
|
||||
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
|
||||
|
||||
// Выставление следующие флагов определяет пользователь
|
||||
unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала
|
||||
unsigned RX_Continue:1; ///< 1 - Продолжить принимать, 0 - Начать прием сначала
|
||||
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
|
||||
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
|
||||
unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании
|
||||
unsigned DataUpdated:1; ///< 1 - Данные были обновлены
|
||||
unsigned DataUpdated:1; ///< 1 - Данные были обновлены:
|
||||
unsigned DeviceBusy:1; ///< 1 - Устройство занято (важно! не rs а именно устрройство)
|
||||
unsigned DeferredResponse:8; ///< >0 - Не начинать передачу в IT, 0 - Ответить в прерывании
|
||||
|
||||
}RS_FlagsTypeDef;
|
||||
|
||||
|
||||
@@ -229,7 +231,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 */
|
||||
@@ -237,6 +239,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 */
|
||||
@@ -280,7 +283,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);
|
||||
|
||||
103
README.md
103
README.md
@@ -10,20 +10,25 @@ 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_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_data.c # Функции доступа к данным
|
||||
│ ├── modbus_diag.c # Диагностические функции и счетчики ошибок
|
||||
│ ├── modbus_oscil.c # Сбор и хранение осциллограмм
|
||||
│ └── rs_message.c # Реализация драйвера RS
|
||||
├── __modbus_config.h # Конфигурация Modbus (надо заменить)
|
||||
├── __modbus_data.h # Структуры данных (надо заменить)
|
||||
@@ -51,16 +56,15 @@ ProjectRoot/
|
||||
```
|
||||
|
||||
### 3. **Настройте конфигурацию** под ваш проект:
|
||||
#### 3.1. Настройка периферии
|
||||
#### 3.1. Настройка периферии
|
||||
|
||||
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
|
||||
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
|
||||
- **Включите прерывания** для UART и TIM
|
||||
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
|
||||
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
|
||||
- **Включите прерывания** для UART и TIM
|
||||
|
||||
#### 3.2. Подключение обработчиков прерываний
|
||||
|
||||
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
|
||||
#### 3.2. Подключение обработчиков прерываний
|
||||
|
||||
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
|
||||
```c
|
||||
#include "modbus.h"
|
||||
|
||||
@@ -78,15 +82,21 @@ void TIMx_IRQHandler(void)
|
||||
HAL_TIM_IRQHandler(&htim);
|
||||
}
|
||||
```
|
||||
#### 3.3. В `modbus_config.h` укажите параметры устройства
|
||||
#### 3.3. В `modbus_config.h` укажите параметры устройства
|
||||
|
||||
#### 3.4. Инициализация в коде
|
||||
#### 3.4. Инициализация в коде
|
||||
|
||||
Чтобы настроить Slave-режим `main()` после инициализации HAL:
|
||||
Чтобы настроить Slave-режим `main()` после инициализации HAL:
|
||||
|
||||
```c
|
||||
#include "modbus.h"
|
||||
|
||||
// TxEnable: 1 - передача, 0 - прием
|
||||
void SetTxDirectionFunc(int TxEnable)
|
||||
{
|
||||
HAL_GPIO_WritePin(SCIDE1_GPIO_Port, SCIDE1_Pin, !TxEnable);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Инициализация HAL
|
||||
@@ -97,7 +107,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
|
||||
@@ -109,29 +119,44 @@ int main(void)
|
||||
}
|
||||
}
|
||||
```
|
||||
Чтобы настроить Master-режим `main()` после инициализации HAL:
|
||||
Чтобы настроить Master-режим `main()` после инициализации HAL:
|
||||
|
||||
```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,11 +175,11 @@ int main(void)
|
||||
|
||||
}
|
||||
```
|
||||
#### 3.5. Настройка карты данных
|
||||
#### 3.5. Настройка карты данных (только для режима Slave)
|
||||
|
||||
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
||||
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
||||
|
||||
**Input Registers (только чтение)**
|
||||
**Input Registers (только чтение)**
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
@@ -167,7 +192,7 @@ typedef struct
|
||||
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров
|
||||
#define R_INPUT_QNT 4 // Количество Input регистров
|
||||
```
|
||||
**Holding Registers (чтение/запись)**
|
||||
**Holding Registers (чтение/запись)**
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
@@ -179,7 +204,7 @@ typedef struct
|
||||
#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров
|
||||
#define R_HOLDING_QNT 3 // Количество Holding регистров
|
||||
```
|
||||
**Coils (1-битные)**
|
||||
**Coils (1-битные)**
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
@@ -193,9 +218,9 @@ typedef struct
|
||||
#define C_COILS_ADDR 0 // Начальный адрес Coils
|
||||
#define C_COILS_QNT 4 // Количество Coils
|
||||
```
|
||||
#### 3.6. Доступ к данным в коде
|
||||
#### 3.6. Доступ к данным в коде
|
||||
|
||||
В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
|
||||
В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
|
||||
```c
|
||||
// Чтение входных регистров
|
||||
uint16_t temp = MB_DATA.InRegs.Temperature;
|
||||
@@ -204,15 +229,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;
|
||||
|
||||
10
Src/modbus.c
10
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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
145
Src/modbus_oscil.c
Normal file
145
Src/modbus_oscil.c
Normal file
@@ -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
|
||||
@@ -7,6 +7,8 @@
|
||||
Файл содержит реализацию функций для работы Modbus в режиме слейва.
|
||||
|
||||
@section slave Функции и макросы
|
||||
- MB_Slave_ResponseLater() — Выставить флаг на ответ вне прерывания
|
||||
- MB_Slave_SendResponse() — Ответить на запрос
|
||||
|
||||
- MB_Slave_Response() — Ответ на запрос
|
||||
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
||||
@@ -15,6 +17,66 @@
|
||||
#include "modbus.h"
|
||||
|
||||
#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 Ответ на сообщение в режиме слейва.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
@@ -29,7 +91,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 +111,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);
|
||||
@@ -112,7 +179,6 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
|
||||
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||
}
|
||||
|
||||
|
||||
// Проверяем режим устройства - если Listen Only, не обрабатываем команды
|
||||
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
|
||||
{
|
||||
@@ -147,8 +213,8 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||
hmodbus->f.DeferredResponse = 0;
|
||||
// RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||
// hmodbus->f.DeferredResponse = 0;
|
||||
}
|
||||
|
||||
hmodbus->RS_STATUS = MB_RES;
|
||||
@@ -168,7 +234,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
|
||||
{
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
|
||||
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
|
||||
if(hmodbus->f.EchoResponse && (modbus_msg->Except_Code == ET_NO_ERRORS)) // if echo response need
|
||||
ind = hmodbus->RS_Message_Size;
|
||||
else
|
||||
{
|
||||
@@ -185,7 +251,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 +270,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 +301,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 +380,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 +414,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 +427,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 +490,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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 - надо поменять их местами.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user