258 lines
11 KiB
Markdown
258 lines
11 KiB
Markdown
# Инструкция по подключению релиза библиотеки `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
|
||
``` |