Добавлен осцилограф на Modbus
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
108
Inc/modbus_oscil.h
Normal 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
145
Src/modbus_oscil.c
Normal 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
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user