сделал новую версию рабаем с 0
This commit is contained in:
9
new rev/core/STM32_Modbus/Inc/__crc_algs.h
Normal file
9
new rev/core/STM32_Modbus/Inc/__crc_algs.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "modbus_config.h"
|
||||
|
||||
// extern here to use in bootloader.c
|
||||
extern uint32_t CRC_calc;
|
||||
extern uint32_t CRC_ref;
|
||||
|
||||
|
||||
uint16_t crc16(uint8_t *data, uint32_t data_size);
|
||||
uint32_t crc32(uint8_t *data, uint32_t data_size);
|
||||
165
new rev/core/STM32_Modbus/Inc/__modbus_compat.h
Normal file
165
new rev/core/STM32_Modbus/Inc/__modbus_compat.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file __modbus_compat.h
|
||||
* @brief Модуль для совместимости библиотеки MODBUS.
|
||||
*******************************************************************************
|
||||
* @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 Не используйте эти функции в новом коде. Они будут удалены в будущих версиях.
|
||||
* Вместо них используйте актуальные 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);
|
||||
|
||||
|
||||
/** MODBUS_LEGACY_API
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @cond Заглушки отключенных модулей */
|
||||
|
||||
#ifndef MODBUS_ENABLE_COILS
|
||||
#define MB_Coil_Write_Global(Addr, WriteVal) ET_ILLEGAL_FUNCTION
|
||||
#define MB_Coil_Read_Global(Addr, Exception) 0
|
||||
#define MB_Process_Read_Coils(modbus_msg) 0
|
||||
#define MB_Process_Write_Single_Coil(modbus_msg) 0
|
||||
#define MB_Process_Write_Miltuple_Coils(modbus_msg) 0
|
||||
#endif
|
||||
|
||||
#ifndef MODBUS_ENABLE_HOLDINGS
|
||||
#define MB_Holding_Write_Global(Addr, WriteVal) ET_ILLEGAL_FUNCTION
|
||||
#define MB_Holding_Read_Global(Addr, Exception) 0
|
||||
#define MB_Process_Read_Hold_Regs(modbus_msg) 0
|
||||
#define MB_Process_Write_Single_Reg(modbus_msg) 0
|
||||
#define MB_Process_Write_Miltuple_Regs(modbus_msg) 0
|
||||
#endif
|
||||
|
||||
#ifndef MODBUS_ENABLE_INPUTS
|
||||
#define MB_Input_Write_Global(Addr, WriteVal) ET_ILLEGAL_FUNCTION
|
||||
#define MB_Input_Read_Global(Addr, Exception) 0
|
||||
#define MB_Process_Read_Input_Regs(modbus_msg) 0
|
||||
#endif
|
||||
|
||||
#ifndef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#define MB_WriteSingleObjectToMessage(mbdata, ind, obj)
|
||||
#define MB_WriteObjectsToMessage(modbus_msg, maxidofobj)
|
||||
#define MB_Process_Read_Device_Identifications(modbus_msg) 0
|
||||
#define MB_DeviceInentificationInit()
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MODBUS_ENABLE_DIAGNOSTICS
|
||||
#define MB_DiagnosticsInit()
|
||||
#define MB_Diagnostics_WriteBit(bit_num, bit_state) 0
|
||||
#define MB_Diagnostics_GetBit(bit_num) 0
|
||||
#define MB_Process_Diagnostics(modbus_msg) 0
|
||||
#define MB_Diagnostics_BusMessageCnt()
|
||||
#define MB_Diagnostics_CommunicationErrorCnt()
|
||||
#define MB_Diagnostics_ExceptionErrorCnt()
|
||||
#define MB_Diagnostics_CharacterOverrunCnt()
|
||||
#define MB_Diagnostics_SlaveMessageCnt()
|
||||
#define MB_Diagnostics_SlaveNoResponseCnt()
|
||||
#define MB_Diagnostics_SlaveNAKCnt()
|
||||
#define MB_Diagnostics_SlaveBusyCnt()
|
||||
#define MB_GetDeviceMode() MODBUS_NORMAL_MODE
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef MODBUS_ENABLE_MASTER
|
||||
#define MB_RespGet_RegisterValue(modbus_msg, reg_addr, reg_value) 0
|
||||
#define MB_RespGet_CoilState(modbus_msg, coil_addr, coil_state) 0
|
||||
#define MB_RespGet_NumberOfObjects(modbus_msg) 0
|
||||
#define MB_RespGet_ObjectById(modbus_msg, obj_id, obj_data, obj_length) 0
|
||||
#define MB_RespGet_ObjectByIndex(modbus_msg, index, obj_id, obj_data, obj_length) 0
|
||||
#define MB_RespGet_Diagnostic(modbus_msg, data) 0
|
||||
#define MB_REQUEST_READ_COILS(slave_addr, start_addr, quantity) {0}
|
||||
#define MB_REQUEST_READ_DISCRETE_INPUTS(slave_addr, start_addr, quantity) {0}
|
||||
#define MB_REQUEST_READ_HOLDING_REGS(slave_addr, start_addr, quantity) {0}
|
||||
#define MB_REQUEST_READ_INPUT_REGS(slave_addr, start_addr, quantity) {0}
|
||||
#define MB_REQUEST_WRITE_SINGLE_COIL(slave_addr, coil_addr, value) {0}
|
||||
#define MB_REQUEST_WRITE_SINGLE_REG(slave_addr, reg_addr, value) {0}
|
||||
#define MB_REQUEST_WRITE_MULTIPLE_COILS(slave_addr, start_addr, quantity, coils_data) {0}
|
||||
#define MB_REQUEST_WRITE_MULTIPLE_REGS(slave_addr, start_addr, quantity, regs_data) {0}
|
||||
#define MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, sub_function, data) {0}
|
||||
#define MB_REQUEST_RETURN_QUERY_DATA(slave_addr) {0}
|
||||
#define MB_REQUEST_RESTART_COMMUNICATIONS(slave_addr, data) {0}
|
||||
#define MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(slave_addr) {0}
|
||||
#define MB_REQUEST_FORCE_LISTEN_ONLY_MODE(slave_addr) {0}
|
||||
#define MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_SLAVE_NAK_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(slave_addr) {0}
|
||||
#define MB_REQUEST_READ_DEVICE_ID_BASIC(slave_addr) {0}
|
||||
#define MB_REQUEST_READ_DEVICE_ID_REGULAR(slave_addr) {0}
|
||||
#define MB_REQUEST_READ_DEVICE_ID_EXTENDED(slave_addr) {0}
|
||||
#define MB_REQUEST_READ_DEVICE_ID_SPECIFIC(slave_addr, object_id) {0}
|
||||
#define MB_Master_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
|
||||
#define MB_Master_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
|
||||
#endif
|
||||
|
||||
#ifndef MODBUS_ENABLE_SLAVE
|
||||
#define MB_Slave_Response(hmodbus, modbus_msg) RS_ERR
|
||||
#define MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
|
||||
#define MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
|
||||
#endif
|
||||
/** @endcond */
|
||||
#endif //__MODBUS_COMPAT_H_
|
||||
144
new rev/core/STM32_Modbus/Inc/modbus.h
Normal file
144
new rev/core/STM32_Modbus/Inc/modbus.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus.h
|
||||
* @brief Главный заголовочный файл Modbus библиотеки
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS Modbus tools
|
||||
@brief Библиотека реализующая протокол Modbus
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_FUNCTIONS Main API for Modbus Library
|
||||
@ingroup MODBUS
|
||||
@brief Публичные функции библиотеки
|
||||
@{
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Объединяющий файл для подключения всей функциональности Modbus.
|
||||
Подключает все необходимые модули:
|
||||
|
||||
|
||||
@section Start Инструкция по подключению
|
||||
Для корректной работы надо:
|
||||
- Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие
|
||||
низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика
|
||||
|
||||
- В modbus_config.h настроить дефайны для нужной работы UART
|
||||
|
||||
- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1
|
||||
- После для запуска Modbus:
|
||||
@code
|
||||
//----------------Слейв модбас----------------//
|
||||
#include "modbus.h"
|
||||
|
||||
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
|
||||
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
||||
MODBUS_SlaveStart(&hmodbus1, NULL);
|
||||
@endcode
|
||||
@code
|
||||
//----------------Мастер модбас----------------//
|
||||
#include "modbus.h"
|
||||
|
||||
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
|
||||
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
|
||||
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
|
||||
|
||||
@section modules Подключаемые модули:
|
||||
- rs_message.h - работа с uart
|
||||
- modbus_core.h - базовые определения
|
||||
- modbus_coils.h - работа с дискретными выходами
|
||||
- modbus_holdregs.h - работа с регистрами хранения
|
||||
- modbus_inputregs.h - работа с входными регистрами
|
||||
- modbus_devid.h - идентификация устройства
|
||||
- modbus_diag.h - диагностика modbus
|
||||
|
||||
|
||||
@section data Структура данных Modbus
|
||||
|
||||
#### Holding/Input Registers:
|
||||
- Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
|
||||
Таким образом, сами регистры могут представлять собой как массив так и структуру.
|
||||
|
||||
#### Coils:
|
||||
- Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель.
|
||||
Таким образом, сами коилы могут представлять собой как массив так и структуру.
|
||||
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_H_
|
||||
#define __MODBUS_H_
|
||||
|
||||
#include "rs_message.h"
|
||||
#ifdef MODBUS_ENABLE_MASTER
|
||||
#include "modbus_master.h"
|
||||
#endif
|
||||
#ifdef MODBUS_ENABLE_SLAVE
|
||||
#include "modbus_slave.h"
|
||||
#endif
|
||||
#ifdef MODBUS_ENABLE_COILS
|
||||
#include "modbus_coils.h"
|
||||
#endif
|
||||
#ifdef MODBUS_ENABLE_HOLDINGS
|
||||
#include "modbus_holdregs.h"
|
||||
#endif
|
||||
#ifdef MODBUS_ENABLE_INPUTS
|
||||
#include "modbus_inputregs.h"
|
||||
#endif
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#include "modbus_devid.h"
|
||||
#endif
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
#include "modbus_diag.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODBUS_ENABLE_MASTER
|
||||
#define MODBUS_MODE_MASTER 1 ///< Псевдо-enum: Режим мастер
|
||||
#endif
|
||||
|
||||
#ifdef MODBUS_ENABLE_SLAVE
|
||||
#define MODBUS_MODE_SLAVE 0 ///< Псевдо-enum: Режим слейв
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
|
||||
//----------------FUNCTIONS FOR USER----------------
|
||||
|
||||
/* Инициализация периферии модбас. */
|
||||
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
|
||||
/* Программная конфигурация модбас. */
|
||||
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
|
||||
/* Запуск слейв устройства */
|
||||
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||
/* Реквест мастера модбас */
|
||||
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*));
|
||||
|
||||
|
||||
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //__MODBUS_H_
|
||||
|
||||
/** MODBUS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
123
new rev/core/STM32_Modbus/Inc/modbus_coils.h
Normal file
123
new rev/core/STM32_Modbus/Inc/modbus_coils.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_coils.h
|
||||
* @brief Работа с коилами Modbus
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_COILS Coils Tools
|
||||
@ingroup MODBUS_INTERNAL
|
||||
@brief Функции для работы с коилами
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль для доступа к coils внутри программы:
|
||||
- Функции для доступа к coils по глобальным адресам
|
||||
- Макросы для доступа к coils по локальным адресам
|
||||
|
||||
Модуль предоставляет функции и макросы для работы с битовыми данными:
|
||||
- Чтение coils (0x01) Упаковка битов в байты
|
||||
- Запись одиночного coil (0x05) Установка/сброс бита
|
||||
- Запись множественных coils (0x0F) - распаковка байтов в биты
|
||||
|
||||
@section cbits Организация битовых данных:
|
||||
Coils упакованы в 16-битные слова для эффективного использования памяти.
|
||||
Биты нумеруются от младшего к старшему внутри каждого слова.
|
||||
|
||||
@section caddr Адресация:
|
||||
- Глобальная - абсолютный адрес в пространстве Modbus
|
||||
- Локальная - относительный адрес внутри массива coils
|
||||
- Макросы автоматически вычисляют смещения и маски
|
||||
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_COILS_H_
|
||||
#define __MODBUS_COILS_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_COILS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access
|
||||
* @ingroup MODBUS_FUNCTIONS
|
||||
* @brief API для доступа к данным модбас внутри программы
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Enum for coils operation */
|
||||
typedef enum
|
||||
{
|
||||
SET_COIL,
|
||||
RESET_COIL,
|
||||
TOOGLE_COIL,
|
||||
}MB_CoilsOpTypeDef;
|
||||
|
||||
/**
|
||||
* @brief Считать коил по локальному адресу.
|
||||
* @param _parr_ - массив коилов.
|
||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||
* @return uint16_t Возвращает запрошенный коил на 0м бите.
|
||||
*
|
||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||
*/
|
||||
#define MB_Coil_Read_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
|
||||
/**
|
||||
* @brief Выставить коил по локальному адресу.
|
||||
* @param _parr_ Указатель на массив коилов.
|
||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||
*
|
||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||
*/
|
||||
#define MB_Coil_Set_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_)
|
||||
/**
|
||||
* @brief Сбросить коил по локальному адресу.
|
||||
* @param _parr_ Указатель на массив коилов.
|
||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||
*
|
||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||
*/
|
||||
#define MB_Coil_Reset_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_))
|
||||
/**
|
||||
* @brief Переключить состояние коила по локальному адресу.
|
||||
* @param _parr_ Указатель на массив коилов.
|
||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||
*
|
||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||
*/
|
||||
#define MB_Coil_Toogle_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_)
|
||||
|
||||
/* Выставить/сбросить коил по глобальному адресу */
|
||||
MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
|
||||
/* Считать коил по глобальному адресу */
|
||||
uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
|
||||
|
||||
/** MODBUS_DATA_ACCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
/* Обработать функцию Read Coils (01 - 0x01) */
|
||||
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg);
|
||||
/* Обработать функцию Write Single Coils (05 - 0x05) */
|
||||
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
|
||||
/* Обработать функцию Write Multiple Coils (15 - 0x0F) */
|
||||
uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
|
||||
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
#endif //MODBUS_ENABLE_COILS
|
||||
#endif //__MODBUS_COILS_H_
|
||||
314
new rev/core/STM32_Modbus/Inc/modbus_core.h
Normal file
314
new rev/core/STM32_Modbus/Inc/modbus_core.h
Normal file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_core.h
|
||||
* @brief Ядро Modbus протокола - определения и структуры
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_INTERNAL Modbus Internal Tools
|
||||
@ingroup MODBUS
|
||||
@brief Внутренние штуки библиотеки
|
||||
@{
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Базовые определения для реализации Modbus RTU устройства:
|
||||
- Структуры сообщений Modbus
|
||||
Коды функций и исключений
|
||||
Константы размеров полей
|
||||
Вспомогательные макросы
|
||||
|
||||
@section msg Структура сообщения:
|
||||
[ADDR][FUNC][DATA...][CRC]
|
||||
- Адрес: 1 байт
|
||||
- Функция: 1 байт
|
||||
- Данные: переменной длины
|
||||
- CRC: 2 байта
|
||||
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_CORE_H_
|
||||
#define __MODBUS_CORE_H_
|
||||
|
||||
#include "modbus_config.h"
|
||||
#include "modbus_data.h"
|
||||
#include "__crc_algs.h"
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
|
||||
* @ingroup MODBUS
|
||||
* @brief Определения протокола модбас
|
||||
* @{
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////---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
|
||||
|
||||
#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)
|
||||
#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)
|
||||
#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
|
||||
|
||||
/** @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 Enum for modbus exception codes
|
||||
* @details Prefix ET for Error Type
|
||||
*/
|
||||
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
|
||||
}MB_ExceptionTypeDef;
|
||||
|
||||
#define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes
|
||||
/**
|
||||
* @brief Enum for modbus func codes
|
||||
* @details Prefix FC for Function Code
|
||||
*/
|
||||
typedef enum //MB_FunctonTypeDef
|
||||
{
|
||||
/* COMMANDS */
|
||||
// reading
|
||||
FC_R_COILS = 0x01, ///< Чтение битовых ячеек
|
||||
FC_R_DISC_IN = 0x02, ///< Чтение дискретных входов
|
||||
#ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
|
||||
FC_R_HOLD_REGS = 0x03, ///< Чтение входных регистров
|
||||
FC_R_IN_REGS = 0x04, ///< Чтение регистров хранения
|
||||
#else
|
||||
FC_R_HOLD_REGS = 0x04, ///< Чтение входных регистров
|
||||
FC_R_IN_REGS = 0x03, ///< Чтение регистров хранения
|
||||
#endif
|
||||
|
||||
// writting
|
||||
FC_W_COIL = 0x05, ///< Запись битовой ячейки
|
||||
FC_W_HOLD_REG = 0x06, ///< Запись одиночного регистра
|
||||
FC_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек
|
||||
FC_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров
|
||||
|
||||
FC_R_DIAGNOSTICS = 0x08, ///< Чтение диагностической информации устройства
|
||||
FC_R_DEVICE_ID = 0x2B, ///< Чтение информации об устройстве
|
||||
|
||||
/* ERRORS */
|
||||
// error reading
|
||||
FC_ERR_R_COILS = FC_R_COILS + FC_ERR_VALUES_START, ///< Ошибка чтения битовых ячеек
|
||||
FC_ERR_R_DISC_IN = FC_R_DISC_IN + FC_ERR_VALUES_START, ///< Ошибка чтения дискретных входов
|
||||
FC_ERR_R_IN_REGS = FC_R_IN_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения регистров хранения
|
||||
FC_ERR_R_HOLD_REGS = FC_R_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения входных регистров
|
||||
|
||||
// error writting
|
||||
FC_ERR_W_COIL = FC_W_COIL + FC_ERR_VALUES_START, ///< Ошибка записи битовой ячейки
|
||||
FC_ERR_W_HOLD_REG = FC_W_HOLD_REG + FC_ERR_VALUES_START, ///< Ошибка записи одиночного регистра
|
||||
FC_ERR_W_COILS = FC_W_COILS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек
|
||||
FC_ERR_W_HOLD_REGS = FC_W_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких регистров
|
||||
|
||||
FC_ERR_R_DIAGNOSTIC = FC_R_DIAGNOSTICS + FC_ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства
|
||||
FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве
|
||||
}MB_FunctonTypeDef;
|
||||
|
||||
/** @brief Enum for MEI func codes */
|
||||
typedef enum //MB_FunctonTypeDef
|
||||
{
|
||||
MEI_DEVICE_IDENTIFICATIONS = 0x0E,
|
||||
}MB_MEITypeDef;
|
||||
|
||||
/**
|
||||
* @brief Enum for Read Device Id codes
|
||||
* @details Prefix RID for Read ID
|
||||
*/
|
||||
typedef enum //MB_FunctonTypeDef
|
||||
{
|
||||
RID_BASIC_IDENTIFICATIONS = 0x01, /*!< @brief Basic Device Identifications.
|
||||
@details All objects of this category are mandatory:
|
||||
VendorName, Product code, and revision number */
|
||||
|
||||
RID_REGULAR_IDENTIFICATIONS = 0x02, /*!< @brief Regular Device Identifications.
|
||||
@details The device provides additional and optional
|
||||
identifications and description data objects */
|
||||
|
||||
RID_EXTENDED_IDENTIFICATIONS = 0x03, /*!< @brief Extended Device Identifications.
|
||||
@details The device provides additional and optional
|
||||
identifications and description private data about the physical
|
||||
device itself. All of these data are device dependent. */
|
||||
|
||||
RID_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications.
|
||||
@details The device provides one specific identifications object. */
|
||||
|
||||
}MB_ReadDevId;
|
||||
|
||||
/** @brief Structure for device identifications message type */
|
||||
typedef struct
|
||||
{
|
||||
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface
|
||||
MB_ReadDevId ReadDevId;
|
||||
uint8_t Conformity; ///< Identification conformity level of the device and type of supported access @ref MODBUS_DEVICE_CONFORMITY
|
||||
uint8_t MoreFollows;
|
||||
uint8_t NextObjId;
|
||||
uint8_t NumbOfObj;
|
||||
}MB_DevIdMsgTypeDef;
|
||||
|
||||
|
||||
/** @brief Structure for modbus messsage */
|
||||
typedef struct // RS_MsgTypeDef
|
||||
{
|
||||
#ifdef MODBUS_PROTOCOL_TCP
|
||||
uint16_t TransactionID; ///< Modbus TCP: ID Transaction
|
||||
uint16_t ProtocolID; ///< Modbus TCP: ID Protocol
|
||||
uint16_t PDULength; ///< Modbus TCP: PDU Length
|
||||
#endif
|
||||
|
||||
uint8_t MbAddr; ///< 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
|
||||
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
|
||||
|
||||
uint16_t MbCRC; ///< Modbus CRC
|
||||
}RS_MsgTypeDef;
|
||||
//--------------------------------------------------
|
||||
extern RS_MsgTypeDef MODBUS_MSG;
|
||||
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
||||
|
||||
/**
|
||||
* @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 Макрос для установки указателя на регистр, содержащий запрашиваемый коил
|
||||
* @param _parr_ - массив коилов.
|
||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||
* @note Используется вместе с @ref MB_Set_Coil_Mask
|
||||
@code Пояснение выражений
|
||||
- (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_
|
||||
|
||||
Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0)
|
||||
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|
||||
|register[0]----| |register[1]----|
|
||||
|skip this------| |get this-------|
|
||||
|shift to 14 bit|
|
||||
@endcode
|
||||
*/
|
||||
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
|
||||
/**
|
||||
* @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра
|
||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
|
||||
@code Пояснение выражений
|
||||
- (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра
|
||||
- _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре
|
||||
|
||||
Визуальный пример: 30 коил будет регистре[1], на 14 бите:
|
||||
register = 30/16 = 1
|
||||
bit = 30 - (16*30/16) = 30 - 16 = 14
|
||||
|
||||
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|
||||
|register[0]----| |register[1]----|
|
||||
|skip this------| |get this-------|
|
||||
|shift to 14 bit|
|
||||
@endcode
|
||||
*/
|
||||
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
|
||||
|
||||
/** GENERAL_MODBUS_STUFF
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
//------------------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
|
||||
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Реализация этих функций лежит в modbus_data.c */
|
||||
|
||||
/* 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);
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
#include "__modbus_compat.h"
|
||||
#endif //__MODBUS_CORE_H_
|
||||
/** MODBUS_INTERNAL
|
||||
* @}
|
||||
*/
|
||||
|
||||
125
new rev/core/STM32_Modbus/Inc/modbus_devid.h
Normal file
125
new rev/core/STM32_Modbus/Inc/modbus_devid.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_devid.h
|
||||
* @brief Идентификаторы устройства Modbus
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_DEVID Device Identifications Tools
|
||||
@ingroup MODBUS_INTERNAL
|
||||
@brief Функции для работы с идентификаторами устройства
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль реализации функции Read Device Identifications (0x2B):
|
||||
- Базовая идентификация (Vendor, Product, Revision)
|
||||
- Расширенная идентификация (URL, Model, User fields)
|
||||
- Поддержка потоковой передачи больших объектов
|
||||
|
||||
@section devobj Объекты идентификации:
|
||||
- VendorName, ProductCode, Revision - обязательные
|
||||
- VendorUrl, ProductName, ModelName - опциональные
|
||||
- User objects - пользовательские поля
|
||||
- Поддержка до 128 пользовательских объектов
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_DEVID_H_
|
||||
#define __MODBUS_DEVID_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DEVID
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if MODBUS_NUMB_OF_USEROBJECTS > 0
|
||||
#define MODBUS_DEVICE_CONFORMITY 0x83
|
||||
#else
|
||||
#define MODBUS_DEVICE_CONFORMITY 0x82
|
||||
#endif
|
||||
|
||||
/** @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_DeviceIdentificationsTypeDef;
|
||||
extern MB_DeviceIdentificationsTypeDef MB_DEVID;
|
||||
void MB_DeviceInentificationInit(void);
|
||||
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
||||
|
||||
/**
|
||||
* @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)
|
||||
|
||||
|
||||
|
||||
/** MODBUS_DEVID
|
||||
* @}
|
||||
*/
|
||||
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DEVID
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Записать Один Объект Идентификатора в массив данных */
|
||||
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj);
|
||||
/* Записать Массив Объектов Идентификатора в массив данных */
|
||||
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj);
|
||||
|
||||
/** MODBUS_DEVID
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */
|
||||
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg);
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#endif //__MODBUS_DEVID_H_
|
||||
|
||||
126
new rev/core/STM32_Modbus/Inc/modbus_diag.h
Normal file
126
new rev/core/STM32_Modbus/Inc/modbus_diag.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_diag.h
|
||||
* @brief Диагностика устройства Modbus
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_DIAG Diagnostics Tools
|
||||
@ingroup MODBUS_INTERNAL
|
||||
@brief Функции для работы с диагностикой
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль реализации Diagnostics (Serial Line only) (0x08):
|
||||
- Полная поддержка всех подфункций диагностики
|
||||
- Возможность выставить/сбросить любой бит в диагностическом регистре
|
||||
- Сбор статистики работы устройства
|
||||
- Управление режимами работы
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_DIAG_H_
|
||||
#define __MODBUS_DIAG_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DIAG
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @brief Режимы работы устройства */
|
||||
typedef enum
|
||||
{
|
||||
MODBUS_NORMAL_MODE = 0,
|
||||
MODBUS_LISTEN_ONLY_MODE = 1
|
||||
} MB_DeviceModeTypeDef;
|
||||
|
||||
|
||||
/** @brief Структура со диагностической информацией устройства модбас */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t DiagnosticRegister; ///< Регистр диагностики. 0 бит - overrun. Остальное заполняется пользователем
|
||||
MB_DeviceModeTypeDef DeviceMode;///< Режим устройства - NORMAL/LISTEN_ONLY
|
||||
struct
|
||||
{
|
||||
uint16_t BusMessage; ///< Все принятые фреймы modbus на линии (с всех адресов)
|
||||
uint16_t BusCommunicationErr; ///< Ошибки при приеме фрейма modbus
|
||||
uint16_t BusExceptionErr; ///< Ошибки при обработке фрейма modbus
|
||||
uint16_t SlaveMessage; ///< Принятые сообщения (только запросы на адрес данного устройства)
|
||||
uint16_t SlaveNoResponse; ///< Счетчик сколько мы раз не ответили на запрос
|
||||
uint16_t SlaveNAK; ///< Счетчик аномальной ошибки при обработке фрейма
|
||||
uint16_t SlaveBusy; ///< Счетчик принятых запросов когда устройство занято. Здесь не работает: из-за архитектуры отследить невозможно
|
||||
uint16_t BusCharacterOverrun; ///< Overrun Error
|
||||
} Counters;
|
||||
} MB_DiagnosticsInfoTypeDef;
|
||||
|
||||
extern MB_DiagnosticsInfoTypeDef MB_DIAG;
|
||||
|
||||
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
/* Инициализация диагностических счетчиков */
|
||||
void MB_DiagnosticsInit(void);
|
||||
|
||||
/** MODBUS_DIAG
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
|
||||
@{
|
||||
*/
|
||||
|
||||
/* Выставить бит в регистре диагностике */
|
||||
int MB_Diagnostics_WriteBit(int bit_num, int bit_state);
|
||||
/*ь Прочитать состояние бита диагностического регистра */
|
||||
int MB_Diagnostics_GetBit(int bit_num);
|
||||
/* Получение текущего режима устройства */
|
||||
MB_DeviceModeTypeDef MB_GetDeviceMode(void);
|
||||
|
||||
|
||||
/* Функции для обновления счетчиков диагностики */
|
||||
void MB_Diagnostics_BusMessageCnt(void);
|
||||
void MB_Diagnostics_CommunicationErrorCnt(void);
|
||||
void MB_Diagnostics_ExceptionErrorCnt(void);
|
||||
void MB_Diagnostics_CharacterOverrunCnt(void);
|
||||
void MB_Diagnostics_SlaveMessageCnt(void);
|
||||
void MB_Diagnostics_SlaveNoResponseCnt(void);
|
||||
void MB_Diagnostics_SlaveNAKCnt(void);
|
||||
void MB_Diagnostics_SlaveBusyCnt(void);
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Обработка команды диагностики (0x08) */
|
||||
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg);
|
||||
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
#endif //__MODBUS_DIAG_H_
|
||||
|
||||
/** MODBUS_DIAG
|
||||
* @}
|
||||
*/
|
||||
|
||||
64
new rev/core/STM32_Modbus/Inc/modbus_holdregs.h
Normal file
64
new rev/core/STM32_Modbus/Inc/modbus_holdregs.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_holdregs.h
|
||||
* @brief Работа с регистрами хранения Modbus
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_INS Input Register Tools
|
||||
@ingroup MODBUS_INTERNAL
|
||||
@brief Функции для работы с входными регистрами
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль для доступа к регистрам внутри программы:
|
||||
- Функции для доступа к регистрам хранения по глобальным адресам
|
||||
|
||||
Модуль обработки команд для регистров хранения (Holding Registers):
|
||||
- Чтение множества регистров (0x03)
|
||||
- Запись одиночного регистра (0x06)
|
||||
- Запись множества регистров (0x10)
|
||||
|
||||
@section hold Регистры хранения:
|
||||
- Read/Write доступ
|
||||
- 16-битные значения (uint16_t)
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_HOLDREGS_H_
|
||||
#define __MODBUS_HOLDREGS_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_HOLDINGS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Записать регистр хранения по глобальному адресу. */
|
||||
MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal);
|
||||
/* Считать регистр хранения по глобальному адресу. */
|
||||
uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
|
||||
|
||||
/** MODBUS_DATA_ACCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
/* Обработать функцию Read Holding Registers (03 - 0x03) */
|
||||
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
|
||||
/* Обработать функцию Write Single Coils (06 - 0x06) */
|
||||
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg);
|
||||
/* Обработать функцию Write Multiple Register (16 - 0x10) */
|
||||
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
|
||||
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_HOLDINGS
|
||||
#endif //__MODBUS_HOLDREGS_H_
|
||||
59
new rev/core/STM32_Modbus/Inc/modbus_inputregs.h
Normal file
59
new rev/core/STM32_Modbus/Inc/modbus_inputregs.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_inputregs.h
|
||||
* @brief Работа с входными регистрами Modbus
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_HOLD Holding Registers Tools
|
||||
@ingroup MODBUS_INTERNAL
|
||||
@brief Функции для работы с регистрами хранения
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль для доступа к регистрам внутри программы:
|
||||
- Функции для доступа к входным регистрам по глобальным адресам
|
||||
|
||||
Модуль обработки команд для входных регистров (Input Registers):
|
||||
- Чтение множества регистров (0x04)
|
||||
|
||||
@section in Входные регистры:
|
||||
- Read-Only доступ
|
||||
- 16-битные значения
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_INPUTREGS_H_
|
||||
#define __MODBUS_INPUTREGS_H_
|
||||
#include "modbus_core.h"
|
||||
#ifdef MODBUS_ENABLE_INPUTS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Записать входной регистр по глобальному адресу. */
|
||||
MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal);
|
||||
/* Считать входной регистр по глобальному адресу. */
|
||||
uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
|
||||
|
||||
/** MODBUS_DATA_ACCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions
|
||||
* @ingroup MODBUS_INTERNAL
|
||||
* @brief Функции обработки запросов модбас
|
||||
* @{
|
||||
*/
|
||||
/* Обработать функцию Read Input Registers (04 - 0x04) */
|
||||
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
|
||||
|
||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
* @}
|
||||
*/
|
||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||
|
||||
#endif //MODBUS_ENABLE_INPUTS
|
||||
#endif //__MODBUS_INPUTREGS_H_
|
||||
232
new rev/core/STM32_Modbus/Inc/modbus_master.h
Normal file
232
new rev/core/STM32_Modbus/Inc/modbus_master.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_master.h
|
||||
* @brief Главный заголовочный файл Modbus библиотеки
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_MASTER Modbus master funtions
|
||||
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
@brief Функции для работы в режиме Master
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль реализации Modbus в режиме мастер
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_MASTER_H_
|
||||
#define __MODBUS_MASTER_H_
|
||||
#include "rs_message.h"
|
||||
#ifdef MODBUS_ENABLE_MASTER
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_REQUEST_MSG API for Master Requests
|
||||
* @ingroup MODBUS_FUNCTIONS
|
||||
* @brief API для формирования фрейма-запроса в режиме мастер
|
||||
* @details Примеры использования:
|
||||
* @code
|
||||
* // Чтение 10 holding registers начиная с адреса 0
|
||||
* RS_MsgTypeDef read_msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
|
||||
*
|
||||
* // Запись одного coil
|
||||
* RS_MsgTypeDef write_coil_msg = MB_REQUEST_WRITE_SINGLE_COIL(1, 5, 1);
|
||||
*
|
||||
* // Диагностический запрос
|
||||
* RS_MsgTypeDef diag_msg = MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(1);
|
||||
*
|
||||
* // Идентификация устройства
|
||||
* RS_MsgTypeDef dev_id_msg = MB_REQUEST_READ_DEVICE_ID_BASIC(1);
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
//---------КЛАССИЧЕСКИЕ ДАННЫЕ-----------
|
||||
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value);
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value);
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data);
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data);
|
||||
|
||||
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr);
|
||||
|
||||
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr);
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id);
|
||||
/** MODBUS_REQUEST_MSG
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_REGS_API API for Registers
|
||||
* @ingroup MODBUS_REQUEST_MSG
|
||||
* @brief API для чтения регистров из ответа в режиме мастер
|
||||
* @details Примеры использования:
|
||||
*
|
||||
* @code
|
||||
* // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105
|
||||
* uint16_t reg_value;
|
||||
* if(MB_RespGet_RegisterValue(modbus_msg, 105, ®_value))
|
||||
* {
|
||||
* printf("Register 105 value: %d\n", reg_value);
|
||||
* }
|
||||
*
|
||||
* // Пример: Получить все запрошенные регистры
|
||||
* uint16_t reg_value[125];
|
||||
* MB_RespGet_RegisterAll(modbus_msg)
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
/* Получить значение ВСЕХ регистров в ответе */
|
||||
int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr);
|
||||
/* Получить значение регистра в ответе по его адресу */
|
||||
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value);
|
||||
|
||||
|
||||
/** MODBUS_REQ_REGS_API
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_REQ_COILS_API API for Coils
|
||||
* @ingroup MODBUS_REQUEST_MSG
|
||||
* @brief API для чтения coils из ответа в режиме мастер
|
||||
* @details Примеры использования:
|
||||
*
|
||||
* @code
|
||||
* // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25
|
||||
* int coil_state;
|
||||
* if(MB_RespGet_CoilState(modbus_msg, 25, &coil_state))
|
||||
* {
|
||||
* printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF");
|
||||
* }
|
||||
*
|
||||
* // Пример: Получить состояние всех запрошенных coils
|
||||
* for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
|
||||
* {
|
||||
* int state;
|
||||
* if(MB_RespGet_CoilState(modbus_msg, addr, &state))
|
||||
* {
|
||||
* printf("Coil %d: %s\n", addr, state ? "ON" : "OFF");
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
/* Получить состояние ВСЕХ coil в ответе */
|
||||
int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr);
|
||||
/* Получить состояние coil в ответе по его адресу */
|
||||
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state);
|
||||
|
||||
/** MODBUS_REQ_COILS_API
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_REQ_DEFID_API API for Device Identifications
|
||||
* @ingroup MODBUS_REQUEST_MSG
|
||||
* @brief API для чтения идентификторов из ответа в режиме мастер
|
||||
* @details Примеры использования:
|
||||
*
|
||||
* @code
|
||||
* // Пример 1: Получить VendorName (ID = 0x00)
|
||||
* uint8_t length;
|
||||
* char vendor_name[64];
|
||||
* if(MB_RespGet_ObjectById(modbus_msg, 0x00, vendor_name, &length))
|
||||
* {
|
||||
* // получено
|
||||
* }
|
||||
*
|
||||
* // Пример 2: Перебрать все объекты в сообщении
|
||||
* uint8_t obj_id, obj_length;
|
||||
* char obj_data[256];
|
||||
*
|
||||
* int obj_count = MB_RespGet_NumberOfObjects(modbus_msg);
|
||||
* printf("Total objects: %d\n", obj_count);
|
||||
*
|
||||
* for(int i = 0; i < obj_count; i++)
|
||||
* {
|
||||
* if(MB_RespGet_ObjectByIndex(modbus_msg, i, &obj_id, obj_data, &obj_length))
|
||||
* {
|
||||
* // получено
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Получить количество объектов в сообщении */
|
||||
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg);
|
||||
/* Найти объект по ID в сообщении */
|
||||
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length);
|
||||
/* Получить объект по индексу в сообщении */
|
||||
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length);
|
||||
|
||||
|
||||
/** MODBUS_REQ_DEFID_API
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_REQ_DIAG_API API for Diagnostics
|
||||
* @ingroup MODBUS_REQUEST_MSG
|
||||
* @brief API для чтения диагностической информации из ответа в режиме мастер
|
||||
* @details Примеры использования:
|
||||
*
|
||||
* @code
|
||||
* // Получить данные диагностики (значение счетчика)
|
||||
* uint16_t counter_value;
|
||||
* if(MB_RespGet_Diagnostic(modbus_msg, &counter_value))
|
||||
* {
|
||||
* printf("Counter value: %d\n", counter_value);
|
||||
* }
|
||||
* @endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Получить */
|
||||
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data);
|
||||
|
||||
/** MODBUS_REQ_DIAG_API
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_MASTER
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart) */
|
||||
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||
/* Парс сообщения в режиме мастер (фрейм слейва из uart -> msg) */
|
||||
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||
|
||||
/** MODBUS_MASTER
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif //MODBUS_ENABLE_MASTER
|
||||
#endif //__MODBUS_MASTER_H_
|
||||
37
new rev/core/STM32_Modbus/Inc/modbus_slave.h
Normal file
37
new rev/core/STM32_Modbus/Inc/modbus_slave.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_slave.h
|
||||
* @brief Главный заголовочный файл Modbus библиотеки
|
||||
*******************************************************************************
|
||||
@addtogroup MODBUS_SLAVE Modbus slave funtions
|
||||
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||
@brief Функции для работы в режиме Slave
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль реализации Modbus в режиме слейв
|
||||
******************************************************************************/
|
||||
#ifndef __MODBUS_SLAVE_H_
|
||||
#define __MODBUS_SLAVE_H_
|
||||
#include "rs_message.h"
|
||||
#ifdef MODBUS_ENABLE_SLAVE
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup MODBUS_SLAVE
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Ответ на сообщение в режиме слейва */
|
||||
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
|
||||
RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||
/* Парс сообщения в режиме слейв (фрейм мастера из uart -> msg) */
|
||||
RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||
|
||||
/** MODBUS_SLAVE
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
#endif //MODBUS_ENABLE_SLAVE
|
||||
#endif //__MODBUS_SLAVE_H_
|
||||
317
new rev/core/STM32_Modbus/Inc/rs_message.h
Normal file
317
new rev/core/STM32_Modbus/Inc/rs_message.h
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file rs_message.h
|
||||
* @brief Библиотека обмена сообщениями по RS-интерфейсу
|
||||
*******************************************************************************
|
||||
@defgroup RS_TOOLS RS Tools
|
||||
@brief Всякое для работы по UART/RS
|
||||
@{
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom)
|
||||
через UART в режиме прерываний с поддержкой таймаутов.
|
||||
|
||||
@section posibility Основные возможности:
|
||||
- Прием/передача в прерываниях
|
||||
- Обработка IDLE линии для определения конца фрейма
|
||||
- Таймауты приема через TIM
|
||||
- Гибкая настройка размера сообщений
|
||||
|
||||
@section usage Использование:
|
||||
1. Определить структуру сообщения и размеры буфера
|
||||
2. Реализовать weak-функции обработки сообщений
|
||||
3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания
|
||||
4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT()
|
||||
|
||||
@section features Особенности:
|
||||
- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи
|
||||
- Состояния: отслеживается через флаги в RS_HandleTypeDef
|
||||
- Таймауты: контролируют максимальное время ожидания фрейма
|
||||
******************************************************************************/
|
||||
#ifndef __RS_LIB_H_
|
||||
#define __RS_LIB_H_
|
||||
|
||||
#include "modbus_core.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////---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.
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @cond Заглушки и внутренний недокументированный стаф
|
||||
*/
|
||||
|
||||
/* Clear message-uart buffer */
|
||||
#define RS_Clear_Buff(_buff_) for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL
|
||||
|
||||
/* Set/Reset flags */
|
||||
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
|
||||
#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1
|
||||
|
||||
#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0;
|
||||
#define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1
|
||||
|
||||
|
||||
#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 1; _hRS_->f.TX_Done = 0
|
||||
|
||||
#define RS_Reset_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 0; \
|
||||
_hRS_->f.RX_Continue = 0;
|
||||
#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0;
|
||||
#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 0
|
||||
|
||||
#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1;
|
||||
#define RS_Set_TX_End_Flag(_hRS_) _hRS_->f.TX_Done = 1
|
||||
|
||||
#define RS_Set_RX_End(_hRS_) RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_)
|
||||
#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 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 RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1)
|
||||
#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1)
|
||||
|
||||
|
||||
#ifndef RS_USER_VARS_NUMB
|
||||
#define RS_USER_VARS_NUMB 0
|
||||
#endif
|
||||
|
||||
#ifndef local_time
|
||||
#define local_time() uwTick
|
||||
#endif
|
||||
/** @endcond */
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup RS_DEBUG Tools for debug RS/UART/TIM
|
||||
* @ingroup RS_TOOLS
|
||||
* @brief Дефайны для отладки периферии
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef RS_USER_VARS_NUMB
|
||||
#define RS_USER_VARS_NUMB 0 ///< Количество переменных в @ref TrackerTypeDef
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Тип структуры для счетчиков-переменных
|
||||
* @param num_user_vars Есть возмоность добавления num_user_vars количества пользовательскиъх переменных
|
||||
*/
|
||||
#define TrackerTypeDef(num_user_vars) void *
|
||||
/** @brief Инкрементировать переменную - успешных событий */
|
||||
#define TrackerCnt_Ok(_cntstruct_)
|
||||
/** @brief Инкрементировать переменную - ошибок */
|
||||
#define TrackerCnt_Err(_cntstruct_)
|
||||
/** @brief Инкрементировать переменную - предупреждений */
|
||||
#define TrackerCnt_Warn(_cntstruct_)
|
||||
|
||||
|
||||
|
||||
#ifndef printf_rs
|
||||
/** @brief Printf обычных событий RS/UART/TIM */
|
||||
#define printf_rs(...)
|
||||
#endif
|
||||
|
||||
#ifndef printf_rs_err
|
||||
/** @brief Printf ошибок RS/UART/TIM */
|
||||
#define printf_rs_err(...)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RS_TIM_Handler_ENTER
|
||||
/** @brief Действия при заходе в прерывания таймера */
|
||||
#define RS_TIM_Handler_ENTER()
|
||||
#endif
|
||||
#ifndef RS_TIM_Handler_EXIT
|
||||
/** @brief Действия при выходе из прерывания таймера */
|
||||
#define RS_TIM_Handler_EXIT()
|
||||
#endif
|
||||
|
||||
#ifndef RS_UART_Handler_ENTER
|
||||
/** @brief Действия при заходе в прерывания UART */
|
||||
#define RS_UART_Handler_ENTER()
|
||||
#endif
|
||||
#ifndef RS_UART_Handler_EXIT
|
||||
/** @brief Действия при выходе из прерывания UART */
|
||||
#define RS_UART_Handler_EXIT()
|
||||
#endif
|
||||
/** RS_TOOLS
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// направление передачи rs485
|
||||
#ifndef RS_EnableReceive
|
||||
#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
|
||||
#endif
|
||||
#ifndef RS_EnableTransmit
|
||||
#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
|
||||
#endif
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
//------------------ENUMERATIONS--------------------
|
||||
/** @brief Enums for respond CMD about RS status */
|
||||
typedef enum // RS_StatusTypeDef
|
||||
{
|
||||
/* IN-CODE STATUS (start from 0x01, and goes up)*/
|
||||
/*0x01*/ RS_OK = 0x01,
|
||||
/*0x02*/ RS_ERR,
|
||||
/*0x03*/ RS_ABORTED,
|
||||
/*0x04*/ RS_BUSY,
|
||||
/*0x05*/ RS_SKIP,
|
||||
/*0x06*/ RS_TIMEOUT,
|
||||
|
||||
/*0x07*/ RS_COLLECT_MSG_ERR,
|
||||
/*0x08*/ RS_PARSE_MSG_ERR,
|
||||
|
||||
// reserved values
|
||||
// /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero)
|
||||
}RS_StatusTypeDef;
|
||||
|
||||
|
||||
#define RS_MASTER_MODE_START 0x3 ///< Начало режимов мастера (до него - режим слейв)
|
||||
/** @brief Enums for RS Modes */
|
||||
typedef enum // RS_ModeTypeDef
|
||||
{
|
||||
RS_SLAVE_ALWAYS_WAIT = 0x01, ///< Слейв в постоянном ожидании
|
||||
RS_RESERVED = 0x02, ///< резерв
|
||||
RS_MASTER_REQUEST = 0x03, ///< Мастер с ручным запросом
|
||||
//RS_MASTER_POLLING = 0x04, ///< Мастер с опросом в фоновом режиме
|
||||
}RS_ModeTypeDef;
|
||||
|
||||
/** @brief Enums for Abort modes */
|
||||
typedef enum // RS_AbortTypeDef
|
||||
{
|
||||
ABORT_TX = 0x01, ///< Отменить передачу
|
||||
ABORT_RX = 0x02, ///< Отменить прием
|
||||
ABORT_RX_TX = 0x03, ///< Отменить прием и передачу
|
||||
ABORT_RS = 0x04, ///< Отменить любую работу UART в целом
|
||||
}RS_AbortTypeDef;
|
||||
|
||||
//-----------STRUCTURE FOR HANDLE RS------------
|
||||
/** @brief Struct for flags RS */
|
||||
typedef struct
|
||||
{
|
||||
unsigned RS_Busy:1; ///< 1 - RS занят, 0 - RS свободен
|
||||
unsigned RX_Ongoing:1; ///< 1 - Прием данных в активном состоянии, 0 - Ожидаем начало приема данных
|
||||
|
||||
unsigned RX_Busy:1; ///< 1 - Режим приема активен, 0 - Прием не активен
|
||||
unsigned TX_Busy:1; ///< 1 - Режим передачи активен, 0 - Прием не активен
|
||||
|
||||
unsigned RX_Done:1; ///< 1 - Прием закончен, 0 - Прием еще в процессе или не инициализирован
|
||||
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
|
||||
|
||||
// Выставление следующие флагов определяет пользователь
|
||||
unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала
|
||||
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
|
||||
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
|
||||
unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании
|
||||
unsigned DataUpdated:1; ///< 1 - Данные были обновлены
|
||||
unsigned blink:1; ///< 1 - flag для использования при реализации linkBlink
|
||||
}RS_FlagsTypeDef;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle for RS communication.
|
||||
* @note Prefixes: h - handle, s - settings, f - flag
|
||||
*/
|
||||
typedef struct // RS_HandleTypeDef
|
||||
{
|
||||
/* MESSAGE */
|
||||
uint8_t ID; ///< ID хендла
|
||||
RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола
|
||||
uint8_t *pBufferPtr; ///< Указатеь на буфер UART
|
||||
int32_t RS_Message_Size; ///< size of whole message, not only data
|
||||
|
||||
/* HANDLERS and SETTINGS */
|
||||
UART_HandleTypeDef *huart; ///< Хендл UART
|
||||
TIM_HandleTypeDef *htim; ///< Хендл TIM
|
||||
RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef
|
||||
uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера
|
||||
void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер
|
||||
|
||||
/* FLAGS */
|
||||
RS_FlagsTypeDef f; ///< Флаги для контроля приема/передачи
|
||||
|
||||
/* RS STATUS */
|
||||
uint32_t lastPacketTick; ///< Время последнего принятого пакета
|
||||
RS_StatusTypeDef RS_STATUS; ///< Статус RS
|
||||
|
||||
TrackerTypeDef(RS_USER_VARS_NUMB) rs_err;
|
||||
}RS_HandleTypeDef;
|
||||
extern RS_HandleTypeDef hmodbus1;
|
||||
|
||||
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
|
||||
/*--------------------Defined by users purposes--------------------*/
|
||||
/* Пользовательская функция для ответа на запрос по UART */
|
||||
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||
|
||||
/* Пользовательская функция для обработки принятого ответа по UART */
|
||||
__weak RS_StatusTypeDef RS_Response_Callback(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||
|
||||
/* Пользовательская функция для сбора сообщения в буфер UART */
|
||||
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
|
||||
|
||||
/* Пользовательская функция для парса сообщения из буфера UART */
|
||||
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
|
||||
|
||||
|
||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||
/*-----------------Should be called from main code-----------------*/
|
||||
/* Начать прием по прерываниям */
|
||||
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/UART */
|
||||
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);
|
||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||
/* Обработчик для начала приема */
|
||||
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||
/* Обработчик для начала передачи */
|
||||
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||
/* UART TX Callback: коллбек после окончания передачи */
|
||||
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS);
|
||||
/* Обработчик прерывания UART */
|
||||
void RS_UART_Handler(RS_HandleTypeDef *hRS);
|
||||
/* Обработчик прерывания TIM */
|
||||
void RS_TIM_Handler(RS_HandleTypeDef *hRS);
|
||||
/* Запуск таймаута приема. */
|
||||
RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS);
|
||||
/* Остановка таймаута приема. */
|
||||
RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS);
|
||||
/* Обновление (сброс) таймаута приема. */
|
||||
RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS);
|
||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
|
||||
/** RS_TOOLS
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif // __RS_LIB_H_
|
||||
258
new rev/core/STM32_Modbus/README.md
Normal file
258
new rev/core/STM32_Modbus/README.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# Инструкция по подключению релиза библиотеки `STM Modbus`
|
||||
|
||||
Данная библиотека подключается напрямую из Git, как субмодуль. Позволяя при желании обновлять её напрямую через git.
|
||||
|
||||
## Структура библиотеки
|
||||
|
||||
*Note: Файлы начинающиеся с `__` и которых **нет** в этом дереве являются **внутренними/непротестированными/недокументированными***
|
||||
```
|
||||
Modbus/ Иерархия модулей:
|
||||
│ inc/ modbus
|
||||
│ ├── modbus.h # Главный заголовочный файл modbus_slave
|
||||
│ ├── modbus_core.h # Базовые определения и структуры modbus_master
|
||||
│ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils
|
||||
│ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs
|
||||
│ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs
|
||||
│ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid
|
||||
│ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag
|
||||
├── src/ └── rs_message
|
||||
│ ├── modbus.c # Основная логика Modbus │
|
||||
│ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро)
|
||||
│ ├── modbus_master.c # Основная логика Master Modbus ├── modbus_config
|
||||
│ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data
|
||||
│ ├── modbus_holdregs.c # Реализация регистров хранения └── __crc_algs
|
||||
│ ├── modbus_inputregs.c # Реализация входных регистров
|
||||
│ ├── modbus_devid.c # Реализация идентификации устройства
|
||||
│ ├── modbus_data.c # Функции доступа к данным
|
||||
│ └── rs_message.c # Реализация драйвера RS
|
||||
├── __modbus_config.h # Конфигурация Modbus (надо заменить)
|
||||
├── __modbus_data.h # Структуры данных (надо заменить)
|
||||
└── __modbus_data.c # Функции доступа (надо заменить)
|
||||
```
|
||||
|
||||
## Инструкция по подключению
|
||||
|
||||
### 1. **Склонируйте субмодуль** в ваш проект:
|
||||
|
||||
```bash
|
||||
git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
### 2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов:
|
||||
|
||||
```
|
||||
ProjectRoot/
|
||||
├── Configs/
|
||||
│ ├── modbus_config.h # скопировать из __modbus_config.h
|
||||
│ ├── modbus_data.h # скопировать из __modbus_data.h
|
||||
│ └── modbus_data.c # скопировать из __modbus_data.c
|
||||
└── Modbus/ # Субмодуль
|
||||
```
|
||||
|
||||
### 3. **Настройте конфигурацию** под ваш проект:
|
||||
#### 3.1. Настройка периферии
|
||||
|
||||
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
|
||||
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
|
||||
- **Включите прерывания** для UART и TIM
|
||||
|
||||
#### 3.2. Подключение обработчиков прерываний
|
||||
|
||||
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
|
||||
|
||||
```c
|
||||
#include "modbus.h"
|
||||
|
||||
void USARTx_IRQHandler(void)
|
||||
{
|
||||
RS_UART_Handler(&hmodbus1);
|
||||
return;
|
||||
HAL_UART_IRQHandler(&huart);
|
||||
}
|
||||
|
||||
void TIMx_IRQHandler(void)
|
||||
{
|
||||
RS_TIM_Handler(&hmodbus1);
|
||||
return;
|
||||
HAL_TIM_IRQHandler(&htim);
|
||||
}
|
||||
```
|
||||
#### 3.3. В `modbus_config.h` укажите параметры устройства
|
||||
|
||||
#### 3.4. Инициализация в коде
|
||||
|
||||
Чтобы настроить Slave-режим `main()` после инициализации HAL:
|
||||
|
||||
```c
|
||||
#include "modbus.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Инициализация HAL
|
||||
HAL_Init();
|
||||
SystemClock_Config();
|
||||
MX_GPIO_Init();
|
||||
MX_USART1_UART_Init();
|
||||
MX_TIM3_Init();
|
||||
|
||||
// Инициализация Modbus
|
||||
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
|
||||
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
||||
|
||||
// Запуск приема Modbus
|
||||
MODBUS_SlaveStart(&hmodbus1, NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Основной цикл
|
||||
}
|
||||
}
|
||||
```
|
||||
Чтобы настроить Master-режим `main()` после инициализации HAL:
|
||||
|
||||
```c
|
||||
#include "modbus.h"
|
||||
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
|
||||
RS_MsgTypeDef read_hold_cmd = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
|
||||
// коллбек, вызовется при получении ответа от слейва
|
||||
read_hold[10];
|
||||
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
// MB_RespGet_... Чтобы достать нужные данные из ответа
|
||||
if(hmodbus->RS_STATUS == RS_OK)
|
||||
{
|
||||
for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
|
||||
{
|
||||
uint16_t value;
|
||||
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
|
||||
{
|
||||
read_hold[i] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
// Инициализация HAL
|
||||
HAL_Init();
|
||||
SystemClock_Config();
|
||||
MX_GPIO_Init();
|
||||
MX_USART1_UART_Init();
|
||||
MX_TIM3_Init();
|
||||
|
||||
// Инициализация Modbus
|
||||
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
|
||||
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
|
||||
|
||||
// Запрос по Modbus
|
||||
MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func);
|
||||
|
||||
}
|
||||
```
|
||||
#### 3.5. Настройка карты данных
|
||||
|
||||
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
||||
|
||||
**Input Registers (только чтение)**
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
uint16_t Temperature; // Адрес 0
|
||||
uint16_t Humidity; // Адрес 1
|
||||
uint16_t Pressure; // Адрес 2
|
||||
uint16_t Voltage; // Адрес 3
|
||||
} MB_DataInRegsTypeDef;
|
||||
|
||||
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров
|
||||
#define R_INPUT_QNT 4 // Количество Input регистров
|
||||
```
|
||||
**Holding Registers (чтение/запись)**
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
uint16_t SetpointTemp; // Адрес 0
|
||||
uint16_t SetpointHumidity; // Адрес 1
|
||||
uint16_t ControlMode; // Адрес 2
|
||||
} MB_DataHoldRegsTypeDef;
|
||||
|
||||
#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров
|
||||
#define R_HOLDING_QNT 3 // Количество Holding регистров
|
||||
```
|
||||
**Coils (1-битные)**
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
unsigned Relay1 : 1; // Адрес 0
|
||||
unsigned Relay2 : 1; // Адрес 1
|
||||
unsigned Pump : 1; // Адрес 2
|
||||
unsigned Heater : 1; // Адрес 3
|
||||
unsigned reserved : 12; // Резерв (выравнивание до 16 бит)
|
||||
} MB_DataCoilsTypeDef;
|
||||
|
||||
#define C_COILS_ADDR 0 // Начальный адрес Coils
|
||||
#define C_COILS_QNT 4 // Количество Coils
|
||||
```
|
||||
#### 3.6. Доступ к данным в коде
|
||||
|
||||
В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
|
||||
```c
|
||||
// Чтение входных регистров
|
||||
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
|
||||
|
||||
// Чтение coil
|
||||
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
|
||||
// Pump включен
|
||||
}
|
||||
```
|
||||
В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()`
|
||||
```c
|
||||
// Чтение регистров: Получить запрошенные регистры
|
||||
uint16_t value;
|
||||
if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, ®_value))
|
||||
{
|
||||
printf("Register 105 value: %d\n", reg_value);
|
||||
}
|
||||
// Чтение коилов: Получить запрошенные коилы
|
||||
int state;
|
||||
if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state))
|
||||
{
|
||||
printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF");
|
||||
}
|
||||
// Чтение диагностики: Получить запрошенныую диагностику
|
||||
uint16_t counter_value;
|
||||
if(MB_RespGet_DiagnosticResponse(&MODBUS_MSG, &counter_value))
|
||||
{
|
||||
printf("Counter value: %d\n", counter_value);
|
||||
}
|
||||
// Чтение идентификаторов: Получить запрошенные идентификаторы
|
||||
uint8_t length;
|
||||
char vendor_name[64];
|
||||
if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length))
|
||||
{
|
||||
printf("Vendor Name: %s (length: %d)\n", vendor_name, length);
|
||||
}
|
||||
|
||||
uint8_t obj_id, obj_length;
|
||||
char obj_data[64];
|
||||
if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, 0x00, &obj_id, obj_data, &obj_length))
|
||||
{
|
||||
printf("First object - ID: 0x%02X, Data: %s\n", obj_id, obj_data);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 5. **Обновление библиотеки**:
|
||||
После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся:
|
||||
|
||||
```bash
|
||||
git submodule update --remote
|
||||
```
|
||||
116
new rev/core/STM32_Modbus/Src/__crc_algs.c
Normal file
116
new rev/core/STM32_Modbus/Src/__crc_algs.c
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "__crc_algs.h"
|
||||
|
||||
|
||||
uint32_t CRC_calc;
|
||||
uint32_t CRC_ref;
|
||||
|
||||
//uint16_t CRC_calc;
|
||||
//uint16_t CRC_ref;
|
||||
|
||||
|
||||
// left this global for debug
|
||||
uint8_t uchCRCHi = 0xFF;
|
||||
uint8_t uchCRCLo = 0xFF;
|
||||
unsigned uIndex;
|
||||
|
||||
|
||||
uint32_t crc32(uint8_t *data, uint32_t data_size)
|
||||
{
|
||||
static const unsigned int crc32_table[] =
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
while (data_size--)
|
||||
{
|
||||
crc = (crc >> 8) ^ crc32_table[(crc ^ *data) & 255];
|
||||
data++;
|
||||
}
|
||||
return crc^0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
uint16_t crc16(uint8_t *data, uint32_t data_size)
|
||||
{
|
||||
/*Table of CRC values for high order byte*/
|
||||
static unsigned char auchCRCHi[]=
|
||||
{
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,
|
||||
0x00,0xC1,0x81,0x40,0x01,0xC0,0x80,0x41,0x01,0xC0,0x80,0x41,0x00,0xC1,0x81,0x40,
|
||||
};
|
||||
/*Table of CRC values for low order byte*/
|
||||
static char auchCRCLo[] =
|
||||
{
|
||||
0x00,0xC0,0xC1,0x01,0xC3,0x03,0x02,0xC2,0xC6,0x06,0x07,0xC7,0x05,0xC5,0xC4,0x04,
|
||||
0xCC,0x0C,0x0D,0xCD,0x0F,0xCF,0xCE,0x0E,0x0A,0xCA,0xCB,0x0B,0xC9,0x09,0x08,0xC8,
|
||||
0xD8,0x18,0x19,0xD9,0x1B,0xDB,0xDA,0x1A,0x1E,0xDE,0xDF,0x1F,0xDD,0x1D,0x1C,0xDC,
|
||||
0x14,0xD4,0xD5,0x15,0xD7,0x17,0x16,0xD6,0xD2,0x12,0x13,0xD3,0x11,0xD1,0xD0,0x10,
|
||||
0xF0,0x30,0x31,0xF1,0x33,0xF3,0xF2,0x32,0x36,0xF6,0xF7,0x37,0xF5,0x35,0x34,0xF4,
|
||||
0x3C,0xFC,0xFD,0x3D,0xFF,0x3F,0x3E,0xFE,0xFA,0x3A,0x3B,0xFB,0x39,0xF9,0xF8,0x38,
|
||||
0x28,0xE8,0xE9,0x29,0xEB,0x2B,0x2A,0xEA,0xEE,0x2E,0x2F,0xEF,0x2D,0xED,0xEC,0x2C,
|
||||
0xE4,0x24,0x25,0xE5,0x27,0xE7,0xE6,0x26,0x22,0xE2,0xE3,0x23,0xE1,0x21,0x20,0xE0,
|
||||
0xA0,0x60,0x61,0xA1,0x63,0xA3,0xA2,0x62,0x66,0xA6,0xA7,0x67,0xA5,0x65,0x64,0xA4,
|
||||
0x6C,0xAC,0xAD,0x6D,0xAF,0x6F,0x6E,0xAE,0xAA,0x6A,0x6B,0xAB,0x69,0xA9,0xA8,0x68,
|
||||
0x78,0xB8,0xB9,0x79,0xBB,0x7B,0x7A,0xBA,0xBE,0x7E,0x7F,0xBF,0x7D,0xBD,0xBC,0x7C,
|
||||
0xB4,0x74,0x75,0xB5,0x77,0xB7,0xB6,0x76,0x72,0xB2,0xB3,0x73,0xB1,0x71,0x70,0xB0,
|
||||
0x50,0x90,0x91,0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,
|
||||
0x9C,0x5C,0x5D,0x9D,0x5F,0x9F,0x9E,0x5E,0x5A,0x9A,0x9B,0x5B,0x99,0x59,0x58,0x98,
|
||||
0x88,0x48,0x49,0x89,0x4B,0x8B,0x8A,0x4A,0x4E,0x8E,0x8F,0x4F,0x8D,0x4D,0x4C,0x8C,
|
||||
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,0x40,
|
||||
};
|
||||
uchCRCHi = 0xFF;
|
||||
uchCRCLo = 0xFF;
|
||||
/* CRC Generation Function */
|
||||
while( data_size--) /* pass through message buffer */
|
||||
{
|
||||
uIndex = uchCRCHi ^ *data++; /* calculate the CRC */
|
||||
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
|
||||
uchCRCLo = auchCRCLo[uIndex];
|
||||
}
|
||||
return uchCRCHi | uchCRCLo<<8;
|
||||
}
|
||||
7
new rev/core/STM32_Modbus/Src/__modbus_compat.c
Normal file
7
new rev/core/STM32_Modbus/Src/__modbus_compat.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file __modbus_compat.c
|
||||
* @brief Модуль для совместимости библиотеки MODBUS.
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
#include "modbus.h"
|
||||
215
new rev/core/STM32_Modbus/Src/modbus.c
Normal file
215
new rev/core/STM32_Modbus/Src/modbus.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus.c
|
||||
* @brief Модуль для реализации MODBUS.
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Файл содержит реализацию функций работы с Modbus.
|
||||
|
||||
@section mbapi Функции и макросы
|
||||
|
||||
### Инициализация:
|
||||
- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM)
|
||||
- MODBUS_Config() — Конфигурацмя Modbus (ID, Timeout).
|
||||
- MODBUS_SlaveStart() — Запуск Modbus как Slave.
|
||||
- MODBUS_MasterRequest() — Отправить запрос в MODBUS как Master.
|
||||
|
||||
### Функции для работы с RS (UART):
|
||||
- RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
|
||||
- RS_Response() — Отправка ответа.
|
||||
******************************************************************************/
|
||||
#include "modbus.h"
|
||||
|
||||
/* MODBUS HANDLES */
|
||||
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);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------FOR USER------------------------------
|
||||
/**
|
||||
* @brief Инициализация периферии модбас.
|
||||
* @param hmodbus Указатель на хендлер RS
|
||||
* @param huart Указатель на хендлер UART
|
||||
* @param htim Указатель на хендлер TIM
|
||||
* @details Подключает хендлы периферии к hmodbus
|
||||
* Конфигурация выставляется по умолчанию из modbus_config.h
|
||||
*/
|
||||
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
|
||||
{
|
||||
if((hmodbus == NULL) || (huart == NULL))
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
MB_DeviceInentificationInit();
|
||||
//-----------SETUP MODBUS-------------
|
||||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||||
hmodbus->ID = MODBUS_DEVICE_ID;
|
||||
hmodbus->sRS_Timeout = MODBUS_TIMEOUT;
|
||||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||
|
||||
// INIT
|
||||
hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
|
||||
|
||||
RS_EnableReceive();
|
||||
|
||||
if(hmodbus->RS_STATUS == RS_OK)
|
||||
return HAL_OK;
|
||||
else
|
||||
return HAL_ERROR;
|
||||
}
|
||||
/**
|
||||
* @brief Программная конфигурация модбас.
|
||||
* @param hmodbus указатель на хендлер RS
|
||||
* @param Timeout Время тишины между двумя байтами после которых перезапускается прием
|
||||
* @param master Режим мастер (пока не сделан)
|
||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||
*/
|
||||
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
|
||||
{
|
||||
if(hmodbus == NULL)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if(!master)
|
||||
{
|
||||
if((ID < 1) || (ID > 247))
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
hmodbus->ID = ID;
|
||||
}
|
||||
else
|
||||
hmodbus->ID = 0;
|
||||
|
||||
hmodbus->sRS_Timeout = Timeout;
|
||||
if(master)
|
||||
hmodbus->sRS_Mode = RS_MASTER_REQUEST;
|
||||
else
|
||||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Запуск слейв модбас.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
(NULL чтобы использовать дефолтную)
|
||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||
*/
|
||||
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
if(hmodbus == NULL)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
MB_DiagnosticsInit();
|
||||
|
||||
if(modbus_msg)
|
||||
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, modbus_msg);
|
||||
else
|
||||
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, &MODBUS_MSG);
|
||||
|
||||
if(hmodbus->RS_STATUS == RS_OK)
|
||||
return HAL_OK;
|
||||
else
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Реквест мастера модбас.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||
*/
|
||||
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*))
|
||||
{
|
||||
if(hmodbus == NULL)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if(modbus_msg == NULL)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
if(hmodbus->f.RS_Busy)
|
||||
return HAL_BUSY;
|
||||
|
||||
if(pClbk) // если задан используем пользовательский коллбек
|
||||
hmodbus->pCallback = (void (*)(void*, void*))(pClbk);
|
||||
else // иначе дефолтный
|
||||
hmodbus->pCallback = (void (*)(void*, void*))(&MB_DefaultCallback);
|
||||
|
||||
hmodbus->RS_STATUS = RS_Transmit_IT(hmodbus, modbus_msg);
|
||||
|
||||
if(hmodbus->RS_STATUS == RS_OK)
|
||||
return HAL_OK;
|
||||
else
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------INTERNAL------------------------------
|
||||
|
||||
/**
|
||||
* @brief Дефолтный коллбек для мастера.
|
||||
* @param hmodbus Указатель на хендлер RS
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @details В этот коллбек попадут все запросы, с NULL-коллбеком
|
||||
*/
|
||||
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
__NOP();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Реализация функций из rs_message.c для протокола */
|
||||
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START)
|
||||
{
|
||||
return RS_ERR;
|
||||
}
|
||||
return MB_Slave_Response(hmodbus, modbus_msg);
|
||||
}
|
||||
|
||||
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
return MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MB_Master_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||
}
|
||||
}
|
||||
|
||||
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
return MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MB_Master_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||
}
|
||||
}
|
||||
248
new rev/core/STM32_Modbus/Src/modbus_coils.c
Normal file
248
new rev/core/STM32_Modbus/Src/modbus_coils.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_coils.c
|
||||
* @brief Реализация работы с коилами Modbus
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль для доступа к coils внутри программы:
|
||||
- Функции для доступа к coils по глобальным адресам
|
||||
- Макросы для доступа к coils по локальным адресам
|
||||
|
||||
Модуль обработки команд для coils (битовых данных):
|
||||
- Чтение coils (0x01) - упаковка битов в байты для передачи
|
||||
- Запись одиночного coil (0x05) - установка/сброс бита
|
||||
- Запись множественных coils (0x0F) - распаковка битов из байтов
|
||||
|
||||
@section cvalid Валидация данных:
|
||||
- Проверка соответствия количества байт и регистров
|
||||
- Валидация адресов через MB_DefineRegistersAddress()
|
||||
- Обработка исключений при некорректных запросах
|
||||
******************************************************************************/
|
||||
#include "modbus_coils.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_COILS
|
||||
|
||||
/**
|
||||
* @brief Выставить/сбросить коил по глобальному адресу.
|
||||
* @param Addr Адрес коила.
|
||||
* @param WriteVal Что записать в коил: 0 или 1.
|
||||
* @return ExceptionCode Код исключения если коила по адресу не существует, и ET_NO_ERRORS если все ок.
|
||||
*
|
||||
* @details Позволяет обратиться к любому коилу по его глобальному адрессу.
|
||||
Вне зависимости от того как коилы размещены в памяти.
|
||||
*/
|
||||
MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
MB_ExceptionTypeDef Exception = ET_NO_ERRORS;
|
||||
uint16_t *coils;
|
||||
uint16_t start_shift = 0; // shift in coils register
|
||||
|
||||
//------------WRITE COIL-------------
|
||||
Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1);
|
||||
if(Exception == ET_NO_ERRORS)
|
||||
{
|
||||
switch(WriteVal)
|
||||
{
|
||||
case SET_COIL:
|
||||
*coils |= (1<<start_shift);
|
||||
break;
|
||||
|
||||
case RESET_COIL:
|
||||
*coils &= ~(1<<start_shift);
|
||||
break;
|
||||
|
||||
case TOOGLE_COIL:
|
||||
*coils ^= (1<<start_shift);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return Exception;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Считать коил по глобальному адресу.
|
||||
* @param Addr Адрес коила.
|
||||
* @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
|
||||
* @return uint16_t Возвращает весь регистр с маской на запрошенном коиле.
|
||||
*
|
||||
* @details Позволяет обратиться к любому коилу по его глобальному адрессу.
|
||||
Вне зависимости от того как коилы размещены в памяти.
|
||||
*/
|
||||
uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
MB_ExceptionTypeDef Exception_tmp;
|
||||
if(Exception == NULL) // if exception is not given to func fill it
|
||||
Exception = &Exception_tmp;
|
||||
|
||||
uint16_t *coils;
|
||||
uint16_t start_shift = 0; // shift in coils register
|
||||
|
||||
//------------READ COIL--------------
|
||||
*Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0);
|
||||
if(*Exception == ET_NO_ERRORS)
|
||||
{
|
||||
return ((*coils)&(1<<start_shift));
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Read Coils (01 - 0x01).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Read Coils.
|
||||
*/
|
||||
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
uint16_t *coils;
|
||||
uint16_t start_shift = 0; // shift in coils register
|
||||
|
||||
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0);
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
//-----------READING COIL------------
|
||||
// setup output message data size
|
||||
modbus_msg->ByteCnt = Divide_Up(modbus_msg->Qnt, 8);
|
||||
// create mask for coils
|
||||
uint16_t mask_for_coils = 0; // mask for coils that've been chosen
|
||||
uint16_t setted_coils = 0; // value of setted coils
|
||||
uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen
|
||||
uint16_t coil_cnt = 0; // counter for processed coils
|
||||
|
||||
// cycle until all registers with requered coils would be processed
|
||||
int shift = start_shift; // set shift to first coil in first register
|
||||
int ind = 0; // index for coils registers and data
|
||||
for(; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
|
||||
{
|
||||
//----SET MASK FOR COILS REGISTER----
|
||||
mask_for_coils = 0;
|
||||
for(; shift < 0x10; shift++)
|
||||
{
|
||||
mask_for_coils |= 1<<(shift); // choose certain coil
|
||||
if(++coil_cnt >= modbus_msg->Qnt)
|
||||
break;
|
||||
}
|
||||
shift = 0; // set shift to zero for the next step
|
||||
|
||||
//-----------READ COILS--------------
|
||||
modbus_msg->MbData[ind] = (*(coils+ind)&mask_for_coils) >> start_shift;
|
||||
if(ind > 0)
|
||||
modbus_msg->MbData[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift;
|
||||
|
||||
}
|
||||
// т.к. MbData 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты
|
||||
for(; ind >= 0; --ind)
|
||||
modbus_msg->MbData[ind] = ByteSwap16(modbus_msg->MbData[ind]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Write Single Coils (05 - 0x05).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Single Coils.
|
||||
*/
|
||||
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
|
||||
{
|
||||
modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
|
||||
return 0;
|
||||
}
|
||||
// define position of coil
|
||||
uint16_t *coils;
|
||||
uint16_t start_shift = 0; // shift in coils register
|
||||
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1);
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
|
||||
//----------WRITTING COIL------------
|
||||
if(modbus_msg->Qnt == 0xFF00)
|
||||
*(coils) |= 1<<start_shift; // write flags corresponding to received data
|
||||
else
|
||||
*(coils) &= ~(1<<start_shift); // write flags corresponding to received data
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Write Multiple Coils (15 - 0x0F).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Multiple Coils.
|
||||
*/
|
||||
uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8))
|
||||
{ // if quantity too large OR if quantity and bytes count arent match
|
||||
modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
|
||||
return 0;
|
||||
}
|
||||
// define position of coil
|
||||
uint16_t *coils; // pointer to coils
|
||||
uint16_t start_shift = 0; // shift in coils register
|
||||
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1);
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
//----------WRITTING COILS-----------
|
||||
// create mask for coils
|
||||
uint16_t mask_for_coils = 0; // mask for coils that've been chosen
|
||||
uint32_t setted_coils = 0; // value of setted coils
|
||||
uint16_t temp_reg = 0; // temp register for saving coils that hasnt been chosen
|
||||
uint16_t coil_cnt = 0; // counter for processed coils
|
||||
|
||||
// cycle until all registers with requered coils would be processed
|
||||
int shift = start_shift; // set shift to first coil in first register
|
||||
for(int ind = 0; ind <= Divide_Up(start_shift + modbus_msg->Qnt, 16); ind++)
|
||||
{
|
||||
//----SET MASK FOR COILS REGISTER----
|
||||
mask_for_coils = 0;
|
||||
for(; shift < 0x10; shift++)
|
||||
{
|
||||
mask_for_coils |= 1<<(shift); // choose certain coil
|
||||
if(++coil_cnt >= modbus_msg->Qnt)
|
||||
break;
|
||||
}
|
||||
shift = 0; // set shift to zero for the next step
|
||||
|
||||
|
||||
|
||||
//-----------WRITE COILS-------------
|
||||
// get current coils
|
||||
temp_reg = *(coils+ind);
|
||||
// set coils
|
||||
setted_coils = ByteSwap16(modbus_msg->MbData[ind]) << start_shift;
|
||||
if(ind > 0)
|
||||
{
|
||||
setted_coils |= ((ByteSwap16(modbus_msg->MbData[ind-1]) << start_shift) >> 16);
|
||||
}
|
||||
// write coils
|
||||
|
||||
*(coils+ind) = setted_coils & mask_for_coils;
|
||||
// restore untouched coils
|
||||
*(coils+ind) |= temp_reg&(~mask_for_coils);
|
||||
|
||||
|
||||
if(coil_cnt >= modbus_msg->Qnt) // if all coils written - break cycle
|
||||
break; // *kind of unnecessary
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_COILS
|
||||
10
new rev/core/STM32_Modbus/Src/modbus_core.c
Normal file
10
new rev/core/STM32_Modbus/Src/modbus_core.c
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_core.c
|
||||
* @brief Базовая реализация ядра Modbus
|
||||
*******************************************************************************
|
||||
* @details
|
||||
В текущей реализации этот файл служит заглушкой для будущего расширения
|
||||
функциональности ядра Modbus протокола.
|
||||
******************************************************************************/
|
||||
#include "modbus_core.h"
|
||||
573
new rev/core/STM32_Modbus/Src/modbus_devid.c
Normal file
573
new rev/core/STM32_Modbus/Src/modbus_devid.c
Normal file
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_devid.c
|
||||
* @brief Реализация идентификаторов устройства Modbus
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
|
||||
- Формирование иерархии объектов идентификации
|
||||
- Поддержка потоковой передачи при большом количестве объектов
|
||||
- Автоматический расчет MoreFollows флагов
|
||||
|
||||
@section stream Потоковая передача:
|
||||
При большом количестве объектов идентификация разбивается на несколько
|
||||
сообщений с установкой флага MoreFollows и указанием NextObjId для
|
||||
продолжения чтения в следующем запросе.
|
||||
******************************************************************************/
|
||||
#include "modbus_devid.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
|
||||
MB_DeviceIdentificationsTypeDef MB_DEVID; ///< Глобальная структура идентификаторов устройства
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Записать Один Объект Идентификатора в массив данных
|
||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||
* @return obj Объект для записи.
|
||||
*/
|
||||
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj)
|
||||
{
|
||||
mbdata[(*ind)++] = obj->length;
|
||||
for (int i = 0; i < obj->length; i++)
|
||||
{
|
||||
mbdata[(*ind)++] = obj->name[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Записать Массив Объектов Идентификатора в массив данных
|
||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||
* @return obj Объект для записи.
|
||||
*/
|
||||
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
|
||||
{
|
||||
MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID;
|
||||
unsigned objidtmp = modbus_msg->DevId.NextObjId;
|
||||
modbus_msg->Except_Code = ET_NO_ERRORS;
|
||||
|
||||
/* Define number of object in one message */
|
||||
unsigned lastobjid = 0;
|
||||
for(int i = 0; i < DATA_SIZE*2;)
|
||||
{
|
||||
/* Если объект за пределами допутимого - выходим из цикла */
|
||||
if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS)
|
||||
break;
|
||||
|
||||
i += 2;
|
||||
i += obj[objidtmp].length;
|
||||
/* Если все еще помещается в массив переходим на следующий объект */
|
||||
if(i < DATA_SIZE*2)
|
||||
{
|
||||
objidtmp++;
|
||||
}
|
||||
|
||||
/* Если объекты для записи закончились - выходим из цикла*/
|
||||
if(objidtmp > maxidofobj)
|
||||
break;
|
||||
}
|
||||
lastobjid = objidtmp-1;
|
||||
|
||||
|
||||
/* Fill message with objects data */
|
||||
char *mbdata = (char *)&modbus_msg->MbData;
|
||||
unsigned ind = 0;
|
||||
unsigned objid = modbus_msg->DevId.NextObjId;
|
||||
for(; objid <= lastobjid; objid++)
|
||||
{
|
||||
mbdata[ind++] = objid;
|
||||
MB_WriteSingleObjectToMessage(mbdata, &ind, &obj[objid]);
|
||||
}
|
||||
objid--;
|
||||
|
||||
if(modbus_msg->ByteCnt != 0)
|
||||
{
|
||||
modbus_msg->ByteCnt = ind;
|
||||
modbus_msg->DevId.NextObjId = lastobjid+1;
|
||||
if(objid == maxidofobj)
|
||||
{
|
||||
modbus_msg->DevId.MoreFollows = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
modbus_msg->DevId.MoreFollows = 0xFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Read Device Identifications (43/14 - 0x2B/0E).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Single Register.
|
||||
*/
|
||||
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
modbus_msg->DevId.Conformity = MODBUS_DEVICE_CONFORMITY;
|
||||
|
||||
switch(modbus_msg->DevId.ReadDevId)
|
||||
{
|
||||
case RID_BASIC_IDENTIFICATIONS:
|
||||
if (modbus_msg->DevId.NextObjId == 0)
|
||||
{
|
||||
modbus_msg->DevId.NextObjId = 0;
|
||||
}
|
||||
|
||||
MB_WriteObjectsToMessage(modbus_msg, 2);
|
||||
modbus_msg->DevId.NumbOfObj = 3;
|
||||
break;
|
||||
|
||||
case RID_REGULAR_IDENTIFICATIONS:
|
||||
if (modbus_msg->DevId.NextObjId == 0)
|
||||
{
|
||||
modbus_msg->DevId.NextObjId = 3;
|
||||
}
|
||||
|
||||
MB_WriteObjectsToMessage(modbus_msg, 6);
|
||||
modbus_msg->DevId.NumbOfObj = 4;
|
||||
break;
|
||||
|
||||
case RID_EXTENDED_IDENTIFICATIONS:
|
||||
if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128)
|
||||
{
|
||||
modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (modbus_msg->DevId.NextObjId == 0)
|
||||
{
|
||||
modbus_msg->DevId.NextObjId = 0x80;
|
||||
}
|
||||
|
||||
MB_WriteObjectsToMessage(modbus_msg, 0x80+MODBUS_NUMB_OF_USEROBJECTS);
|
||||
modbus_msg->DevId.NumbOfObj = MODBUS_NUMB_OF_USEROBJECTS;
|
||||
break;
|
||||
|
||||
case RID_SPEDIFIC_IDENTIFICATIONS:
|
||||
MB_WriteObjectsToMessage(modbus_msg, modbus_msg->DevId.NextObjId);
|
||||
modbus_msg->DevId.NumbOfObj = 1;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация идентификаторов.
|
||||
*/
|
||||
void MB_DeviceInentificationInit(void)
|
||||
{
|
||||
MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME);
|
||||
MB_ObjectInit(&MB_DEVID.ProductCode, MODBUS_PRODUCT_CODE);
|
||||
MB_ObjectInit(&MB_DEVID.Revision, MODBUS_REVISION);
|
||||
MB_ObjectInit(&MB_DEVID.VendorUrl, MODBUS_VENDOR_URL);
|
||||
MB_ObjectInit(&MB_DEVID.ProductName, MODBUS_PRODUCT_NAME);
|
||||
MB_ObjectInit(&MB_DEVID.ModelName, MODBUS_MODEL_NAME);
|
||||
|
||||
#if defined(MODBUS_USEROBJECT_0_NAME) && MODBUS_NUMB_OF_USEROBJECTS>0
|
||||
MB_ObjectInit(&MB_DEVID.User[0], MODBUS_USEROBJECT_0_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_1_NAME) && MODBUS_NUMB_OF_USEROBJECTS>1
|
||||
MB_ObjectInit(&MB_DEVID.User[1], MODBUS_USEROBJECT_1_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_2_NAME) && MODBUS_NUMB_OF_USEROBJECTS>2
|
||||
MB_ObjectInit(&MB_DEVID.User[2], MODBUS_USEROBJECT_2_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_3_NAME) && MODBUS_NUMB_OF_USEROBJECTS>3
|
||||
MB_ObjectInit(&MB_DEVID.User[3], MODBUS_USEROBJECT_3_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_4_NAME) && MODBUS_NUMB_OF_USEROBJECTS>4
|
||||
MB_ObjectInit(&MB_DEVID.User[4], MODBUS_USEROBJECT_4_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_5_NAME) && MODBUS_NUMB_OF_USEROBJECTS>5
|
||||
MB_ObjectInit(&MB_DEVID.User[5], MODBUS_USEROBJECT_5_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_6_NAME) && MODBUS_NUMB_OF_USEROBJECTS>6
|
||||
MB_ObjectInit(&MB_DEVID.User[6], MODBUS_USEROBJECT_6_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_7_NAME) && MODBUS_NUMB_OF_USEROBJECTS>7
|
||||
MB_ObjectInit(&MB_DEVID.User[7], MODBUS_USEROBJECT_7_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_8_NAME) && MODBUS_NUMB_OF_USEROBJECTS>8
|
||||
MB_ObjectInit(&MB_DEVID.User[8], MODBUS_USEROBJECT_8_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_9_NAME) && MODBUS_NUMB_OF_USEROBJECTS>9
|
||||
MB_ObjectInit(&MB_DEVID.User[9], MODBUS_USEROBJECT_9_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_10_NAME) && MODBUS_NUMB_OF_USEROBJECTS>10
|
||||
MB_ObjectInit(&MB_DEVID.User[10], MODBUS_USEROBJECT_10_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_11_NAME) && MODBUS_NUMB_OF_USEROBJECTS>11
|
||||
MB_ObjectInit(&MB_DEVID.User[11], MODBUS_USEROBJECT_11_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_12_NAME) && MODBUS_NUMB_OF_USEROBJECTS>12
|
||||
MB_ObjectInit(&MB_DEVID.User[12], MODBUS_USEROBJECT_12_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_13_NAME) && MODBUS_NUMB_OF_USEROBJECTS>13
|
||||
MB_ObjectInit(&MB_DEVID.User[13], MODBUS_USEROBJECT_13_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_14_NAME) && MODBUS_NUMB_OF_USEROBJECTS>14
|
||||
MB_ObjectInit(&MB_DEVID.User[14], MODBUS_USEROBJECT_14_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_15_NAME) && MODBUS_NUMB_OF_USEROBJECTS>15
|
||||
MB_ObjectInit(&MB_DEVID.User[15], MODBUS_USEROBJECT_15_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_16_NAME) && MODBUS_NUMB_OF_USEROBJECTS>16
|
||||
MB_ObjectInit(&MB_DEVID.User[16], MODBUS_USEROBJECT_16_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_17_NAME) && MODBUS_NUMB_OF_USEROBJECTS>17
|
||||
MB_ObjectInit(&MB_DEVID.User[17], MODBUS_USEROBJECT_17_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_18_NAME) && MODBUS_NUMB_OF_USEROBJECTS>18
|
||||
MB_ObjectInit(&MB_DEVID.User[18], MODBUS_USEROBJECT_18_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_19_NAME) && MODBUS_NUMB_OF_USEROBJECTS>19
|
||||
MB_ObjectInit(&MB_DEVID.User[19], MODBUS_USEROBJECT_19_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_20_NAME) && MODBUS_NUMB_OF_USEROBJECTS>20
|
||||
MB_ObjectInit(&MB_DEVID.User[20], MODBUS_USEROBJECT_20_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_21_NAME) && MODBUS_NUMB_OF_USEROBJECTS>21
|
||||
MB_ObjectInit(&MB_DEVID.User[21], MODBUS_USEROBJECT_21_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_22_NAME) && MODBUS_NUMB_OF_USEROBJECTS>22
|
||||
MB_ObjectInit(&MB_DEVID.User[22], MODBUS_USEROBJECT_22_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_23_NAME) && MODBUS_NUMB_OF_USEROBJECTS>23
|
||||
MB_ObjectInit(&MB_DEVID.User[23], MODBUS_USEROBJECT_23_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_24_NAME) && MODBUS_NUMB_OF_USEROBJECTS>24
|
||||
MB_ObjectInit(&MB_DEVID.User[24], MODBUS_USEROBJECT_24_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_25_NAME) && MODBUS_NUMB_OF_USEROBJECTS>25
|
||||
MB_ObjectInit(&MB_DEVID.User[25], MODBUS_USEROBJECT_25_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_26_NAME) && MODBUS_NUMB_OF_USEROBJECTS>26
|
||||
MB_ObjectInit(&MB_DEVID.User[26], MODBUS_USEROBJECT_26_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_27_NAME) && MODBUS_NUMB_OF_USEROBJECTS>27
|
||||
MB_ObjectInit(&MB_DEVID.User[27], MODBUS_USEROBJECT_27_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_28_NAME) && MODBUS_NUMB_OF_USEROBJECTS>28
|
||||
MB_ObjectInit(&MB_DEVID.User[28], MODBUS_USEROBJECT_28_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_29_NAME) && MODBUS_NUMB_OF_USEROBJECTS>29
|
||||
MB_ObjectInit(&MB_DEVID.User[29], MODBUS_USEROBJECT_29_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_30_NAME) && MODBUS_NUMB_OF_USEROBJECTS>30
|
||||
MB_ObjectInit(&MB_DEVID.User[30], MODBUS_USEROBJECT_30_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_31_NAME) && MODBUS_NUMB_OF_USEROBJECTS>31
|
||||
MB_ObjectInit(&MB_DEVID.User[31], MODBUS_USEROBJECT_31_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_32_NAME) && MODBUS_NUMB_OF_USEROBJECTS>32
|
||||
MB_ObjectInit(&MB_DEVID.User[32], MODBUS_USEROBJECT_32_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_33_NAME) && MODBUS_NUMB_OF_USEROBJECTS>33
|
||||
MB_ObjectInit(&MB_DEVID.User[33], MODBUS_USEROBJECT_33_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_34_NAME) && MODBUS_NUMB_OF_USEROBJECTS>34
|
||||
MB_ObjectInit(&MB_DEVID.User[34], MODBUS_USEROBJECT_34_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_35_NAME) && MODBUS_NUMB_OF_USEROBJECTS>35
|
||||
MB_ObjectInit(&MB_DEVID.User[35], MODBUS_USEROBJECT_35_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_36_NAME) && MODBUS_NUMB_OF_USEROBJECTS>36
|
||||
MB_ObjectInit(&MB_DEVID.User[36], MODBUS_USEROBJECT_36_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_37_NAME) && MODBUS_NUMB_OF_USEROBJECTS>37
|
||||
MB_ObjectInit(&MB_DEVID.User[37], MODBUS_USEROBJECT_37_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_38_NAME) && MODBUS_NUMB_OF_USEROBJECTS>38
|
||||
MB_ObjectInit(&MB_DEVID.User[38], MODBUS_USEROBJECT_38_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_39_NAME) && MODBUS_NUMB_OF_USEROBJECTS>39
|
||||
MB_ObjectInit(&MB_DEVID.User[39], MODBUS_USEROBJECT_39_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_40_NAME) && MODBUS_NUMB_OF_USEROBJECTS>40
|
||||
MB_ObjectInit(&MB_DEVID.User[40], MODBUS_USEROBJECT_40_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_41_NAME) && MODBUS_NUMB_OF_USEROBJECTS>41
|
||||
MB_ObjectInit(&MB_DEVID.User[41], MODBUS_USEROBJECT_41_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_42_NAME) && MODBUS_NUMB_OF_USEROBJECTS>42
|
||||
MB_ObjectInit(&MB_DEVID.User[42], MODBUS_USEROBJECT_42_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_43_NAME) && MODBUS_NUMB_OF_USEROBJECTS>43
|
||||
MB_ObjectInit(&MB_DEVID.User[43], MODBUS_USEROBJECT_43_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_44_NAME) && MODBUS_NUMB_OF_USEROBJECTS>44
|
||||
MB_ObjectInit(&MB_DEVID.User[44], MODBUS_USEROBJECT_44_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_45_NAME) && MODBUS_NUMB_OF_USEROBJECTS>45
|
||||
MB_ObjectInit(&MB_DEVID.User[45], MODBUS_USEROBJECT_45_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_46_NAME) && MODBUS_NUMB_OF_USEROBJECTS>46
|
||||
MB_ObjectInit(&MB_DEVID.User[46], MODBUS_USEROBJECT_46_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_47_NAME) && MODBUS_NUMB_OF_USEROBJECTS>47
|
||||
MB_ObjectInit(&MB_DEVID.User[47], MODBUS_USEROBJECT_47_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_48_NAME) && MODBUS_NUMB_OF_USEROBJECTS>48
|
||||
MB_ObjectInit(&MB_DEVID.User[48], MODBUS_USEROBJECT_48_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_49_NAME) && MODBUS_NUMB_OF_USEROBJECTS>49
|
||||
MB_ObjectInit(&MB_DEVID.User[49], MODBUS_USEROBJECT_49_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_50_NAME) && MODBUS_NUMB_OF_USEROBJECTS>50
|
||||
MB_ObjectInit(&MB_DEVID.User[50], MODBUS_USEROBJECT_50_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_51_NAME) && MODBUS_NUMB_OF_USEROBJECTS>51
|
||||
MB_ObjectInit(&MB_DEVID.User[51], MODBUS_USEROBJECT_51_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_52_NAME) && MODBUS_NUMB_OF_USEROBJECTS>52
|
||||
MB_ObjectInit(&MB_DEVID.User[52], MODBUS_USEROBJECT_52_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_53_NAME) && MODBUS_NUMB_OF_USEROBJECTS>53
|
||||
MB_ObjectInit(&MB_DEVID.User[53], MODBUS_USEROBJECT_53_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_54_NAME) && MODBUS_NUMB_OF_USEROBJECTS>54
|
||||
MB_ObjectInit(&MB_DEVID.User[54], MODBUS_USEROBJECT_54_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_55_NAME) && MODBUS_NUMB_OF_USEROBJECTS>55
|
||||
MB_ObjectInit(&MB_DEVID.User[55], MODBUS_USEROBJECT_55_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_56_NAME) && MODBUS_NUMB_OF_USEROBJECTS>56
|
||||
MB_ObjectInit(&MB_DEVID.User[56], MODBUS_USEROBJECT_56_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_57_NAME) && MODBUS_NUMB_OF_USEROBJECTS>57
|
||||
MB_ObjectInit(&MB_DEVID.User[57], MODBUS_USEROBJECT_57_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_58_NAME) && MODBUS_NUMB_OF_USEROBJECTS>58
|
||||
MB_ObjectInit(&MB_DEVID.User[58], MODBUS_USEROBJECT_58_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_59_NAME) && MODBUS_NUMB_OF_USEROBJECTS>59
|
||||
MB_ObjectInit(&MB_DEVID.User[59], MODBUS_USEROBJECT_59_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_60_NAME) && MODBUS_NUMB_OF_USEROBJECTS>60
|
||||
MB_ObjectInit(&MB_DEVID.User[60], MODBUS_USEROBJECT_60_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_61_NAME) && MODBUS_NUMB_OF_USEROBJECTS>61
|
||||
MB_ObjectInit(&MB_DEVID.User[61], MODBUS_USEROBJECT_61_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_62_NAME) && MODBUS_NUMB_OF_USEROBJECTS>62
|
||||
MB_ObjectInit(&MB_DEVID.User[62], MODBUS_USEROBJECT_62_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_63_NAME) && MODBUS_NUMB_OF_USEROBJECTS>63
|
||||
MB_ObjectInit(&MB_DEVID.User[63], MODBUS_USEROBJECT_63_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_64_NAME) && MODBUS_NUMB_OF_USEROBJECTS>64
|
||||
MB_ObjectInit(&MB_DEVID.User[64], MODBUS_USEROBJECT_64_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_65_NAME) && MODBUS_NUMB_OF_USEROBJECTS>65
|
||||
MB_ObjectInit(&MB_DEVID.User[65], MODBUS_USEROBJECT_65_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_66_NAME) && MODBUS_NUMB_OF_USEROBJECTS>66
|
||||
MB_ObjectInit(&MB_DEVID.User[66], MODBUS_USEROBJECT_66_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_67_NAME) && MODBUS_NUMB_OF_USEROBJECTS>67
|
||||
MB_ObjectInit(&MB_DEVID.User[67], MODBUS_USEROBJECT_67_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_68_NAME) && MODBUS_NUMB_OF_USEROBJECTS>68
|
||||
MB_ObjectInit(&MB_DEVID.User[68], MODBUS_USEROBJECT_68_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_69_NAME) && MODBUS_NUMB_OF_USEROBJECTS>69
|
||||
MB_ObjectInit(&MB_DEVID.User[69], MODBUS_USEROBJECT_69_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_70_NAME) && MODBUS_NUMB_OF_USEROBJECTS>70
|
||||
MB_ObjectInit(&MB_DEVID.User[70], MODBUS_USEROBJECT_70_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_71_NAME) && MODBUS_NUMB_OF_USEROBJECTS>71
|
||||
MB_ObjectInit(&MB_DEVID.User[71], MODBUS_USEROBJECT_71_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_72_NAME) && MODBUS_NUMB_OF_USEROBJECTS>72
|
||||
MB_ObjectInit(&MB_DEVID.User[72], MODBUS_USEROBJECT_72_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_73_NAME) && MODBUS_NUMB_OF_USEROBJECTS>73
|
||||
MB_ObjectInit(&MB_DEVID.User[73], MODBUS_USEROBJECT_73_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_74_NAME) && MODBUS_NUMB_OF_USEROBJECTS>74
|
||||
MB_ObjectInit(&MB_DEVID.User[74], MODBUS_USEROBJECT_74_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_75_NAME) && MODBUS_NUMB_OF_USEROBJECTS>75
|
||||
MB_ObjectInit(&MB_DEVID.User[75], MODBUS_USEROBJECT_75_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_76_NAME) && MODBUS_NUMB_OF_USEROBJECTS>76
|
||||
MB_ObjectInit(&MB_DEVID.User[76], MODBUS_USEROBJECT_76_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_77_NAME) && MODBUS_NUMB_OF_USEROBJECTS>77
|
||||
MB_ObjectInit(&MB_DEVID.User[77], MODBUS_USEROBJECT_77_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_78_NAME) && MODBUS_NUMB_OF_USEROBJECTS>78
|
||||
MB_ObjectInit(&MB_DEVID.User[78], MODBUS_USEROBJECT_78_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_79_NAME) && MODBUS_NUMB_OF_USEROBJECTS>79
|
||||
MB_ObjectInit(&MB_DEVID.User[79], MODBUS_USEROBJECT_79_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_80_NAME) && MODBUS_NUMB_OF_USEROBJECTS>80
|
||||
MB_ObjectInit(&MB_DEVID.User[80], MODBUS_USEROBJECT_80_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_81_NAME) && MODBUS_NUMB_OF_USEROBJECTS>81
|
||||
MB_ObjectInit(&MB_DEVID.User[81], MODBUS_USEROBJECT_81_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_82_NAME) && MODBUS_NUMB_OF_USEROBJECTS>82
|
||||
MB_ObjectInit(&MB_DEVID.User[82], MODBUS_USEROBJECT_82_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_83_NAME) && MODBUS_NUMB_OF_USEROBJECTS>83
|
||||
MB_ObjectInit(&MB_DEVID.User[83], MODBUS_USEROBJECT_83_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_84_NAME) && MODBUS_NUMB_OF_USEROBJECTS>84
|
||||
MB_ObjectInit(&MB_DEVID.User[84], MODBUS_USEROBJECT_84_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_85_NAME) && MODBUS_NUMB_OF_USEROBJECTS>85
|
||||
MB_ObjectInit(&MB_DEVID.User[85], MODBUS_USEROBJECT_85_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_86_NAME) && MODBUS_NUMB_OF_USEROBJECTS>86
|
||||
MB_ObjectInit(&MB_DEVID.User[86], MODBUS_USEROBJECT_86_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_87_NAME) && MODBUS_NUMB_OF_USEROBJECTS>87
|
||||
MB_ObjectInit(&MB_DEVID.User[87], MODBUS_USEROBJECT_87_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_88_NAME) && MODBUS_NUMB_OF_USEROBJECTS>88
|
||||
MB_ObjectInit(&MB_DEVID.User[88], MODBUS_USEROBJECT_88_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_89_NAME) && MODBUS_NUMB_OF_USEROBJECTS>89
|
||||
MB_ObjectInit(&MB_DEVID.User[89], MODBUS_USEROBJECT_89_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_90_NAME) && MODBUS_NUMB_OF_USEROBJECTS>90
|
||||
MB_ObjectInit(&MB_DEVID.User[90], MODBUS_USEROBJECT_90_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_91_NAME) && MODBUS_NUMB_OF_USEROBJECTS>91
|
||||
MB_ObjectInit(&MB_DEVID.User[91], MODBUS_USEROBJECT_91_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_92_NAME) && MODBUS_NUMB_OF_USEROBJECTS>92
|
||||
MB_ObjectInit(&MB_DEVID.User[92], MODBUS_USEROBJECT_92_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_93_NAME) && MODBUS_NUMB_OF_USEROBJECTS>93
|
||||
MB_ObjectInit(&MB_DEVID.User[93], MODBUS_USEROBJECT_93_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_94_NAME) && MODBUS_NUMB_OF_USEROBJECTS>94
|
||||
MB_ObjectInit(&MB_DEVID.User[94], MODBUS_USEROBJECT_94_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_95_NAME) && MODBUS_NUMB_OF_USEROBJECTS>95
|
||||
MB_ObjectInit(&MB_DEVID.User[95], MODBUS_USEROBJECT_95_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_96_NAME) && MODBUS_NUMB_OF_USEROBJECTS>96
|
||||
MB_ObjectInit(&MB_DEVID.User[96], MODBUS_USEROBJECT_96_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_97_NAME) && MODBUS_NUMB_OF_USEROBJECTS>97
|
||||
MB_ObjectInit(&MB_DEVID.User[97], MODBUS_USEROBJECT_97_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_98_NAME) && MODBUS_NUMB_OF_USEROBJECTS>98
|
||||
MB_ObjectInit(&MB_DEVID.User[98], MODBUS_USEROBJECT_98_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_99_NAME) && MODBUS_NUMB_OF_USEROBJECTS>99
|
||||
MB_ObjectInit(&MB_DEVID.User[99], MODBUS_USEROBJECT_99_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_100_NAME) && MODBUS_NUMB_OF_USEROBJECTS>100
|
||||
MB_ObjectInit(&MB_DEVID.User[100], MODBUS_USEROBJECT_100_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_101_NAME) && MODBUS_NUMB_OF_USEROBJECTS>101
|
||||
MB_ObjectInit(&MB_DEVID.User[101], MODBUS_USEROBJECT_101_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_102_NAME) && MODBUS_NUMB_OF_USEROBJECTS>102
|
||||
MB_ObjectInit(&MB_DEVID.User[102], MODBUS_USEROBJECT_102_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_103_NAME) && MODBUS_NUMB_OF_USEROBJECTS>103
|
||||
MB_ObjectInit(&MB_DEVID.User[103], MODBUS_USEROBJECT_103_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_104_NAME) && MODBUS_NUMB_OF_USEROBJECTS>104
|
||||
MB_ObjectInit(&MB_DEVID.User[104], MODBUS_USEROBJECT_104_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_105_NAME) && MODBUS_NUMB_OF_USEROBJECTS>105
|
||||
MB_ObjectInit(&MB_DEVID.User[105], MODBUS_USEROBJECT_105_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_106_NAME) && MODBUS_NUMB_OF_USEROBJECTS>106
|
||||
MB_ObjectInit(&MB_DEVID.User[106], MODBUS_USEROBJECT_106_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_107_NAME) && MODBUS_NUMB_OF_USEROBJECTS>107
|
||||
MB_ObjectInit(&MB_DEVID.User[107], MODBUS_USEROBJECT_107_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_108_NAME) && MODBUS_NUMB_OF_USEROBJECTS>108
|
||||
MB_ObjectInit(&MB_DEVID.User[108], MODBUS_USEROBJECT_108_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_109_NAME) && MODBUS_NUMB_OF_USEROBJECTS>109
|
||||
MB_ObjectInit(&MB_DEVID.User[109], MODBUS_USEROBJECT_109_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_110_NAME) && MODBUS_NUMB_OF_USEROBJECTS>110
|
||||
MB_ObjectInit(&MB_DEVID.User[110], MODBUS_USEROBJECT_110_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_111_NAME) && MODBUS_NUMB_OF_USEROBJECTS>111
|
||||
MB_ObjectInit(&MB_DEVID.User[111], MODBUS_USEROBJECT_111_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_112_NAME) && MODBUS_NUMB_OF_USEROBJECTS>112
|
||||
MB_ObjectInit(&MB_DEVID.User[112], MODBUS_USEROBJECT_112_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_113_NAME) && MODBUS_NUMB_OF_USEROBJECTS>113
|
||||
MB_ObjectInit(&MB_DEVID.User[113], MODBUS_USEROBJECT_113_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_114_NAME) && MODBUS_NUMB_OF_USEROBJECTS>114
|
||||
MB_ObjectInit(&MB_DEVID.User[114], MODBUS_USEROBJECT_114_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_115_NAME) && MODBUS_NUMB_OF_USEROBJECTS>115
|
||||
MB_ObjectInit(&MB_DEVID.User[115], MODBUS_USEROBJECT_115_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_116_NAME) && MODBUS_NUMB_OF_USEROBJECTS>116
|
||||
MB_ObjectInit(&MB_DEVID.User[116], MODBUS_USEROBJECT_116_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_117_NAME) && MODBUS_NUMB_OF_USEROBJECTS>117
|
||||
MB_ObjectInit(&MB_DEVID.User[117], MODBUS_USEROBJECT_117_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_118_NAME) && MODBUS_NUMB_OF_USEROBJECTS>118
|
||||
MB_ObjectInit(&MB_DEVID.User[118], MODBUS_USEROBJECT_118_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_119_NAME) && MODBUS_NUMB_OF_USEROBJECTS>119
|
||||
MB_ObjectInit(&MB_DEVID.User[119], MODBUS_USEROBJECT_119_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_120_NAME) && MODBUS_NUMB_OF_USEROBJECTS>120
|
||||
MB_ObjectInit(&MB_DEVID.User[120], MODBUS_USEROBJECT_120_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_121_NAME) && MODBUS_NUMB_OF_USEROBJECTS>121
|
||||
MB_ObjectInit(&MB_DEVID.User[121], MODBUS_USEROBJECT_121_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_122_NAME) && MODBUS_NUMB_OF_USEROBJECTS>122
|
||||
MB_ObjectInit(&MB_DEVID.User[122], MODBUS_USEROBJECT_122_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_123_NAME) && MODBUS_NUMB_OF_USEROBJECTS>123
|
||||
MB_ObjectInit(&MB_DEVID.User[123], MODBUS_USEROBJECT_123_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_124_NAME) && MODBUS_NUMB_OF_USEROBJECTS>124
|
||||
MB_ObjectInit(&MB_DEVID.User[124], MODBUS_USEROBJECT_124_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_125_NAME) && MODBUS_NUMB_OF_USEROBJECTS>125
|
||||
MB_ObjectInit(&MB_DEVID.User[125], MODBUS_USEROBJECT_125_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_126_NAME) && MODBUS_NUMB_OF_USEROBJECTS>126
|
||||
MB_ObjectInit(&MB_DEVID.User[126], MODBUS_USEROBJECT_126_NAME);
|
||||
#endif
|
||||
#if defined(MODBUS_USEROBJECT_127_NAME) && MODBUS_NUMB_OF_USEROBJECTS>127
|
||||
MB_ObjectInit(&MB_DEVID.User[127], MODBUS_USEROBJECT_127_NAME);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
296
new rev/core/STM32_Modbus/Src/modbus_diag.c
Normal file
296
new rev/core/STM32_Modbus/Src/modbus_diag.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_diag.c
|
||||
* @brief Реализация диагностики устройства Modbus
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль обработки запросов диагностической информации (0x08):
|
||||
- Полная поддержка всех подфункций диагностики согласно спецификации Modbus
|
||||
- Выставление любого бита в Diagnostics Register
|
||||
- Сбор статистики работы устройства
|
||||
- Управление режимами работы (Normal/Listen Only)
|
||||
******************************************************************************/
|
||||
#include "modbus_diag.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
|
||||
MB_DiagnosticsInfoTypeDef MB_DIAG = {0}; ///< Глобальная структура диагностики
|
||||
|
||||
/**
|
||||
* @brief Инициализация диагностических счетчиков
|
||||
*/
|
||||
void MB_DiagnosticsInit(void)
|
||||
{
|
||||
MB_DIAG.DiagnosticRegister = 0;
|
||||
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
|
||||
|
||||
// Инициализация счетчиков
|
||||
MB_DIAG.Counters.BusMessage = 0;
|
||||
MB_DIAG.Counters.BusCommunicationErr = 0;
|
||||
MB_DIAG.Counters.BusExceptionErr = 0;
|
||||
MB_DIAG.Counters.SlaveMessage = 0;
|
||||
MB_DIAG.Counters.SlaveNoResponse = 0;
|
||||
MB_DIAG.Counters.SlaveNAK = 0;
|
||||
MB_DIAG.Counters.SlaveBusy = 0;
|
||||
MB_DIAG.Counters.BusCharacterOverrun = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Выставить бит в регистре диагностике
|
||||
* @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить)
|
||||
* @param bit_state Состояние бита для выставления (Выставить/Сбросить)
|
||||
* @return >0 - номер выставленного бита, 0 - ошибка
|
||||
*/
|
||||
int MB_Diagnostics_WriteBit(int bit_num, int bit_state)
|
||||
{
|
||||
if(bit_num == 0 || bit_num > 15)
|
||||
return 0;
|
||||
|
||||
if(bit_state)
|
||||
MB_DIAG.DiagnosticRegister |= (1 << bit_num);
|
||||
else
|
||||
MB_DIAG.DiagnosticRegister &= ~(1 << bit_num);
|
||||
|
||||
return bit_num;
|
||||
}
|
||||
/**
|
||||
* @brief Прочитать состояние бита диагностического регистра
|
||||
* @param bit_num Номер бита (0-15)
|
||||
* @return 1 - бит установлен, 0 - бит сброшен или ошибка
|
||||
*/
|
||||
int MB_Diagnostics_GetBit(int bit_num)
|
||||
{
|
||||
if(bit_num < 0 || bit_num > 15)
|
||||
return 0;
|
||||
|
||||
return (MB_DIAG.DiagnosticRegister >> bit_num) & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Diagnostics (Serial Line only) (0x08)
|
||||
* @param modbus_msg Указатель на структуру сообщения modbus
|
||||
* @return fMessageHandled Статус обработки команды
|
||||
*/
|
||||
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
uint16_t sub_function = modbus_msg->MbData[0];
|
||||
uint16_t request_data = modbus_msg->MbData[1];
|
||||
|
||||
// Если устройство в режиме Listen Only, отвечаем только на sub-function 0x01
|
||||
if (MB_DIAG.DeviceMode == MODBUS_LISTEN_ONLY_MODE && sub_function != 0x0001)
|
||||
{
|
||||
return 0; // Не отвечаем в режиме Listen Only
|
||||
}
|
||||
|
||||
switch(sub_function)
|
||||
{
|
||||
case 0x0000: // Return Query Data
|
||||
// Эхо-ответ с теми же данными
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = request_data;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0001: // Restart Communications
|
||||
// Перезапуск коммуникаций - выходим из Listen Only режима
|
||||
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
|
||||
|
||||
// Если request_data = 0xFF00, очищаем лог событий
|
||||
if (request_data == 0xFF00)
|
||||
{
|
||||
MB_DiagnosticsInit(); // Полный сброс
|
||||
}
|
||||
else
|
||||
{
|
||||
// Очищаем только счетчики, но не регистр диагностики
|
||||
MB_DIAG.Counters.BusMessage = 0;
|
||||
MB_DIAG.Counters.BusCommunicationErr = 0;
|
||||
MB_DIAG.Counters.BusExceptionErr = 0;
|
||||
MB_DIAG.Counters.SlaveMessage = 0;
|
||||
MB_DIAG.Counters.SlaveNoResponse = 0;
|
||||
MB_DIAG.Counters.SlaveNAK = 0;
|
||||
MB_DIAG.Counters.SlaveBusy = 0;
|
||||
MB_DIAG.Counters.BusCharacterOverrun = 0;
|
||||
}
|
||||
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = request_data;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0002: // Return Diagnostic Register
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.DiagnosticRegister;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0003: // Change ASCII Input Delimiter
|
||||
// В RTU режиме не поддерживается
|
||||
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
|
||||
modbus_msg->Except_Code = ET_ILLEGAL_FUNCTION;
|
||||
return 0;
|
||||
|
||||
case 0x0004: // Force Listen Only Mode
|
||||
MB_DIAG.DeviceMode = MODBUS_LISTEN_ONLY_MODE;
|
||||
// В режиме Listen Only не отправляем ответ
|
||||
return 0;
|
||||
|
||||
case 0x000A: // Clear Counters and Diagnostic Register
|
||||
MB_DiagnosticsInit(); // Полный сброс
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = 0;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000B: // Return Bus Message Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.BusMessage;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000C: // Return Bus Communication Error Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.BusCommunicationErr;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000D: // Return Bus Exception Error Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.BusExceptionErr;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000E: // Return Server Message Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveMessage;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x000F: // Return Slave No Response Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveNoResponse;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0010: // Return Slave NAK Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveNAK;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0011: // Return Slave Busy Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveBusy;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0012: // Return Bus Character Overrun Count
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = MB_DIAG.Counters.BusCharacterOverrun;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
case 0x0014: // Clear Overrun Counter and Flag
|
||||
MB_DIAG.Counters.BusCharacterOverrun = 0;
|
||||
// Сбрасываем флаг переполнения в DiagnosticRegister
|
||||
MB_DIAG.DiagnosticRegister &= ~(1<<0);
|
||||
modbus_msg->MbData[0] = sub_function;
|
||||
modbus_msg->MbData[1] = 0;
|
||||
modbus_msg->ByteCnt = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
|
||||
modbus_msg->Except_Code = ET_ILLEGAL_FUNCTION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик сообщений на шине
|
||||
*/
|
||||
void MB_Diagnostics_BusMessageCnt(void)
|
||||
{
|
||||
MB_DIAG.Counters.BusMessage++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик ошибок связи
|
||||
*/
|
||||
void MB_Diagnostics_CommunicationErrorCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.BusCommunicationErr < 0xFFFF)
|
||||
MB_DIAG.Counters.BusCommunicationErr++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик исключений
|
||||
*/
|
||||
void MB_Diagnostics_ExceptionErrorCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.BusExceptionErr < 0xFFFF)
|
||||
MB_DIAG.Counters.BusExceptionErr++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик переполнения символов
|
||||
*/
|
||||
void MB_Diagnostics_CharacterOverrunCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.BusCharacterOverrun < 0xFFFF)
|
||||
{
|
||||
MB_DIAG.Counters.BusCharacterOverrun++;
|
||||
// Устанавливаем флаг переполнения в DiagnosticRegister
|
||||
MB_DIAG.DiagnosticRegister |= (1 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик отсутствия ответов
|
||||
*/
|
||||
void MB_Diagnostics_SlaveMessageCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveMessage < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveMessage++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик отсутствия ответов
|
||||
*/
|
||||
void MB_Diagnostics_SlaveNoResponseCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveNoResponse < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveNoResponse++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик NAK ответов
|
||||
*/
|
||||
void MB_Diagnostics_SlaveNAKCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveNAK < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveNAK++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Увеличивает счетчик занятости устройства
|
||||
*/
|
||||
void MB_Diagnostics_SlaveBusyCnt(void)
|
||||
{
|
||||
if (MB_DIAG.Counters.SlaveBusy < 0xFFFF)
|
||||
MB_DIAG.Counters.SlaveBusy++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получение текущего режима устройства
|
||||
* @return Текущий режим работы устройства
|
||||
*/
|
||||
MB_DeviceModeTypeDef MB_GetDeviceMode(void)
|
||||
{
|
||||
return MB_DIAG.DeviceMode;
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
161
new rev/core/STM32_Modbus/Src/modbus_holdregs.c
Normal file
161
new rev/core/STM32_Modbus/Src/modbus_holdregs.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_holdregs.c
|
||||
* @brief Реализация работы с регистрами хранения Modbus
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль для доступа к регистрам внутри программы:
|
||||
- Функции для доступа к регистрам хранения по глобальным адресам
|
||||
|
||||
Модуль обработки команд для holding registers (регистров хранения):
|
||||
- Чтение множественных регистров (0x03) - копирование данных в буфер ответа
|
||||
- Запись одиночного регистра (0x06) - прямая запись значения
|
||||
- Запись множественных регистров (0x10) - пакетная запись из буфера
|
||||
|
||||
@section hvalid Валидация данных:
|
||||
- Проверка соответствия количества байт и регистров
|
||||
- Валидация адресов через MB_DefineRegistersAddress()
|
||||
- Обработка исключений при некорректных запросах
|
||||
******************************************************************************/
|
||||
#include "modbus_inputregs.h"
|
||||
|
||||
|
||||
#ifdef MODBUS_ENABLE_HOLDINGS
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Записать регистр хранения по глобальному адресу.
|
||||
* @param Addr Адрес регистра.
|
||||
* @param WriteVal Число для записи.
|
||||
* @return ExceptionCode Код исключения если регистра по адресу не существует, и ET_NO_ERRORS если все ок.
|
||||
*
|
||||
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
|
||||
Вне зависимости от того как регистры размещены в памяти.
|
||||
*/
|
||||
MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
MB_ExceptionTypeDef Exception = ET_NO_ERRORS;
|
||||
uint16_t *pHoldRegs;
|
||||
|
||||
//------------WRITE COIL-------------
|
||||
Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding);
|
||||
if(Exception == ET_NO_ERRORS)
|
||||
{
|
||||
*(pHoldRegs) = WriteVal;
|
||||
}
|
||||
return Exception;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Считать регистр хранения по глобальному адресу.
|
||||
* @param Addr Адрес регистра.
|
||||
* @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
|
||||
* @return uint16_t Возвращает значение регистра.
|
||||
*
|
||||
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
|
||||
Вне зависимости от того как регистры размещены в памяти.
|
||||
*/
|
||||
uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
MB_ExceptionTypeDef Exception_tmp = 0;
|
||||
|
||||
uint16_t *pHoldRegs;
|
||||
|
||||
//------------READ COIL--------------
|
||||
Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding);
|
||||
|
||||
if(Exception) // if exception is not given to func fill it
|
||||
*Exception = Exception_tmp;
|
||||
|
||||
if(Exception_tmp == ET_NO_ERRORS)
|
||||
{
|
||||
return *(pHoldRegs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Read Holding Registers (03 - 0x03).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Read Holding Registers.
|
||||
*/
|
||||
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); // определение адреса регистров
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
|
||||
//-----------READING REGS------------
|
||||
// setup output message data size
|
||||
modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
|
||||
// read data
|
||||
int i;
|
||||
for (i = 0; i<modbus_msg->Qnt; i++)
|
||||
{
|
||||
modbus_msg->MbData[i] = *(pHoldRegs++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Write Single Register (06 - 0x06).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Single Register.
|
||||
*/
|
||||
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); // определение адреса регистров
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
//-----------WRITTING REG------------
|
||||
*(pHoldRegs) = modbus_msg->Qnt;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Write Multiple Registers (16 - 0x10).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Write Multiple Registers.
|
||||
*/
|
||||
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
|
||||
{ // if quantity and bytes count arent match
|
||||
modbus_msg->Except_Code = 3;
|
||||
return 0;
|
||||
}
|
||||
// get origin address for data
|
||||
uint16_t *pHoldRegs;
|
||||
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
//-----------WRITTING REGS-----------
|
||||
for (int i = 0; i<modbus_msg->Qnt; i++)
|
||||
{
|
||||
*(pHoldRegs++) = modbus_msg->MbData[i];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_HOLDINGS
|
||||
112
new rev/core/STM32_Modbus/Src/modbus_inputregs.c
Normal file
112
new rev/core/STM32_Modbus/Src/modbus_inputregs.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_inputregs.c
|
||||
* @brief Реализация работы с входными регистрами Modbus
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль для доступа к регистрам внутри программы:
|
||||
- Функции для доступа к входным регистрам по глобальным адресам
|
||||
|
||||
Модуль обработки команды чтения input registers (0x04):
|
||||
|
||||
@section ivalid Валидация данных:
|
||||
- Проверка соответствия количества байт и регистров
|
||||
- Валидация адресов через MB_DefineRegistersAddress()
|
||||
- Обработка исключений при некорректных запросах
|
||||
******************************************************************************/
|
||||
#include "modbus_inputregs.h"
|
||||
|
||||
|
||||
#ifdef MODBUS_ENABLE_INPUTS
|
||||
|
||||
|
||||
/**
|
||||
* @brief Записать входной регистр по глобальному адресу.
|
||||
* @param Addr Адрес регистра.
|
||||
* @param WriteVal Число для записи.
|
||||
* @return ExceptionCode Код исключения если регистра по адресу не существует, и ET_NO_ERRORS если все ок.
|
||||
*
|
||||
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
|
||||
Вне зависимости от того как регистры размещены в памяти.
|
||||
*/
|
||||
MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
MB_ExceptionTypeDef Exception = ET_NO_ERRORS;
|
||||
uint16_t *pInRegs;
|
||||
|
||||
//------------WRITE COIL-------------
|
||||
Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input);
|
||||
if(Exception == ET_NO_ERRORS)
|
||||
{
|
||||
*(pInRegs) = WriteVal;
|
||||
}
|
||||
return Exception;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Считать входной регистр по глобальному адресу.
|
||||
* @param Addr Адрес регистра.
|
||||
* @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
|
||||
* @return uint16_t Возвращает значение регистра.
|
||||
*
|
||||
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
|
||||
Вне зависимости от того как регистры размещены в памяти.
|
||||
*/
|
||||
uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
||||
{
|
||||
//---------CHECK FOR ERRORS----------
|
||||
MB_ExceptionTypeDef Exception_tmp = 0;
|
||||
|
||||
uint16_t *pInRegs;
|
||||
|
||||
//------------READ COIL--------------
|
||||
Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input);
|
||||
|
||||
if(Exception) // if exception is not given to func fill it
|
||||
*Exception = Exception_tmp;
|
||||
|
||||
if(Exception_tmp == ET_NO_ERRORS)
|
||||
{
|
||||
return *(pInRegs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработать функцию Read Input Registers (04 - 0x04).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
* @return fMessageHandled Статус о результате обработки комманды.
|
||||
* @details Обработка команды Read Input Registers.
|
||||
*/
|
||||
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); // определение адреса регистров
|
||||
if(modbus_msg->Except_Code != ET_NO_ERRORS)
|
||||
return 0;
|
||||
|
||||
|
||||
//-----------READING REGS------------
|
||||
// setup output message data size
|
||||
modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
|
||||
// read data
|
||||
int i;
|
||||
for (i = 0; i<modbus_msg->Qnt; i++)
|
||||
{
|
||||
if(*((int16_t *)pInRegs) > 0)
|
||||
modbus_msg->MbData[i] = (*pInRegs++);
|
||||
else
|
||||
modbus_msg->MbData[i] = (*pInRegs++);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_INPUTS
|
||||
755
new rev/core/STM32_Modbus/Src/modbus_master.c
Normal file
755
new rev/core/STM32_Modbus/Src/modbus_master.c
Normal file
@@ -0,0 +1,755 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_master.c
|
||||
* @brief Модуль для реализации мастера MODBUS.
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Файл содержит реализацию функций для работы Modbus в режиме мастера.
|
||||
|
||||
@section mast Функции и макросы
|
||||
- MB_RespGet_RegisterAll() — Считать все регистра из ответа
|
||||
- MB_RespGet_RegisterValue() — Считать один регистр из ответа
|
||||
- MB_RespGet_CoilAll() — Считать все коилы из ответа
|
||||
- MB_RespGet_CoilState() — Считать один коил из ответа
|
||||
- MB_RespGet_NumberOfObjects() — Считать количество принятых объектов идентификатора
|
||||
- MB_RespGet_ObjectById() — Считать объект идентификатора по
|
||||
его ID
|
||||
- MB_RespGet_ObjectByIndex() — Считать объект идентификатора по
|
||||
порядковому номеру в сообщении
|
||||
- MB_RespGet_Diagnostic() — Считать запрошенный диагностический счетчик
|
||||
|
||||
- MB_Master_Collect_Message() — Сбор сообщения в режиме мастера
|
||||
- MB_Master_Parse_Message() — Парс сообщения в режиме мастера
|
||||
******************************************************************************/
|
||||
#include "modbus.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_MASTER
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------FOR USER------------------------------
|
||||
/**
|
||||
* @brief Получить значение ВСЕХ регистров в ответе
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param reg_addr Адрес регистра, значение которого нужно получить
|
||||
* @param reg_arr Указатель для массив для сохранения значений регистров
|
||||
* @return количество считанных регистров, 0 - ошибка
|
||||
*/
|
||||
int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr)
|
||||
{
|
||||
if(modbus_msg == NULL || reg_arr == NULL)
|
||||
return 0;
|
||||
int read_cnt = 0;
|
||||
int i = 0;
|
||||
for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++)
|
||||
{
|
||||
if(MB_RespGet_RegisterValue(modbus_msg, addr, ®_arr[i]))
|
||||
{
|
||||
read_cnt++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return read_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить значение регистра в ответе по его адресу
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param reg_addr Адрес регистра, значение которого нужно получить
|
||||
* @param reg_value Указатель для значения регистра
|
||||
* @return 1 - успех, 0 - ошибка или reg_addr вне диапазона запроса
|
||||
*/
|
||||
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value)
|
||||
{
|
||||
if(modbus_msg == NULL || reg_value == NULL)
|
||||
return 0;
|
||||
|
||||
// Проверяем что ответ связан с регистрами
|
||||
if((modbus_msg->FuncCode != FC_R_DISC_IN) &&
|
||||
(modbus_msg->FuncCode != FC_R_HOLD_REGS) &&
|
||||
(modbus_msg->FuncCode != FC_R_IN_REGS))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Проверяем что reg_addr в пределах запрошенного диапазона
|
||||
if(reg_addr < modbus_msg->Addr || reg_addr >= modbus_msg->Addr + modbus_msg->Qnt)
|
||||
return 0;
|
||||
|
||||
// Вычисляем индекс регистра в полученных данных
|
||||
uint16_t reg_index = reg_addr - modbus_msg->Addr;
|
||||
|
||||
// Проверяем что регистр существует в данных
|
||||
if(reg_index >= modbus_msg->ByteCnt / 2)
|
||||
return 0;
|
||||
|
||||
// Получаем значение регистра
|
||||
*reg_value = modbus_msg->MbData[reg_index];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить состояние ВСЕХ coil в ответе
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param coil_arr Указатель для массив доя сохранения состояний coil (1 - ON, 0 - OFF)
|
||||
* @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса
|
||||
*/
|
||||
int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr)
|
||||
{
|
||||
if(modbus_msg == NULL || coil_arr == NULL)
|
||||
return 0;
|
||||
|
||||
int read_cnt = 0;
|
||||
int i = 0;
|
||||
for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++)
|
||||
{
|
||||
if(MB_RespGet_CoilState(modbus_msg, addr, &coil_arr[i]))
|
||||
{
|
||||
read_cnt++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить состояние coil в ответе по его адресу
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param coil_addr Адрес coil, состояние которого нужно получить
|
||||
* @param coil_state Указатель для состояния coil (1 - ON, 0 - OFF)
|
||||
* @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса
|
||||
*/
|
||||
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state)
|
||||
{
|
||||
if(modbus_msg == NULL || coil_state == NULL)
|
||||
return 0;
|
||||
|
||||
// Проверяем что ответ связан с коилами
|
||||
if(modbus_msg->FuncCode != FC_R_COILS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Проверяем что coil_addr в пределах запрошенного диапазона
|
||||
if(coil_addr < modbus_msg->Addr || coil_addr >= modbus_msg->Addr + modbus_msg->Qnt)
|
||||
return 0;
|
||||
|
||||
// Вычисляем индекс coil в полученных данных
|
||||
uint16_t coil_index = coil_addr - modbus_msg->Addr;
|
||||
|
||||
// Вычисляем байт и бит
|
||||
uint8_t byte_index = coil_index / 8;
|
||||
uint8_t data_index = coil_index / 16;
|
||||
uint8_t bit_index = coil_index % 16;
|
||||
|
||||
// Проверяем что байт существует в данных
|
||||
if(byte_index >= modbus_msg->ByteCnt)
|
||||
return 0;
|
||||
|
||||
// Получаем байт и проверяем бит
|
||||
if(bit_index < 8)
|
||||
*coil_state = (modbus_msg->MbData[data_index] >> (bit_index+8)) & 0x01;
|
||||
else
|
||||
*coil_state = ((modbus_msg->MbData[data_index]&0xFF) >> (bit_index-8)) & 0x01;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить количество объектов в сообщении
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @return int Количество объектов
|
||||
*/
|
||||
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
if(modbus_msg == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Проверяем что ответ связан с диагностикой
|
||||
if(modbus_msg->FuncCode != FC_R_DEVICE_ID)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return modbus_msg->DevId.NumbOfObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Найти объект по ID в сообщении
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param obj_id ID искомого объекта
|
||||
* @param obj_data Буфер для данных объекта (может быть NULL)
|
||||
* @param obj_length Указатель для длины объекта
|
||||
* @return int Найден ли объект (1 - да, 0 - нет)
|
||||
*/
|
||||
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length)
|
||||
{
|
||||
if((modbus_msg == NULL) || (obj_data == NULL))
|
||||
return 0;
|
||||
|
||||
// Проверяем что ответ связан с диагностикой
|
||||
if(modbus_msg->FuncCode != FC_R_DEVICE_ID)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *data = (uint8_t*)modbus_msg->MbData;
|
||||
unsigned ind = 0;
|
||||
|
||||
for(int i = 0; i < modbus_msg->DevId.NumbOfObj; i++)
|
||||
{
|
||||
uint8_t current_id = data[ind++];
|
||||
uint8_t current_length = data[ind++];
|
||||
|
||||
if(current_id == obj_id)
|
||||
{
|
||||
if(obj_length)
|
||||
*obj_length = current_length;
|
||||
|
||||
for(int j = 0; j < current_length; j++)
|
||||
{
|
||||
obj_data[j] = data[ind++];
|
||||
}
|
||||
obj_data[current_length] = '\0'; // добавляем \0
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Пропускаем данные этого объекта
|
||||
ind += current_length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получить объект по индексу в сообщении
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param index Индекс объекта (0..N-1)
|
||||
* @param obj_id Указатель для ID объекта
|
||||
* @param obj_data Буфер для данных объекта
|
||||
* @param obj_length Указатель для длины объекта
|
||||
* @return int Успешность получения (1 - получен, 0 - не найден)
|
||||
*/
|
||||
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length)
|
||||
{
|
||||
if((modbus_msg == NULL) || (obj_data == NULL))
|
||||
return 0;
|
||||
|
||||
// Проверяем что ответ связан с диагностикой
|
||||
if(modbus_msg->FuncCode != FC_R_DEVICE_ID)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(index >= modbus_msg->DevId.NumbOfObj)
|
||||
return 0;
|
||||
|
||||
uint8_t *data = (uint8_t*)modbus_msg->MbData;
|
||||
unsigned ind = 0;
|
||||
|
||||
for(int i = 0; i <= index; i++)
|
||||
{
|
||||
uint8_t current_id = data[ind++];
|
||||
uint8_t current_length = data[ind++];
|
||||
|
||||
if(obj_id)
|
||||
*obj_id = current_id;
|
||||
if(obj_length)
|
||||
*obj_length = current_length;
|
||||
|
||||
if(i == index)
|
||||
{
|
||||
for(int j = 0; j < current_length; j++)
|
||||
{
|
||||
obj_data[j] = data[ind++];
|
||||
}
|
||||
obj_data[current_length] = '\0'; // добавляем \0
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Пропускаем данные этого объекта
|
||||
ind += current_length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить данные диагностики из сообщения (MbData[1])
|
||||
* @param modbus_msg Указатель на структуру сообщения
|
||||
* @param data Указатель куда положить данные
|
||||
* @return 1 - успех, 0 - ошибка
|
||||
*/
|
||||
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data)
|
||||
{
|
||||
if(modbus_msg == NULL || data == NULL)
|
||||
return 0;
|
||||
|
||||
// Проверяем что ответ связан с диагностикой
|
||||
if(modbus_msg->FuncCode != FC_R_DIAGNOSTICS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
*data = modbus_msg->MbData[1];
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-----------------------------INTERNAL------------------------------
|
||||
/**
|
||||
* @brief Определить размер модбас запроса (МАСТЕР версия).
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия.
|
||||
* @return RS_RES Статус о корректности рассчета кол-ва байт для принятия.
|
||||
* @details Определение сколько байтов надо принять по протоколу.
|
||||
*/
|
||||
static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
RS_StatusTypeDef MB_RES = 0;
|
||||
int mb_func_size = 0;
|
||||
|
||||
|
||||
// Master mode - calculating response size from slave
|
||||
if (modbus_msg->FuncCode & FC_ERR_VALUES_START)
|
||||
{
|
||||
// Error response: [Addr][Func|0x80][ExceptCode][CRC]
|
||||
mb_func_size = -1; // Only Exception Code
|
||||
}
|
||||
else if (modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
|
||||
{
|
||||
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||
mb_func_size = 1;
|
||||
}
|
||||
else if (modbus_msg->FuncCode == FC_R_DEVICE_ID)
|
||||
{
|
||||
// Device identifications: variable size, need to read first to determine
|
||||
mb_func_size = 0; // Will be determined after reading header
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (modbus_msg->FuncCode & ~FC_ERR_VALUES_START)
|
||||
{
|
||||
case 0x01: // Read Coils
|
||||
case 0x02: // Read Discrete Inputs
|
||||
case 0x03: // Read Holding Registers
|
||||
case 0x04: // Read Input Registers
|
||||
// Response: [ByteCount][Data...]
|
||||
mb_func_size = modbus_msg->ByteCnt + 2; // ByteCount + variable data
|
||||
break;
|
||||
|
||||
case 0x05: // Write Single Coil
|
||||
case 0x06: // Write Single Register
|
||||
// Echo response: [Addr][Value][CRC]
|
||||
mb_func_size = 4; // Address(2) + Value(2)
|
||||
break;
|
||||
|
||||
case 0x0F: // Write Multiple Coils
|
||||
case 0x10: // Write Multiple Registers
|
||||
// Echo response: [Addr][Qty][CRC]
|
||||
mb_func_size = 4; // Address(2) + Quantity(2)
|
||||
break;
|
||||
|
||||
default:
|
||||
mb_func_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
|
||||
return mb_func_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения буфера.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
|
||||
//------INFO ABOUT DATA/MESSAGE------
|
||||
//-----------[first bytes]-----------
|
||||
// set ID of slave device
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
||||
|
||||
// set function code
|
||||
modbus_uart_buff[ind++] = modbus_msg->FuncCode;
|
||||
|
||||
if(modbus_msg->FuncCode < FC_ERR_VALUES_START) // if no error occur
|
||||
{
|
||||
// fill modbus header
|
||||
if(0) {}
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // device identifications request
|
||||
{
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
|
||||
{
|
||||
// Diagnostics: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[0] >> 8; // Sub-function HI
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[0] & 0xFF; // Sub-function LO
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[1] >> 8; // Data HI
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[1] & 0xFF; // Data LO
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
else // classic modbus request
|
||||
{
|
||||
// set address
|
||||
modbus_uart_buff[ind++] = modbus_msg->Addr >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->Addr & 0xFF;
|
||||
|
||||
// set quantity
|
||||
modbus_uart_buff[ind++] = modbus_msg->Qnt >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->Qnt & 0xFF;
|
||||
|
||||
// for write multiple functions
|
||||
if((modbus_msg->FuncCode == 0x0F) || (modbus_msg->FuncCode == 0x10))
|
||||
{
|
||||
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
||||
|
||||
// write data bytes
|
||||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->MbData;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||
{
|
||||
modbus_uart_buff[ind++] = tmp_data_addr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ind < 0)
|
||||
return RS_COLLECT_MSG_ERR;
|
||||
|
||||
//---------------CRC----------------
|
||||
//---------[last 2 bytes]----------
|
||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||
modbus_msg->MbCRC = CRC_VALUE;
|
||||
modbus_uart_buff[ind++] = CRC_VALUE & 0xFF;
|
||||
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
||||
|
||||
hmodbus->RS_Message_Size = ind;
|
||||
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Парс сообщения в режиме мастер (фрейм слейва из uart -> msg).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения структуры.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
int expected_size = 0;
|
||||
|
||||
// get ID of slave device
|
||||
modbus_msg->MbAddr = modbus_uart_buff[ind++];
|
||||
|
||||
// get function code (check if error response)
|
||||
modbus_msg->FuncCode = modbus_uart_buff[ind++];
|
||||
|
||||
if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // error response
|
||||
{
|
||||
modbus_msg->Except_Code = modbus_uart_buff[ind++];
|
||||
}
|
||||
else if(modbus_msg->FuncCode < FC_ERR_VALUES_START) // normal response
|
||||
{
|
||||
if(0) {}
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // device identifications response
|
||||
{
|
||||
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.Conformity = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.MoreFollows = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.NumbOfObj = modbus_uart_buff[ind++];
|
||||
|
||||
modbus_msg->ByteCnt = 0;
|
||||
|
||||
// Парсинг объектов идентификации устройства
|
||||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->MbData;
|
||||
int data_index = 0;
|
||||
|
||||
for(int obj = 0; obj < modbus_msg->DevId.NumbOfObj; obj++)
|
||||
{
|
||||
// Читаем ID объекта
|
||||
uint8_t object_id = modbus_uart_buff[ind++];
|
||||
tmp_data_addr[data_index++] = object_id;
|
||||
|
||||
// Читаем длину объекта
|
||||
uint8_t object_length = modbus_uart_buff[ind++];
|
||||
tmp_data_addr[data_index++] = object_length;
|
||||
|
||||
// Читаем данные объекта
|
||||
for(int i = 0; i < object_length; i++)
|
||||
{
|
||||
tmp_data_addr[data_index++] = modbus_uart_buff[ind++];
|
||||
}
|
||||
|
||||
modbus_msg->ByteCnt += (2 + object_length); // ID + длина + данные
|
||||
}
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
|
||||
{
|
||||
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||
modbus_msg->MbData[0] = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->MbData[0] |= modbus_uart_buff[ind++];
|
||||
modbus_msg->MbData[1] = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->MbData[1] |= modbus_uart_buff[ind++];
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
else // classic modbus response
|
||||
{
|
||||
// get byte count for read functions
|
||||
if((modbus_msg->FuncCode == 0x01) || (modbus_msg->FuncCode == 0x02) ||
|
||||
(modbus_msg->FuncCode == 0x03) || (modbus_msg->FuncCode == 0x04))
|
||||
{
|
||||
modbus_msg->ByteCnt = modbus_uart_buff[ind++];
|
||||
|
||||
// read data bytes
|
||||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->MbData;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||
{
|
||||
if(i % 2 == 0) // HI byte
|
||||
tmp_data_addr[i/2] = (uint16_t)modbus_uart_buff[ind++] << 8;
|
||||
else // LO byte
|
||||
tmp_data_addr[i/2] |= modbus_uart_buff[ind++];
|
||||
}
|
||||
}
|
||||
// for write functions - echo address and quantity
|
||||
else if((modbus_msg->FuncCode == 0x05) || (modbus_msg->FuncCode == 0x06) ||
|
||||
(modbus_msg->FuncCode == 0x0F) || (modbus_msg->FuncCode == 0x10))
|
||||
{
|
||||
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
||||
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------CRC----------------
|
||||
//----------[last 2 bytes]----------
|
||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||
modbus_msg->MbCRC = modbus_uart_buff[ind++];
|
||||
modbus_msg->MbCRC |= modbus_uart_buff[ind++] << 8;
|
||||
|
||||
if(modbus_msg->MbCRC != CRC_VALUE)
|
||||
{
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
return RS_PARSE_MSG_ERR;
|
||||
}
|
||||
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @brief Сформировать запрос на чтение коилов */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на чтение дискретных регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_DISC_IN, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на чтение холдинг регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на чтение инпут регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_IN_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись одного коила */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_W_COIL, {0}, coil_addr, (value ? 0xFF00 : 0x0000), 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись одного регистра */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_W_HOLD_REG, {0}, reg_addr, value, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись нескольких регистров */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_W_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
|
||||
// Calculate byte count and prepare data
|
||||
uint8_t byte_count = (quantity + 7) / 8;
|
||||
msg.ByteCnt = byte_count;
|
||||
|
||||
// Copy coil data to message MbData array
|
||||
for(int i = 0; i < byte_count; i++) {
|
||||
if(i < DATA_SIZE) {
|
||||
msg.MbData[i] = coils_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/** @brief Сформировать запрос на запись нескольких коилов */
|
||||
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_W_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||
|
||||
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++) {
|
||||
msg.MbData[i] = regs_data[i];
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_DIAGNOSTICS, {0}, 0, 0, 0, {sub_function, data}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0000, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0001, data);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0002, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0004, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000A, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000B, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000C, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000D, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000E, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000F, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0010, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0011, 0x0000);
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr)
|
||||
{
|
||||
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0012, 0x0000);
|
||||
}
|
||||
|
||||
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x01, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x02, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x03, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id)
|
||||
{
|
||||
RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x04, object_id, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||
return msg;
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_MASTER
|
||||
467
new rev/core/STM32_Modbus/Src/modbus_slave.c
Normal file
467
new rev/core/STM32_Modbus/Src/modbus_slave.c
Normal file
@@ -0,0 +1,467 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file modbus_slave.c
|
||||
* @brief Модуль для реализации слейв MODBUS.
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Файл содержит реализацию функций для работы Modbus в режиме слейва.
|
||||
|
||||
@section slave Функции и макросы
|
||||
|
||||
- MB_Slave_Response() — Ответ на запрос
|
||||
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
||||
- MB_Slave_Parse_Message() — Парс сообщения в режиме слейва.
|
||||
******************************************************************************/
|
||||
#include "modbus.h"
|
||||
|
||||
#ifdef MODBUS_ENABLE_SLAVE
|
||||
/**
|
||||
* @brief Ответ на сообщение в режиме слейва.
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о результате ответа на комманду.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
RS_StatusTypeDef MB_RES = 0;
|
||||
hmodbus->f.MessageHandled = 0;
|
||||
hmodbus->f.EchoResponse = 0;
|
||||
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
|
||||
|
||||
MB_Diagnostics_BusMessageCnt();
|
||||
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0)
|
||||
{
|
||||
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
|
||||
hmodbus->RS_STATUS = RS_SKIP;
|
||||
return RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||
}
|
||||
MB_Diagnostics_SlaveMessageCnt();
|
||||
|
||||
if(modbus_msg->FuncCode < FC_ERR_VALUES_START)// if no errors after parsing
|
||||
{
|
||||
switch (modbus_msg->FuncCode)
|
||||
{
|
||||
// Read Coils
|
||||
case FC_R_COILS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Read_Coils(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
// Read Hodling Registers
|
||||
case FC_R_HOLD_REGS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
|
||||
break;
|
||||
case FC_R_IN_REGS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
|
||||
// Write Single Coils
|
||||
case FC_W_COIL:
|
||||
hmodbus->f.MessageHandled = MB_Process_Write_Single_Coil(hmodbus->pMessagePtr);
|
||||
if(hmodbus->f.MessageHandled)
|
||||
{
|
||||
hmodbus->f.DataUpdated = 1;
|
||||
hmodbus->f.EchoResponse = 1;
|
||||
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
||||
}
|
||||
break;
|
||||
|
||||
case FC_W_HOLD_REG:
|
||||
hmodbus->f.MessageHandled = MB_Process_Write_Single_Reg(hmodbus->pMessagePtr);
|
||||
if(hmodbus->f.MessageHandled)
|
||||
{
|
||||
hmodbus->f.DataUpdated = 1;
|
||||
hmodbus->f.EchoResponse = 1;
|
||||
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
||||
}
|
||||
break;
|
||||
|
||||
// Write Multiple Coils
|
||||
case FC_W_COILS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Coils(hmodbus->pMessagePtr);
|
||||
if(hmodbus->f.MessageHandled)
|
||||
{
|
||||
hmodbus->f.DataUpdated = 1;
|
||||
hmodbus->f.EchoResponse = 1;
|
||||
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
||||
}
|
||||
break;
|
||||
|
||||
// Write Multiple Registers
|
||||
case FC_W_HOLD_REGS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Regs(hmodbus->pMessagePtr);
|
||||
if(hmodbus->f.MessageHandled)
|
||||
{
|
||||
hmodbus->f.DataUpdated = 1;
|
||||
hmodbus->f.EchoResponse = 1;
|
||||
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
||||
}
|
||||
break;
|
||||
|
||||
case FC_R_DEVICE_ID:
|
||||
hmodbus->f.MessageHandled = MB_Process_Read_Device_Identifications(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
// Добавить в switch-case после других case:
|
||||
case FC_R_DIAGNOSTICS:
|
||||
hmodbus->f.MessageHandled = MB_Process_Diagnostics(hmodbus->pMessagePtr);
|
||||
break;
|
||||
|
||||
/* unknown func code */
|
||||
default:
|
||||
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||
}
|
||||
|
||||
|
||||
// Проверяем режим устройства - если Listen Only, не обрабатываем команды
|
||||
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
|
||||
{
|
||||
MB_Diagnostics_SlaveNoResponseCnt();
|
||||
hmodbus->RS_STATUS = RS_SKIP;
|
||||
return RS_Handle_Receive_Start(hmodbus, modbus_msg);;
|
||||
}
|
||||
|
||||
// Проверяем статус обработки запроса
|
||||
if(hmodbus->f.MessageHandled == 0)
|
||||
{
|
||||
MB_Diagnostics_ExceptionErrorCnt();
|
||||
TrackerCnt_Warn(hmodbus->rs_err);
|
||||
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
TrackerCnt_Ok(hmodbus->rs_err);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// if we need response - check that transmit isnt busy
|
||||
if( RS_Is_TX_Busy(hmodbus) )
|
||||
RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free
|
||||
|
||||
// Transmit right there, or sets (fDeferredResponse) to transmit response in main code
|
||||
if(hmodbus->f.DeferredResponse == 0)
|
||||
{
|
||||
MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||
hmodbus->f.DeferredResponse = 0;
|
||||
}
|
||||
|
||||
hmodbus->RS_STATUS = MB_RES;
|
||||
return MB_RES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения буфера.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
|
||||
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
|
||||
ind = hmodbus->RS_Message_Size;
|
||||
else
|
||||
{
|
||||
//------INFO ABOUT DATA/MESSAGE------
|
||||
#ifdef MODBUS_PROTOCOL_TCP
|
||||
modbus_uart_buff[ind++] = modbus_msg->TransactionID >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->TransactionID& 0xFF;
|
||||
|
||||
modbus_uart_buff[ind++] = modbus_msg->ProtocolID >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->ProtocolID& 0xFF;
|
||||
|
||||
modbus_uart_buff[ind++] = modbus_msg->PDULength >> 8;
|
||||
modbus_uart_buff[ind++] = modbus_msg->PDULength& 0xFF;
|
||||
#endif
|
||||
//-----------[first bytes]-----------
|
||||
// set ID of message/user
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
||||
|
||||
// set dat or err response
|
||||
modbus_uart_buff[ind++] = modbus_msg->FuncCode;
|
||||
|
||||
if (modbus_msg->FuncCode < FC_ERR_VALUES_START) // if no error occur
|
||||
{
|
||||
// fill modbus header
|
||||
if(0) {}
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // devide identifications header
|
||||
{
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity;
|
||||
modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows;
|
||||
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
|
||||
{
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
return RS_COLLECT_MSG_ERR;
|
||||
}
|
||||
|
||||
|
||||
//---------------DATA----------------
|
||||
//-----------[data bytes]------------
|
||||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->MbData;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
||||
{ // set data
|
||||
modbus_uart_buff[ind++] = *tmp_data_addr;
|
||||
tmp_data_addr++;
|
||||
}
|
||||
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
|
||||
{
|
||||
// Diagnostics special format: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[0] >> 8; // Sub-function HI
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[0] & 0xFF; // Sub-function LO
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[1] >> 8; // Data HI
|
||||
modbus_uart_buff[ind++] = modbus_msg->MbData[1] & 0xFF; // Data LO
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
else // modbus data header
|
||||
{
|
||||
// set size of received data
|
||||
if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
||||
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
||||
else // otherwise return data_size err
|
||||
{
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
return RS_COLLECT_MSG_ERR;
|
||||
}
|
||||
|
||||
//---------------DATA----------------
|
||||
//-----------[data bytes]------------
|
||||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->MbData;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
||||
{ // set data
|
||||
if (i%2 == 0) // HI byte
|
||||
modbus_uart_buff[ind++] = (*tmp_data_addr)>>8;
|
||||
else // LO byte
|
||||
{
|
||||
modbus_uart_buff[ind++] = *tmp_data_addr;
|
||||
tmp_data_addr++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else // if some error occur
|
||||
{ // send expection code
|
||||
modbus_uart_buff[ind++] = modbus_msg->Except_Code;
|
||||
}
|
||||
}
|
||||
if(ind < 0)
|
||||
return RS_COLLECT_MSG_ERR;
|
||||
|
||||
//---------------CRC----------------
|
||||
//---------[last 16 bytes]----------
|
||||
#ifndef MODBUS_PROTOCOL_TCP
|
||||
// calc crc of received data
|
||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||
// write crc to message structure and modbus-uart buffer
|
||||
modbus_msg->MbCRC = CRC_VALUE;
|
||||
modbus_uart_buff[ind++] = CRC_VALUE;
|
||||
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
||||
#endif
|
||||
|
||||
hmodbus->RS_Message_Size = ind;
|
||||
|
||||
return RS_OK; // returns ok
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Определить размер модбас запроса (СЛЕЙВ версия).
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия.
|
||||
* @return RS_RES Статус о корректности рассчета кол-ва байт для принятия.
|
||||
* @details Определение сколько байтов надо принять по протоколу.
|
||||
*/
|
||||
static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||
{
|
||||
RS_StatusTypeDef MB_RES = 0;
|
||||
int mb_func_size = 0;
|
||||
|
||||
if (modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
|
||||
{
|
||||
mb_func_size = 1;
|
||||
}
|
||||
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID)
|
||||
{
|
||||
mb_func_size = 0;
|
||||
}
|
||||
else if ((modbus_msg->FuncCode & ~FC_ERR_VALUES_START) < 0x0F)
|
||||
{
|
||||
mb_func_size = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mb_func_size = modbus_msg->ByteCnt + 2;
|
||||
}
|
||||
|
||||
|
||||
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
|
||||
return mb_func_size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Парс сообщения в режиме слейв (фрейм мастера из uart -> msg).
|
||||
* @param hmodbus Указатель на хендлер RS.
|
||||
* @param modbus_msg Указатель на структуру сообщения.
|
||||
* @param modbus_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения структуры.
|
||||
* @details Заполнение структуры сообщения из буффера UART.
|
||||
*/
|
||||
RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||
{
|
||||
uint32_t check_empty_buff;
|
||||
int ind = 0; // ind for modbus-uart buffer
|
||||
hmodbus->f.RX_Continue = 0;
|
||||
int expected_size = 0;
|
||||
//-----INFO ABOUT DATA/MESSAGE-------
|
||||
#ifdef MODBUS_PROTOCOL_TCP
|
||||
modbus_msg->TransactionID =modbus_uart_buff[ind++]<<8;
|
||||
modbus_msg->TransactionID |=modbus_uart_buff[ind++];
|
||||
|
||||
modbus_msg->ProtocolID =modbus_uart_buff[ind++]<<8;
|
||||
modbus_msg->ProtocolID |=modbus_uart_buff[ind++];
|
||||
|
||||
modbus_msg->PDULength =modbus_uart_buff[ind++]<<8;
|
||||
modbus_msg->PDULength |=modbus_uart_buff[ind++];
|
||||
#endif
|
||||
//-----------[first bits]------------
|
||||
// get ID of message/user
|
||||
if(modbus_uart_buff[ind] != hmodbus->ID)
|
||||
{
|
||||
modbus_msg->MbAddr = 0;
|
||||
ind++;
|
||||
}
|
||||
else
|
||||
{
|
||||
modbus_msg->MbAddr = modbus_uart_buff[ind++];
|
||||
}
|
||||
|
||||
// get func code
|
||||
modbus_msg->FuncCode = modbus_uart_buff[ind++];
|
||||
if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // явная херня
|
||||
{
|
||||
MB_Diagnostics_SlaveNAKCnt();
|
||||
modbus_msg->MbAddr = 0;
|
||||
return RS_SKIP;
|
||||
}
|
||||
|
||||
if(0) {}
|
||||
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // if it device identifications request
|
||||
{
|
||||
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
|
||||
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
|
||||
modbus_msg->ByteCnt = 0;
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||
#ifdef MODBUS_ENABLE_DIAGNOSTICS
|
||||
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
|
||||
{
|
||||
// Diagnostics: читаем 4 байта в MbData[0] и MbData[1]
|
||||
// Sub-function
|
||||
modbus_msg->MbData[0] = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->MbData[0] |= modbus_uart_buff[ind++];
|
||||
// Data
|
||||
modbus_msg->MbData[1] = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->MbData[1] |= modbus_uart_buff[ind++];
|
||||
modbus_msg->Addr = 0; // не использует Addr
|
||||
modbus_msg->Qnt = 0; // не использует Qnt
|
||||
}
|
||||
#endif //MODBUS_ENABLE_DIAGNOSTICS
|
||||
else // if its classic modbus request
|
||||
{
|
||||
// get address from CMD
|
||||
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
||||
|
||||
// get address from CMD
|
||||
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
||||
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
||||
}
|
||||
|
||||
if((hmodbus->pMessagePtr->FuncCode == 0x0F) || (hmodbus->pMessagePtr->FuncCode == 0x10))
|
||||
hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++];
|
||||
else
|
||||
hmodbus->pMessagePtr->ByteCnt = 0;
|
||||
|
||||
expected_size = MB_Define_Size_of_Function(hmodbus, modbus_msg);
|
||||
// если размер меньше ожидаемого - продолжаем принимать
|
||||
if(hmodbus->RS_Message_Size < expected_size)
|
||||
{
|
||||
hmodbus->f.RX_Continue = 1;
|
||||
return RS_SKIP;
|
||||
}
|
||||
// если больше Ошибка
|
||||
else if (hmodbus->RS_Message_Size > expected_size)
|
||||
{
|
||||
MB_Diagnostics_CommunicationErrorCnt();
|
||||
return RS_PARSE_MSG_ERR;
|
||||
}
|
||||
|
||||
//---------------DATA----------------
|
||||
// (optional)
|
||||
if (modbus_msg->ByteCnt != 0)
|
||||
{
|
||||
//check that data size is correct
|
||||
if (modbus_msg->ByteCnt > DATA_SIZE*2)
|
||||
{
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
|
||||
MB_Diagnostics_CommunicationErrorCnt();
|
||||
return RS_PARSE_MSG_ERR;
|
||||
}
|
||||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->MbData;
|
||||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||
{ // set data
|
||||
if (i%2 == 0)
|
||||
*tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8);
|
||||
else
|
||||
{
|
||||
*tmp_data_addr |= modbus_uart_buff[ind++];
|
||||
tmp_data_addr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------CRC----------------
|
||||
//----------[last 16 bits]----------
|
||||
#ifndef MODBUS_PROTOCOL_TCP
|
||||
// calc crc of received data
|
||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||
// get crc of received data
|
||||
modbus_msg->MbCRC = modbus_uart_buff[ind++];
|
||||
modbus_msg->MbCRC |= modbus_uart_buff[ind++] << 8;
|
||||
// compare crc
|
||||
if (modbus_msg->MbCRC != CRC_VALUE)
|
||||
{
|
||||
MB_Diagnostics_CommunicationErrorCnt();
|
||||
TrackerCnt_Err(hmodbus->rs_err);
|
||||
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
|
||||
}
|
||||
#endif
|
||||
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
#endif //MODBUS_ENABLE_SLAVE
|
||||
571
new rev/core/STM32_Modbus/Src/rs_message.c
Normal file
571
new rev/core/STM32_Modbus/Src/rs_message.c
Normal file
@@ -0,0 +1,571 @@
|
||||
/**
|
||||
*******************************************************************************
|
||||
* @file rs_message.c
|
||||
* @brief Реализация протоколов обмена по RS/UART
|
||||
*******************************************************************************
|
||||
* @details
|
||||
Модуль реализует асинхронный обмен сообщениями через UART с использованием:
|
||||
- Прерываний по приему/передаче
|
||||
- Детектирования конца фрейма по IDLE линии
|
||||
- Таймаутов через таймер
|
||||
- Двухстадийного приема (заголовок + данные)
|
||||
|
||||
@section arch Архитектура:
|
||||
В режиме слейв:
|
||||
- Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX
|
||||
- При срабатывании прерывания IDLE - обработка полученного сообщения
|
||||
В режиме мастер (пока не реализовано):
|
||||
- Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX
|
||||
- При срабатывании прерывания IDLE - обработка полученного ответа
|
||||
|
||||
@section ithandler Необходимые обработчики:
|
||||
- RS_UART_Handler() в UARTx_IRQHandler вместо HAL_UART_IRQHandler()
|
||||
- RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler()
|
||||
******************************************************************************/
|
||||
#include "rs_message.h"
|
||||
#include "modbus_diag.h"
|
||||
#include "linkBlink.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);
|
||||
extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||
/**
|
||||
* @brief Начать прием по прерываниям.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации приема.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
RS_StatusTypeDef RS_RES = 0;
|
||||
HAL_StatusTypeDef uart_res = 0;
|
||||
|
||||
//-------------CHECK RS LINE----------------
|
||||
// check that receive isnt busy
|
||||
if( RS_Is_RX_Busy(hRS) ) // if tx busy - return busy status
|
||||
return RS_BUSY;
|
||||
|
||||
//-----------INITIALIZE RECEIVE-------------
|
||||
// if all OK: start receiving
|
||||
RS_EnableReceive();
|
||||
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
|
||||
if(!hRS->f.RX_Continue) // if not continue receiving
|
||||
hRS->RS_Message_Size = 0; // set ptr to start buffer
|
||||
|
||||
// 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,
|
||||
// then in Callback restart receive for rest bytes
|
||||
|
||||
// if receive isnt started - abort RS
|
||||
if(uart_res != HAL_OK)
|
||||
{
|
||||
RS_RES = RS_Abort(hRS, ABORT_RS);
|
||||
printf_rs_err("Failed to start RS receiving...");
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_RES = RS_OK;
|
||||
printf_rs("Start Receiving...");
|
||||
TrackerCnt_Ok(hRS->rs_err);
|
||||
}
|
||||
|
||||
hRS->RS_STATUS = RS_RES;
|
||||
return RS_RES; // returns result of receive init
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Начать передачу по прерываниям.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
RS_StatusTypeDef RS_RES = 0;
|
||||
HAL_StatusTypeDef uart_res = 0;
|
||||
|
||||
//-------------CHECK RS LINE----------------
|
||||
// check that transmit isnt busy
|
||||
if( RS_Is_TX_Busy(hRS) ) // if tx busy - return busy status
|
||||
return RS_BUSY;
|
||||
// check receive line
|
||||
|
||||
|
||||
//------------COLLECT MESSAGE---------------
|
||||
RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr);
|
||||
if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES
|
||||
{// need collect message status, so doesnt write abort to RS_RES
|
||||
RS_Abort(hRS, ABORT_RS);
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // restart receive
|
||||
}
|
||||
else // if collect successful
|
||||
{
|
||||
|
||||
//----------INITIALIZE TRANSMIT-------------
|
||||
RS_EnableTransmit();
|
||||
|
||||
RS_Set_Busy(hRS); // set RS busy
|
||||
RS_Set_TX_Flags(hRS); // initialize flags for transmit IT
|
||||
hRS->pMessagePtr = RS_msg; // set pointer for filling given structure from UARTHandler fucntion
|
||||
if(hRS->RS_Message_Size <= 0)
|
||||
{
|
||||
RS_RES = RS_Abort(hRS, ABORT_RS);
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
return RS_ERR;
|
||||
}
|
||||
// if all OK: start transmitting
|
||||
uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size);
|
||||
// if transmit isnt started - abort RS
|
||||
if(uart_res != HAL_OK)
|
||||
{
|
||||
RS_RES = RS_Abort(hRS, ABORT_RS);
|
||||
printf_rs_err("Failed to start RS transmitting...");
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_RES = RS_OK;
|
||||
printf_rs("Start Transmitting...");
|
||||
TrackerCnt_Ok(hRS->rs_err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hRS->RS_STATUS = RS_RES;
|
||||
return RS_RES; // returns result of transmit init
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициалазация структуры @ref RS_HandleTypeDef.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param suart Указатель на структуру с настройками UART.
|
||||
* @param stim Указатель на структуру с настройками таймера.
|
||||
* @param pRS_BufferPtr Указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации.
|
||||
* @details Инициализация перефирии и структуры для приема-передачи по RS.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr)
|
||||
{
|
||||
// check that hRS is defined
|
||||
if (hRS == NULL)
|
||||
return RS_ERR;
|
||||
// check that huart is defined
|
||||
if (huart == NULL)
|
||||
return RS_ERR;
|
||||
|
||||
hRS->huart = huart;
|
||||
|
||||
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
|
||||
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Отменить прием/передачу RS/UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param AbortMode Выбор, что надо отменить.
|
||||
- ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX,
|
||||
- ABORT_RX: Отмена приема по ЮАРТ, с очищением флагов RX,
|
||||
- ABORT_RX_TX: Отмена приема и передачи по ЮАРТ,
|
||||
- ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры.
|
||||
* @return RS_RES Статус о состоянии RS после аборта.
|
||||
* @details Отмена работы UART в целом или отмена приема/передачи RS.
|
||||
Также очищается хендл hRS.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode)
|
||||
{
|
||||
HAL_StatusTypeDef uart_res = 0;
|
||||
|
||||
RS_Timeout_Stop(hRS);
|
||||
|
||||
if((AbortMode&ABORT_RS) == 0x00)
|
||||
{
|
||||
if((AbortMode&ABORT_RX) == ABORT_RX)
|
||||
{
|
||||
uart_res = HAL_UART_AbortReceive(hRS->huart); // abort receive
|
||||
RS_Reset_RX_Flags(hRS);
|
||||
}
|
||||
|
||||
if((AbortMode&ABORT_TX) == ABORT_TX)
|
||||
{
|
||||
uart_res = HAL_UART_AbortTransmit(hRS->huart); // abort transmit
|
||||
RS_Reset_TX_Flags(hRS);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uart_res = HAL_UART_Abort(hRS->huart);
|
||||
RS_Clear_All(hRS);
|
||||
}
|
||||
hRS->RS_STATUS = RS_ABORTED;
|
||||
return RS_ABORTED;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||
/**
|
||||
* @brief Обработчик для начала приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации приема или окончания общения.
|
||||
* @details Определяет начинать прием команды/ответа или нет.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
RS_StatusTypeDef RS_RES = 0;
|
||||
|
||||
switch(hRS->sRS_Mode)
|
||||
{
|
||||
// В режиме мастер
|
||||
case RS_MASTER_REQUEST:
|
||||
RS_Timeout_Start(hRS); // сразу запускаем таймаут и начинаем прием
|
||||
// В режиме слейв
|
||||
case RS_SLAVE_ALWAYS_WAIT:
|
||||
RS_RES = RS_Receive_IT(hRS, RS_msg); // Просто запускаем фоновый прием
|
||||
break;
|
||||
|
||||
case RS_RESERVED:
|
||||
RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy)
|
||||
}
|
||||
|
||||
if(RS_RES != RS_OK)
|
||||
{
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
}
|
||||
|
||||
return RS_RES;
|
||||
}
|
||||
/**
|
||||
* @brief Обработчик для начала передачи.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
||||
* @details Определяет отвечать ли на команду или нет.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
RS_StatusTypeDef RS_RES = 0;
|
||||
|
||||
switch(hRS->sRS_Mode)
|
||||
{
|
||||
case RS_SLAVE_ALWAYS_WAIT: // in slave mode always response
|
||||
case RS_RESERVED: // transmit response
|
||||
case RS_MASTER_REQUEST: // transmit response
|
||||
RS_RES = RS_Transmit_IT(hRS, RS_msg); break;
|
||||
}
|
||||
|
||||
if(RS_RES != RS_OK)
|
||||
{
|
||||
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
RS_Handle_Receive_Start(hRS, RS_msg);
|
||||
}
|
||||
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
}
|
||||
|
||||
return RS_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART TX Callback: коллбек после окончания передачи.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус о состоянии RS после обработки приема.
|
||||
* @details Определяет поведение RS после передачи сообщения.
|
||||
*/
|
||||
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
RS_StatusTypeDef RS_RES = RS_OK;
|
||||
HAL_StatusTypeDef uart_res = 0;
|
||||
|
||||
//--------------ENDING TRANSMITTING-------------
|
||||
RS_Set_TX_End(hRS);
|
||||
|
||||
//-----------START RECEIVING or END RS----------
|
||||
RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
|
||||
return RS_RES;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработчик прерывания UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @details Обрабатывает ошибки если есть и вызывает RS Коллбеки.
|
||||
* Добавить вызов этой функции в UARTx_IRQHandler() ВМЕСТО HAL_UART_IRQHandler().
|
||||
*/
|
||||
void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
|
||||
|
||||
if(hRS->huart == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RS_UART_Handler_ENTER();
|
||||
hRS->f.blink=1;
|
||||
|
||||
//-------------CHECK IDLE FLAG FIRST-------------
|
||||
/* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */
|
||||
if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE))
|
||||
{
|
||||
|
||||
__HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE
|
||||
//-------------STANDARD UART HANDLING-------------
|
||||
HAL_UART_IRQHandler(hRS->huart);
|
||||
hRS->f.RX_Continue = 0;
|
||||
|
||||
// Если прием активен и мы получили IDLE - это конец фрейма
|
||||
if(RS_Is_RX_Busy(hRS) && hRS->f.RX_Ongoing)
|
||||
{
|
||||
// Получаем количество фактически принятых байтов
|
||||
hRS->RS_Message_Size += hRS->huart->RxXferSize - hRS->huart->RxXferCount;
|
||||
|
||||
|
||||
if(hRS->RS_Message_Size > 0)
|
||||
{
|
||||
// Принудительно завершаем прием (получили сообщение)
|
||||
HAL_UART_AbortReceive(hRS->huart); // abort receive
|
||||
|
||||
// Завершаем прием в нашей структуре
|
||||
RS_Set_RX_End(hRS);
|
||||
|
||||
// Парсим наше сообщение
|
||||
hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr);
|
||||
|
||||
// Если сообещине принято корректно
|
||||
if(hRS->RS_STATUS == RS_OK)
|
||||
{
|
||||
RS_Timeout_Stop(hRS);
|
||||
|
||||
hRS->lastPacketTick = local_time();
|
||||
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||
{
|
||||
RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_Set_Free(hRS); // освобожднаем RS
|
||||
if(hRS->pCallback)
|
||||
{
|
||||
hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); // если сообщение пришло не полностью - продолжаем прием до таймаута
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return; // Выходим после обработки IDLE
|
||||
}
|
||||
else
|
||||
{
|
||||
//-------------STANDARD UART HANDLING-------------
|
||||
HAL_UART_IRQHandler(hRS->huart);
|
||||
}
|
||||
|
||||
|
||||
//-------------CALL RS CALLBACKS------------
|
||||
/* IF NO ERROR OCCURS */
|
||||
if(hRS->huart->ErrorCode == 0)
|
||||
{
|
||||
|
||||
// if first byte is received and receive is active
|
||||
if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS))
|
||||
{
|
||||
RS_Timeout_Start(hRS);
|
||||
}
|
||||
RS_Timeout_Update(hRS);
|
||||
|
||||
/* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */
|
||||
|
||||
/* TX Callback */
|
||||
if ((hRS->huart->TxXferCount == 0U) && RS_Is_TX_Busy(hRS) && // if all bytes are transmited and transmit is active
|
||||
hRS->huart->gState != HAL_UART_STATE_BUSY_TX) // also check that receive "REALLY" isnt busy
|
||||
RS_UART_TxCpltCallback(hRS);
|
||||
|
||||
/* NOTE: RX Callback больше не вызывается здесь - ждем IDLE для гарантии конца фрейма */
|
||||
}
|
||||
//----------------ERRORS HANDLER----------------
|
||||
else
|
||||
{
|
||||
if (hRS->huart->ErrorCode & HAL_UART_ERROR_ORE)
|
||||
{
|
||||
MB_Diagnostics_CharacterOverrunCnt(); // <-- Обнаружено переполнение
|
||||
}
|
||||
//TrackerCnt_Err(hRS->rs_err);
|
||||
/* de-init uart transfer */
|
||||
RS_Abort(hRS, ABORT_RS);
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
|
||||
// later, maybe, will be added specific handlers for err
|
||||
}
|
||||
RS_UART_Handler_EXIT();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработчик прерывания TIM.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @details Попадание сюда = таймаут и перезапуск RS приема
|
||||
* Добавить вызов этой функции в TIMx_IRQHandler() ВМЕСТО HAL_TIM_IRQHandler().
|
||||
*/
|
||||
void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RS_TIM_Handler_ENTER();
|
||||
|
||||
HAL_TIM_IRQHandler(hRS->htim);
|
||||
|
||||
RS_Abort(hRS, ABORT_RS);
|
||||
|
||||
hRS->RS_STATUS = RS_TIMEOUT;
|
||||
|
||||
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||
if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
|
||||
TrackerCnt_Err(hRS->rs_err);
|
||||
|
||||
if(hRS->sRS_Mode >= RS_MASTER_MODE_START)
|
||||
{ // Мастер: коллбек и освобождение для нового запроса
|
||||
RS_Set_Free(hRS);
|
||||
if(hRS->pCallback)
|
||||
{
|
||||
hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ
|
||||
}
|
||||
} else {
|
||||
// Слейв: перезапускаем прием
|
||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||
}
|
||||
RS_TIM_Handler_EXIT();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Запуск таймаута приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус операции.
|
||||
* @details Запускает таймер для отсчета времени ожидания следующего байта.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||
if(hRS->sRS_Timeout) // if timeout setted
|
||||
{
|
||||
hRS->htim->Instance->ARR = hRS->sRS_Timeout;
|
||||
HAL_TIM_Base_Start_IT(hRS->htim);
|
||||
RS_Set_RX_Active_Flags(hRS);
|
||||
}
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Остановка таймаута приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус операции.
|
||||
* @details Останавливает таймер ожидания.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
// Останавливаем таймаут
|
||||
if(hRS->sRS_Timeout)
|
||||
HAL_TIM_Base_Stop_IT(hRS->htim);
|
||||
hRS->htim->Instance->CNT = 0;
|
||||
__HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE);
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Обновление (сброс) таймаута приема.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @return RS_RES Статус операции.
|
||||
* @details Сбрасывает счетчик таймера в 0.
|
||||
*/
|
||||
RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS)
|
||||
{
|
||||
if(hRS->htim)
|
||||
{
|
||||
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE---------------
|
||||
/**
|
||||
* @brief Пользовательская функция для ответа на запрос по UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @return RS_RES Статус о результате ответа на комманду.
|
||||
*/
|
||||
__weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||
{
|
||||
/* Redefine function for user purposes */
|
||||
return RS_ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Пользовательская функция для сбора сообщения в буфер UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @param msg_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения буфера.
|
||||
*/
|
||||
__weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
||||
{
|
||||
/* Redefine function for user purposes */
|
||||
return RS_ERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Пользовательская функция для парса сообщения из буфера UART.
|
||||
* @param hRS Указатель на хендлер RS.
|
||||
* @param RS_msg Указатель на структуру сообщения.
|
||||
* @param msg_uart_buff Указатель на буффер UART.
|
||||
* @return RS_RES Статус о результате заполнения структуры.
|
||||
*/
|
||||
__weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
||||
{
|
||||
/* Redefine function for user purposes */
|
||||
return RS_ERR;
|
||||
}
|
||||
//--------------WEAK PROTOTYPES FOR PROCESSING MESSAGE---------------
|
||||
//-------------------------------------------------------------------
|
||||
71
new rev/core/STM32_Modbus/__modbus_config.h
Normal file
71
new rev/core/STM32_Modbus/__modbus_config.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_config.h
|
||||
* @brief Конфигурационные параметры Modbus устройства
|
||||
******************************************************************************
|
||||
@addtogroup MODBUS_CONFIGS Modbus configs
|
||||
@ingroup MODBUS
|
||||
@brief Конфигурация библиотеки
|
||||
@{
|
||||
******************************************************************************
|
||||
* @details
|
||||
Файл содержит настройки для работы Modbus:
|
||||
- Подключение библиотек контроллера
|
||||
- ID устройства и таймауты
|
||||
- Строковые идентификаторы (Vendor, Product, Revision)
|
||||
- Настройки периферии (UART, TIMER)
|
||||
- Подключение модулей Modbus
|
||||
- Опциональные функции (переключение команд 0x03/0x04)
|
||||
******************************************************************************/
|
||||
#ifndef _MODBUS_CONFIG_H_
|
||||
#define _MODBUS_CONFIG_H_
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
// Общие параметры
|
||||
#define MODBUS_DEVICE_ID 1 ///< Адрес устройства в сети Modbus
|
||||
#define MODBUS_TIMEOUT 5000 ///< Таймаут в тиках таймера
|
||||
|
||||
// Строковые идентификаторы устройства
|
||||
#define MODBUS_VENDOR_NAME "NIO-12"
|
||||
#define MODBUS_PRODUCT_CODE ""
|
||||
#define MODBUS_REVISION ""
|
||||
#define MODBUS_VENDOR_URL ""
|
||||
#define MODBUS_PRODUCT_NAME ""
|
||||
#define MODBUS_MODEL_NAME ""
|
||||
#define MODBUS_USER_APPLICATION_NAME ""
|
||||
|
||||
#define MODBUS_NUMB_OF_USEROBJECTS 0 ///< Количество пользовательских объектов
|
||||
#define MODBUS_USEROBJECT_0_NAME "" ///< Строка пользовательского идентификатора 0. По аналогии можно определить строки до <=128 USEROBJECT
|
||||
|
||||
// Периферия (опционально)
|
||||
#define mb_huart huart1 ///< Удобный дефайн для модбасовского uart
|
||||
#define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера
|
||||
//#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
|
||||
//#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
|
||||
|
||||
|
||||
// Модули modbus
|
||||
#define MODBUS_ENABLE_SLAVE ///< Включить обработку СЛЕЙВ режима
|
||||
#define MODBUS_ENABLE_MASTER ///< Включить обработку МАСТЕР режима
|
||||
|
||||
#define MODBUS_ENABLE_COILS ///< Включить обработку коилов
|
||||
#define MODBUS_ENABLE_HOLDINGS ///< Включить обработку регистров хранения
|
||||
#define MODBUS_ENABLE_INPUTS ///< Включить обработку входных регистров
|
||||
#define MODBUS_ENABLE_DEVICE_IDENTIFICATIONS ///< Включить обработку идентификаторы устройства
|
||||
#define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас
|
||||
|
||||
//#define MODBUS_PROTOCOL_TCP ///< Включить TCP-протокол, иначе - RTU
|
||||
|
||||
/**
|
||||
* @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей)
|
||||
* @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS
|
||||
* Поэтому чтобы считывать Input Regs - надо поменять их местами.
|
||||
*/
|
||||
//#define MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////---CALC DEFINES---//////////////////////////
|
||||
|
||||
|
||||
|
||||
#endif //_MODBUS_CONFIG_H_
|
||||
141
new rev/core/STM32_Modbus/__modbus_data.c
Normal file
141
new rev/core/STM32_Modbus/__modbus_data.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_data.c
|
||||
* @brief Функции доступа к данным Modbus
|
||||
******************************************************************************
|
||||
* @details
|
||||
Модуль реализует функции валидации адресов и доступа к данным:
|
||||
- Проверка корректности запрашиваемых адресов
|
||||
- Определение указателей на реальные данные в памяти
|
||||
- Поддержка пользовательских массивов регистров и coils
|
||||
|
||||
@section Валидация адресов:
|
||||
- MB_Check_Address_For_Arr() - проверка принадлежности адреса массиву
|
||||
- MB_DefineRegistersAddress() - получение указателя на регистры
|
||||
- MB_DefineCoilsAddress() - получение указателя на coils
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include "modbus_core.h"
|
||||
#include "modbus_coils.h"
|
||||
#include "modbus_holdregs.h"
|
||||
#include "modbus_inputregs.h"
|
||||
#include "modbus_devid.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check is address valid for certain array.
|
||||
* @param Addr Начальный адресс.
|
||||
* @param Qnt Количество запрашиваемых элементов.
|
||||
* @param R_ARR_ADDR Начальный адресс массива R_ARR.
|
||||
* @param R_ARR_NUMB Количество элементов в массиве R_ARR.
|
||||
* @return ExceptionCode - ET_ILLEGAL_DATA_ADRESS если адресс недействителен, и ET_NO_ERRORS если все ок.
|
||||
*
|
||||
* @details Позволяет определить, принадлежит ли адресс Addr массиву R_ARR:
|
||||
* Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR.
|
||||
* Если адресс Addr находится за пределами адрессов массива R_ARR - ET_ILLEGAL_DATA_ADDRESSю.
|
||||
*/
|
||||
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB)
|
||||
{
|
||||
// if address from this array
|
||||
if(Addr >= R_ARR_ADDR)
|
||||
{
|
||||
// if quantity too big return error
|
||||
if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB)
|
||||
{
|
||||
return ET_ILLEGAL_DATA_ADDRESS; // return exception code
|
||||
}
|
||||
// if all ok - return no errors
|
||||
return ET_NO_ERRORS;
|
||||
}
|
||||
// if address isnt from this array return error
|
||||
else
|
||||
return ET_ILLEGAL_DATA_ADDRESS; // return exception code
|
||||
}
|
||||
/**
|
||||
* @brief Define Address Origin for Input/Holding Registers
|
||||
* @param pRegs Указатель на указатель регистров.
|
||||
* @param Addr Адрес начального регистра.
|
||||
* @param Qnt Количество запрашиваемых регистров.
|
||||
* @param WriteFlag Флаг регистр нужны для чтения или записи.
|
||||
* @return ExceptionCode Код исключения если есть, и ET_NO_ERRORS если нет.
|
||||
*
|
||||
* @details Определение адреса начального регистра.
|
||||
* @note WriteFlag пока не используется.
|
||||
*/
|
||||
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType)
|
||||
{
|
||||
/* check quantity error */
|
||||
if (Qnt > DATA_SIZE)
|
||||
{
|
||||
return ET_ILLEGAL_DATA_VALUE; // return exception code
|
||||
}
|
||||
|
||||
if(RegisterType == RegisterType_Holding)
|
||||
{
|
||||
// Default holding registers
|
||||
if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == ET_NO_ERRORS)
|
||||
{
|
||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр
|
||||
}
|
||||
// if address doesnt match any array - return illegal data address response
|
||||
else
|
||||
{
|
||||
return ET_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
}
|
||||
else if(RegisterType == RegisterType_Input)
|
||||
{
|
||||
// Default input registers
|
||||
if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == ET_NO_ERRORS)
|
||||
{
|
||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr - R_INPUT_ADDR); // указатель на выбранный по Addr регистр
|
||||
}
|
||||
// if address doesnt match any array - return illegal data address response
|
||||
else
|
||||
{
|
||||
return ET_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ET_ILLEGAL_FUNCTION;
|
||||
}
|
||||
// if found requeried array return no err
|
||||
return ET_NO_ERRORS; // return no errors
|
||||
}
|
||||
/**
|
||||
* @brief Define Address Origin for coils
|
||||
* @param pCoils Указатель на указатель коилов.
|
||||
* @param Addr Адресс начального коила.
|
||||
* @param Qnt Количество запрашиваемых коилов.
|
||||
* @param start_shift Указатель на переменную содержащую сдвиг внутри регистра для начального коила.
|
||||
* @param WriteFlag Флаг коилы нужны для чтения или записи.
|
||||
* @return ExceptionCode Код исключения если есть, и ET_NO_ERRORS если нет.
|
||||
*
|
||||
* @details Определение адреса начального регистра запрашиваемых коилов.
|
||||
* @note WriteFlag используется для определния регистров GPIO: ODR или IDR.
|
||||
*/
|
||||
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag)
|
||||
{
|
||||
/* check quantity error */
|
||||
if (Qnt > 2000)
|
||||
{
|
||||
return ET_ILLEGAL_DATA_VALUE; // return exception code
|
||||
}
|
||||
|
||||
// Default coils
|
||||
if(MB_Check_Address_For_Arr(Addr, Qnt, C_COILS_ADDR, C_COILS_QNT) == ET_NO_ERRORS)
|
||||
{
|
||||
*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr - C_COILS_ADDR); // указатель на выбранный по Addr массив коилов
|
||||
}
|
||||
// if address doesnt match any array - return illegal data address response
|
||||
else
|
||||
{
|
||||
return ET_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
|
||||
*start_shift = Addr % 16; // set shift to requested coil
|
||||
// if found requeried array return no err
|
||||
return ET_NO_ERRORS; // return no errors
|
||||
}
|
||||
159
new rev/core/STM32_Modbus/__modbus_data.h
Normal file
159
new rev/core/STM32_Modbus/__modbus_data.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file modbus_data.h
|
||||
* @brief Определения структур данных Modbus устройства
|
||||
******************************************************************************
|
||||
@defgroup MODBUS_DATA Modbus Registers Map
|
||||
@ingroup MODBUS
|
||||
@brief Определение карты регистров и коилов
|
||||
******************************************************************************
|
||||
* @details
|
||||
Файл содержит объявления структур данных, доступных через Modbus:
|
||||
- Holding Registers (R/W) - регистры хранения
|
||||
- Input Registers (R/O) - входные регистры
|
||||
- Coils (R/W) - дискретные выходы
|
||||
|
||||
@section datinit Базовая настройка под устройство:
|
||||
1. Настроить диапазоны адресов
|
||||
- @ref R_INPUT_ADDR и @ref R_INPUT_QNT для входных регистров
|
||||
- @ref R_HOLDING_ADDR и @ref R_HOLDING_QNT для регистров хранения
|
||||
- @ref C_COILS_ADDR и @ref C_COILS_ADDR для коилов
|
||||
3. Настроить структуры данных:
|
||||
- @ref MB_DataInRegsTypeDef
|
||||
- @ref MB_DataHoldRegsTypeDef
|
||||
- @ref MB_DataCoilsTypeDef
|
||||
|
||||
|
||||
@section datexpert Расширенная настройка под устройство:
|
||||
1. Добавить новый массив с нужными данными.
|
||||
2. Добавить дефайны для определения его начального адреса и количества элементов
|
||||
3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress.
|
||||
|
||||
Пример:
|
||||
@code
|
||||
#define R_USER_ADDR 555
|
||||
#define R_USER_QNT 16
|
||||
uint16_t user_regs[16];
|
||||
|
||||
//...
|
||||
else if(MB_Check_Address_For_Arr(Addr, Qnt, R_USER_ADDR, R_USER_QNT) == ET_NO_ERRORS)
|
||||
{
|
||||
*pRegs = MB_Set_Register_Ptr(&user_regs, Addr-R_USER_ADDR); // ВАЖНО!
|
||||
// -R_USER_ADDR нужен чтобы взять адрес относительно начала массива
|
||||
}
|
||||
else
|
||||
{
|
||||
return ET_ILLEGAL_DATA_ADDRESS;
|
||||
}
|
||||
@endcode
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _MODBUS_DATA_H_
|
||||
#define _MODBUS_DATA_H_
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
|
||||
//--------------SIZES OF DATA---------------
|
||||
|
||||
// DEFINES FOR INPUT REGISTERS ARRAYS
|
||||
#define R_INPUT_ADDR 0 ///< Начальный адрес входных регистров
|
||||
#define R_INPUT_QNT 16 ///< Количество входных регистров
|
||||
|
||||
// DEFINES FOR HOLDING REGISTERS ARRAYS
|
||||
#define R_HOLDING_ADDR 0 ///< Начальный адрес регистров хранения
|
||||
#define R_HOLDING_QNT 16 ///< Количество регистров хранения
|
||||
|
||||
// DEFINES FOR COIL ARRAYS
|
||||
#define C_COILS_ADDR 0 ///< Начальный адрес коилов
|
||||
#define C_COILS_QNT 16 ///< Количество регистров коилов
|
||||
|
||||
//--------------DEFINES FOR REGISTERS---------------
|
||||
// DEFINES FOR ARRAYS
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_RERISTERS_DEFINES Registers structures
|
||||
* @ingroup MODBUS_DATA
|
||||
* @brief Стуруктура регистров (входных и хранения)
|
||||
@code
|
||||
Для массивов регистров:
|
||||
R_<NAME_ARRAY>_ADDR - модбас адресс первого регистра в массиве
|
||||
R_<NAME_ARRAY>_QNT - количество регистров в массиве
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Регистры хранения
|
||||
*/
|
||||
typedef struct //MB_DataInRegsTypeDef
|
||||
{
|
||||
uint16_t in[16];
|
||||
}MB_DataInRegsTypeDef;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Входные регистры
|
||||
*/
|
||||
typedef struct //MB_DataInRegsTypeDef
|
||||
{
|
||||
uint16_t out[16];
|
||||
}MB_DataHoldRegsTypeDef;
|
||||
|
||||
|
||||
/** MODBUS_DATA_RERISTERS_DEFINES
|
||||
* @}
|
||||
*/
|
||||
|
||||
//----------------DEFINES FOR COILS-----------------
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_COILS_DEFINES Coils Structure
|
||||
* @ingroup MODBUS_DATA
|
||||
* @brief Структура коилов
|
||||
@code
|
||||
Структура дефайна
|
||||
Для массивов коилов:
|
||||
C_<NAME_ARRAY>_ADDR - модбас адресс первого коила в массиве
|
||||
C_<NAME_ARRAY>_QNT - количество коилов в массиве (минимум 16)
|
||||
@endcode
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Коилы
|
||||
* @details Желательно с помощью reserved делать стркутуру кратной 16-битам
|
||||
*/
|
||||
typedef struct //MB_DataCoilsTypeDef
|
||||
{
|
||||
unsigned reserved:16;
|
||||
}MB_DataCoilsTypeDef;
|
||||
|
||||
/** MODBUS_DATA_COILS_DEFINES
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
//-----------MODBUS DEVICE DATA SETTING-------------
|
||||
// MODBUS DATA STRUCTTURE
|
||||
/**
|
||||
* @brief Структура со всеми регистрами и коилами модбас
|
||||
* @ingroup MODBUS_DATA
|
||||
*/
|
||||
typedef struct // tester modbus data
|
||||
{
|
||||
MB_DataInRegsTypeDef InRegs; ///< Modbus input registers @ref MB_DataInRegsTypeDef
|
||||
|
||||
MB_DataCoilsTypeDef Coils; ///< Modbus coils @ref MB_DataCoilsTypeDef
|
||||
|
||||
MB_DataHoldRegsTypeDef HoldRegs; ///< Modbus holding registers @ref MB_DataHoldRegsTypeDef
|
||||
}MB_DataStructureTypeDef;
|
||||
extern MB_DataStructureTypeDef MB_DATA;
|
||||
|
||||
|
||||
#endif //_MODBUS_DATA_H_
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
///////////////////////TEMP/OUTDATE/OTHER////////////////////
|
||||
@@ -0,0 +1 @@
|
||||
F:\set\workspace\setcorp\set506\git_project\ds128b20\new rev\john103C8T6\.codex-restored-sessions\codex_sessions_restored_20260609132029
|
||||
@@ -0,0 +1,16 @@
|
||||
# Restored Codex sessions
|
||||
|
||||
Source archive: `C:\Users\z\Documents\Codex\2026-06-09\c-users-z-codex-sessions\outputs\codex_sessions_restored_20260609132029`
|
||||
Project CWD: `F:\set\workspace\setcorp\set506\git_project\ds128b20\new rev\john103C8T6`
|
||||
Generated copy: `2026-06-09T16:29:15.1490867+03:00`
|
||||
|
||||
## Dialogues
|
||||
|
||||
| Started | Title | Transcript |
|
||||
|---|---|---|
|
||||
| 2026-05-28T16:32:05.792Z | собери проект убери ошибки ,если нужны библиотеки подтяни их уровнем выше | [transcript](transcripts/001_14220bef_session.md) |
|
||||
| 2026-05-28T16:47:52.141Z | настроить RTC с календарем и backup в modbuds сделать регистр времени часы минуты секунды дата | [transcript](transcripts/002_a30c80b2_RTC_backup_modbuds.md) |
|
||||
|
||||
## Restored files from patch records
|
||||
|
||||
Recovered embedded file contents, if any, are in `files_from_patches/`. Original project files were not overwritten.
|
||||
42
new rev/john103C8T6/.mxproject
Normal file
42
new rev/john103C8T6/.mxproject
Normal file
File diff suppressed because one or more lines are too long
13
new rev/john103C8T6/Core/Inc/Proj_setup.h
Normal file
13
new rev/john103C8T6/Core/Inc/Proj_setup.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __PROJ_SETUP
|
||||
#define __PROJ_SETUP
|
||||
|
||||
//**********BEGIN defines***********
|
||||
//#define OldVer
|
||||
#define MAX_SENSE 32 // НЕ ДЕЛАТЬ МЕНЬШЕ 16
|
||||
|
||||
|
||||
|
||||
|
||||
//**********END defines***********
|
||||
|
||||
#endif
|
||||
52
new rev/john103C8T6/Core/Inc/adc.h
Normal file
52
new rev/john103C8T6/Core/Inc/adc.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file adc.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the adc.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __ADC_H__
|
||||
#define __ADC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern ADC_HandleTypeDef hadc1;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_ADC1_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ADC_H__ */
|
||||
|
||||
52
new rev/john103C8T6/Core/Inc/can.h
Normal file
52
new rev/john103C8T6/Core/Inc/can.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file can.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the can.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __CAN_H__
|
||||
#define __CAN_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern CAN_HandleTypeDef hcan;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_CAN_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CAN_H__ */
|
||||
|
||||
170
new rev/john103C8T6/Core/Inc/dallas_tools.h
Normal file
170
new rev/john103C8T6/Core/Inc/dallas_tools.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file dallas_tools.h
|
||||
* @brief Драйвер датчиков температуры DALLAS
|
||||
******************************************************************************
|
||||
* Этот файл предоставляет объявления и определения для работы с датчиками
|
||||
* температуры DS18B20. Он включает структуры данных, макросы и прототипы
|
||||
* функций для инициализации, чтения температуры
|
||||
* и управления датчиками.
|
||||
*
|
||||
* Работа с датчиками ведётся через протокол OneWire.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef DALLAS_TOOLS_H
|
||||
#define DALLAS_TOOLS_H
|
||||
|
||||
/* Includes -----------------------------------------------------------------*/
|
||||
#include "ds18b20_driver.h"
|
||||
#include "onewire.h"
|
||||
|
||||
|
||||
/* Определения пользовательских байтов для записи чтения */
|
||||
#define DALLAS_USER_BYTE_1 (1<<0) ///< Первый пользовательский байт
|
||||
#define DALLAS_USER_BYTE_2 (1<<1) ///< Второй пользовательский байт
|
||||
#define DALLAS_USER_BYTE_3 (1<<2) ///< Третий пользовательский байт
|
||||
#define DALLAS_USER_BYTE_4 (1<<3) ///< Четвёртый пользовательский байт
|
||||
|
||||
#define DALLAS_USER_BYTE_12 (DALLAS_USER_BYTE_1|DALLAS_USER_BYTE_2) ///< Первые два байта
|
||||
#define DALLAS_USER_BYTE_34 (DALLAS_USER_BYTE_3|DALLAS_USER_BYTE_4) ///< Вторые два байта
|
||||
#define DALLAS_USER_BYTE_ALL (DALLAS_USER_BYTE_12|DALLAS_USER_BYTE_34) ///< Все пользовательские байты
|
||||
|
||||
/* Declarations and definitions ---------------------------------------------*/
|
||||
#define DALLAS_ROM_SIZE 8
|
||||
|
||||
#define DALLAS_CONFIG_9_BITS 0x1F
|
||||
#define DALLAS_CONFIG_10_BITS 0x3F
|
||||
#define DALLAS_CONFIG_11_BITS 0x5F
|
||||
#define DALLAS_CONFIG_12_BITS 0x7F
|
||||
|
||||
#define DALLAS_DELAY_MS_9_BITS 94
|
||||
#define DALLAS_DELAY_MS_10_BITS 188
|
||||
#define DALLAS_DELAY_MS_11_BITS 375
|
||||
#define DALLAS_DELAY_MS_12_BITS 750
|
||||
#define DALLAS_DELAY_MS_MAX DALLAS_DELAY_MS_12_BITS
|
||||
|
||||
typedef struct _SensorHandleStruct DALLAS_SensorHandleTypeDef;
|
||||
typedef struct _DallasHandleStruct DALLAS_HandleTypeDef;
|
||||
|
||||
/** @brief Структура Scratchpad датчика DALLAS */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t TemperatureLSB; ///< Младший байт температуры
|
||||
uint8_t TemperatureMSB; ///< Старший байт температуры
|
||||
uint8_t tHighRegister; ///< Верхний температурный порог
|
||||
uint8_t tLowRegister; ///< Нижний температурный порог
|
||||
uint8_t ConfigRegister; ///< Конфигурационный регистр
|
||||
uint8_t reserved; ///< Зарезервировано
|
||||
uint8_t UserByte3; ///< Пользовательский байт 3
|
||||
uint8_t UserByte4; ///< Пользовательский байт 4
|
||||
uint8_t ScratchpadCRC; ///< Контрольная сумма
|
||||
}DALLAS_ScratchpadTypeDef;
|
||||
|
||||
/** @brief Структура флагов ошибок датчиков DALLAS */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t disconnect_cnt; ///< Счетчик отключений датчика
|
||||
uint8_t read_temperature_err_cnt; ///< Счетчик ошибок чтения температуры
|
||||
uint8_t timeout_convertion_cnt; ///< Счетчик ошибок таймаута конвертации
|
||||
uint8_t write_err_cnt; ///< Счетчик других ошибок
|
||||
}DALLAS_FlagsTypeDef;
|
||||
|
||||
|
||||
/** @brief Структура инициализации датчика DALLAS */
|
||||
typedef struct __packed
|
||||
{
|
||||
union
|
||||
{
|
||||
uint64_t Ind; ///< порядковый номер датчика
|
||||
uint64_t ROM; ///< ROM датчика
|
||||
struct
|
||||
{
|
||||
uint8_t UserByte1; ///< Младший байт (бит 0–7)
|
||||
uint8_t UserByte2; ///< Следующий байт (бит 8–15)
|
||||
uint8_t UserByte3; ///< Байт (бит 16–23)
|
||||
uint8_t UserByte4; ///< Байт (бит 24–31)
|
||||
uint8_t Reserved[4]; ///< Остальные байты (бит 32–63, если нужно)
|
||||
} UserBytes; ///< UserBytes датчика
|
||||
}InitParam; ///< Параметр для инициализации: ROM/UserBytes/Индекс
|
||||
uint8_t Resolution; ///< Разрешение датчика
|
||||
HAL_StatusTypeDef (*init_func)(DALLAS_HandleTypeDef *, DALLAS_SensorHandleTypeDef *); ///< Функция инициализации
|
||||
} DALLAS_InitStructTypeDef;
|
||||
|
||||
|
||||
|
||||
/** @brief Cтруктура обработчика DALLAS для общения с датчиком*/
|
||||
struct _DallasHandleStruct
|
||||
{
|
||||
OneWire_t *onewire;
|
||||
DS18B20_Drv_t *ds_devices;
|
||||
DALLAS_ScratchpadTypeDef scratchpad;
|
||||
};
|
||||
extern DALLAS_HandleTypeDef hdallas;
|
||||
|
||||
/** @brief Основная структура обработчика датчика DALLAS */
|
||||
struct _SensorHandleStruct
|
||||
{
|
||||
unsigned isConnected:1; ///< Флаг соединения
|
||||
unsigned isInitialized:1; ///< Флаг инициализации
|
||||
unsigned isLost:1; ///< Флаг потери связи
|
||||
uint16_t lost_cnt;
|
||||
DALLAS_FlagsTypeDef f; ///< Флаги
|
||||
|
||||
|
||||
float set_temp;
|
||||
uint16_t hyst;
|
||||
|
||||
DALLAS_HandleTypeDef *hdallas;
|
||||
uint64_t sensROM; ///< ROM-код датчика
|
||||
|
||||
float temperature; ///< Текущая температура
|
||||
|
||||
DALLAS_InitStructTypeDef Init; ///< Структура инициализации
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** @brief Варианты ожидания окончания конверсии */
|
||||
typedef enum
|
||||
{
|
||||
DALLAS_WAIT_NONE = 0x00, ///< Без ожидания окончания конверсии
|
||||
DALLAS_WAIT_BUS = 0x01, ///< Ожидание окончания конверсии по шине (опрос датчиков - чтение бита)
|
||||
DALLAS_WAIT_DELAY = 0x02, ///< Без ожидания окончания через задержку (максимальная задержка для заданной разрядности)
|
||||
} DALLAS_WaitConvertionTypeDef;
|
||||
|
||||
|
||||
|
||||
/* Functions ---------------------------------------------------------------*/
|
||||
|
||||
HAL_StatusTypeDef Dallas_BusFirstInit(TIM_HandleTypeDef *htim);
|
||||
/* Функция для иниицализации нового датчика в структуре */
|
||||
HAL_StatusTypeDef Dallas_AddNewSensors(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Инициализирует структуру датчика по ROM */
|
||||
HAL_StatusTypeDef Dallas_SensorInitByROM(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Инициализирует структуру датчика по пользовательским байтам */
|
||||
HAL_StatusTypeDef Dallas_SensorInitByUserBytes(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Инициализирует структуру датчика по порядковому номеру */
|
||||
HAL_StatusTypeDef Dallas_SensorInitByInd(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Инициализирует датчик для работы */
|
||||
HAL_StatusTypeDef Dallas_SensorInit(DALLAS_HandleTypeDef *hdallas, DALLAS_SensorHandleTypeDef *sensor, uint8_t (*ROM)[DALLAS_ROM_SIZE]);
|
||||
/* Деинициализирует структуру датчика */
|
||||
HAL_StatusTypeDef Dallas_SensorDeInit(DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Функция для нахождения нового датчика на место потерянного */
|
||||
HAL_StatusTypeDef Dallas_ReplaceLostedSensor(DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Запускает измерение температуры на всех датчиках */
|
||||
HAL_StatusTypeDef Dallas_StartConvertTAll(DALLAS_HandleTypeDef *hdallas, DALLAS_WaitConvertionTypeDef waitCondition, uint8_t dallas_delay_ms);
|
||||
/* Измеряет температуру на датчике */
|
||||
HAL_StatusTypeDef Dallas_ConvertT(DALLAS_SensorHandleTypeDef *sensor, DALLAS_WaitConvertionTypeDef waitCondition);
|
||||
/* Читает измеренную датчиком температуру */
|
||||
HAL_StatusTypeDef Dallas_ReadTemperature(DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Проверяет подключен ли датчик (чтение scratchpad) */
|
||||
HAL_StatusTypeDef Dallas_IsConnected(DALLAS_SensorHandleTypeDef *sensor);
|
||||
/* Записывает пользовательские байты */
|
||||
HAL_StatusTypeDef Dallas_WriteUserBytes(DALLAS_SensorHandleTypeDef *sensor, uint16_t UserBytes12, uint16_t UserBytes34, uint8_t UserBytesMask);
|
||||
/* Записывает пользовательские байты */
|
||||
HAL_StatusTypeDef Dallas_ReadScratchpad(DALLAS_SensorHandleTypeDef *sensor);
|
||||
|
||||
|
||||
#endif // #ifndef DALLAS_TOOLS_H
|
||||
14
new rev/john103C8T6/Core/Inc/def.h
Normal file
14
new rev/john103C8T6/Core/Inc/def.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __DEF_H
|
||||
#define __DEF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_DEVICES 10
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAIN_H */
|
||||
53
new rev/john103C8T6/Core/Inc/dma.h
Normal file
53
new rev/john103C8T6/Core/Inc/dma.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file dma.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the dma.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __DMA_H__
|
||||
#define __DMA_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* DMA memory to memory transfer handles -------------------------------------*/
|
||||
extern DMA_HandleTypeDef hdma_memtomem_dma1_channel1;
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_DMA_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __DMA_H__ */
|
||||
|
||||
104
new rev/john103C8T6/Core/Inc/ds18b20_driver.h
Normal file
104
new rev/john103C8T6/Core/Inc/ds18b20_driver.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ds18b20_driver.h
|
||||
* @brief This file contains all the constants parameters for the DS18B20
|
||||
* 1-Wire Digital Thermometer
|
||||
******************************************************************************
|
||||
* @attention
|
||||
* Usage:
|
||||
* Uncomment LL Driver for HAL driver
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef DS18B20_H
|
||||
#define DS18B20_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "onewire.h"
|
||||
#include "PROJ_setup.h"
|
||||
|
||||
|
||||
|
||||
/* Data Structure ------------------------------------------------------------*/
|
||||
#define DS18B20_DEVICE_AMOUNT MAX_SENSE
|
||||
|
||||
/* Register ------------------------------------------------------------------*/
|
||||
#define DS18B20_CMD_CONVERT 0x44
|
||||
#define DS18B20_CMD_ALARM_SEARCH 0xEC
|
||||
#define DS18B20_CMD_READSCRATCHPAD 0xBE
|
||||
#define DS18B20_CMD_WRITESCRATCHPAD 0x4E
|
||||
#define DS18B20_CMD_COPYSCRATCHPAD 0x48
|
||||
/* Data Structure ------------------------------------------------------------*/
|
||||
#define DS18B20_FAMILY_CODE 0x28
|
||||
|
||||
|
||||
#define DS18B20_SERIAL_NUMBER_LEN_BYTES 6
|
||||
#define DS18B20_SERIAL_NUMBER_OFFSET_BYTES 1
|
||||
|
||||
#define DS18B20_SCRATCHPAD_T_LSB_BYTE_IDX 0
|
||||
#define DS18B20_SCRATCHPAD_T_MSB_BYTE_IDX 1
|
||||
#define DS18B20_SCRATCHPAD_T_LIMIT_H_BYTE_IDX 2
|
||||
#define DS18B20_SCRATCHPAD_T_LIMIT_L_BYTE_IDX 3
|
||||
#define DS18B20_SCRATCHPAD_CONFIG_BYTE_IDX 4
|
||||
#define DS18B20_SCRATCHPAD_USER_BYTE_3_IDX 6
|
||||
#define DS18B20_SCRATCHPAD_USER_BYTE_4_IDX 7
|
||||
#define DS18B20_SCRATCHPAD_CRC_IDX 8
|
||||
|
||||
/* Bits locations for resolution */
|
||||
#define DS18B20_RESOLUTION_R1 6
|
||||
#define DS18B20_RESOLUTION_R0 5
|
||||
|
||||
#define DS18B20_DECIMAL_STEP_12BIT 0.0625
|
||||
#define DS18B20_DECIMAL_STEP_11BIT 0.125
|
||||
#define DS18B20_DECIMAL_STEP_10BIT 0.25
|
||||
#define DS18B20_DECIMAL_STEP_9BIT 0.5
|
||||
|
||||
#define DS18B20_DELAY_MS_9_BITS 94
|
||||
#define DS18B20_DELAY_MS_10_BITS 188
|
||||
#define DS18B20_DELAY_MS_11_BITS 375
|
||||
#define DS18B20_DELAY_MS_12_BITS 750
|
||||
#define DS18B20_DELAY_MS_MAX DS18B20_DELAY_MS_12_BITS
|
||||
|
||||
|
||||
/* DS18B20 Resolutions */
|
||||
typedef enum {
|
||||
DS18B20_RESOLUTION_9BITS = 0x1F,
|
||||
DS18B20_RESOLUTION_10BITS = 0x3F,
|
||||
DS18B20_RESOLUTION_11BITS = 0x5F,
|
||||
DS18B20_RESOLUTION_12BITS = 0x7F
|
||||
} DS18B20_Res_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t DevAddr[DS18B20_DEVICE_AMOUNT][8];
|
||||
} DS18B20_Drv_t;
|
||||
extern DS18B20_Drv_t DS;
|
||||
extern OneWire_t OW;
|
||||
|
||||
/* External Function ---------------------------------------------------------*/
|
||||
HAL_StatusTypeDef DS18B20_Search(DS18B20_Drv_t *DS, OneWire_t *OW);
|
||||
HAL_StatusTypeDef DS18B20_StartConvT(OneWire_t* OW, uint8_t *ROM);
|
||||
HAL_StatusTypeDef DS18B20_StartConvTAll(OneWire_t* OW);
|
||||
HAL_StatusTypeDef DS18B20_CalcTemperature(OneWire_t* OW, uint8_t *ROM, uint8_t *Scratchpad, float *destination);
|
||||
HAL_StatusTypeDef DS18B20_ReadScratchpad(OneWire_t* OW, uint8_t *ROM, uint8_t *Scratchpad);
|
||||
HAL_StatusTypeDef DS18B20_WaitForEndConvertion(OneWire_t* OW);
|
||||
HAL_StatusTypeDef DS18B20_WaitForEndConvertion_NonBlocking(OneWire_t* OW);
|
||||
HAL_StatusTypeDef DS18B20_SetTempAlarm(OneWire_t* OW, uint8_t *ROM, int8_t Low,
|
||||
int8_t High);
|
||||
HAL_StatusTypeDef DS18B20_WriteUserBytes(OneWire_t* OW, uint8_t *ROM, int16_t UserBytes12,
|
||||
int16_t UserBytes34, uint8_t UserBytesMask);
|
||||
uint8_t DS18B20_AlarmSearch(DS18B20_Drv_t *DS, OneWire_t* OW);
|
||||
|
||||
HAL_StatusTypeDef DS18B20_SetResolution(OneWire_t* OW, uint8_t *ROM,
|
||||
DS18B20_Res_t Resolution);
|
||||
HAL_StatusTypeDef DS18B20_IsValidAddress(uint8_t *ROM);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DS18B20_H */
|
||||
49
new rev/john103C8T6/Core/Inc/gpio.h
Normal file
49
new rev/john103C8T6/Core/Inc/gpio.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file gpio.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the gpio.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __GPIO_H__
|
||||
#define __GPIO_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_GPIO_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__ GPIO_H__ */
|
||||
|
||||
52
new rev/john103C8T6/Core/Inc/i2c.h
Normal file
52
new rev/john103C8T6/Core/Inc/i2c.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file i2c.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the i2c.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern I2C_HandleTypeDef hi2c1;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_I2C1_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __I2C_H__ */
|
||||
|
||||
150
new rev/john103C8T6/Core/Inc/main.h
Normal file
150
new rev/john103C8T6/Core/Inc/main.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
***************************************************************
|
||||
* 1 2 3 4 5 6 7 8 *
|
||||
* --- +++ *
|
||||
* *
|
||||
*****************************************************************
|
||||
|
||||
|
||||
******************************************************************************
|
||||
* @file : main.h
|
||||
* @brief : Header for main.c file.
|
||||
* This file contains the common defines of the application.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __MAIN_H
|
||||
#define __MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "Proj_setup.h"
|
||||
#include "dallas_tools.h"
|
||||
#include "modbus.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FuncOK=0,
|
||||
FuncERROR=1
|
||||
|
||||
}FuncStat;
|
||||
|
||||
|
||||
typedef enum {
|
||||
CONFIG_DEVICE_ID = 0,
|
||||
CONFIG_BAUDRATE,
|
||||
CONFIG_CALIBRATION,
|
||||
CONFIG_SETTINGS
|
||||
} ConfigParams;
|
||||
|
||||
|
||||
|
||||
typedef enum {
|
||||
STATE_OPEN_VALVE = 0, // open
|
||||
STATE_CLOSE_VALVE= 1 // close
|
||||
} ValveState;
|
||||
typedef struct
|
||||
{
|
||||
uint32_t id[2];
|
||||
float temp;
|
||||
uint16_t location;
|
||||
uint8_t t_open;
|
||||
float t_set;
|
||||
uint8_t t_close;
|
||||
uint8_t status_T_sense:1 ;
|
||||
ValveState state;
|
||||
uint16_t count;
|
||||
}TEMP_TypeDef;
|
||||
typedef struct {
|
||||
uint32_t init_tsens : 1; // Update Interrupt Flag (бит 0) — флаг переполнения/обновления
|
||||
|
||||
// ... (другие биты могут быть зарезервированы или использоваться в расширенных таймерах)
|
||||
} Flags_TypeDef;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN ET */
|
||||
#define reset_blink_delay 50
|
||||
#define rest_iter 10
|
||||
#define GPIOB11_valve MB_DATA.Coils.coils[0].state_val_bit.state_val_01
|
||||
#define ralay_5v_on GPIOA->ODR&(1<<10);
|
||||
|
||||
|
||||
|
||||
extern void handle_command(char* cmd);
|
||||
typedef void (*FunctionPointer)(void);
|
||||
|
||||
uint16_t handle_valves(TEMP_TypeDef* temp_sense[MAX_SENSE]);
|
||||
void init_setpoint_all_T_sense(TEMP_TypeDef* temp_sense, int size_array);
|
||||
void iwdg_refresh(void);
|
||||
void led_blink(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,uint8_t iter,uint16_t delay);
|
||||
FuncStat Field_modbus(MB_DataStructureTypeDef* MB_DATA, Flags_TypeDef* flag);
|
||||
FuncStat packStruct(MB_DataStructureTypeDef* MB_DATA,int sizeARR);
|
||||
void Check_Tconnect(MB_DataStructureTypeDef* MB_DATA, Flags_TypeDef* flag ,DALLAS_HandleTypeDef* hdallas, int a[50]);
|
||||
FuncStat value_control(void );
|
||||
|
||||
void reinit_t_sens(void);
|
||||
HAL_StatusTypeDef ModbusMaster_Request(RS_MsgTypeDef *request,
|
||||
void (*callback)(RS_HandleTypeDef *, RS_MsgTypeDef *));
|
||||
|
||||
/* USER CODE END ET */
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EC */
|
||||
|
||||
/* USER CODE END EC */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EM */
|
||||
|
||||
/* USER CODE END EM */
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
void Error_Handler(void);
|
||||
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
||||
/* USER CODE END EFP */
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
#define Relay_dc5v_Pin GPIO_PIN_10
|
||||
#define Relay_dc5v_GPIO_Port GPIOA
|
||||
#define One_wire_Pin GPIO_PIN_15
|
||||
#define One_wire_GPIO_Port GPIOA
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MAIN_H */
|
||||
77
new rev/john103C8T6/Core/Inc/onewire.h
Normal file
77
new rev/john103C8T6/Core/Inc/onewire.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file onewire.h
|
||||
* @brief This file contains all the constants parameters for the OneWire
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef ONEWIRE_H
|
||||
#define ONEWIRE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "ow_port.h"
|
||||
|
||||
/* Driver Selection ----------------------------------------------------------*/
|
||||
//#define LL_Driver
|
||||
//#define CMSIS_Driver
|
||||
/* OneWire Timings -----------------------------------------------------------*/
|
||||
#define ONEWIRE_RESET_PULSE_US 480 // Длительность импульса сброса
|
||||
#define ONEWIRE_PRESENCE_WAIT_US 70 // Ожидание ответа от датчика
|
||||
#define ONEWIRE_PRESENCE_DURATION_US 410 // Длительность сигнала присутствия
|
||||
|
||||
#define ONEWIRE_WRITE_1_US 8 // Длительность записи "1"
|
||||
#define ONEWIRE_WRITE_0_US 57 // Длительность записи "0"
|
||||
#define ONEWIRE_READ_CMD_US 2 // Время комманды чтения бита
|
||||
#define ONEWIRE_READ_DELAY_US 6 // Задержка перед считыванием бита
|
||||
#define ONEWIRE_COMMAND_SLOT_US 58 // Общее время комманды OneWire
|
||||
#define ONEWIRE_RECOVERY_TIME_US 1 // Восстановление перед следующим слотом
|
||||
/* Common Register -----------------------------------------------------------*/
|
||||
#define ONEWIRE_CMD_SEARCHROM 0xF0
|
||||
#define ONEWIRE_CMD_READROM 0x33
|
||||
#define ONEWIRE_CMD_MATCHROM 0x55
|
||||
#define ONEWIRE_CMD_SKIPROM 0xCC
|
||||
|
||||
/* Data Structure ------------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
Input,
|
||||
Output
|
||||
} PinMode;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t LastDiscrepancy;
|
||||
uint8_t LastFamilyDiscrepancy;
|
||||
uint8_t LastDeviceFlag;
|
||||
uint8_t RomByte[8];
|
||||
uint8_t RomCnt;
|
||||
uint16_t DataPin;
|
||||
GPIO_TypeDef *DataPort;
|
||||
} OneWire_t;
|
||||
|
||||
/* External Function ---------------------------------------------------------*/
|
||||
void OneWire_Init(OneWire_t* OW);
|
||||
uint8_t OneWire_Search(OneWire_t* OW, uint8_t Cmd);
|
||||
void OneWire_GetDevRom(OneWire_t* OW, uint8_t *dev);
|
||||
uint8_t OneWire_Reset(OneWire_t* OW);
|
||||
uint8_t OneWire_ReadBit(OneWire_t* OW);
|
||||
uint8_t OneWire_ReadByte(OneWire_t* OW);
|
||||
void OneWire_WriteByte(OneWire_t* OW, uint8_t byte);
|
||||
void OneWire_MatchROM(OneWire_t* OW, uint8_t *Rom);
|
||||
void OneWire_Skip(OneWire_t* OW);
|
||||
uint8_t OneWire_CRC8(uint8_t *addr, uint8_t len);
|
||||
|
||||
void OneWire_Pin_Mode(OneWire_t* OW, PinMode Mode);
|
||||
void OneWire_Pin_Level(OneWire_t* OW, uint8_t Level);
|
||||
uint8_t OneWire_Pin_Read(OneWire_t* OW);
|
||||
void OneWire_WriteBit(OneWire_t* OW, uint8_t bit);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ONEWIRE_H */
|
||||
60
new rev/john103C8T6/Core/Inc/ow_port.h
Normal file
60
new rev/john103C8T6/Core/Inc/ow_port.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file ow_port.h
|
||||
* @brief This file includes the driver for port for OneWire purposes
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef ONEWIRE_PORT_H
|
||||
#define ONEWIRE_PORT_H
|
||||
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
/* I/O Port ------------------------------------------------------------------*/
|
||||
//#define LL_Driver ///< использовать CMSIS для управления ножкой
|
||||
#define CMSIS_Driver ///< использовать CMSIS для управления ножкой
|
||||
// если ничего не выбрано - используется HAL
|
||||
|
||||
|
||||
/**
|
||||
* @def OW_GPIO_Port
|
||||
* @brief Порт вывода для шины 1-Wire.
|
||||
* @details Указывает порт GPIO, к которому подключена линия данных 1-Wire (например, для DS18B20).
|
||||
*/
|
||||
#define OW_GPIO_Port GPIOA
|
||||
|
||||
/**
|
||||
* @def OW_Pin_Numb
|
||||
* @brief Номер пина в порту OW_GPIO_Port.
|
||||
* @details Используется для формирования маски пина и настройки ввода/вывода.
|
||||
*/
|
||||
#define OW_Pin_Numb 15
|
||||
|
||||
/**
|
||||
* @def OW_Pin
|
||||
* @brief Маска пина, соответствующая номеру OW_Pin_Numb.
|
||||
* @details Используется при доступе к регистрам порта для управления состоянием линии 1-Wire.
|
||||
*/
|
||||
#define OW_Pin (1<<OW_Pin_Numb)
|
||||
|
||||
/**
|
||||
* @def OW_TIM
|
||||
* @brief Аппаратный таймер для формирования временных интервалов протокола 1-Wire.
|
||||
* @details Применяется для создания точных задержек при обмене данными по шине 1-Wire.
|
||||
*/
|
||||
#define OW_TIM TIM1
|
||||
|
||||
/**
|
||||
* @def OW_TIM_1US_PERIOD
|
||||
* @brief Количество тактов таймера OW_TIM, соответствующее 1 микросекунде.
|
||||
* @details Вычисляется на основе частоты таймера. Например, для таймера с частотой 24 МГц значение будет равно 24.
|
||||
*/
|
||||
#define OW_TIM_1US_PERIOD 72
|
||||
|
||||
|
||||
/* OneWire Timings -----------------------------------------------------------*/
|
||||
void OneWire_Delay_us(uint32_t us);
|
||||
/* Common Register -----------------------------------------------------------*/
|
||||
#endif /* ONEWIRE_PORT_H */
|
||||
65
new rev/john103C8T6/Core/Inc/rtc.h
Normal file
65
new rev/john103C8T6/Core/Inc/rtc.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the rtc.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __RTC_H__
|
||||
#define __RTC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t hours;
|
||||
uint16_t minutes;
|
||||
uint16_t seconds;
|
||||
uint16_t date;
|
||||
uint16_t month;
|
||||
uint16_t year;
|
||||
uint16_t weekday;
|
||||
} RTC_CalendarTypeDef;
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_RTC_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
uint8_t RTC_CalendarIsValid(const RTC_CalendarTypeDef *calendar);
|
||||
HAL_StatusTypeDef RTC_CalendarGet(RTC_CalendarTypeDef *calendar);
|
||||
HAL_StatusTypeDef RTC_CalendarSet(const RTC_CalendarTypeDef *calendar);
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RTC_H__ */
|
||||
|
||||
52
new rev/john103C8T6/Core/Inc/spi.h
Normal file
52
new rev/john103C8T6/Core/Inc/spi.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file spi.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the spi.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __SPI_H__
|
||||
#define __SPI_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern SPI_HandleTypeDef hspi1;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_SPI1_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SPI_H__ */
|
||||
|
||||
391
new rev/john103C8T6/Core/Inc/stm32f1xx_hal_conf.h
Normal file
391
new rev/john103C8T6/Core/Inc/stm32f1xx_hal_conf.h
Normal file
@@ -0,0 +1,391 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f1xx_hal_conf.h
|
||||
* @brief HAL configuration file.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F1xx_HAL_CONF_H
|
||||
#define __STM32F1xx_HAL_CONF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/* ########################## Module Selection ############################## */
|
||||
/**
|
||||
* @brief This is the list of modules to be used in the HAL driver
|
||||
*/
|
||||
|
||||
#define HAL_MODULE_ENABLED
|
||||
#define HAL_ADC_MODULE_ENABLED
|
||||
/*#define HAL_CRYP_MODULE_ENABLED */
|
||||
#define HAL_CAN_MODULE_ENABLED
|
||||
/*#define HAL_CAN_LEGACY_MODULE_ENABLED */
|
||||
/*#define HAL_CEC_MODULE_ENABLED */
|
||||
/*#define HAL_CORTEX_MODULE_ENABLED */
|
||||
/*#define HAL_CRC_MODULE_ENABLED */
|
||||
/*#define HAL_DAC_MODULE_ENABLED */
|
||||
/*#define HAL_DMA_MODULE_ENABLED */
|
||||
/*#define HAL_ETH_MODULE_ENABLED */
|
||||
/*#define HAL_FLASH_MODULE_ENABLED */
|
||||
#define HAL_GPIO_MODULE_ENABLED
|
||||
#define HAL_I2C_MODULE_ENABLED
|
||||
/*#define HAL_I2S_MODULE_ENABLED */
|
||||
/*#define HAL_IRDA_MODULE_ENABLED */
|
||||
/*#define HAL_IWDG_MODULE_ENABLED */
|
||||
/*#define HAL_NOR_MODULE_ENABLED */
|
||||
/*#define HAL_NAND_MODULE_ENABLED */
|
||||
/*#define HAL_PCCARD_MODULE_ENABLED */
|
||||
/*#define HAL_PCD_MODULE_ENABLED */
|
||||
/*#define HAL_HCD_MODULE_ENABLED */
|
||||
/*#define HAL_PWR_MODULE_ENABLED */
|
||||
/*#define HAL_RCC_MODULE_ENABLED */
|
||||
#define HAL_RTC_MODULE_ENABLED
|
||||
/*#define HAL_SD_MODULE_ENABLED */
|
||||
/*#define HAL_MMC_MODULE_ENABLED */
|
||||
/*#define HAL_SDRAM_MODULE_ENABLED */
|
||||
/*#define HAL_SMARTCARD_MODULE_ENABLED */
|
||||
#define HAL_SPI_MODULE_ENABLED
|
||||
/*#define HAL_SRAM_MODULE_ENABLED */
|
||||
#define HAL_TIM_MODULE_ENABLED
|
||||
#define HAL_UART_MODULE_ENABLED
|
||||
/*#define HAL_USART_MODULE_ENABLED */
|
||||
/*#define HAL_WWDG_MODULE_ENABLED */
|
||||
|
||||
#define HAL_CORTEX_MODULE_ENABLED
|
||||
#define HAL_DMA_MODULE_ENABLED
|
||||
#define HAL_FLASH_MODULE_ENABLED
|
||||
#define HAL_EXTI_MODULE_ENABLED
|
||||
#define HAL_GPIO_MODULE_ENABLED
|
||||
#define HAL_PWR_MODULE_ENABLED
|
||||
#define HAL_RCC_MODULE_ENABLED
|
||||
|
||||
/* ########################## Oscillator Values adaptation ####################*/
|
||||
/**
|
||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSE is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSE_STARTUP_TIMEOUT)
|
||||
#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
|
||||
#endif /* HSE_STARTUP_TIMEOUT */
|
||||
|
||||
/**
|
||||
* @brief Internal High Speed oscillator (HSI) value.
|
||||
* This value is used by the RCC HAL module to compute the system frequency
|
||||
* (when HSI is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/**
|
||||
* @brief Internal Low Speed oscillator (LSI) value.
|
||||
*/
|
||||
#if !defined (LSI_VALUE)
|
||||
#define LSI_VALUE 40000U /*!< LSI Typical Value in Hz */
|
||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
|
||||
The real value may vary depending on the variations
|
||||
in voltage and temperature. */
|
||||
|
||||
/**
|
||||
* @brief External Low Speed oscillator (LSE) value.
|
||||
* This value is used by the UART, RTC HAL module to compute the system frequency
|
||||
*/
|
||||
#if !defined (LSE_VALUE)
|
||||
#define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/
|
||||
#endif /* LSE_VALUE */
|
||||
|
||||
#if !defined (LSE_STARTUP_TIMEOUT)
|
||||
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
|
||||
#endif /* LSE_STARTUP_TIMEOUT */
|
||||
|
||||
/* Tip: To avoid modifying this file each time you need to use different HSE,
|
||||
=== you can define the HSE value in your toolchain compiler preprocessor. */
|
||||
|
||||
/* ########################### System Configuration ######################### */
|
||||
/**
|
||||
* @brief This is the HAL system configuration section
|
||||
*/
|
||||
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
|
||||
#define TICK_INT_PRIORITY 15U /*!< tick interrupt priority (lowest by default) */
|
||||
#define USE_RTOS 0U
|
||||
#define PREFETCH_ENABLE 1U
|
||||
|
||||
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
|
||||
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
|
||||
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
|
||||
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
|
||||
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
|
||||
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
|
||||
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
|
||||
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
|
||||
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
|
||||
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
|
||||
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
|
||||
#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */
|
||||
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
|
||||
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
|
||||
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
|
||||
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
|
||||
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
|
||||
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
|
||||
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
|
||||
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
|
||||
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
|
||||
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
|
||||
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
|
||||
|
||||
/* ########################## Assert Selection ############################## */
|
||||
/**
|
||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the
|
||||
* HAL drivers code
|
||||
*/
|
||||
/* #define USE_FULL_ASSERT 1U */
|
||||
|
||||
/* ################## Ethernet peripheral configuration ##################### */
|
||||
|
||||
/* Section 1 : Ethernet peripheral configuration */
|
||||
|
||||
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
|
||||
#define MAC_ADDR0 2U
|
||||
#define MAC_ADDR1 0U
|
||||
#define MAC_ADDR2 0U
|
||||
#define MAC_ADDR3 0U
|
||||
#define MAC_ADDR4 0U
|
||||
#define MAC_ADDR5 0U
|
||||
|
||||
/* Definition of the Ethernet driver buffers size and count */
|
||||
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
|
||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
|
||||
#define ETH_RXBUFNB 8U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
|
||||
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
|
||||
|
||||
/* Section 2: PHY configuration section */
|
||||
|
||||
/* DP83848_PHY_ADDRESS Address*/
|
||||
#define DP83848_PHY_ADDRESS 0x01U
|
||||
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
|
||||
#define PHY_RESET_DELAY 0x000000FFU
|
||||
/* PHY Configuration delay */
|
||||
#define PHY_CONFIG_DELAY 0x00000FFFU
|
||||
|
||||
#define PHY_READ_TO 0x0000FFFFU
|
||||
#define PHY_WRITE_TO 0x0000FFFFU
|
||||
|
||||
/* Section 3: Common PHY Registers */
|
||||
|
||||
#define PHY_BCR ((uint16_t)0x00) /*!< Transceiver Basic Control Register */
|
||||
#define PHY_BSR ((uint16_t)0x01) /*!< Transceiver Basic Status Register */
|
||||
|
||||
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
|
||||
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
|
||||
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
|
||||
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
|
||||
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
|
||||
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
|
||||
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
|
||||
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
|
||||
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
|
||||
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
|
||||
|
||||
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
|
||||
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
|
||||
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
|
||||
|
||||
/* Section 4: Extended PHY Registers */
|
||||
#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */
|
||||
|
||||
#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */
|
||||
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */
|
||||
|
||||
/* ################## SPI peripheral configuration ########################## */
|
||||
|
||||
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
|
||||
* Activated: CRC code is present inside driver
|
||||
* Deactivated: CRC code cleaned from driver
|
||||
*/
|
||||
|
||||
#define USE_SPI_CRC 0U
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Include module's header file
|
||||
*/
|
||||
|
||||
#ifdef HAL_RCC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_rcc.h"
|
||||
#endif /* HAL_RCC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_GPIO_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_gpio.h"
|
||||
#endif /* HAL_GPIO_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_EXTI_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_exti.h"
|
||||
#endif /* HAL_EXTI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DMA_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_dma.h"
|
||||
#endif /* HAL_DMA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ETH_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_eth.h"
|
||||
#endif /* HAL_ETH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_can.h"
|
||||
#endif /* HAL_CAN_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
|
||||
#include "Legacy/stm32f1xx_hal_can_legacy.h"
|
||||
#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CEC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_cec.h"
|
||||
#endif /* HAL_CEC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CORTEX_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_cortex.h"
|
||||
#endif /* HAL_CORTEX_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_ADC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_adc.h"
|
||||
#endif /* HAL_ADC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_CRC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_crc.h"
|
||||
#endif /* HAL_CRC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_DAC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_dac.h"
|
||||
#endif /* HAL_DAC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_FLASH_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_flash.h"
|
||||
#endif /* HAL_FLASH_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SRAM_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_sram.h"
|
||||
#endif /* HAL_SRAM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NOR_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_nor.h"
|
||||
#endif /* HAL_NOR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2C_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_i2c.h"
|
||||
#endif /* HAL_I2C_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_I2S_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_i2s.h"
|
||||
#endif /* HAL_I2S_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IWDG_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_iwdg.h"
|
||||
#endif /* HAL_IWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PWR_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_pwr.h"
|
||||
#endif /* HAL_PWR_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_RTC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_rtc.h"
|
||||
#endif /* HAL_RTC_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCCARD_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_pccard.h"
|
||||
#endif /* HAL_PCCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SD_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_sd.h"
|
||||
#endif /* HAL_SD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_NAND_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_nand.h"
|
||||
#endif /* HAL_NAND_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SPI_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_spi.h"
|
||||
#endif /* HAL_SPI_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_TIM_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_tim.h"
|
||||
#endif /* HAL_TIM_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_UART_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_uart.h"
|
||||
#endif /* HAL_UART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_USART_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_usart.h"
|
||||
#endif /* HAL_USART_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_IRDA_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_irda.h"
|
||||
#endif /* HAL_IRDA_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_SMARTCARD_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_smartcard.h"
|
||||
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_WWDG_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_wwdg.h"
|
||||
#endif /* HAL_WWDG_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_PCD_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_pcd.h"
|
||||
#endif /* HAL_PCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_HCD_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_hcd.h"
|
||||
#endif /* HAL_HCD_MODULE_ENABLED */
|
||||
|
||||
#ifdef HAL_MMC_MODULE_ENABLED
|
||||
#include "stm32f1xx_hal_mmc.h"
|
||||
#endif /* HAL_MMC_MODULE_ENABLED */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief The assert_param macro is used for function's parameters check.
|
||||
* @param expr If expr is false, it calls assert_failed function
|
||||
* which reports the name of the source file and the source
|
||||
* line number of the call that failed.
|
||||
* If expr is true, it returns no value.
|
||||
* @retval None
|
||||
*/
|
||||
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void assert_failed(uint8_t* file, uint32_t line);
|
||||
#else
|
||||
#define assert_param(expr) ((void)0U)
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F1xx_HAL_CONF_H */
|
||||
|
||||
76
new rev/john103C8T6/Core/Inc/stm32f1xx_it.h
Normal file
76
new rev/john103C8T6/Core/Inc/stm32f1xx_it.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f1xx_it.h
|
||||
* @brief This file contains the headers of the interrupt handlers.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __STM32F1xx_IT_H
|
||||
#define __STM32F1xx_IT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN ET */
|
||||
|
||||
/* USER CODE END ET */
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EC */
|
||||
|
||||
/* USER CODE END EC */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EM */
|
||||
|
||||
/* USER CODE END EM */
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void MemManage_Handler(void);
|
||||
void BusFault_Handler(void);
|
||||
void UsageFault_Handler(void);
|
||||
void SVC_Handler(void);
|
||||
void DebugMon_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
void RTC_IRQHandler(void);
|
||||
void TIM1_BRK_IRQHandler(void);
|
||||
void TIM1_UP_IRQHandler(void);
|
||||
void TIM1_TRG_COM_IRQHandler(void);
|
||||
void TIM1_CC_IRQHandler(void);
|
||||
void TIM2_IRQHandler(void);
|
||||
void TIM3_IRQHandler(void);
|
||||
void TIM4_IRQHandler(void);
|
||||
void USART1_IRQHandler(void);
|
||||
void USART2_IRQHandler(void);
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
||||
/* USER CODE END EFP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STM32F1xx_IT_H */
|
||||
57
new rev/john103C8T6/Core/Inc/tim.h
Normal file
57
new rev/john103C8T6/Core/Inc/tim.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file tim.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the tim.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __TIM_H__
|
||||
#define __TIM_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern TIM_HandleTypeDef htim4;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_TIM1_Init(void);
|
||||
void MX_TIM2_Init(void);
|
||||
void MX_TIM4_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TIM_H__ */
|
||||
|
||||
54
new rev/john103C8T6/Core/Inc/usart.h
Normal file
54
new rev/john103C8T6/Core/Inc/usart.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file usart.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the usart.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __USART_H__
|
||||
#define __USART_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern UART_HandleTypeDef huart1;
|
||||
extern UART_HandleTypeDef huart2;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_USART1_UART_Init(void);
|
||||
void MX_USART2_UART_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __USART_H__ */
|
||||
|
||||
129
new rev/john103C8T6/Core/Src/UART_TERM.c
Normal file
129
new rev/john103C8T6/Core/Src/UART_TERM.c
Normal file
@@ -0,0 +1,129 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "def.h"
|
||||
//extern uint8_t devices_found ;
|
||||
extern uint8_t roms[MAX_DEVICES][8];
|
||||
extern char rx_buffer[64];
|
||||
extern TEMP_TypeDef temp_sense[30];
|
||||
extern uint8_t init;
|
||||
int test_var=0;
|
||||
//void handle_command(char* cmd)
|
||||
//
|
||||
//{
|
||||
// if (strncmp(cmd, "list", 4) == 0)
|
||||
// {
|
||||
// printf("find %d devices:\r\n", devices_found);
|
||||
// for (int i = 0; i < devices_found; i++)
|
||||
// {
|
||||
// printf("Device #%d: ", i);
|
||||
// for (int j = 0; j < 8; j++)
|
||||
// printf("%02X ", roms[i][j]);
|
||||
// printf("\r\n");
|
||||
// }
|
||||
// }
|
||||
// else if (strncmp(cmd, "temp all", 8) == 0)
|
||||
// {
|
||||
// for (int i = 0; i < devices_found; i++)
|
||||
// {
|
||||
// ds_reset();
|
||||
// ds_write_byte(0x55);
|
||||
// for (int j = 0; j < 8; j++)
|
||||
// ds_write_byte(roms[i][j]);
|
||||
// ds_write_byte(0x44);
|
||||
// }
|
||||
|
||||
// HAL_Delay(750);
|
||||
|
||||
// for (int i = 0; i < devices_found; i++)
|
||||
// {
|
||||
// ds_reset();
|
||||
// ds_write_byte(0x55);
|
||||
// for (int j = 0; j < 8; j++)
|
||||
// ds_write_byte(roms[i][j]);
|
||||
// ds_write_byte(0xBE);
|
||||
// uint8_t tl = ds_read_byte();
|
||||
// uint8_t th = ds_read_byte();
|
||||
// int16_t t = (th << 8) | tl;
|
||||
// float temp = t / 16.0;
|
||||
// printf("T[%d] = %.2f C\r\n", i, temp);
|
||||
// }
|
||||
// }
|
||||
// else if (strncmp(cmd, "temp ", 5) == 0)
|
||||
// {
|
||||
// int id = atoi(&cmd[5]);
|
||||
// if (id < 0 || id >= devices_found)
|
||||
// {
|
||||
// printf("unknown ID\r\n");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// ds_reset();
|
||||
// ds_write_byte(0x55);
|
||||
// for (int j = 0; j < 8; j++)
|
||||
// ds_write_byte(roms[id][j]);
|
||||
// ds_write_byte(0x44);
|
||||
// HAL_Delay(750);
|
||||
|
||||
// ds_reset();
|
||||
// ds_write_byte(0x55);
|
||||
// for (int j = 0; j < 8; j++)
|
||||
// ds_write_byte(roms[id][j]);
|
||||
// ds_write_byte(0xBE);
|
||||
// uint8_t tl = ds_read_byte();
|
||||
// uint8_t th = ds_read_byte();
|
||||
// int16_t t = (th << 8) | tl;
|
||||
// float temp = t / 16.0;
|
||||
// printf("T[%d] = %.2f C\r\n", id, temp);
|
||||
// }
|
||||
// else if (strncmp(cmd, "ts_1_open_minus",15 ) == 0)
|
||||
// {
|
||||
// temp_sense[0].t_open-=1;
|
||||
//
|
||||
// }
|
||||
// else if (strncmp(cmd, "ts_1_open_plus",14 ) == 0)
|
||||
// {
|
||||
// temp_sense[0].t_open+=1;
|
||||
//
|
||||
// }
|
||||
// else if (strncmp(cmd, "ts_1_close_minus",16 ) == 0)
|
||||
// {
|
||||
// temp_sense[0].t_close-=1;
|
||||
//
|
||||
// }
|
||||
// else if (strncmp(cmd, "ts_1_close_plus",15 ) == 0)
|
||||
// {
|
||||
//
|
||||
// temp_sense[0].t_close+=1;
|
||||
// }
|
||||
// else if (strncmp(cmd, "init",4 ) == 0)
|
||||
// {
|
||||
// init=1;
|
||||
// printf("init %s\r\n", "OK");
|
||||
// }
|
||||
// else if
|
||||
// (strncmp(cmd, "set_temp ", 9) == 0)
|
||||
// {
|
||||
// uint8_t sense_num = (atoi(&cmd[9])&0x7c0)>>10;
|
||||
// int parse_uart=atoi(&cmd[10]);
|
||||
//
|
||||
// temp_sense[sense_num].t_set=(float)parse_uart/10.;
|
||||
// printf("temp_sense %i %s\r\n",sense_num, "OK");
|
||||
//
|
||||
//
|
||||
// }
|
||||
// else if (strncmp(cmd, "temp ", 5) == 0)
|
||||
// {
|
||||
//
|
||||
//
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// printf("unknown CMD: %s\r\n", cmd);
|
||||
// for (int i=0;i<63;i++)
|
||||
// rx_buffer[i]=0;
|
||||
//
|
||||
// }
|
||||
//}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user