release 0.5 (*API CHANGED)

- чуть переделаны некоторые дефайны для универсализации
- смена направления сделана через указател на функцию, а не глобальный дефайн
- добавлен бета осцилограф модбас
- некоторый рефакторинг
This commit is contained in:
2026-02-20 10:41:31 +03:00
parent 3aa279736d
commit a880f46a56
18 changed files with 415 additions and 114 deletions

View File

@@ -65,6 +65,9 @@ CREATE_DEPRECATED_ALIAS(MB_EXTENDED_IDENTIFICATIONS, RID_EXTENDED_IDENTIFICATIO
CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIONS, MB_ReadDevId); CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIONS, MB_ReadDevId);
#define MbAddr DeviceAddr
/** MODBUS_LEGACY_API /** MODBUS_LEGACY_API
* @} * @}
*/ */

View File

@@ -29,7 +29,7 @@
//----------------Слейв модбас----------------// //----------------Слейв модбас----------------//
#include "modbus.h" #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_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
MODBUS_SlaveStart(&hmodbus1, NULL); MODBUS_SlaveStart(&hmodbus1, NULL);
@endcode @endcode
@@ -37,19 +37,24 @@
//----------------Мастер модбас----------------// //----------------Мастер модбас----------------//
#include "modbus.h" #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); MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
// При получении ответа вызовется функция callback_func()
RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func);
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
// MB_RespGet_... Чтобы достать нужные данные из ответа // MB_RespGet_... Чтобы достать нужные данные из ответа
if(hmodbus->RS_STATUS == RS_OK)
if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок
{ {
for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
{ {
// Запись регистров из ответа в массив
uint16_t value; uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
{ {
@@ -57,6 +62,9 @@
} }
} }
} }
else // Ответ получен с ошибкой или не получен вовсе
{
}
} }
@endcode @endcode
@@ -107,6 +115,10 @@
#ifdef MODBUS_ENABLE_DIAGNOSTICS #ifdef MODBUS_ENABLE_DIAGNOSTICS
#include "modbus_diag.h" #include "modbus_diag.h"
#endif #endif
#ifdef MODBUS_ENABLE_OSCIL
#include "modbus_oscil.h"
#endif
#include "modbus_data.h"
#ifdef MODBUS_ENABLE_MASTER #ifdef MODBUS_ENABLE_MASTER
@@ -124,7 +136,7 @@
//----------------FUNCTIONS FOR USER---------------- //----------------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); HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
/* Запуск слейв устройства */ /* Запуск слейв устройства */

View File

@@ -27,7 +27,6 @@
#define __MODBUS_CORE_H_ #define __MODBUS_CORE_H_
#include "modbus_config.h" #include "modbus_config.h"
#include "modbus_data.h"
#include "__crc_algs.h" #include "__crc_algs.h"
/** /**
@@ -41,31 +40,31 @@
////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
//-------------DEFINES FOR STRUCTURE---------------- //-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */ /* defines for structure of modbus message */
#define TransactionID_size 2 ///< size of (Transaction ID) #define MbTransactionID_size 2 ///< size of (Transaction ID)
#define ProtocolID_size 2 ///< size of (Protocol ID) #define MbProtocolID_size 2 ///< size of (Protocol ID)
#define PDULength_size 2 ///< size of (PDU Length) #define MbPDULength_size 2 ///< size of (PDU Length)
#define MbAddr_SIZE 1 ///< size of (Slave Addr) #define MbDeviceAddr_size 1 ///< size of (Slave Addr)
#define Func_Code_SIZE 1 ///< size of (Function Code) #define MbFuncCode_size 1 ///< size of (Function Code)
#define Addr_SIZE 2 ///< size of (Address) #define MbAddr_size 2 ///< size of (Address)
#define Qnt_SIZE 2 ///< size of (Quantity) #define MbQnt_size 2 ///< size of (Quantity)
#define ByteCnt_SIZE 1 ///< size of (Byte Count) #define MbByteCnt_size 1 ///< size of (Byte Count)
#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) #define MbData_size 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE)
#define CRC_SIZE 2 ///< size of (MbCRC) in bytes #define MbCRC_size 2 ///< size of (MbCRC) in bytes
#ifndef MODBUS_PROTOCOL_TCP #ifndef MODBUS_PROTOCOL_TCP
/** @brief Size of whole RTU message */ /** @brief Size of whole RTU message */
#define 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 #else
/** @brief Size of whole TCP message */ /** @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 #endif
/** @brief Size of first part of message that will be received /** @brief Size of first part of message that will be received
first receive info part of message, than defines size of rest message*/ first receive info part of message, than defines size of rest message*/
#define 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 */ /** @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 * @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, ///< Ошибка чтения информации об устройстве FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве
}MB_FunctonTypeDef; }MB_FunctonTypeDef;
/** @brief Enum for MEI func codes */ /**
* @brief Enum for MEI func codes
*/
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
MEI_DEVICE_IDENTIFICATIONS = 0x0E, MEI_DEVICE_IDENTIFICATIONS = 0x0E,
@@ -180,14 +181,14 @@ typedef struct // RS_MsgTypeDef
uint16_t PDULength; ///< Modbus TCP: PDU Length uint16_t PDULength; ///< Modbus TCP: PDU Length
#endif #endif
uint8_t MbAddr; ///< Modbus Slave Address uint8_t DeviceAddr; ///< Modbus Slave Address
MB_FunctonTypeDef FuncCode; ///< Modbus Function Code MB_FunctonTypeDef FuncCode; ///< Modbus Function Code
MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct
uint16_t Addr; ///< Modbus Address of data uint16_t Addr; ///< Modbus Address of data
uint16_t Qnt; ///< Quantity of modbus data uint16_t Qnt; ///< Quantity of modbus data
uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive
uint16_t MbData[DATA_SIZE]; ///< Modbus Data uint16_t MbData[MbData_size]; ///< Modbus Data
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
uint16_t MbCRC; ///< Modbus CRC uint16_t MbCRC; ///< Modbus CRC
@@ -298,7 +299,7 @@ extern RS_MsgTypeDef MODBUS_MSG;
/* Check is address valid for certain array */ /* Check is address valid for certain array */
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB); MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB);
/* Define Address Origin for Input/Holding Registers */ /* Define Address Origin for Input/Holding Registers */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType); MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag);
/* Define Address Origin for coils */ /* Define Address Origin for coils */
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag); MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag);
/** MODBUS_CMD_PROCESS_FUNCTIONS /** MODBUS_CMD_PROCESS_FUNCTIONS

View File

@@ -3,9 +3,9 @@
* @file modbus_holdregs.h * @file modbus_holdregs.h
* @brief Работа с регистрами хранения Modbus * @brief Работа с регистрами хранения Modbus
******************************************************************************* *******************************************************************************
@addtogroup MODBUS_INS Input Register Tools @addtogroup MODBUS_HOLD Holding Registers Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с входными регистрами @brief Функции для работы с регистрами хранения
******************************************************************************* *******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы: Модуль для доступа к регистрам внутри программы:

View File

@@ -3,9 +3,9 @@
* @file modbus_inputregs.h * @file modbus_inputregs.h
* @brief Работа с входными регистрами Modbus * @brief Работа с входными регистрами Modbus
******************************************************************************* *******************************************************************************
@addtogroup MODBUS_HOLD Holding Registers Tools @addtogroup MODBUS_INS Input Register Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
@brief Функции для работы с регистрами хранения @brief Функции для работы с входными регистрами
******************************************************************************* *******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы: Модуль для доступа к регистрам внутри программы:

111
Inc/modbus_oscil.h Normal file
View 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
* @}
*/

View File

@@ -24,7 +24,7 @@
4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT() 4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT()
@section features Особенности: @section features Особенности:
- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи - Буфер: RS_Buffer[RS_MSG_SIZE_MAX] Общий для приема/передачи
- Состояния: отслеживается через флаги в RS_HandleTypeDef - Состояния: отслеживается через флаги в RS_HandleTypeDef
- Таймауты: контролируют максимальное время ожидания фрейма - Таймауты: контролируют максимальное время ожидания фрейма
******************************************************************************/ ******************************************************************************/
@@ -36,8 +36,8 @@
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---//////////////////////////// ////////////////////////////---DEFINES---////////////////////////////
/* Check that all defines required by RS are defined */ /* Check that all defines required by RS are defined */
#ifndef MSG_SIZE_MAX #ifndef RS_MSG_SIZE_MAX
#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. #error Define RS_MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
#endif #endif
/** /**
@@ -45,7 +45,7 @@
*/ */
/* Clear message-uart buffer */ /* Clear message-uart buffer */
#define RS_Clear_Buff(_buff_) for(int i=0; i<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 */ /* Set/Reset flags */
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0 #define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
@@ -68,7 +68,7 @@
#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) #define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_)
/* Clear all RS stuff */ /* Clear all RS stuff */
#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->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_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX)
//#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) //#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX)
@@ -237,7 +237,7 @@ typedef struct // RS_HandleTypeDef
/* MESSAGE */ /* MESSAGE */
uint8_t ID; ///< ID хендла uint8_t ID; ///< ID хендла
RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола 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 int32_t RS_Message_Size; ///< size of whole message, not only data
/* HANDLERS and SETTINGS */ /* HANDLERS and SETTINGS */
@@ -245,6 +245,7 @@ typedef struct // RS_HandleTypeDef
TIM_HandleTypeDef *htim; ///< Хендл TIM TIM_HandleTypeDef *htim; ///< Хендл TIM
RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef
uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера
void (*pSetDirection)(int Tx); ///< Указатель на функцию: смена направления
void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер
/* FLAGS */ /* FLAGS */
@@ -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); RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Инициалазация структуры @ref RS_HandleTypeDef */ /* Инициалазация структуры @ref RS_HandleTypeDef */
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr); RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx));
/* Отменить прием/передачу RS/UART */ /* Отменить прием/передачу RS/UART */
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);

View File

@@ -10,20 +10,25 @@ Modbus/
│ inc/ modbus │ inc/ modbus
│ ├── modbus.h # Главный заголовочный файл modbus_slave │ ├── modbus.h # Главный заголовочный файл modbus_slave
│ ├── modbus_core.h # Базовые определения и структуры modbus_master │ ├── modbus_core.h # Базовые определения и структуры modbus_master
│ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils │ ├── modbus_coils.h # Работа с дискретными коилами ├── modbus_coils
│ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs │ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs
│ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs │ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs
│ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid │ ├── modbus_devid.h # Идентификаторы устройства ├── modbus_devid
│ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag │ ├── modbus_master.h # Заголовочный файл Master режима ├── modbus_diag
├── src/ ── rs_message │ ├── modbus_slave.h # Заголовочный файл Slave режима ── modbus_oscil
│ ├── modbus.c # Основная логика Modbus │ ├── modbus_diag.h # Диагностика Modbus └── rs_message
│ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро) │ ├── modbus_oscil.h # Осциллографирование данных
── modbus_master.c # Основная логика Master Modbus ── modbus_config ── rs_message.h # Драйвер обмена по RS/UART ── modbus_core (единое ядро)
│ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data ├── src/ ├── modbus_config
│ ├── modbus_holdregs.c # Реализация регистров хранения ── __crc_algs │ ├── 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_inputregs.c # Реализация входных регистров
│ ├── modbus_devid.c # Реализация идентификации устройства │ ├── modbus_devid.c # Реализация идентификации устройства
│ ├── modbus_data.c # Функции доступа к данным │ ├── modbus_diag.c # Диагностические функции и счетчики ошибок
│ ├── modbus_oscil.c # Сбор и хранение осциллограмм
│ └── rs_message.c # Реализация драйвера RS │ └── rs_message.c # Реализация драйвера RS
├── __modbus_config.h # Конфигурация Modbus (надо заменить) ├── __modbus_config.h # Конфигурация Modbus (надо заменить)
├── __modbus_data.h # Структуры данных (надо заменить) ├── __modbus_data.h # Структуры данных (надо заменить)
@@ -97,7 +102,7 @@ int main(void)
MX_TIM3_Init(); MX_TIM3_Init();
// Инициализация Modbus // Инициализация 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_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
// Запуск приема Modbus // Запуск приема Modbus
@@ -113,17 +118,28 @@ int main(void)
```c ```c
#include "modbus.h" #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 штук // Запрос на 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]; read_hold[10];
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
// MB_RespGet_... Чтобы достать нужные данные из ответа // MB_RespGet_... Чтобы достать нужные данные из ответа
if(hmodbus->RS_STATUS == RS_OK)
if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок
{ {
for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
{ {
// Запись регистров из ответа в массив
uint16_t value; uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
{ {
@@ -131,7 +147,11 @@ void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
} }
} }
} }
else // Ответ получен с ошибкой или не получен вовсе
{
} }
}
int main(void) int main(void)
{ {
// Инициализация HAL // Инициализация HAL
@@ -150,7 +170,7 @@ int main(void)
} }
``` ```
#### 3.5. Настройка карты данных #### 3.5. Настройка карты данных (только для режима Slave)
В `modbus_data.h` настройте регистры и coils под ваше устройство: В `modbus_data.h` настройте регистры и coils под ваше устройство:
@@ -195,7 +215,7 @@ typedef struct
``` ```
#### 3.6. Доступ к данным в коде #### 3.6. Доступ к данным в коде
В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
```c ```c
// Чтение входных регистров // Чтение входных регистров
uint16_t temp = MB_DATA.InRegs.Temperature; uint16_t temp = MB_DATA.InRegs.Temperature;
@@ -204,15 +224,15 @@ uint16_t temp = MB_DATA.InRegs.Temperature;
MB_DATA.HoldRegs.SetpointTemp = 2500; MB_DATA.HoldRegs.SetpointTemp = 2500;
// Управление coils // Управление coils
MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить Relay1 MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить 0 бит в Coils
MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2 MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить 1 бит в Coils
// Чтение coil // Чтение coil
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) { if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
// Pump включен // Pump включен
} }
``` ```
В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()` В режиме **мастера** есть функции для получения информации из ответа `MB_RespGet_...()`
```c ```c
// Чтение регистров: Получить запрошенные регистры // Чтение регистров: Получить запрошенные регистры
uint16_t value; uint16_t value;

View File

@@ -24,8 +24,6 @@
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
@@ -36,10 +34,11 @@ static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_
* @param hmodbus Указатель на хендлер RS * @param hmodbus Указатель на хендлер RS
* @param huart Указатель на хендлер UART * @param huart Указатель на хендлер UART
* @param htim Указатель на хендлер TIM * @param htim Указатель на хендлер TIM
* @param pSetDirection Указатель на функцию для смены направления RS485
* @details Подключает хендлы периферии к hmodbus * @details Подключает хендлы периферии к hmodbus
* Конфигурация выставляется по умолчанию из modbus_config.h * Конфигурация выставляется по умолчанию из modbus_config.h
*/ */
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim) HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx))
{ {
if((hmodbus == NULL) || (huart == NULL)) 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; hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
// INIT // 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) if(hmodbus->RS_STATUS == RS_OK)
return HAL_OK; return HAL_OK;

View File

@@ -51,7 +51,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
/* Define number of object in one message */ /* Define number of object in one message */
unsigned lastobjid = 0; unsigned lastobjid = 0;
for(int i = 0; i < DATA_SIZE*2;) for(int i = 0; i < MbData_size*2;)
{ {
/* Если объект за пределами допутимого - выходим из цикла */ /* Если объект за пределами допутимого - выходим из цикла */
if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS) if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS)
@@ -60,7 +60,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
i += 2; i += 2;
i += obj[objidtmp].length; i += obj[objidtmp].length;
/* Если все еще помещается в массив переходим на следующий объект */ /* Если все еще помещается в массив переходим на следующий объект */
if(i < DATA_SIZE*2) if(i < MbData_size*2)
{ {
objidtmp++; objidtmp++;
} }

View File

@@ -40,7 +40,7 @@ MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal)
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
//------------WRITE COIL------------- //------------WRITE COIL-------------
Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding); Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 1);
if(Exception == ET_NO_ERRORS) if(Exception == ET_NO_ERRORS)
{ {
*(pHoldRegs) = WriteVal; *(pHoldRegs) = WriteVal;
@@ -66,7 +66,7 @@ uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
//------------READ COIL-------------- //------------READ COIL--------------
Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding); Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 0);
if(Exception) // if exception is not given to func fill it if(Exception) // if exception is not given to func fill it
*Exception = Exception_tmp; *Exception = Exception_tmp;
@@ -94,7 +94,7 @@ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 0); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -121,7 +121,7 @@ uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
{ {
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding, 1); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -146,7 +146,7 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
} }
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 1); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;

View File

@@ -36,7 +36,7 @@ MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal)
uint16_t *pInRegs; uint16_t *pInRegs;
//------------WRITE COIL------------- //------------WRITE COIL-------------
Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input); Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 1);
if(Exception == ET_NO_ERRORS) if(Exception == ET_NO_ERRORS)
{ {
*(pInRegs) = WriteVal; *(pInRegs) = WriteVal;
@@ -62,7 +62,7 @@ uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
uint16_t *pInRegs; uint16_t *pInRegs;
//------------READ COIL-------------- //------------READ COIL--------------
Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input); Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 0);
if(Exception) // if exception is not given to func fill it if(Exception) // if exception is not given to func fill it
*Exception = Exception_tmp; *Exception = Exception_tmp;
@@ -89,7 +89,7 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
//---------CHECK FOR ERRORS---------- //---------CHECK FOR ERRORS----------
// get origin address for data // get origin address for data
uint16_t *pInRegs; uint16_t *pInRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input, 0); // определение адреса регистров
if(modbus_msg->Except_Code != ET_NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;

View File

@@ -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; return mb_func_size;
} }
@@ -392,7 +392,7 @@ RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgType
//------INFO ABOUT DATA/MESSAGE------ //------INFO ABOUT DATA/MESSAGE------
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of slave device // set ID of slave device
modbus_uart_buff[ind++] = modbus_msg->MbAddr; modbus_uart_buff[ind++] = modbus_msg->DeviceAddr;
// set function code // set function code
modbus_uart_buff[ind++] = modbus_msg->FuncCode; 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; int expected_size = 0;
// get ID of slave device // 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) // get function code (check if error response)
modbus_msg->FuncCode = modbus_uart_buff[ind++]; 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 // Copy coil data to message MbData array
for(int i = 0; i < byte_count; i++) { for(int i = 0; i < byte_count; i++) {
if(i < DATA_SIZE) { if(i < MbData_size) {
msg.MbData[i] = coils_data[i]; 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 msg.ByteCnt = quantity * 2; // Each register is 2 bytes
// Copy register data to message MbData array // Copy register data to message MbData array
for(int i = 0; i < quantity && i < DATA_SIZE; i++) { for(int i = 0; i < quantity && i < MbData_size; i++) {
msg.MbData[i] = regs_data[i]; msg.MbData[i] = regs_data[i];
} }

145
Src/modbus_oscil.c Normal file
View 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

View File

@@ -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 RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
MB_Diagnostics_BusMessageCnt(); MB_Diagnostics_BusMessageCnt();
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0) if(hmodbus->ID == 0 || modbus_msg->DeviceAddr == 0)
{ {
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
hmodbus->RS_STATUS = RS_SKIP; hmodbus->RS_STATUS = RS_SKIP;
@@ -49,6 +49,11 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
// Read Hodling Registers // Read Hodling Registers
case FC_R_HOLD_REGS: case FC_R_HOLD_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
#ifdef MODBUS_ENABLE_OSCIL
int is_oscil_data_register = ((hmodbus->pMessagePtr->Addr >= R_HOLDING_OSCIL_ADDR+4) && (hmodbus->pMessagePtr->Addr + hmodbus->pMessagePtr->Qnt <= (R_HOLDING_OSCIL_ADDR+5+(sizeof(MB_OscilTypeDef)/2))));
if(is_oscil_data_register)
MB_Oscil_UpdateTail(&MB_INTERNAL.oscil);
#endif
break; break;
case FC_R_IN_REGS: case FC_R_IN_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);
@@ -185,7 +190,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
#endif #endif
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of message/user // set ID of message/user
modbus_uart_buff[ind++] = modbus_msg->MbAddr; modbus_uart_buff[ind++] = modbus_msg->DeviceAddr;
// set dat or err response // set dat or err response
modbus_uart_buff[ind++] = modbus_msg->FuncCode; 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.NextObjId;
modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj; 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); TrackerCnt_Err(hmodbus->rs_err);
return RS_COLLECT_MSG_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 else // modbus data header
{ {
// set size of received data // 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; modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
else // otherwise return data_size err 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; return mb_func_size;
} }
@@ -348,12 +353,12 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
// get ID of message/user // get ID of message/user
if(modbus_uart_buff[ind] != hmodbus->ID) if(modbus_uart_buff[ind] != hmodbus->ID)
{ {
modbus_msg->MbAddr = 0; modbus_msg->DeviceAddr = 0;
ind++; ind++;
} }
else else
{ {
modbus_msg->MbAddr = modbus_uart_buff[ind++]; modbus_msg->DeviceAddr = modbus_uart_buff[ind++];
} }
// get func code // 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) // явная херня if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // явная херня
{ {
MB_Diagnostics_SlaveNAKCnt(); MB_Diagnostics_SlaveNAKCnt();
modbus_msg->MbAddr = 0; modbus_msg->DeviceAddr = 0;
return RS_SKIP; return RS_SKIP;
} }
@@ -424,7 +429,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
if (modbus_msg->ByteCnt != 0) if (modbus_msg->ByteCnt != 0)
{ {
//check that data size is correct //check that data size is correct
if (modbus_msg->ByteCnt > DATA_SIZE*2) if (modbus_msg->ByteCnt > MbData_size*2)
{ {
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
modbus_msg->FuncCode |= FC_ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;

View File

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

View File

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

View File

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