Меню
+7 (495) 785-95-25
sale@lcard.ru
sale@lcard.ru
нет это не задание буфера, это только желание задать буфер в плате. буферов 2 - в плате и в PC. в примере L7XX.TST из lcomp есть комментарии. в хелпе есть описание принципа сбора данных с модуля. такой вот некий автономный режим сбора и обработки не был предусмотрен. вернее его ручками придется задавать записывая нужные данные в нужные ячейки памяти через put/get. или запустить потоковый сбор и просто не забирать данные, а читать что нужно.
Товарищи... Ну вот совершенно нет желания разбираться в тонкостях работы библиотеки.
Вот в LUSBAPI все удалось сделать не залезая в дебри ваших сложных построений. С вашей (сотрудников фирмы, спасибо им) помощью дописали в биос несколько строк... и вуаля.
А тут я про"""бался """ знает сколько времени, а Вы мне рассказываете о буферах. Оно мне зачем? Если можете помочь - напишите, плз, для меня, тупого, последовательность вызовов функций для реализации моей задачи - запуска сбора данных с требуемыми параметрами. Вставки в биос у меня есть - если АЦП будет ацпировать, то дальше я уж как-нибудь...
Разве вот это не задание буфера?
// Сразу заполним структуры с параметрами АЦП и ЦАП
With ap.t1 do
begin
s_Type := L_ADC_PARAM;
AutoInit := 1;
dRate := 400.0;
dKadr := 0.01;
dScale := 0;
SynchroType := 0;
SynchroSensitivity := 0;
SynchroMode := 0;
AdChannel := 0;
AdPorog := 0;
NCh := 1;
Chn [ 0 ] := $0;
FIFO := 64;
IrqStep := 4096;
Pages := 1;
IrqEna := 0;
AdcEna := 0;
end;
не только. нужен полный запуск потокового сбора как в примере. с выделением хоть небольшого буфера и дальше по порядку.
Не понимаю. В LUSBAPI нужно было задать параметры и запустить АЦП.
Здесь я делаю так же. Но оказывается, что нужно еще что-то плюс.
Разве в моих текстах нет выделения буфера и запуска сбора? Судя по поведению устройства, я только не до конца задавал параметры, и АЦП работало с параметрами по умолчанию.
Оно так работать не будет. FillADCparameters в драйвер передаст, а в модуль их передаст StarLdevice.
А....
pLDev.InitStartLDevice;
pLDev.StartLDevice;
Вот это?
И обе строчки?
Файл ADC.H
GetAdData:
{ ЇҐаҐ©¤Ґ¬ ўв®а®© Ў Є ॣЁбва®ў }
ENA SEC_REG;
{ гбв ®ўЄ б«Ґ¤го饣® Є « Ђ–Џ }
AR = PM(I5, M5); IO(SET_ADC_CHANNEL) = AR;
{ з⥨Ґ ¤ ле б Ђ–Џ }
AR = IO(READ_ADC);
AR = AR + AY1, AY1 = PM(I6, M6);
MR = AR * MY1(SU), MY1 = PM(I6, M6);
MR = MR(RND); DM(I3, M3) = MR1;
{ Тут моя вставка }
AY0 = I4;
{ Усредняем несколько последних значений }
M3 = -1;
MODIFY (I3,M3);
AY1=DM(I3, M3);
AR = 0;
CNTR=4;
DO MyL2 UNTIL CE;
AR=AR+AY1,AY1=DM(I3, M3);
MyL2: NOP;
M3 = 6;
MODIFY (I3, M3);
M3=0x1;
{ записываем в ячейку "текущее данное с АЦП" и сравниваем с порогом }
PutPm(AR,CurrADRESAddr);
AY1=AR;
GetPm(AR,ThresholdAddr);
AR=AY1-AR;
IF LT JUMP MyL1;
GetPm(AR,TtlOutAddr);
{AR = TSTBIT 0 OF AR;
IF EQ JUMP MyL1;
GetPm(AR,TtlOutAddr);}
AR= CLRBIT 0 OF AR;
IO(TTL_OUT)=AR;
MyL1:
AY1=PM(I6,M6);
MY1=PM(I6,M6);
M3 = 0x1;
I4 = AY0;
{ Ґб«Ё 㦮, в® ¤ҐЄаҐ¬ҐвЁа㥬 бзҐвзЁЄ ®вбзҐв®ў ў Є ¤аҐ, Ё зҐ RTI }
.................................
Файл CONST.H
.const ScaleFactorAddr = VariableBaseAddress + 0x30;
.const ZeroOffsetAddr = VariableBaseAddress + 0x34;
// След 2 строки
.const CurrADRESAddr = VariableBaseAddress + 0x3A;
.const ThresholdAddr = VariableBaseAddress + 0x3B;
.const NaladkaTestNumberAddr = VariableBaseAddress + 0x38;
.const NaladkaIrq0CounterAddr = VariableBaseAddress + 0x39;
....................
Файл VAR.H
{ ZeroOffset array for all gains }
.VAR/SEG=INT_PM_USER/ABS=ZeroOffsetAddr/PM/RAM ZeroOffset[4];
.INIT ZeroOffset: M(0x0), M(0x0), M(0x0), M(0x0);
{-----------------------------------------------------------------------}
{ Текущее значение с АЦП - будем читать }
.VAR/SEG=INT_PM_USER/ABS=CurrADRESAddr/PM/RAM CurrADRES;
.INIT CurrADRES: M(0x0);
{ Пороговое значение АЦП - будем сравнивать }
.VAR/SEG=INT_PM_USER/ABS=ThresholdAddr/PM/RAM Threshold;
.INIT Threshold: M(0x0);
{-----------------------------------------------------------------------}
По биосу все
ПРограмма для РС
// Сразу заполним структуры с параметрами АЦП и ЦАП
With ap.t1 do
begin
s_Type := L_ADC_PARAM;
AutoInit := 1;
dRate := 400.0;
dKadr := 0.01;
dScale := 0;
SynchroType := 0;
SynchroSensitivity := 0;
SynchroMode := 0;
AdChannel := 0;
AdPorog := 0;
NCh := 1;
Chn [ 0 ] := $0;
FIFO := 64;
IrqStep := 4096;
Pages := 1;
IrqEna := 0;
AdcEna := 0;
end;
{---------------------------------}
// Получить текущие показания АЦП в Вольтах
function TE440_Res.GetADCResult : extended;
var
i : integer;
begin
i := ReadLBIOSWord ( $6A );
FADCOverLoad := ( i >= ( 8 * 1024 - 2 ) * E440_Res_QuantAver );
Result := i / 800 / FADCScaleCoef / E440_Res_QuantAver;
end; // TE440_Res.GetADCResult
{---------------------------------}
// Установка параметров работы AЦП
procedure TE440_Res.SetADCPars;
begin
With ap.t1 do
begin
Chn [ 0 ] := 0 or ( FADCScale * $40 );
end;
inherited SetADCPars;
StartADC;
end; // TE440_Res.SetADCPars
{---------------------------------}
// Установка параметров работы АЦП
procedure TE440_Base.SetADCPars;
type
WA = array [ 0..1023 ] of SHORT;
PWA = ^WA;
var
i : integer;
Res : ULONG;
begin
// Передадим требуемые параметры работы АЦП в модуль
If FExists
then begin
FADCStarted := false;
While FBusy do Application.ProcessMessages;
FBusy := true;
try
For i := 1 to Rep do
begin
Res := pLDev.FillDAQparameters ( ap.t1 );
If Res = L_SUCCESS
then break;
If ( i < Rep )
then Sleep ( 50 );
end;
If Res <> L_SUCCESS
then begin
ShowInfo ( Inttostr ( Res ) );
raise Exception.Create ( E440FillADCParsError );
end;
finally
FBusy := false;
end;
end;
end; // TE440_Base.SetADCPars
{---------------------------------}
// Запустить АЦП
procedure TE440_Base.StartADC;
var
i : byte;
Res : ULONG;
begin
// EXIT;
If FADCStarted
then EXIT;
If FExists
then begin
While FBusy do Application.ProcessMessages;
FBusy := true;
try
For i := 1 to 3 do
begin
Res := pLDev.SendCommand ( cmSTOP_ADC_E440 );
If Res = L_SUCCESS
then break;
If ( i < Rep )
then Sleep ( 50 );
end;
If Res <> L_SUCCESS
then raise Exception.Create ( E440StopADCError );
For i := 1 to 3 do
begin
Res := pLDev.SendCommand ( cmSTART_ADC_E440 );
If Res = L_SUCCESS
then break;
If ( i < Rep )
then Sleep ( 50 );
end;
If Res <> L_SUCCESS
then raise Exception.Create ( E440StartADCError );
FADCStarted := true;
finally
FBusy := false;
end;
end;
end; // TE440_Base.StartADC
Спасибо. Переделанная под 64 бита LUSBAPI задышала нормально. Будем проверять подробнее, но пока работает. Если там нет подводных камней, то это устроит.
Проблема с LCOMP мне не понятна. Я тут сверху писал - я складываю (суммирую)4 последних отсчета АЦП в ячейку памяти и сравниваю значение с соседней ячейкой. Так вот, при том же биосе при использовании LUSBAPI в первой ячейке (читая ее из верхней программы) я вижу прекрасные правильные значения АЦП, а при чтении через LCOMP какую-то хрень, как будто в эту ячейку ИНОГДА попадает правильное значение АЦП, а остальное время, в основном, там складываются значения близкие к 0. Как вариант, что-то не так при инициализации работы АЦП, но что - понять я не могу, параметры вроде одни и те же. Пробовал менять настройки - ничего не меняется в результате.
Спасибо. Буду пробовать.
И все-таки, еще бы исходники биоса, соответствующего работе с LCOMP - по размеру файла они отличаются от 3.4
Приходится возвращаться к вопросу поддержки Е14-440 под 64 битами. Пользовали 502, там с этим вопросов нет. Но вот вернулись к 440, а там таки засада.
1. Библиотеку Lusbapi под 64 бита так и не переписали?
2. Есть исходники биоса, соответствующие библиотеке LCOMP? В поставке только файл .bio, а мне нужно править. Со старым биосом не хочет правильно работать, причин понять не могу.
Как там с обещанием сделать 64-битную версию iusbapi.dll?
это первый такой запрос за все время как я написал эту библиотеку. а сейчас это уже не моя печаль...
Понятно...
За совет спасибо. Воспользуюсь.
#define LBIOS_OUTVAR(v) ((unsigned int)v<<8)
ULONG EnableCorrection(USHORT Ena)
{
for(int i = 0; i < 4; i++)
{
if(pI->PutWord_PM(L_ZERO_E440+i, LBIOS_OUTVAR(pd.t4.KoefADC[ i ]))) return L_ERROR;
if(pI->PutWord_PM(L_SCALE_E440+i, LBIOS_OUTVAR(pd.t4.KoefADC[4+i]))) return L_ERROR;
}
// enable or disable
if(pI->PutWord_PM(L_CORRECTION_ENABLED_E440, LBIOS_OUTVAR(Ena))) return L_ERROR;
return L_SUCCESS;
}
просто реализуйте ее у себя на верху и передавайте свои коэф. сколько угодно. ну и вызывайте ее вместо встроенной
Это я видел, но навскидку не разобрался.
Просто PutWord_PM(L_ZERO_E440+i, свой коэф);
Спасибо.
Остается риторический вопрос, почему в библиотеке было не сделать?
В библиотеке LComp нет возможности напрямую передать в модуль пользовательские корректировочные коэффициенты.
А почему, собственно? Трудно было приписать?
Я не могу корректировать в моем приложении. Я дописывал БИОС для работы нашего оборудования с вашим АЦП. Прямо там у вас с большой скоростью складываются 4 отсчета и сумма сравнивается с неким порогом. При превышении порога на цифровой выход выводится 0 (запрещая генерацию лазера). Это подгонка резисторов, там надо все очень быстро (и как можно более точно). Мне в верхней программе показания АЦП практически не нужны, так, для тестовых вещей.
Как-то странно это с LComp выглядит. Я понимаю, что делали одну библиотеку на все устройства. Но почему при этом часть функций потеряли? И с примерами, кстати, ну просто ТБМ.
lusbapi на 64 бита - это было бы прекрасно. Все же работало под 32, а теперь масса проблем. Готов пару недель и подождать, не страшно.
Или же есть какие-то особые условия, требующие исключительно 64-битность от Вашего приложения?
Да, есть. Требования Заказчика.
Большая просьба не обсуждать зачем мне это нужно. Помогите просто решить проблему.
Используем Е14-440 уже больше 15 лет. До настоящего момента использовалась библиотека lusbapi. Потребовался переход на Вин64, естественно, все развалилось. Нужно использовать LComp.
Помогите переползти, плз. Задачи:
1. Задать СВОИ коэффициенты коррекции для АЦП. Раньше они лежали в параметрах АЦП, теперь там нет. Вижу их в дескрипторе платы, но не пойму, можно ли их там править, имея в виду:
2. Нужно иметь возможность восстанавливать коэффициенты коррекции, записанные производителем, в случае каких-либо проблем с новыми. То есть, затирать их (коэффициенты коррекции, записанные производителем) нельзя.
Спасибо. Я понял.
Не хватало вот этой фразы "добавляется нулевой байт справа"
Заработало.
Да, я использую X502_SetAdcCoef.
Описание на нее я читал. Но не понял.
Я же вижу то, что вы выдаете в функции X502_GetAdcCoef. K там близок к 1. Таким образом, умножая полученные с АЦП данные на примерно 1, нельзя получить размах в 6000000.
Собственно вопрос отсюда. Нерастянутые данные я получить не могу. Имею только растянутые. как они из нерастянутых получаются?
Еще раз - как, имея данные с АЦП в диапазоне +-6000000 получить число для задания смещения в X502_SetAdcCoef?
Запутался в коэффициентах с этой вашей растяжкой до 6000000.
Нужно произвести собственную калибровку АЦП.
1. Сбрасываю коэффициенты для данной шкалы в 1 (наклон) и 0 (смещение). Работает.
2. Подаю напряжение V1 (близко к 0В). Запоминаю точное значение напряжение и показания АЦП ( N1).
3. Подаю напряжение V2 (близко к максимуму шкалы). Запоминаю точное значение напряжение и показания АЦП (N2).
Наклон понятно. Но как посчитать СМЕЩЕНИЕ? Не понимаю, когда вы его там внутри применяете - до растяжки или после.
Спасибо.
Спасибо, то что нужно.
Если можно, подскажите еще немного.
Мне нужно передать из программы на РС в нижнюю программу некоторую величину в ДИСКРЕТАХ (в формате 24 бита, так у вас это там выглядит), соответствующую заданной величине в ВОЛЬТАХ.
Как выглядит ФОРМУЛА такого перевода?
Спасибо.
Еще раз спасибо - так заработало.
Спасибо.
Буду пробовать с глобальным флагом.
Здравствуйте.
Не обращайте внимание на передачу наверх. Она работает.
Что мне нужно в принципе - в первом сообщении в ветке.
Я должен запускать съем N данных (это шаг буфера), последние M из них усреднить и принять некое решение (обнулить DO1 или не трогать). Дальше опять запустить сбор. В принципе, в некоторых случаях этот сбор запускается от SYN1, в других - от внутренней синхронизации - сейчас пока только от внутренней. А результат усреднения может быть передан в РС с помощью пользовательской команды.
Я это написал и получил совершенно непонятный результат. Результат усреднения никак не похож на реальные данные. То, что описано в последнем моем сообщении - результат 2-х дней евпатории - было выброшена вся реальная обработка и написана просто передача трех элементов наверх.
Еще раз. Предельно простая задача. Нужно запустить сбор (ТОЛЬКО АЦП, только канал 1 с общей землей) N (несколько десятков) отсчетов с частотой 1МГц, остановить сбор после их получения, обработать, запустить сбор снова.
Что я делаю не так? Откуда там данные от других каналов? и даже пользовательские????
Алексей, нужна помощь еще.
Модуль Е-502 запустился, программу внутри правлю, в этом смысле все ОК.
Мои изменения (условно) - для отладки - было несколько больше, но пока все лишнее убрал.
1. В функции usr_in_proc_data выбросил передачу в РС по ДМА вообще - она (передача) там мне не нужна - просто закомментировал.
2. В функции usr_in_proc_data вставил запись данных (3 первых слова) в некие ячейки памяти Arr, примерно:
int32_t i;
for ( i = 0; i < 2; i++ ) Arr [ i ] = *data++;
streams_stop ();
stream_in_buf_free ( size );
streams_start ();
return ( size );
То есть пока вся обработка сводится к этому - только для разборок с непонятками.
3. Добавил пользовательскую команду, которая пересылает Arr в РС.
В программе на РС примерная инициализация настроек:
X502_SetLChannelCount ( FE502Hnd, 1 ); // Один лог канал
X502_SetLChannel ( FE502Hnd, 0, 0, X502_LCH_MODE_COMM, 0, 2 ); // на физич канал 1
X502_SetSyncMode ( FE502Hnd, X502_SYNC_INTERNAL );
X502_SetSyncStartMode ( FE502Hnd, X502_SYNC_INTERNAL );
X502_SetRefFreq ( FE502Hnd, X502_REF_FREQ_2000KHZ );
X502_SetAdcFreqDivider ( FE502Hnd, 2 );
X502_SetAdcInterframeDelay ( FE502Hnd, 0 );
X502_Configure ( FE502Hnd, info );
X502_StreamsStop ( FE502Hnd );
X502_SetStreamBufSize ( FE502Hnd, X502_STREAM_CH_IN, 10000 );
X502_StreamsDisable ( FE502Hnd, X502_STREAM_ADC or X502_STREAM_DIN or X502_STREAM_DAC1 or X502_STREAM_DAC2 or X502_STREAM_DOUT );
X502_SetStreamStep ( FE502Hnd, X502_STREAM_CH_IN, 150 ); // На самом деле здесь переменная примерно от 3 до 500
X502_StreamsEnable ( FE502Hnd, X502_STREAM_ADC );
X502_Configure ( FE502Hnd, info );
X502_StreamsStart ( FE502Hnd );
То есть я должен видеть переданные на РС данные в виде 0xD0xxxxxx - с первого физ канала, с общей землей. Я их и вижу, но не всегда. С вероятностью примерно 30% я вижу абстракцию типа 0xEBxxxxxx 0x5Bxxxxxx 0xD3xxxxxx, причем стабильно именно такие наборы (в следующем запуске программы, правда, могут быть и другие, но похожие). По косвенным данным в процессе отладки таких странных данных может быть либо часть буфера (стабильная по длине для данных настроек шага буфера), либо вообще все.
ЧТО ЭТО???????????????????????
При всем при том LGraph вроде работает нормально (без моих дописок в прогу, естественно).
Алексей, большое спасибо. В общих чертах понял. Буду разбираться.
Алексей, спасибо за ответ.
Меня бы устроил первый вариант - внешняя синхронизация по фронту SYNx.
Вопрос прежний - куда вписывать?
То есть, в обработчике пользовательских команд я этот режим запущу однократно. Но теперь мне нужно, чтобы он "самоподдерживался", пока я его не выключу. И это место - точно не обработчик команд пользователя - там мне нужно будет другие команды обрабатывать во время этого процесса.
Ну, и все-таки пример, если можно.
1. Запустить
2. Дождаться и считать во временный буфер.
3. Остановить и очистить буфер для следующего запуска.
Спасибо.
Адрес: 117105, Москва, Варшавское шоссе, д. 5, корп. 4, стр. 2
Многоканальный телефон:
+7 (495) 785-95-25
Отдел продаж: sale@lcard.ru
Техническая поддержка: support@lcard.ru
Время работы: с 9-00 до 19-00 мск