Modbus 0.3
Библиотека Modbus для STM
Loading...
Searching...
No Matches
Инструкция по подключению релиза библиотеки 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. Склонируйте субмодуль в ваш проект:

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)
{
return;
HAL_UART_IRQHandler(&huart);
}
void TIMx_IRQHandler(void)
{
return;
HAL_TIM_IRQHandler(&htim);
}
void RS_TIM_Handler(RS_HandleTypeDef *hRS)
Обработчик прерывания TIM.
Definition rs_message.c:433
void RS_UART_Handler(RS_HandleTypeDef *hRS)
Обработчик прерывания UART.
Definition rs_message.c:320
RS_HandleTypeDef hmodbus1
Default Handle for Modbus.
Definition modbus.c:24
Главный заголовочный файл Modbus библиотеки

3.3. В modbus_config.h укажите параметры устройства

3.4. Инициализация в коде

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

#include "modbus.h"
int main(void)
{
// Инициализация HAL
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
// Инициализация Modbus
// Запуск приема Modbus
while (1)
{
// Основной цикл
}
}
#define mb_huart
Удобный дефайн для модбасовского uart.
#define MODBUS_TIMEOUT
Таймаут в тиках таймера
#define mb_htim
Удобный дефайн для модбасовского таймера
#define MODBUS_DEVICE_ID
Адрес устройства в сети Modbus.
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
Программная конфигурация модбас.
Definition modbus.c:72
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
Запуск слейв модбас.
Definition modbus.c:105
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
Инициализация периферии модбас.
Definition modbus.c:42
#define MODBUS_MODE_SLAVE
Псевдо-enum: Режим слейв
Definition modbus.h:117

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

#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;
{
read_hold[i] = value;
}
}
}
}
int main(void)
{
// Инициализация HAL
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
// Инициализация Modbus
// Запрос по Modbus
MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func);
}
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void(*pClbk)(RS_HandleTypeDef *, RS_MsgTypeDef *))
Реквест мастера модбас.
Definition modbus.c:136
#define MODBUS_MODE_MASTER
Псевдо-enum: Режим мастер
Definition modbus.h:113
RS_MsgTypeDef MODBUS_MSG
Default Message Struct for Modbus.
Definition modbus.c:25
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value)
Получить значение регистра в ответе по его адресу
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
Сформировать запрос на чтение холдинг регистров
Handle for RS communication.
Definition rs_message.h:228
RS_StatusTypeDef RS_STATUS
Статус RS.
Definition rs_message.h:247
Structure for modbus messsage.

3.5. Настройка карты данных

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

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

typedef struct
{
uint16_t Temperature; // Адрес 0
uint16_t Humidity; // Адрес 1
uint16_t Pressure; // Адрес 2
uint16_t Voltage; // Адрес 3
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров
#define R_INPUT_QNT 4 // Количество Input регистров
Регистры хранения
Definition modbus_data.h:91

Holding Registers (чтение/запись)

typedef struct
{
uint16_t SetpointTemp; // Адрес 0
uint16_t SetpointHumidity; // Адрес 1
uint16_t ControlMode; // Адрес 2
#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 бит)
#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); // Включить Relay1
MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2
// Чтение coil
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
// Pump включен
}
#define MB_Coil_Read_Local(_parr_, _coil_)
Считать коил по локальному адресу.
#define MB_Coil_Set_Local(_parr_, _coil_)
Выставить коил по локальному адресу.
#define MB_Coil_Reset_Local(_parr_, _coil_)
Сбросить коил по локальному адресу.

В режиме мастера есть функции для получения информации из ответа 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);
}
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state)
Получить состояние coil в ответе по его адресу
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length)
Найти объект по ID в сообщении
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length)
Получить объект по индексу в сообщении

5. Обновление библиотеки:

После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся:

git submodule update --remote