Добавлен осцилограф на Modbus

This commit is contained in:
2026-02-14 19:00:40 +03:00
parent f03ffd5bfc
commit c4c8024512
6 changed files with 263 additions and 2 deletions

View File

@@ -107,6 +107,10 @@
#ifdef MODBUS_ENABLE_DIAGNOSTICS
#include "modbus_diag.h"
#endif
#ifdef MODBUS_ENABLE_OSCIL
#include "modbus_oscil.h"
#endif
#include "modbus_data.h"
#ifdef MODBUS_ENABLE_MASTER

View File

@@ -27,7 +27,6 @@
#define __MODBUS_CORE_H_
#include "modbus_config.h"
#include "modbus_data.h"
#include "__crc_algs.h"
/**

108
Inc/modbus_oscil.h Normal file
View File

@@ -0,0 +1,108 @@
/**
*******************************************************************************
* @file modbus_oscil.h
* @brief Заголовочный файл модуля осциллографа через MODBUS.
*******************************************************************************
* @addtogroup MODBUS_OSCIL Modbus Oscilloscope
* @ingroup MODBUS
* @brief Модуль для сбора и хранения данных осциллографа
* @details
* Реализует кольцевой буфер для хранения данных с нескольких каналов
* с возможностью чтения через Modbus. Данные 8-битные, упаковываются
* по 2 сэмпла в 16-битный регистр Modbus.
*
* Карта Modbus регистров (адрес относительный):
* | Адрес | Биты | Назначение | Диапазон | Описание |
* |--------|------|------------|----------|----------|
* | 0x0000 | 0-3 | channels | 1-16 | Количество каналов |
* | | 4-7 | reserved | 0 | Зарезервировано |
* | | 8-15 | buffer_size| 1-125 | Размер буфера в регистрах |
* | 0x0001 | 0-7 | tail | 0-124 | Начало новых данных |
* | | 8-15 | head | 0-124 | Конец новых данных |
* | 0x0002...| 0-15| data | - | Буфер данных |
* @{
******************************************************************************/
#ifndef __MODBUS_OSCIL_H_
#define __MODBUS_OSCIL_H_
#include "modbus_core.h"
#ifdef MODBUS_ENABLE_OSCIL
/**
* @brief Структура конфигурации осциллографа
*/
typedef struct
{
uint16_t Overrun:1; ///< Overrun
uint16_t NumbOfChannels:4; ///< Количество каналов (1-16)
uint16_t BufferSize:7; ///< Размер буфера в регистрах (1-125)
uint16_t SampleTime; ///< Время между сэмплами в мкс/мс
uint32_t LastTick; ///< Время последнего добавления
} MB_ConfigTypeDef;
/**
* @brief Структура указателей буфера
*/
typedef struct
{
uint16_t Head:8; ///< Указатель на последний записанный байт
uint16_t Tail:8; ///< Указатель на начало непрочитанных данных (байты)
} MB_PreambleTypeDef;
/**
* @brief Основная структура осциллографа
*/
typedef struct
{
MB_ConfigTypeDef Config; ///< Конфигурация
uint16_t User[6];
MB_PreambleTypeDef Preamble; ///< Указатели буфера
uint8_t Data[MbData_size*2-1]; ///< Буфер данных (в байтах)
} MB_OscilTypeDef;
/**
* @addtogroup MODBUS_OSCIL_API API for Oscilloscope
* @ingroup MODBUS_OSCIL
* @brief API для работы с буфером осциллографа
* @details Примеры использования:
* @code
* MB_OscilTypeDef oscil;
*
* // Инициализация осциллографа
* MB_Oscil_Init(&oscil, 120, 4, 1000);
*
* // В цикле сбора данных
* uint8_t ch_data[4] = {adc1, adc2, adc3, adc4};
* MB_Oscil_Add(&oscil, ch_data);
*
* // После чтения данных через Modbus
* MB_Oscil_UpdateTail(&oscil);
* @endcode
* @{
*/
/* Инициализация структуры осциллографа */
HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime);
/* Добавление данных всех каналов в буфер */
HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data);
/* Обновление указателя Tail */
HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil);
/** MODBUS_OSCIL_API
* @}
*/
#endif //MODBUS_ENABLE_OSCIL
#endif //__MODBUS_OSCIL_H_
/** MODBUS_OSCIL
* @}
*/

145
Src/modbus_oscil.c Normal file
View File

@@ -0,0 +1,145 @@
/**
*******************************************************************************
* @file modbus_oscil.c
* @brief Модуль для реализации осциллографа через MODBUS.
*******************************************************************************
* @details
* Файл содержит реализацию функций для работы с буфером осциллографа.
*
* @section oscil_functions Функции
* - MB_Oscil_Init() — Инициализация структуры осциллографа
* - MB_Oscil_Add() — Добавление данных в буфер
* - MB_Oscil_UpdateTail() — Обновление указателя Tail
******************************************************************************/
#include "modbus_oscil.h"
#ifdef MODBUS_ENABLE_OSCIL
/**
* @brief Инициализация структуры осциллографа
* @param oscil Указатель на структуру осциллографа
* @param BufferSize Размер буфера в Modbus регистрах (max 125)
* @param NumbOfChannels Количество каналов (должно быть четным)
* @param SampleTime Период дискретизации
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime)
{
if(!oscil || (BufferSize >= MbData_size) || (NumbOfChannels > 15) || !SampleTime)
return HAL_ERROR;
if(NumbOfChannels % 2 != 0)
return HAL_ERROR;
oscil->Config.BufferSize = BufferSize;
oscil->Config.NumbOfChannels = NumbOfChannels;
oscil->Config.SampleTime = SampleTime;
oscil->Config.LastTick = 0;
oscil->Preamble.Head = 0;
oscil->Preamble.Tail = 0;
oscil->Config.Overrun = 0;
return HAL_OK;
}
/**
* @brief Инициализация структуры осциллографа
* @param oscil Указатель на структуру осциллографа
* @param BufferSize Размер буфера в Modbus регистрах (max 125)
* @param NumbOfChannels Количество каналов (должно быть четным)
* @param SampleTime Период дискретизации
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Set_SampleTime(MB_OscilTypeDef *oscil, uint16_t SampleTime)
{
if(!oscil || !SampleTime)
return HAL_ERROR;
oscil->Config.SampleTime = SampleTime;
return HAL_OK;
}
/**
* @brief Добавление данных всех каналов в буфер
* @param oscil Указатель на структуру осциллографа
* @param Data Массив с данными каналов (длина = NumbOfChannels)
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data)
{
if(!oscil || !Data)
return HAL_ERROR;
if(local_time() - oscil->Config.LastTick < oscil->Config.SampleTime)
return HAL_BUSY;
oscil->Config.LastTick = local_time();
uint8_t head_max = oscil->Config.BufferSize * 2;
uint8_t start_pos = oscil->Preamble.Head;
uint8_t channels = oscil->Config.NumbOfChannels;
uint8_t tail = oscil->Preamble.Tail;
// Пишем данные
for(uint8_t i = 0; i < channels; i++)
{
uint8_t write_pos = (start_pos + i) % head_max;
oscil->Data[write_pos] = Data[i];
}
// Новое положение Head
uint8_t new_head = (start_pos + channels) % head_max;
// Проверяем, есть ли непрочитанные данные (Tail != Head)
// if(tail != start_pos) {
// Если есть непрочитанные данные, проверяем не перетерли ли мы их
if(start_pos < new_head) {
// Линейный случай
if(tail > start_pos && tail <= new_head) {
oscil->Preamble.Tail = (new_head + 1) % head_max;
oscil->Config.Overrun = 1;
}
} else if(start_pos > new_head) {
// Кольцевой случай (было переполнение)
if(tail > start_pos || tail <= new_head) {
oscil->Preamble.Tail = (new_head + 1) % head_max;
oscil->Config.Overrun = 1;
}
}
// }
oscil->Preamble.Head = new_head;
return HAL_OK;
}
/**
* @brief Обновление указателя Tail
* @param oscil Указатель на структуру осциллографа
* @return HAL Status
*
* @details Вызывается после того, как данные были прочитаны через Modbus.
* Tail устанавливается на следующий байт за Head.
*/
HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil)
{
if(!oscil)
return HAL_ERROR;
// Сдвигаем Tail на следующий байт за Head
uint8_t head_max = oscil->Config.BufferSize * 2;
oscil->Preamble.Tail = oscil->Preamble.Head;
if(oscil->Preamble.Tail >= head_max)
oscil->Preamble.Tail = 0;
oscil->Config.Overrun = 0;
return HAL_OK;
}
#endif //MODBUS_ENABLE_OSCIL

View File

@@ -49,6 +49,11 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
// Read Hodling Registers
case FC_R_HOLD_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
#ifdef MODBUS_ENABLE_OSCIL
int is_oscil_data_register = ((hmodbus->pMessagePtr->Addr >= R_HOLDING_OSCIL_ADDR+4) && (hmodbus->pMessagePtr->Addr + hmodbus->pMessagePtr->Qnt <= (R_HOLDING_OSCIL_ADDR+5+(sizeof(MB_OscilTypeDef)/2))));
if(is_oscil_data_register)
MB_Oscil_UpdateTail(&MB_INTERNAL.oscil);
#endif
break;
case FC_R_IN_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);