Меню
+7 (495) 785-95-25
sale@lcard.ru
sale@lcard.ru
1. lusbapi34 (но использую не dll, а статическую lib из папки DLL\Lib\MicroSoft)
Вообще это не статическая, а dll-import lib. Чтобы линкер смог собрать .exe с нужными импортами. Так что .dll при запуске программы нужна.
После вызова ReadData GetLastErrorInfo() возвращает код ошибки 422
Данная интерфейсная функция не выполняет классификацию ошибок для интерфейсной функции ReadData(). Т.к. эта функция фактически является слепком со стандартной Windows API функций ReadFile(), то для выявления ошибок следует пользоваться классификацией ошибок, присущей системе Windows."
Если так написано, то это для актуальной версии неправильно, см. исходные тексты lusbapi.
422 - это действительно таймаут:
#define E2010_BASE_ERROR_ID (400)
#define E2010_ERROR_ID_22 (E2010_BASE_ERROR_ID + 22)
E2010_ERROR_ID_22, "Таймаут ожидания ввода данных."
Собственно, эту строку и должна была вернуть функция GetLastErrorInfo.
А вот почему, я пока не понял. Пуск АЦП, говорите, точно успешно выполнился? Внешний запуск вроде бы не включен.
Величина таймаута рассчитывается странно (по-моему, для получения времени сбора надо было разделить еще на число каналов), но это в большую сторону ошибка, а потом еще +1000 (секунда).
Вообще-то бывают фокусы с большим размером запроса в зависимости от USB хост-контроллера на компьютере. 512 кБайт (SHORT[256*1024]) - это не так уж мало, а что если попробовать уменьшить буфер в 2, 4, 8 раз?
Если выключили overlapped, то надо менять всю логику сбора (убрать двойную буферизацию, не делать два запроса в начале, исключить WaitFor... и GetOverlappedResult - короче говоря, просто ReadData в цикле). Однако использовать двойную буферизацию все-таки рекомендуется, тем более что у Вас самый быстрый модуль.
Советую еще вот эту статью.
P.S. На самом деле внутри lusbapi все равно overlapped i/o, просто в этом случае он делается внутри незаметно для вызывающей программы (ReadFile - WaitForSingleObject - GetOverlappedResult) и не дает никакого выигрыша (если не использовать потоки).
Евгений, по такому описанию очень трудно что-либо понять.
Функцию main не вызывают явно.
Если Вы хотите переделать консольный пример на GUI, надо разнести соответствующий код по обработчикам события элементов управления. Например, можно расписать блок-схему консольной программы (в каком порядке и с какими параметрами вызываются функции библиотеки) и потом, руководствуясь этой блок-схемой и общими правилами написания GUI приложений, реализовать аналогичную функциональность.
Консольный вывод (printf, puts...) надо переделать на соответствующие вызовы GUI. Например, писать их в text box.
Цикл чтения данных и записи в файл по идее надо бы вынести в отдельный поток, т.к. он исполняется длительно, а кнопки в интерфейсе надо обрабатывать. Или (хуже) вызывать функцию для обработки GUI - смотря на чем Вы пишете - типа ProcessMessages, ProcessSystemEvents и т.п.
Начинающие часто засовывают весь алгоритм в обработчик события кнопки "начать" - смотреть на это больно, но для первой пробы хотя бы так.
Если "не компилируется" - значит, что-то не так в самом тексте или заголовочный файл не включили. Если не линкуется (ошибка типа undefined external) - то это может быть связано с тем, что не добавлен необходимый .lib файл.
Нужны конкретные сообщения об ошибках и, возможно, исходный текст (если он небольшой).
Если индекс больше либо равен нулю - отбрасываем данные, если меньше нуля отбрасываем данные. Так мы все данные отбрасываем. Или я недопонимаю?
Если больше нуля, то отбросить еще кол-во отсчетов, равное этому индексу - то есть возвращаемое неотрицательное значение - это номер элемента в массиве, с которого начинается кадр ("начало кадра найдено на позиции N от начала переданного блока"). А меньше нуля - это "начало кадра не найдено", тогда отбрасывается весь блок.
Только, очевидно, PCI плату придется программировать своими силами на низком уровне, основываясь на исходных текстах lcomp_linux или l502api. Думаю, пригодится какой-нибудь 32-битный DOS extender, что-то вроде DJGPP.
В "совсем голом досе" будет тяжело - нужен прямой доступ в верхнюю память. Хотя есть и big real mode.
Так и настройки, и старт-стоп АЦП тоже общие. То есть такое разделение должно быть 1) кооперативным и 2) существенно ограниченным в функциях по сравнению с монопольной работой.
Заставить работать два приложения, написанные для стандартной библиотеки, одновременно с одним устройством не получится.
Отсюда идея с промежуточным сервером: с устройством через драйвер работает одна программа, которая в свою очередь предоставляет приложениям некий свой собственный интерфейс.
Например, можно разбирать поток данных по каналам и отдавать их разным клиентам (с одной частотой или даже с разными, если делать программную передискретизацию). Как формировать управление, тоже зависит от задачи: от монопольного (только одно приложение имеет право устанавливать параметры, запускать и останавливать АЦП) до однорангового (но, видимо, с большими ограничениями и блокировками).
Позволю себе чуть подробнее раскрыть совет Poul.
Если речь о том, чтобы одновременно работать с одним и тем же устройством, то в общем случае такая задача едва ли решается, поскольку устройство физически одно и его состояние зависит от предыдущих операций.
Чтобы получилось что-то осмысленное, надо фактически придумать протокол более высокого уровня, учитывающий логику вашей задачи и сообразно ей ограничивающий и сериализующий действия приложений (например, одно приложение управляет, а второе только наблюдает копию данных, или одно работает только с ЦАП, а второе только с АЦП). Вспомогательная программа, реализующая такой протокол, и будет "сервером" (демоном, службой).
Еще можно подумать в направлении встраиваемых компьютеров - по надежности и габаритам должны быть подходящие решения.
Это похоже на задачу измерения АЧХ/ФЧХ, тогда надо действительно запустить одновременно ЦАП и АЦП, соединив (корректным образом) выход ЦАП со входом тестируемой схемы, а выход тестируемой схемы со входом АЦП.
И важно не забыть настроить не только ЦАП (параграф 3.1.2), но и АЦП (параграф 3.1.1).
Multao, из буфера ЦАП в буфер АЦП данные не передаются, это два разных функциональных блока прибора.
ЦАП преобразует цифровые данные в напряжение на аналоговом выходе.
АЦП измеряет напряжение на аналоговом входе и представляет его в цифровом виде.
Вы можете соединить физически выход ЦАП со входом АЦП, но получите не те же данные, а результат преобразования цифра-аналог-цифра с неизбежными погрешностями. Это будет своего рода тест аналогового тракта, наподобие копирования фонограммы на аналоговом кассетном магнитофоне.
А какая у Вас задача? Почему возникло желание увидеть в буфере АЦП данные, посланные на ЦАП?
Артем, спасибо за диагностику.
На скриншоте ошибка возникла после 184194 успешных циклов - это такое поведение (т.е. ошибка возникает не сразу) или это Вы отсоединили "паразитное питание" на ходу и сразу произошел сбой?
Добрый день. Имеется похожая проблема.
Тогда есть смысл действовать по тому же алгоритму.
Для синхронного см. документацию на сайте.
У E14-440 по e14_440_programmers_guide.pdf сетка частот 24000000/N Гц, где N = 60...65535
У L-502 по l502api.pdf опорная частота 2 МГц или 1.5 МГц делится на N = 1...1048576
Александр: как я понял, вопрос был про асинхронный ввод одного кадра в цикле.
Юзер: В асинхронном режиме не стоит говорить о частоте дискретизации, потому что интервалы между преобразованиями случайны. Это получится просто серия измерений.
Кое-что на эту тему написано тут.
Получается, что вопрос трансформируется в "сколько примерно асинхронных измерений в секунду получается с этого прибора на каком-то наугад взятом ПК". Это можно сделать, но информативно ли?
Для задачи, в которой встает вопрос о количестве измерений в секунду (то есть не все равно, 50 это будет или 500), я бы рекомендовал все-таки синхронный режим. Можно читать сигнал маленькими порциями и обрабатывать с небольшим запаздыванием (см. статью по ссылке выше) - по-моему, это лучше, чем асинхронный вызов, который по сути запускает тот же синхронный сбор на один кадр, добавляя накладные расходы: прием команды, пуск и останов АЦП.
Да просто заполняете массив отсчетов и пишете его через LTR_Send. (Естественно, после процедуры инициализации и старта.) В отличие от USB модулей (Exx-xxx), для LTR34, если я не ошибаюсь, не нужно писать специальную двойную буферизацию и т.п., скорость вывода регулирует ltrserver (ltrd). То есть можно писать "просто подряд", как будто в файл на диске эти массивы записываете.
Все сводится к тому, что не исправна ПЛИС. Можно ли отправить устройство вам на починку и сколько это будет стоить?
То есть, если я правильно понимаю,
1) прибор раньше работал, потом что-то произошло.
2) все программы выдают ошибку в функциях start_adc, stop_adc, ttl_in, ttl_out и т.п. - то есть тогда, когда нужно сделать что-то "физическое", затрагивающее входные/выходные цепи?
Тогда похоже, что не приходит сигнал готовности внутренних узлов модуля. Неисправна может быть и не ПЛИС, а, например, преобразователь питания или другие узлы, так что при передаче в ремонт лучше не говорить "неисправна ПЛИС", а, как сказал lalex, дать ссылку на тему форума и перечислить функции, при которых ошибка (STOP_ADC, START_ADC, TTL_IN и т.п.)
Если есть подозрения, что могло послужить причиной поломки, это тоже полезная информация.
Пока две версии: либо неправильно собрана программа, либо прибор неисправен (не может включить ПЛИС?)
1. А при каких обстоятельствах прибор последний раз успешно использовался?
2. LGraph2 пробовали?
3. Из вот этого архива попробуйте программы unidir.exe ttl_speed.exe
Можно задействовать линию SYNC и синхронизировать пуск каждого преобразования АЦП (один прибор будет ведущий, второй ведомый, частота дискретизации и межкадровая задержка будет браться от ведущего). После настройки параметров START_ADC сначала делаем на ведомом (он садится ждать синхроимпульса и пока ничего не посылает), потом на ведущем.
Можно синхронизировать только пуск, но тогда время будет немножко расходиться (существенно при длительном измерении).
Количество опрашиваемых каналов на каждом приборе, по-видимому, должно быть одинаковым или кратным, иначе будет неудобно обрабатывать поток данных.
Поток данных будет у каждого прибора свой.
В документации на прибор исключительно мало информации по работе с цифровыми входами.
Дело в том, что этой информации объективно немного: работа с TTL линиями в E14-440 и подобных приборах - не основная функция. Возможности ее скромные: просто записать или считать регистр, однократно, по команде от компьютера.
Все режимы синхронизации, линия INT и прочее относится к работе АЦП.
Пока у меня два варианта:
1.Висеть в цикле и постоянно читая ( ILE440::TTL_IN() ) ждать определенный сигнал на IN<1...16>, к примеру 0xffff, который будет обозначать такт передачи. Типа так 0xffff, 0x1010, 0xffff, 0x2020....
Например. Только надо учитывать, что когда Вы приводите константы типа IN<1...16> = 0x2020, это получается состояние всех 16 каналов в один момент времени, а не последовательность бит по одному каналу.
А ведь еще надо предусмотреть сигнал окончания передачи, а то так и будем в цикле жить, пока программу не прибьют.
Возможны разные решения. Можно написать программный аналог USART (в синхронном режиме) или SPI, используя какую-то линию как CLOCK (например, при изменении с 0 на 1 брать биты данных с другой линии). Но из-за работы в режиме опроса этот интерфейс получится медленным. Возможно, Вам удастся опрашивать TTL_IN() до 250 раз в секунду, но важно понимать, что эти считывания не привязаны к равномерным интервалам времени, а происходят "как получится". Если компьютер "задумается", можно пропустить импульс. Поэтому надо либо оставлять большой запас по времени (и программно защищаться от сбоев), либо делать интерфейс с подтверждением (как STROBE/ACK у LPT порта).
У нас на сайте есть заметка, в которой рассмотрен похожий вопрос.
2. Програмить dsp по своему. Может и не сложно, но точно долго.
Пожалуй, только так можно сделать на этом устройстве более продвинутую работу с TTL линиями.
Такое поведение может быть, например, если не установлен драйвер.
Попробуйте отсоединить прибор, поставить пакет lcomp и подключить прибор.
Попробуйте скачать дистибутив lcomp и поставить его.
Какую функцию выполняет тогда параметр
adcPar.t2.Chn[]
?
Это логический номер канала, для E2010 там номер физического канала (0..3), см. параграф 3.2.3 в e2010_programmers_guide.pdf
как посчитать, за какое время будет заполняться буфер размером 1048576 машинных слов (DWORD)? Известно время между кадрами в миллисекундах, но неизвестно время заполнения одного кадра, содержащего данные по двум каналам.
Если "время между кадрами" - это период кадра, то это одно и то же.
Размер буфера в байтах разделить на размер отсчета АЦП (если отсчет 16-битный, то 2) - получится размер буфера в отсчетах.
Если дополнительная межкадровая задержка не используется, то размер буфера в отсчетах просто разделить на частоту дискретизации и всё.
А если межкадровая задержка есть, то разделить на количество каналов в кадре (получится количество кадров в буфере) и умножить на период следования кадров (см. 3.2.4. "Формат кадра отсчетов" в том же руководстве).
Скажите пожалуйста можно ли при сборе и обработке данных рассматривать весь буфер целиком
Если я правильно понял вопрос, то кольцевой буфер во время потокового сбора данных всегда "занят" - находится в процессе заполнения (идет запись в буфер данных по мере их поступления от АЦП).
Если начать обрабатывать весь буфер целиком, то начало массива будет испорчено, потому что АЦП запишет отсчет x(t+N*dt) поверх x(t).
Поэтому и рассматривают буфер в виде двух половин: как только пройдена отметка в полбуфера, у нас есть время забрать и обработать эти данные, пока пишется вторая половина.
Советую прочитать статьи FAQ про буферизацию: здесь и здесь.
Адрес: 117105, Москва, Варшавское шоссе, д. 5, корп. 4, стр. 2
Многоканальный телефон:
+7 (495) 785-95-25
Отдел продаж: sale@lcard.ru
Техническая поддержка: support@lcard.ru
Время работы: с 9-00 до 19-00 мск