PDA

Показать полную графическую версию : C# Программирование АЦП


tumanovalex
01-02-2021, 11:22
АЦП Zet 220 (USB), есть библиотека zadc.dll на C. Функций в dll много, поэтому хотел бы в одном файле разместить обращение к dll. Начал с функций ZOpen и ZClose:namespace CsZet220cons
{
class ZetFun
{
[DllImport("Zadc.dll", ExactSpelling = true)]
static extern int ZOpen(int typeDevice, int numberDSP);

[DllImport("Zadc.dll", ExactSpelling = true)]
static extern int ZClose(int typeDevice, int numberDSP);
}
}В другом файле хотел бы разместить программу считывания данных из АЦП. Но уже при попытке вызвать ZOpen в Main возникли проблемы: ZetFun не видится в файле программы и после точки не показываются функции dll (если описание функций разместить в классе Program, то все работает). Пробовал сделать public ZOpen и ZClose - результат тот же. Если разместить методы в одном файле с программой - все работает. Подскажите, пожалуйста, что нужно изменить в файле (классе) ZetFun c функциями dll и файле (классе) Program, чтобы можно было обращаться к функциям dll из файла (класса) Program. Проект прикрепил.

greg zakharov
03-02-2021, 17:53
Какбэ... есть такая штука, модфикаторы называется: public, protect, internal. В C# объявление класса без явных модификаторов подразумевает private класс, то есть если вы разбиваете проект на сборки, данный аспект особенно чувствителен.
using System;
using System.Runtime.InteropServices;

namespace KakayaToZhopa {
inetrnal static class ExternalCall {
// импорты
[DllImport("tugoybolt.dll", SetLastError = true]
internal static extern Int32 ZhOpen(Int32 DeviceType, Int32 DSPNumber);
}

internal sealed class Program {
static void Main() {
// ... точка входа
}
}
}

tumanovalex
04-02-2021, 14:59
Спасибо за ответ. Я попробовал internal и public сразу же после того, как задал вопрос - не получилось. Оказалось, что я случайно исключил файл с функциями из DLL из компилирования. Прошу прощения за свою невнимательность.

Возникла более серьезная проблема. Есть пример программы на C++ (Test_Zadc.cpp), который я поместил в архив. Код на С++ работает, я проверял на АЦП с подключенными к первому (0) и второму (1) входам АЦП батарейками на 1.5 и 3 V. Все функции из zadc.dll работают нормально в программе на C#, ошибок не выдают. Но у меня не получается правильно перевести строки с указателями. В коде на C++ (проверку на ошибки убрал):short *pBuffer16ADC = NULL; // Указатель на начало буфера драйвера для АЦП с разрядностью не более 16 бит
long *pBuffer32ADC = NULL; // Указатель на начало буфера драйвера для АЦП с разрядностью более 16 бит
long sizeBufferADC; // Размер буфера драйвера в словах
long pointerADC = 0; // Указатель на текущий элемент заполнения буфера драйвера (кратен 2)
long pointerADC_old = 0; // Предыдущее значение указателя на буфер драйвера
// Запрос буфера АЦП
Err = ZGetBufferADC(typeDevice, numberDSP, (void**) &pBuffer16ADC, &sizeBufferADC);
pBuffer32ADC = (long*) pBuffer16ADC;
// Запрос на останов АЦП
Err = ZStopADC(typeDevice, numberDSP);
// Запрос на запуск АЦП
Err = ZStartADC(typeDevice, numberDSP);
// Цикл чтения данных АЦП
while(!kbhit())
{
// Задержка обновления данных АЦП для отображения
Sleep(500);
// Запрос указателя на текущий элемент буфера
Err = ZGetPointerADC(typeDevice, numberDSP, &pointerADC);
// Если новые данные в буфер от АЦП не поступили, то перейти в начало цикла и подождать
if(pointerADC == pointerADC_old)
continue;
// Обновление предыдущего значения указателя
pointerADC_old = pointerADC;
// Переход на отсчет первого включенного канала последнего кадра АЦП
if(pointerADC - numWordsADC * numChannelsADC < 0)
pointerADC = sizeBufferADC + pointerADC - numWordsADC * numChannelsADC;
else
pointerADC = pointerADC - numWordsADC * numChannelsADC;
// Вычисление из целого значения отсчета АЦП вещественного значение отсчета (в вольтах) для первого канала
if(numWordsADC == 1)
volt0 = resolutionADC0 * (pBuffer16ADC[pointerADC]) / amplifyADC0;
else
volt0 = resolutionADC0 * (pBuffer32ADC[pointerADC / numWordsADC]) / amplifyADC0;
// Вывод мгновенного значения напряжения для первого канала
printf("%+8.4f", volt0);
// Если количество каналов устройства больше одного
if(numChannelsADC > 1)
{
// Переход на следующий отсчет АЦП
pointerADC += numWordsADC;
// При выходе за границу буфера, осуществляется переход в начало
if(pointerADC >= sizeBufferADC)
pointerADC = pointerADC - sizeBufferADC;
// Вычисление из целого значения отсчета АЦП вещественного значение отсчета (в вольтах) для второго канала
if(numWordsADC == 1)
volt1 = resolutionADC1 * (pBuffer16ADC[pointerADC]) / amplifyADC1;
else
volt1 = resolutionADC1 * (pBuffer32ADC[pointerADC/numWordsADC]) / amplifyADC1;
// Вывод мгновенного значения напряжения для второго канала
printf("\t%+8.4f", volt1);Я попытался переписать код на C#:IntPtr pBuffer16;
int sizeBuffer;
if (ZetFun.ZGetBufferADC(typeDevice, numberDSP, out pBuffer16, out sizeBuffer) != 0)
ShowMes("Не удалось получить указатель на буфер АЦП!");
IntPtr pBuffer32 = pBuffer16; //НАВЕРНОЕ, НУЖНО КАКОЕ-ТО ПРЕОБРАЗОВАНИЕ
if (ZetFun.ZStartADC(typeDevice, numberDSP) != 0) // инициализация АЦП
ShowMes("Не удалось запустить АЦП!");
var watch = new Stopwatch();
double[] volt = new double[nChan];
int pointer; int pointer_old;
watch.Start();
while (true)
{
Thread.Sleep(500);
if (watch.ElapsedMilliseconds >= 6000)
break;
if (ZetFun.ZGetPointerADC(typeDevice, numberDSP, out pointer) != 0)
ShowMes("Не удалось получить указатель на текущий элемент буфера!");
if (pointer == pointer_old)
continue;
pointer_old = pointer;
for (int i = 0; i < ariNumberChannel.Length; i++)
{
if (pointer - numWords * ariNumberChannel[i] < 0)
pointer = sizeBuffer + pointer - numWords * ariNumberChannel[i];
else
pointer = pointer - numWords * ariNumberChannel[i];
volt[i] = ardResol[i] * (pBuffer32[pointer / numWords]) / ardAmplify[i]; // ТУТ ОШИБКА
// (pBuffer32[pointer / numWords]) подчеркнут красным, я не знаю, как правильно записать эту строку
Console.WriteLine(volt[i]);
pointer += numWords;
if (pointer >= sizeBuffer)
pointer = pointer - sizeBuffer;
} // for
} // while
watch.Stop();
// Запрос на останов АЦП
if(ZetFun.ZStopADC(typeDevice, numberDSP) != 0)
ShowMes("Не удалось остановить АЦП!");
// Запрос на освобождение буфера АЦП
if (pBuffer16 != null)
{
if(ZetFun.ZRemBufferADC(typeDevice, numberDSP, ref pBuffer16) != 0)
ShowMes("Не удалось освободить буфер!");
}
if (ZetFun.ZClose(typeDevice, numberDSP) != 0)
ShowMes("Ошибка ZClose!");Помогите, пожалуйста, разобраться, как нужно переписать строки с указателями в коде на C# так, чтобы получался правильный результат измерения входного сигнала АЦП. Проект прикрепить не смог, максимальная сумма всех вложений достигнута. Подскажите, пожалуйста, как обнулить свои сложения или размещать код по URL.

greg zakharov
04-02-2021, 16:34
В C# указатели реализуются через unsafe code.

tumanovalex
04-02-2021, 22:00
Это я знаю. Только никак не могу понять, как при получении указателя с помощью функцииZetFun.ZRemBufferADC(typeDevice, numberDSP, ref pBuffer16получить из pBuffer16 указатель pBuffer32 и правильно записать формулуvolt[i] = ardResol[i] * (pBuffer32[pointer / numWords]) / ardAmplify[i];Я выделял кусок кода с помощью unsafe{...}, но возникали ошибки. Особенно мне не ясно, что значит выражение (pBuffer32[pointer / numWords]), которое похоже на указание элемента указателя и записывается как массив. В квадратных скобках получается число типа int, поделенное в моем случае на двойку.




© OSzone.net 2001-2012