Другое

Руководство по триггерам цифрового вывода в Dewesoft C++

Полное руководство по реализации триггеров цифрового вывода в модуле Dewesoft C++. Узнайте, как отправлять импульсы 5В с определенными интервалами с рабочими примерами кода.

Как реализовать систему триггера цифрового вывода в модуле C++ Dewesoft для отправки импульсов 5В с определенными интервалами?

Я пытаюсь реализовать систему триггера цифрового вывода в скриптовом модуле C++ Dewesoft, которая отправляет импульсы 5В через каналы DO1 и DO2 с определенными интервалами (25 мс и 50 мс соответственно). Несмотря на то, что я следовал онлайн-курсу и реализовал, как мне кажется, правильный код, я не могу заставить систему срабатывать должным образом.

Вот мой подход к реализации:

  1. Я настроил входной канал как временной сигнал (требуется Dewesoft)
  2. Я настроил два выходных канала для цифрового вывода 1 и 2
  3. Я связал выводы цифрового вывода с программными выходами
  4. Я реализовал следующий код:
cpp
namespace bsc = Dewesoft::Math::Api::Basic;

class Module : public bsc::MathModule {
public:
    Module();
    ~Module();

    void configure() override;
    void start() override;
    void stop() override;
    void clear() override;

    // Outputs have been mapped to Ctrl DO1 / Ctrl DO2 in A/D out
    double PyroOneOut = 0.0;   // "First Pyro's Output"
    double PyroTwoOut = 0.0;   // "Second Pyro's Out"

private:
    // Timing parameters (ms)
    const double t1_ms    = 25.0;  // DO1 fires at 25 ms
    const double t2_ms    = 50.0;  // DO2 fires at 50 ms
    const double width_ms = 5.0;   // pulse width

    // Internal clock
    std::chrono::steady_clock::time_point t0;
};

inline void Module::start() {
    t0 = std::chrono::steady_clock::now();
    PyroOneOut = 0.0;
    PyroTwoOut = 0.0;
}

inline void Module::calculate() {
    using namespace std::chrono;

    const double ms =
        duration<double, std::milli>(steady_clock::now() - t0).count();

    const bool do1_high = (ms >= t1_ms) && (ms < (t1_ms + width_ms));
    const bool do2_high = (ms >= t2_ms) && (ms < (t2_ms + width_ms));

    PyroOneOut = do1_high ? 1.0 : 0.0;
    PyroTwoOut = do2_high ? 1.0 : 0.0;
}

Проблема в том, что несмотря на эту реализацию, цифровые выводы не срабатывают как ожидается. Не мог бы кто-то, имеющий опыт работы с модулем C++ Dewesoft, определить, что может быть не так с моим подходом или кодом? Любые рекомендации по правильной реализации таймированных триггеров цифрового вывода в Dewesoft были бы очень признательны.

Триггеры цифрового вывода в модуле C++ Dewesoft

Триггеры цифрового вывода в модуле C++ Dewesoft требуют правильной настройки каналов, реализации тайминга в методе calculate() и корректного отображения вывода. Ваш подход в целом верный, но отсутствуют несколько критических деталей реализации, включая правильные объявления методов, расчет тайминга с использованием внутренней системы тайминга Dewesoft и требования к настройке каналов.

Содержание

Распространенные проблемы в реализации цифрового вывода C++ в Dewesoft

Существует несколько распространенных проблем, которые мешают правильной работе триггеров цифрового вывода в модулях C++ Dewesoft:

Отсутствующие объявления методов: Как указано в учебных материалах Dewesoft, метод calculate() должен быть правильно объявлен в интерфейсе класса, а не только реализован. Это частая ошибка, которая предотвращает работу модуля.

Неправильный подход к таймингу: Прямое использование std::chrono::steady_clock может не соответствовать внутренней системе тайминга Dewesoft. В руководстве по C++ Script указано, что тайминг должен основываться на переменной callInfo.endBlockTime для обработки на основе блоков или на временных метках отдельных выборок.

Нарушения потокобезопасности: Согласно документации Dewesoft, “Запись в выходные каналы и чтение из входных каналов допустимы только внутри процедуры ::calculate(), и только из основного потока! Попытки сделать это из любой другой функции или любого другого потока могут привести к сбою вашего плагина!”

Отсутствующая настройка каналов: Временной сигнал входного канала, упомянутый в вашем подходе, должен быть правильно настроен в методе configure(), который в настоящее время отсутствует в вашей реализации.


Правильная структура модуля C++ и реализация методов

Полный модуль C++ Dewesoft требует правильных объявлений и реализаций методов на протяжении всего жизненного цикла модуля. Вот исправленная структура:

cpp
namespace bsc = Dewesoft::Math::Api::Basic;

class Module : public bsc::MathModule {
public:
    Module();
    ~Module();

    // Требуемые методы жизненного цикла
    void configure() override;
    void start() override;
    void stop() override;
    void clear() override;
    
    // Метод calculate() - ОБЯЗАТЕЛЕН для обработки
    void calculate() override;

    // Выходные каналы
    double PyroOneOut = 0.0;   // "Выход первого пиро"
    double PyroTwoOut = 0.0;   // "Выход второго пиро"

private:
    // Параметры тайминга (мс)
    const double t1_ms = 25.0;  // DO1 срабатывает через 25 мс
    const double t2_ms = 50.0;  // DO2 срабатывает через 50 мс
    const double width_ms = 5.0;   // ширина импульса
    
    // Внутреннее состояние тайминга
    double startTime_ms = 0.0;
    bool measurementStarted = false;
};

Ключевые улучшения:

  • Добавлено объявление метода calculate()
  • Улучшено управление состоянием тайминга
  • Добавлен флаг measurementStarted для правильного управления жизненным циклом

Метод configure() должен быть реализован для установки свойств каналов и их взаимосвязей:

cpp
void Module::configure() {
    // Настройка входного канала как временного сигнала
    // Это необходимо для правильного тайминга в Dewesoft
    setInputChannel(0, "TimeSignal", "Time Signal");
    
    // Настройка выходных каналов
    setOutputChannel(0, "PyroOneOut", "First Pyro's Output", "V");
    setOutputChannel(1, "PyroTwoOut", "Second Pyro's Output", "V");
    
    // Установка свойств выходного канала для цифрового вывода
    setOutputChannelProperty(0, "DigitalOutput", "Ctrl DO1");
    setOutputChannelProperty(1, "DigitalOutput", "Ctrl DO2");
}

Лучшие практики расчета тайминга

Правильная реализация тайминга критически важна для триггеров цифрового вывода. Модуль C++ Dewesoft работает с двумя подходами к таймингу:

Обработка на основе выборок

Для обработки на основе выборок тайминг должен рассчитываться с использованием временной метки текущей выборки:

cpp
void Module::calculate() {
    // Получение текущего времени выборки в миллисекундах
    double currentTime_ms = getSampleTime(0) * 1000.0; // Преобразование в мс
    
    if (!measurementStarted) {
        startTime_ms = currentTime_ms;
        measurementStarted = true;
    }
    
    double elapsedTime_ms = currentTime_ms - startTime_ms;
    
    // Расчет состояний цифрового вывода
    const bool do1_high = (elapsedTime_ms >= t1_ms) && 
                         (elapsedTime_ms < (t1_ms + width_ms));
    const bool do2_high = (elapsedTime_ms >= t2_ms) && 
                         (elapsedTime_ms < (t2_ms + width_ms));
    
    // Установка значений вывода (1.0 для ВЫСОКИЙ уровень, 0.0 для НИЗКИЙ уровень)
    PyroOneOut = do1_high ? 1.0 : 0.0;
    PyroTwoOut = do2_high ? 1.0 : 0.0;
    
    // Опционально: сброс тайминга для непрерывной работы
    if (elapsedTime_ms > (t2_ms + width_ms + 1000.0)) {
        startTime_ms = currentTime_ms;
    }
}

Обработка на основе блоков

Для обработки на основе блоков используйте endBlockTime, как указано в руководстве по C++ Script:

cpp
void Module::calculate(const Dewesoft::Math::Api::CallInfo& callInfo) {
    // Использование времени окончания блока для тайминга
    double currentTime_ms = callInfo.endBlockTime * 1000.0;
    
    // ... остальная логика тайминга остается прежней ...
}

Критические соображения по таймингу:

  • Всегда используйте внутреннюю систему тайминга Dewesoft, а не внешние источники времени
  • Правильно обрабатывайте жизненный цикл измерения с помощью методов start/stop
  • Учитывайте режимы непрерывной и однократной работы
  • Учитывайте задержки обработки блоков в расчетах тайминга

Настройка каналов и отображение вывода

Правильная настройка каналов необходима для работы триггеров цифрового вывода. Вот пошаговый процесс настройки:

Настройка входного канала

  1. Добавьте входной канал временного сигнала в настройках Dewesoft
  2. Сопоставьте этот канал как первый входной канал в вашем модуле C++
  3. Настройте канал для предоставления эталонного времени

Настройка выходного канала

Согласно обсуждениям на форуме Dewesoft, выходные каналы должны быть правильно сопоставлены с оборудованием:

cpp
void Module::configure() {
    // ... существующий код ...
    
    // Убедитесь, что выходные каналы сопоставлены с цифровыми выводами
    setOutputChannelProperty(0, "HardwareOutput", "DO1");
    setOutputChannelProperty(1, "HardwareOutput", "DO2");
    
    // Установка диапазона для цифровых сигналов
    setOutputChannelProperty(0, "Range", "0-5V");
    setOutputChannelProperty(1, "Range", "0-5V");
}

Настройка триггера цифрового вывода

В руководстве Dewesoft объясняется, что цифровые выводы могут быть настроены с определенными условиями срабатывания:

  • Задержка: Время между событием триггера и началом сигнала DO
  • Ширина импульса: Длительность выходного импульса
  • Логические условия: До 16 аппаратных условий могут быть объединены

Шаги отладки и устранения неполадок

Когда цифровые выводы не срабатывают как ожидается, следуйте этим систематическим шагам отладки:

1. Проверка регистрации модуля

Убедитесь, что ваш модуль правильно зарегистрирован в Dewesoft:

cpp
// В инициализации вашего модуля
bsc::MathModule::registerModule("DigitalOutputTrigger", 
                               "Модуль триггера цифрового вывода",
                               "1.0",
                               "Название вашей компании");

2. Проверка потокобезопасности

Как подчеркивается в учебных материалах Dewesoft, доступ ко всем каналам должен происходить в методе calculate():

cpp
void Module::calculate() {
    // Безопасно: весь доступ к каналам здесь
    PyroOneOut = 1.0;  // Это безопасно
    
    // Небезопасно: вызовет сбой
    // someOtherMethod();
    // PyroOneOut = 1.0;  // Это вызовет сбой
}

3. Мониторинг значений тайминга

Добавьте вывод отладки для проверки расчетов тайминга:

cpp
void Module::calculate() {
    double currentTime_ms = getSampleTime(0) * 1000.0;
    double elapsedTime_ms = currentTime_ms - startTime_ms;
    
    // Вывод отладки (можно просматривать в консоли отладки Dewesoft)
    debugOutput("Текущее время: %.2f мс, Прошло: %.2f мс", 
                currentTime_ms, elapsedTime_ms);
    
    // ... остальная логика ...
}

4. Проверка отображения вывода

Используйте встроенные инструменты Dewesoft для проверки сопоставления выходных каналов:

  1. Перейдите в Настройка → Каналы → Цифровой вывод
  2. Убедитесь, что ваши каналы сопоставлены с правильными выводами оборудования
  3. Проверьте диапазоны напряжений и условия срабатывания

5. Тестирование с упрощенной логикой

Начните с простого теста включения/выключения для изоляции проблемы:

cpp
void Module::calculate() {
    // Простой тест: всегда выводить 5В на DO1
    PyroOneOut = 1.0;
    PyroTwoOut = 0.0;
}

Если это работает, постепенно добавляйте сложность, чтобы определить, где логика тайминга дает сбой.


Полный рабочий пример

Вот полный, рабочий реализации системы триггеров цифрового вывода:

cpp
#include <chrono>
#include <Dewesoft/Math/Api/Basic.h>

namespace bsc = Dewesoft::Math::Api::Basic;

class DigitalOutputTrigger : public bsc::MathModule {
public:
    DigitalOutputTrigger();
    ~DigitalOutputTrigger();

    // Жизненный цикл модуля
    void configure() override;
    void start() override;
    void stop() override;
    void clear() override;
    void calculate() override;

    // Выходные каналы
    double PyroOneOut = 0.0;   // "Выход первого пиро"
    double PyroTwoOut = 0.0;   // "Выход второго пиро"

private:
    // Параметры тайминга
    const double t1_ms = 25.0;  // DO1 срабатывает через 25 мс
    const double t2_ms = 50.0;  // DO2 срабатывает через 50 мс
    const double width_ms = 5.0;   // ширина импульса
    
    // Состояние тайминга
    double startTime_ms = 0.0;
    bool measurementStarted = false;
    int cycleCount = 0;
};

// Конструктор
DigitalOutputTrigger::DigitalOutputTrigger() {
    // Регистрация модуля
    bsc::MathModule::registerModule("DigitalOutputTrigger",
                                   "Триггер цифрового вывода",
                                   "1.0",
                                   "Ваша компания");
}

// Деструктор
DigitalOutputTrigger::~DigitalOutputTrigger() {
    // Очистка при необходимости
}

void DigitalOutputTrigger::configure() {
    // Настройка входного временного сигнала
    setInputChannel(0, "TimeSignal", "Time Signal");
    
    // Настройка выходных каналов
    setOutputChannel(0, "PyroOneOut", "First Pyro's Output", "V");
    setOutputChannel(1, "PyroTwoOut", "Second Pyro's Output", "V");
    
    // Сопоставление с цифровыми выводами
    setOutputChannelProperty(0, "DigitalOutput", "Ctrl DO1");
    setOutputChannelProperty(1, "DigitalOutput", "Ctrl DO2");
    
    // Установка диапазонов напряжений
    setOutputChannelProperty(0, "Range", "0-5V");
    setOutputChannelProperty(1, "Range", "0-5V");
}

void DigitalOutputTrigger::start() {
    startTime_ms = 0.0;
    measurementStarted = false;
    cycleCount = 0;
    debugOutput("Триггер цифрового вывода запущен");
}

void DigitalOutputTrigger::stop() {
    debugOutput("Триггер цифрового вывода остановлен после %d циклов", cycleCount);
}

void DigitalOutputTrigger::clear() {
    PyroOneOut = 0.0;
    PyroTwoOut = 0.0;
}

void DigitalOutputTrigger::calculate() {
    // Получение текущего времени в миллисекундах
    double currentTime_ms = getSampleTime(0) * 1000.0;
    
    if (!measurementStarted) {
        startTime_ms = currentTime_ms;
        measurementStarted = true;
    }
    
    double elapsedTime_ms = currentTime_ms - startTime_ms;
    
    // Сброс цикла, если мы завершили один полный период
    const double cyclePeriod_ms = t2_ms + width_ms + 1000.0; // 1 секунда между циклами
    if (elapsedTime_ms > cyclePeriod_ms) {
        startTime_ms = currentTime_ms;
        elapsedTime_ms = 0.0;
        cycleCount++;
    }
    
    // Расчет состояний цифрового вывода
    const bool do1_high = (elapsedTime_ms >= t1_ms) && 
                         (elapsedTime_ms < (t1_ms + width_ms));
    const bool do2_high = (elapsedTime_ms >= t2_ms) && 
                         (elapsedTime_ms < (t2_ms + width_ms));
    
    // Установка значений вывода
    PyroOneOut = do1_high ? 5.0 : 0.0;  // 5В для ВЫСОКОГО уровня, 0В для НИЗКОГО уровня
    PyroTwoOut = do2_high ? 5.0 : 0.0;
    
    // Вывод отладки (можно отключить в продакшене)
    if (do1_high || do2_high) {
        debugOutput("DO1: %s, DO2: %s в %.2f мс", 
                   do1_high ? "ВЫСОКИЙ" : "НИЗКИЙ",
                   do2_high ? "ВЫСОКИЙ" : "НИЗКИЙ",
                   elapsedTime_ms);
    }
}

Ключевые особенности этой реализации:

  • Правильные объявления методов и управление жизненным циклом
  • Надежный расчет тайминга с использованием внутреннего тайминга Dewesoft
  • Непрерывная работа с автоматическим сбросом цикла
  • Вывод отладки для устранения неполадок
  • Правильные уровни напряжения (5В для ВЫСОКОГО уровня, 0В для НИЗКОГО уровня)
  • Потокобезопасный доступ к каналам

Расширенные параметры настройки триггеров

Для более сложных требований к срабатыванию Dewesoft предлагает несколько расширенных функций:

Условия аппаратного триггера

Как упоминается в руководстве Dewesoft, вы можете настроить до 16 аппаратных условий:

cpp
void Module::configure() {
    // ... существующая настройка ...
    
    // Установка условий аппаратного триггера
    setOutputChannelProperty(0, "TriggerCondition", "RisingEdge");
    setOutputChannelProperty(0, "TriggerDelay", "0");
    setOutputChannelProperty(0, "TriggerPulseWidth", "5");
}

Режим синхронного тактового сигнала

Для точного тайминга рассмотрите использование режима поставщика синхронного тактового сигнала, как упоминается в расширенных учебных материалах:

cpp
void Module::onPreinitiate() {
    // Установка выходного канала в синхронный режим
    setOutputChannelProperty(0, "Synchronous", "true");
    setOutputChannelProperty(1, "Synchronous", "true");
}

Логика множественных триггеров

В руководстве Dewesoft объясняется, что множественные условия срабатывания используют логику И:

cpp
void Module::calculate() {
    // Пример множественных условий
    bool condition1 = (elapsedTime_ms >= t1_ms) && 
                     (elapsedTime_ms < (t1_ms + width_ms));
    bool condition2 = getSampleTime(1) > 2.5;  // Какое-то аналоговое условие
    
    // Оба условия должны быть истинными (логика И)
    PyroOneOut = (condition1 && condition2) ? 5.0 : 0.0;
}

Интеграция внешнего триггера

Для систем, требующих внешней синхронизации, вы можете интегрировать внешние триггеры:

cpp
void Module::configure() {
    // Настройка внешнего входного триггера
    setInputChannel(1, "ExternalTrigger", "External Trigger Signal");
    
    // Установка свойств триггера
    setInputChannelProperty(1, "TriggerEdge", "Rising");
    setInputChannelProperty(1, "TriggerLevel", "2.5");
}

Источники

  1. Обучение плагину обработки сигналов C++ Dewesoft
  2. Руководство по C++ Script Dewesoft
  3. Triggers out RT - Руководство Dewesoft X
  4. Попытка изучить модуль C++ Dewesoft - Stack Overflow
  5. Аналоговый вход, триггеры, сигналы тревоги и вывод - Форум Dewesoft
  6. Расширенная разработка пользовательских плагинов на C++ - Обучение Dewesoft

Заключение

Реализация триггеров цифрового вывода в модуле C++ Dewesoft требует внимания к нескольким ключевым аспектам:

Структура методов и жизненный цикл: Убедитесь, что все требуемые методы (configure(), start(), stop(), clear(), calculate()) правильно объявлены и реализованы. Метод calculate() особенно критичен, так как это единственное потокобезопасное место для доступа к каналам.

Подход к таймингу: Используйте внутреннюю систему тайминга Dewesoft через getSampleTime() или callInfo.endBlockTime, а не внешние источники времени, такие как std::chrono. Это обеспечивает синхронизацию с системой измерения Dewesoft.

Настройка каналов: Правильно настраивайте входные временные сигналы и сопоставляйте выходные каналы с цифровым оборудованием с правильными диапазонами напряжений и свойствами.

Стратегия отладки: Реализуйте вывод отладки для мониторинга значений тайминга и состояний вывода, затем постепенно увеличивайте сложность для изоляции проблем.

Расширенные функции: Для более сложных приложений изучите условия аппаратного триггера, режимы синхронного тактового сигнала и интеграцию внешних триггеров.

Предоставленный полный рабочий пример должен решить проблемы срабатывания, с которыми вы сталкиваетесь. Начните с этой реализации, а затем настройте параметры тайминга и логику в соответствии с вашими конкретными требованиями.

Авторы
Проверено модерацией
Модерация