Files
STM32_Modbus/README.md
2026-02-20 11:26:15 +03:00

12 KiB
Raw Permalink Blame History

Инструкция по подключению релиза библиотеки 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
│   ├── modbus_master.h         # Заголовочный файл Master режима                       ├── modbus_diag
│   ├── modbus_slave.h          # Заголовочный файл Slave режима                        ├── modbus_oscil
│   ├── modbus_diag.h           # Диагностика Modbus                                    └── rs_message
│   ├── modbus_oscil.h          # Осциллографирование данных                                    │
│   └── rs_message.h            # Драйвер обмена по RS/UART                                      └── modbus_core (единое ядро)
├── src/                                                                                             ├── modbus_config
│   ├── modbus.c                # Основная логика Modbus                                             ├── modbus_data
│   ├── modbus_slave.c          # Основная логика Slave Modbus                                       └── __crc_algs
│   ├── modbus_master.c         # Основная логика Master Modbus
│   ├── modbus_coils.c          # Реализация работы с coils
│   ├── modbus_holdregs.c       # Реализация регистров хранения
│   ├── modbus_inputregs.c      # Реализация входных регистров
│   ├── modbus_devid.c          # Реализация идентификации устройства
│   ├── modbus_diag.c           # Диагностические функции и счетчики ошибок
│   ├── modbus_oscil.c          # Сбор и хранение осциллограмм
│   └── rs_message.c            # Реализация драйвера RS                        
├── __modbus_config.h       # Конфигурация Modbus (надо заменить)                       
├── __modbus_data.h         # Структуры данных (надо заменить)                      
└── __modbus_data.c         # Функции доступа (надо заменить)     

Инструкция по подключению

1. Склонируйте субмодуль в ваш проект:

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-обработчиков:

#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:

#include "modbus.h"

// TxEnable: 1 - передача, 0 - прием
void SetTxDirectionFunc(int TxEnable)
{
  HAL_GPIO_WritePin(SCIDE1_GPIO_Port, SCIDE1_Pin, !TxEnable);
}

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, &SetTxDirectionFunc);
    MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
    
    // Запуск приема Modbus
    MODBUS_SlaveStart(&hmodbus1, NULL);
    
    while (1)
    {
        // Основной цикл
    }
}

Чтобы настроить Master-режим main() после инициализации HAL:

#include "modbus.h"

// Инициализация Modbus
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, &SetTxDirectionFunc);
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
    

// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
// При получении ответа вызовется функция callback_func()
RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func);

// коллбек, вызовется при получении ответа от слейва
read_hold[10];
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) 
{
    // MB_RespGet_... Чтобы достать нужные данные из ответа

    if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок
    {
        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;
        }
        }
    }
    else // Ответ получен с ошибкой или не получен вовсе
    {
    }
}

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. Настройка карты данных (только для режима Slave)

В modbus_data.h настройте регистры и coils под ваше устройство:

Input Registers (только чтение)

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 (чтение/запись)

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-битные)

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. Доступ к данным в коде

В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля

// Чтение входных регистров
uint16_t temp = MB_DATA.InRegs.Temperature;

// Запись в регистры хранения
MB_DATA.HoldRegs.SetpointTemp = 2500;

// Управление coils
MB_Coil_Set_Local(&MB_DATA.Coils, 0);  // Включить 0 бит в Coils
MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить 1 бит в Coils

// Чтение coil
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
    // Pump включен
}

В режиме мастера есть функции для получения информации из ответа MB_RespGet_...()

//  Чтение регистров: Получить запрошенные регистры
uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, &reg_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, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся:

git submodule update --remote