Российский производитель и разработчик сертифицированного измерительного оборудования с 1987 года


Многопоточное приложение для Е14-140-М

Вы не вошли.

 Поиск | Регистрация | Вход 

Сергей Николаевич
17.09.2011 19:10:10
#1

Гость

Многопоточное приложение для Е14-140-М

Есть потребность одновременно вести непрерывный потоковой сбор аналоговых данных и в то же время выводить логические сигналы из модуля вовне для управления техпроцессом на основании тех же данных.
Можно ли решить эту задачу, реализовав программу с двумя потоками, в одном из коих выполняется непрерывный сбор данных, а в другом осуществляется вызов иных полезных функций востребованных пользователем?

18.09.2011 09:21:21
#2

Сотрудник "Л Кард"
Откуда: Москва
Здесь с 23.04.2014
Сообщений: 3,727

Re: Многопоточное приложение для Е14-140-М

можно, но нужно оценить необходимое время реакции системы управления... может и нельзя...

Сергей Николаевич
18.09.2011 09:55:54
#3

Гость

Re: Многопоточное приложение для Е14-140-М

Мне нужно чтобы программа прекращала разгон двигателя при достижении заданных оборотов. Надеюсь, она в любом случае сделает это быстрее оператора жмущего красную кнопку.
Благодарю за обнадёживающий ответ, буду писать программу.

19.09.2011 11:45:47
#4

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Многопоточное приложение для Е14-140-М

Команда по управляющему каналу USB (к которым относится TTL_OUT()) обычно выполняется за время порядка десятков миллисекунд. Подавать команду во время сбора данных можно. Нельзя из нескольких потоков программы одновременно подавать команды (например, START_ADC, STOP_ADC, SET_ADC_PARS, TTL_OUT и т.п. - их надо сериализовать), но в задаче такого типа инициализацию и пуск АЦП можно выполнить до пуска потоков обработки и обойтись без критических секций.
Время реакции будет зависеть еше и от размера блока чтения из АЦП и от логики программы, т.к. от задержки между моментом оцифровки и моментом обработки порции данных программой. Уменьшать блок можно в разумных пределах, чтобы программа успевала закончить обработку до заполнения следующего блока (советую использовать двойную буферизацию).

Сергей Николаевич
29.09.2011 16:23:12
#5

Гость

Re: Многопоточное приложение для Е14-140-М

А если запустить одновременно два модуля Е14-140-М?
Можно ли тогда в одном из них производить сбор данных, а во втором вызывать функции ADC_KADR() и  TTL_OUT()? По логике модули совершенно независимы друг от друга. Даст ли подобное решение какой либо выигрыш в быстродействии и надёжности работы?

29.09.2011 16:36:22
#6

Сотрудник "Л Кард"
Откуда: Москва
Здесь с 23.04.2014
Сообщений: 3,727

Re: Многопоточное приложение для Е14-140-М

кардинального - нет.

03.10.2011 13:12:29
#7

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Многопоточное приложение для Е14-140-М

Это не повлияет на два основных фактора:
1) время между моментом измерения физического напряжения в АЦП и моментом, когда полученные данные будут проанализированы программой.
2) время между вызовом функции TTL_OUT() и моментом выполнения команды, поданной через USB, и установки напряжения на выходе.

Вообще я бы сказал, что включать обычный ПК в обратную связь какой-то физической установки надо крайне осторожно. На конкретной лабораторной машине, не запуская в фоне тяжелых программ и т.д. Времена, думаю, будут порядка десятков или сотен мс.

Но в любом случае это не должна быть система, критичная по безопасности (скажем, если запоздалая реакция приводит к разрыву маховика и т.п.). В конце концов, компьютер ведь может и просто зависнуть в произвольный момент...

Можно, кстати, попробовать вводить по одному отсчету через ADC_SAMPLE (если не важна равномерность оцифровки во времени).

Сделайте тестовую программу и замерьте максимальное-минимальное-среднее время выполнения одного цикла измерение-проверка-ttlout на конкретной машине. Или время реакции на ступеньку (по осциллографу).

Сергей Николаевич
03.10.2011 19:48:40
#8

Гость

Re: Многопоточное приложение для Е14-140-М

Александр, благодарю за полезные советы. Собственно говоря, программу под Е14-140-М для машины трения (это такая установка, где испытываются углеродные образцы путём их сжатия на высоких оборотах) я написал ещё год назад, переработав прилагаемые к модулю примеры. Сейчас это работает (и очень успешно) примерно так: вначале, после инициализации модуля, управление передаётся в цикл, где посредством периодических (10 Гц) вызовов ADC_KADR() с нескольких каналов обновляются разные переменные: скорости, силы сжатия, тормозного момента, и выводятся на экран. Цикл работает, пока скорость не превысит определённый порог, а затем оператором break по условию вываливаемся вниз по коду в основной поток сбора данных, где всё и записывается в файл. Частота 10 кгц для 10 каналов (т. е. 1 кгц на канал).

Проблема в том, что машиной очень желательно управлять программно во время  сбора данных, а это по-видимому возможно только если запустить цикл с вызовами ADC_KADR()и TTL_OUT() в параллельном потоке. То есть одновременно порциями собирать данные в файл и управлять машиной посредством ADC_KADR()и TTL_OUT().

Непонятно только, можно ли одновременно в одном потоке собирать данные в файл, а в другом вызывать ADC_KADR()и TTL_OUT()? И нужно ли часть кода заключать в критические секции? Думаю, если ничего не получиться, в самом крайнем случае использовать два модуля.

Кстати, в руководстве сказано, что ADC_KADR() можно вызывать с частотой "порядка нескольких десятков герц", а TTL_OUT() "порядка нескольких сотен герц". Это обнадёживает. Буду экспериментировать.

04.10.2011 11:34:25
#9

Сотрудник "Л Кард"
Здесь с 18.04.2014
Сообщений: 810

Re: Многопоточное приложение для Е14-140-М

Как я понял, природа сигналов не требует привязки к сетке времени, поэтому ADC_KADR() годится (но о частоте дискретизации в этом случае можно говорить только условно).
Вызывать ADC_KADR одновременно с TTL_OUT нельзя, поскольку в обоих случаях даются команды.

Поясню природу процесса. Прибор имеет два канала связи с ПК: относительно медленный побайтовый командный (используется USB control pipe) и относительно быстрый пакетный для данных (USB bulk). По bulk передаются только сами данные АЦП или ЦАП в потоковом режиме, т.е. ReadData/WriteData. Все остальное - GetModuleName, SET_ADC_PARS, START_ADC, STOP_ADC, ADC_KADR, ADC_SAMPLE, TTL и т.д. - это команды.

Одновременно можно:
- подавать одну команду
- читать данные потокового АЦП (ReadData или ReadFile)
- писать данные потокового ЦАП (WriteData или WriteFile)

Естественно, команды ADC_KADR и ADC_SAMPLE не сочетаются с чтением потоковых данных - не работают, если АЦП был запущен через START_ADC.
Аналогично DAC_SAMPLES и START_DAC.

В Вашей задаче проще всего вставить TTL_OUT в цикл между очередными ADC_KADRами.
А если это неудобно с точки зрения логики программы и хочется, чтобы были разные потоки - тогда нужны критические секции. Однако по скорости это никак не быстрее, даже формально чуть медленнее из-за оверхеда (но на таких низких для ПК скоростях можно считать, что одинаково).

Команды можно вызывать так часто, как они успеют выполниться smile Частота, написанная в руководстве - это просто условная оценка, полученная в тесте типа

#include <time.h>
#define TEST_TIME_SEC 10
unsigned long count;
time_t endtime = clock() + TEST_TIME_SEC * CLOCKS_PER_SEC;
for (count = 0; clock() < endtime; count++)
{
TTL_OUT(...);
}
cycles_per_second = count / TEST_TIME_SEC;

Можете потестировать сами - это время не регламентируется и зависит от машины, USB-контроллера и т.д.

Сергей Николаевич
25.10.2011 19:28:38
#10

Гость

Re: Многопоточное приложение для Е14-140-М

Задачу осилил посредством одновременной работы двух модулей. Разумеется, пришлось запустить в программе и два отдельных потока: для модуля использующего START_ADC и модуля использующего ADC_KADR и TTL_OUT.
Проверил, всё работает как надо. Время отклика выходных линий на перепад напряжения через функции ADC_KADR и TTL_OUT лежит где-то между 6 и 18 миллисекундами (средний разброс, смотрел по выводимому графику), что более чем достаточно по быстроте.

Однако удивила трудность инициализации сразу двух модулей. Постоянно выскакивали ошибки вроде: GET_MODULE_DESCRIPTION() --> Bad и SET_ADC_PARS() --> Bad и приложение закрывается. Что любопытно, с одним модулем таких проблем никогда не было. Вывернулся - переписал функцию AbortProgram, убрал из неё exit(1), добавил рекурсивный вызов функции - той, где выполняется инициализация модуля. То есть, попытки инициализации теперь выполняются несколько раз вплоть до успешной.
Вроде всё.