Инструкция по подключению релиза библиотеки 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
  1. Скопируйте файлы конфигурации в отдельную папку в вашем проекте (вне субмодуля) и удалите __ из имени файлов:
ProjectRoot/
├── Configs/
│   ├── modbus_config.h          # скопировать из __modbus_config.h
│   ├── modbus_data.h            # скопировать из __modbus_data.h
│   └── modbus_data.c            # скопировать из __modbus_data.c
└── Modbus/						 # Субмодуль
  1. Настройте конфигурацию под ваш проект:

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

    #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 (только чтение)

    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);  // Включить Relay1
    MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2
    
    // Чтение 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);
    }	
    
  2. Обновление библиотеки:

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

git submodule update --remote
Description
Библиотека модбас для STM32
Readme 18 MiB
Languages
C 100%