Files
STM32_Modbus/Modbus/modbus.h
2025-11-03 13:36:38 +03:00

489 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
**************************************************************************
* @file modbus.h
* @brief Заголовочный файл модуля MODBUS.
* @details Данный файл необходимо подключить в rs_message.h. После подключать
* rs_message.h к основному проекту.
*
* @defgroup MODBUS
* @brief Modbus stuff
*
*************************************************************************/
#ifndef __MODBUS_H_
#define __MODBUS_H_
#include "modbus_config.h"
#include "modbus_data.h"
#include "__crc_algs.h"
/**
* @addtogroup MODBUS_SETTINGS
* @ingroup MODBUS
* @brief Some defines for modbus
@{
*/
/////////////////////////////////////////////////////////////////////
//////////////////////////---SETTINGS---/////////////////////////////
// USER SETTINGS FOR MODBUS IN interface_config.h
/**
* @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей)
* @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS
* Поэтому чтобы считывать Input Regs - надо поменять их местами.
*/
//#define MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
//////////////////////////---SETTINGS---/////////////////////////////
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
//-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */
#define MbAddr_SIZE 1 ///< size of (MbAddr)
#define Func_Code_SIZE 1 ///< size of (Func_Code)
#define Addr_SIZE 2 ///< size of (Addr)
#define Qnt_SIZE 2 ///< size of (Qnt)
#define ByteCnt_SIZE 1 ///< size of (ByteCnt)
#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE)
#define CRC_SIZE 2 ///< size of (MB_CRC) in bytes
/** @brief Size of whole message */
#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE)
/** @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
/** @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
/** @brief Structure for modbus exception codes */
typedef enum //MB_ExceptionTypeDef
{
// reading
NO_ERRORS = 0x00, ///< no errors
ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
// ACKNOWLEDGE = 0x05, ///< idk
// SLAVE_DEVICE_BUSY = 0x06, ///< idk
// MEMORY_PARITY_ERROR = 0x08, ///< idk
}MB_ExceptionTypeDef;
#define ERR_VALUES_START 0x80U ///< from this value starts error func codes
/** @brief Structure for modbus func codes */
typedef enum //MB_FunctonTypeDef
{
/* COMMANDS */
// reading
MB_R_COILS = 0x01, ///< Чтение битовых ячеек
MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов
#ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров
MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения
#else
MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров
MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения
#endif
// writting
MB_W_COIL = 0x05, ///< Запись битовой ячейки
MB_W_HOLD_REG = 0x06, ///< Запись одиночного регистра
MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек
MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров
MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства
MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве
/* ERRORS */
// error reading
MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек
MB_ERR_R_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов
MB_ERR_R_IN_REGS = MB_R_IN_REGS + ERR_VALUES_START, ///< Ошибка чтения регистров хранения
MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров
// error writting
MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки
MB_ERR_W_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра
MB_ERR_W_COILS = MB_W_COILS + ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек
MB_ERR_W_HOLD_REGS = MB_W_HOLD_REGS + ERR_VALUES_START, ///< Ошибка записи нескольких регистров
MB_ERR_R_DIAGNOSTIC = MB_R_DIAGNOSTIC + ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства
MB_ERR_R_DEVICE_INFO = MB_R_DEVICE_INFO + ERR_VALUES_START, ///< Ошибка чтения информации об устройстве
}MB_FunctonTypeDef;
/** @brief Structure for modbus diagnostics sub-functions codes */
typedef enum
{
RETURN_QUERRY_DATA = 0x0,
RESTART_COMM_OPTIONS = 0x1,
RETURN_DIAG_REG = 0x2,
CHANGE_ASCII_INPUT_DELIMITER = 0x3,
FORCE_LISTEN_ONLY_MODE = 0x4,
CLEAR_CNT_AND_DIAG_REG = 0xA,
RETURN_BUS_MSG_CNT = 0xB,
RETURN_BUS_COMM_ERR_CNT = 0xC,
RETURN_BUS_EXCEPT_ERR_CNT = 0xD,
RETURN_SLAVE_MSG_CNT = 0xE,
RETURN_SLAVE_NO_RESP_CNT = 0xF,
RETURN_SLAVE_NAK_CNT = 0x10,
RETURN_SLAVE_BUSY_CNT = 0x11,
RETURN_BUS_CHAR_OVERRUN = 0x12,
CLEAR_OVR_CNT_AND_FLAG = 0x12,
}MB_DiagnosticsSubFunctionTypeDef;
/** @brief Structure for MEI func codes */
typedef enum //MB_FunctonTypeDef
{
MEI_DEVICE_IDENTIFICATION = 0x0E,
}MB_MEITypeDef;
/** @brief Structure for comformity */
typedef enum //MB_FunctonTypeDef
{
MB_BASIC_IDENTIFICATION = 0x01, /*!< @brief Basic Device Identification.
@details All objects of this category are mandatory:
VendorName,Product code, and revision number */
MB_REGULAR_IDENTIFICATION = 0x02, /*!< @brief Regular Device Identification.
@details The device provides additional and optional
identification and description data objects */
MB_EXTENDED_IDENTIFICATION = 0x03, /*!< @brief Extended Device Identification.
@details The device provides additional and optional
identification and description private data about the physical
device itself. All of these data are device dependent. */
MB_SPEDIFIC_IDENTIFICATION = 0x04, /*!< @brief Specific Device Identification.
@details The device provides one specific identification object. */
/* ERRORS */
MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_REGULAR_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_EXTENDED_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_SPEDIFIC_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
}MB_ConformityTypeDef;
/** @brief Structure for decive identification message type */
typedef struct
{
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identification Interface
MB_ConformityTypeDef ReadDevId;
MB_ConformityTypeDef Conformity;
uint8_t MoreFollows;
uint8_t NextObjId;
uint8_t NumbOfObj;
}MB_DevIdMsgTypeDef;
/** @brief Structure for modbus messsage */
typedef struct // RS_MsgTypeDef
{
uint8_t MbAddr; ///< Modbus Slave Address
MB_FunctonTypeDef Func_Code; ///< Modbus Function Code
MB_DevIdMsgTypeDef DevId; ///< Read Device Identification 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 DATA[DATA_SIZE]; ///< Modbus Data
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
uint16_t MB_CRC; ///< Modbus CRC
}RS_MsgTypeDef;
//--------------------------------------------------
extern RS_MsgTypeDef MODBUS_MSG;
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
/////////////////////////////////////////////////////////////////////
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
/** @brief Структура для объекта (идентификатора устройства модбас) */
typedef struct
{
unsigned length;
char *name;
}MB_DeviceObjectTypeDef;
/** @brief Структура со идентификаторами устройства модбас */
typedef struct
{
MB_DeviceObjectTypeDef VendorName;
MB_DeviceObjectTypeDef ProductCode;
MB_DeviceObjectTypeDef Revision;
MB_DeviceObjectTypeDef VendorUrl;
MB_DeviceObjectTypeDef ProductName;
MB_DeviceObjectTypeDef ModelName;
MB_DeviceObjectTypeDef UserApplicationName;
MB_DeviceObjectTypeDef Reserved[0x79];
MB_DeviceObjectTypeDef User[MODBUS_NUMB_OF_USEROBJECTS];
}MB_DeviceIdentificationTypeDef;
extern MB_DeviceIdentificationTypeDef MB_DEVID;
void MB_DeviceInentificationInit(void);
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
/////////////////////////////////////////////////////////////////////
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/** @brief Структура со диагностической информацией устройства модбас */
typedef struct
{
uint16_t DiagnosticRegister;
struct
{
uint16_t BusMessage;
uint16_t BusCommunicationErr;
uint16_t BusExceptionErr;
uint16_t SlaveMessage;
uint16_t SlaveNoResponse;
uint16_t SlaveNAK;
uint16_t SlaveBusy;
uint16_t BusCharacterOverrun;
}Counters;
}MB_DiagnosticsInfoTypeDef;
extern MB_DiagnosticsInfoTypeDef MB_DINFO;
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/** MODBUS_SETTINGS
* @}
*/
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
/**
* @addtogroup MODBUS_MESSAGE_DEFINES
* @ingroup MODBUS
* @brief Some defines for modbus
@{
*/
/** @brief Structure for coils operation */
typedef enum
{
SET_COIL,
RESET_COIL,
TOOGLE_COIL,
}MB_CoilsOpTypeDef;
//--------------------------------------------------
/**
* @brief Macros to set pointer to 16-bit array
* @param _arr_ - массив регистров (16-бит).
*/
#define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_)))
/**
* @brief Macros to set pointer to register
* @param _parr_ - массив регистров.
* @param _addr_ - Номер регистра (его индекс) от начала массива _arr_.
*/
#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_))
/**
* @brief Macros to set pointer to a certain register that contains certain coil
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Mask
@verbatim Пояснение выражений
(_coil_/16) - get index (address shift) of register that contain certain coil
Visual explanation: 30th coil in coils registers array
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----|
|skip this------| |get this-------|
|shift to 14 bit|
@endverbatim
*/
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
/**
* @brief Macros to set mask to a certain bit in coils register
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
@verbatim Пояснение выражений
(16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register
_coil_-(16*(_coil_/16)) - shift to certain coil in certain register
e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14)
Visual explanation: 30th coil in coils registers array
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----|
|skip this------| |get this-------|
|shift to 14 bit|
@endverbatim
*/
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
/**
* @brief Read Coil at its local address.
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @return uint16_t - Возвращает запрошенный коил на 0м бите.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
/**
* @brief Set Coil at its local address.
* @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_)
/**
* @brief Reset Coil at its local address.
* @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_))
/**
* @brief Set Coil at its local address.
* @param _parr_ - указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_)
/**
* @brief Инициализация объектов
* @details С помозью этого дефайна инициализируются объекты в @ref MB_DeviceInentificationInit
*/
#define MB_ObjectInit(_p_obj_, _userstring_) (_p_obj_)->length = sizeof(_userstring_);\
(_p_obj_)->name = _userstring_;
/**
* @brief Инициализация пользовательских объектов
* @details С помозью этого дефайна инициализируются пользовательские объекты в MB_DeviceInentificationInit
*/
#define MB_UserObjectInit(_pinfostruct_, _user_numb_) MB_ObjectInit(&(_pinfostruct_)->User[_user_numb_], MODBUS_USEROBJECT##_user_numb_##_NAME)
//--------------------------------------------------
//------------------OTHER DEFINES-------------------
#define RegisterType_Holding 0
#define RegisterType_Input 1
#define RegisterType_Discrete 2
// create hadnles and settings for uart, tim, rs with _modbus_ name
//--------------------------------------------------
#ifndef Divide_Up
/**
* @brief Calc dividing including remainder
* @param _val_ - делимое.
* @param _div_ - делитель.
* @details Если результат деления без остатка: он возвращается как есть
Если с остатком - округляется вверх
*/
//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */
#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */
#endif
#ifndef ByteSwap16
/**
* @brief Swap between Little Endian and Big Endian
* @param v - Переменная для свапа.
* @return v (new) - Свапнутая переменная.
* @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты.
*/
#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8)))
#endif
/** GENERAL_MODBUS_STUFF
* @}
*/
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
/**
* @addtogroup MODBUS_FUNCTIONS
* @ingroup MODBUS
* @brief Function for controling modbus communication
*/
//----------------FUNCTIONS FOR USER----------------
/**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
* @ingroup MODBUS_FUNCTIONS
* @brief Function for user use
@{
*/
/* First set up of MODBUS */
void MODBUS_FirstInit(void);
/* Set or Reset Coil at its global address */
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
/* Read Coil at its global address */
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
/** MODBUS_DATA_ACCESS_FUNCTIONS
* @}
*/
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
* @ingroup MODBUS_FUNCTIONS
* @brief Function process commands
@{
*/
/* 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);
/* 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);
/* Proccess command Read Coils (01 - 0x01) */
uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg);
/* Proccess command Read Holding Registers (03 - 0x03) */
uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
/* Proccess command Read Input Registers (04 - 0x04) */
uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Single Coils (05 - 0x05) */
uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Single Coils (06 - 0x06) */
uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Multiple Coils (15 - 0x0F) */
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Multiple Register (16 - 0x10) */
uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
/** MODBUS_DATA_ACCESS_FUNCTIONS
* @}
*/
/////////////////////////---FUNCTIONS---/////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////---CALC DEFINES---//////////////////////////
// TRACES DEFINES
#ifndef Trace_MB_UART_Enter
#define Trace_MB_UART_Enter()
#endif //Trace_MB_UART_Enter
#ifndef Trace_MB_UART_Exit
#define Trace_MB_UART_Exit()
#endif //Trace_MB_UART_Exit
#ifndef Trace_MB_TIM_Enter
#define Trace_MB_TIM_Enter()
#endif //Trace_MB_TIM_Enter
#ifndef Trace_MB_TIM_Exit
#define Trace_MB_TIM_Exit()
#endif //Trace_MB_TIM_Exit
#endif //__MODBUS_H_