Форум ZETLAB

Архив обсуждений, технических вопросов и ответов по оборудованию, программному обеспечению и внедрению измерительных систем.

Страницы: 1
RSS
Неправильный вывод значений напряжения (ZET 220) на трех каналах
 
ZetLab ZET 220 с интерфейсом USB нужно использовать как многоканальный АЦП (количество подключенных каналов не менее 8). Я взял пример с сайта ZetLab Test_Zadc_C++ и немного его переделал:
Код
#include <windows.h> 
#include <conio.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include "zadc_int.h"   

using namespace std;

int ErrorMessage(std::string MessageError)
{
   std::cout << MessageError << std::endl;
   std::cin.get();
   exit(EXIT_FAILURE);
}

template<typename T, long n>  
inline long arraySize(const T(&arr)[n])
{
   return n;
}

template<typename T>
inline string NumToStr(T num)
{
   ostringstream stream;
   stream << num;
   string str = stream.str();
   return str;
}

int main(int argc, char* argv[])
{
   setlocale(LC_ALL, "");
   long numChannelsOn[] = {1, 4, 15}; // 2, 5 и 16 каналы
   //long numChannelsOn[] = {1, 15}; // программа работает правильно
   long typeDevice = 16;                  // Тип устройства
   long numberDSP = 0;                  // Порядковый номер сигнального процессора
   long enable;                     // Флаг поддерживается / не поддерживается
   long numChannelsADC;               // Количество включенных каналов АЦП
   long numWordsADC;                  // Количество слов (по два байта) в одном отсчете АЦП
   short *pBuffer16ADC = NULL;            // Указатель на начало буфера драйвера для АЦП с разрядностью не более 16 бит
   long *pBuffer32ADC = NULL;            // Указатель на начало буфера драйвера для АЦП с разрядностью более 16 бит 
   long sizeBufferADC;                  // Размер буфера драйвера в словах
   long pointerADC = 0;               // Указатель на текущий элемент заполнения буфера драйвера (кратен 2)
   long pointerADC_old = 0;            // Предыдущее значение указателя на буфер драйвера
   // Открытие устройства
   if(ZOpen(typeDevice, numberDSP) != 0 ) 
      ErrorMessage("Не удалось открыть АЦП");
   // Проверка возможности АЦП   
   if(ZGetEnableADC(typeDevice, numberDSP, &enable) != 0 && enable != 0) 
      ErrorMessage("Устройство не может работать как АЦП");
   std::cout << "Устройство может работать как АЦП"  << std::endl;
      // Определение количества каналов   
   if(ZGetQuantityChannelADC(typeDevice, numberDSP, &numChannelsADC) != 0)
      ErrorMessage("Не удалось определить общее количество каналов: " + NumToStr(numChannelsADC));
   std::cout << "АЦП имеет " +  NumToStr(numChannelsADC) + " каналов" << std::endl;
   // Отключение всех каналов
  enable = 0;   
   for(long i = 0; i < numChannelsADC; i++) 
   {
      if(ZSetInputADC(typeDevice, numberDSP, i, enable) != 0)
         std::cout << "Не удалось отключить канал: " + NumToStr(i) << std::endl;
   }
   long NumChannelsOn = arraySize(numChannelsOn); // число включенных каналов
   // включение нужных каналов   
  enable = 1;   
   for(long i = 0; i < NumChannelsOn; i++)
   {
      if(ZSetInputADC(typeDevice, numberDSP, numChannelsOn[i], 1) != 0)
         ErrorMessage("Не удалось включить канал: " + NumToStr(numChannelsOn[i]));
      else
        std::cout << "Включен канал: " + NumToStr(numChannelsOn[i] + 1) << std::endl;
  }
   // проверка правильности определения количества включенных каналов   
   if(ZGetNumberInputADC(typeDevice, numberDSP, &numChannelsADC) != 0)
      ErrorMessage("Не удалось определить количество включенных каналов");
   if(NumChannelsOn != numChannelsADC)
      ErrorMessage("Количество нужных каналов " + NumToStr(NumChannelsOn) + " не соответствует " 
                                                      + NumToStr(numChannelsADC) + " включенным каналам");
   std::cout << "Количество заданных каналов "    + NumToStr(NumChannelsOn) + 
                      " равно " + NumToStr(numChannelsADC) + " - результату выполнения функции ZGetNumberInputADC "  << std::endl;
   double *ardAmpl = new double[NumChannelsOn];
   for (long i = 0; i < NumChannelsOn; i++)
   {
      if (ZGetAmplifyADC(typeDevice, numberDSP, numChannelsOn[i], &ardAmpl[i]) != 0)
         ErrorMessage("Не удалось определить усиление канала: " + NumToStr(numChannelsOn[i]));
      else
         std::cout << "Усиление канала " + NumToStr(numChannelsOn[i] + 1) + " равно " + NumToStr(ardAmpl[i]) << std::endl;
   }
   // Опрос веса младшего разряда АЦП включенных каналов устройства
   double *ardResol = new double[numChannelsADC];
   for (long i = 0; i < NumChannelsOn; i++)
   {
      if (ZGetDigitalResolChanADC(typeDevice, numberDSP, numChannelsOn[i], &ardResol[i]) != 0)
         ErrorMessage("Не удалось определить разрешение канала: " + NumToStr(i));
      else
         std::cout << "Разрешение канала " + NumToStr(numChannelsOn[i] + 1) + " равно " + NumToStr(ardResol[i]) << std::endl;
   }
   // Опрос количества слов в одном отсчета АЦП устройства
   if (ZGetWordsADC(typeDevice, numberDSP, &numWordsADC) != 0)
      ErrorMessage("Не удалось определить количество слов в одном отсчете АЦП");
   else
      std::cout << "В одном отсчета АЦП " + NumToStr(numWordsADC) + " слова" << std::endl;
   // Запрос буфера АЦП
   if (ZGetBufferADC(typeDevice, numberDSP, (void**) &pBuffer16ADC, &sizeBufferADC) != 0)
      ErrorMessage("Не удалось определить буфер устройства");
   pBuffer32ADC = (long*) pBuffer16ADC;
   std::cout << "Указатель на буфер pBuffer32ADC равен " + NumToStr(pBuffer32ADC) << std::endl;
    //Запрос на останов АЦП
   if(ZStopADC(typeDevice, numberDSP) != 0)
      ErrorMessage("Не удалось остановить устройство"); 
    //Запрос на запуск АЦП
  if(ZStartADC(typeDevice, numberDSP) != 0)
      ErrorMessage("Не удалось запустить устройство");
   double *volt = new double[numChannelsADC];
   std::cout.setf(ios::fixed);
   std::cout.width(10); // задает ширину поля
   std::cout.precision(5);  // задает количество знаков после десятичной точки
   // Цикл чтения данных АЦП
   while(!_kbhit())
   {
      // Задержка обновления данных АЦП для отображения
      Sleep(500);
      // Запрос указателя на текущий элемент буфера
      if(ZGetPointerADC(typeDevice, numberDSP, &pointerADC) != 0)
         ErrorMessage("Не удалось получить указатель на буфер устройства");
      // Если новые данные в буфер от АЦП не поступили, то перейти в начало цикла и подождать
      if(pointerADC == pointerADC_old)
         continue;
      // Обновление предыдущего значения указателя
      pointerADC_old = pointerADC;
      //Переход на отсчет первого включенного канала последнего кадра АЦП
      if(pointerADC - numWordsADC * numChannelsADC < 0)
         pointerADC = sizeBufferADC + pointerADC - numWordsADC * numChannelsADC;
      else 
         pointerADC = pointerADC - numWordsADC * numChannelsADC; 
      volt[0] = ardResol[0] * (pBuffer32ADC[pointerADC / numWordsADC]) / ardAmpl[0];
      cout << volt[0] << endl;
      for(long i = 1; i < NumChannelsOn; i++)
      { 
         //Переход на следующий отсчет АЦП
         pointerADC += numWordsADC;
         //При выходе за границу буфера, осуществляется переход в начало
     
         if(pointerADC >= sizeBufferADC)
            pointerADC = pointerADC - sizeBufferADC;
         volt[i] = ardResol[i] * (pBuffer32ADC[pointerADC / numWordsADC]) / ardAmpl[i];
         cout << volt[i] << endl;
      } // for
      cout << " ---------------------------------------------" << endl;
   } // while
   // Запрос на останов АЦП
   if (ZStopADC(typeDevice, numberDSP) != 0)
      ErrorMessage("Не удалось остановить устройство");
   // Запрос на освобождение буфера АЦП
   if(pBuffer16ADC != NULL)
   {
      if(ZRemBufferADC(typeDevice, numberDSP, (void**) &pBuffer16ADC) != 0)
         ErrorMessage("Не удалось освободить буфер устройства");
   }
   // Отключение от драйвера устройства
   if(ZClose(typeDevice, numberDSP) != 0)
         ErrorMessage("Не удалось отключить устройство");
   delete [] volt;
   delete [] ardResol;
   delete [] ardAmpl;

   if(!_kbhit())
      _getch();

   std::cout << "Press any key for exit..." << std::endl;
   _getch();

    return 0;
}
Проверку правильности работы программы я сделал на 3 каналах: второй канал подключил к одной батарейке (1,5 В), 5 и 16 каналы - соотвественно к 2 и 4 батарейкам (3 и 6 В). Значения напряжение определяются правильно, но вывод значений не соответствует порядку каналов:
Код
6.53385
1.45083
3.19009
 ---------------------------------------------
3.20306
6.51513
1.44911
 ---------------------------------------------
1.45500
3.19388
6.50739
 ---------------------------------------------
6.53386
1.45084
3.19009
 ---------------------------------------------
3.20306
6.51515
1.44911
 ---------------------------------------------
1.45500
3.19388
6.50740
Мне нужно строить графики и при таком выводе это невозможно. Если использовать только 2 канала (2 и 15) вместо трех, то вывод идет нормально:
Код
1.45499
6.47789
 ---------------------------------------------
1.45494
6.47786
 ---------------------------------------------
1.45501
6.47784
 ---------------------------------------------
1.45497
6.47788
Подскажите, пожалуйста, как исправить программу, чтобы при количестве каналов более двух порядок вывода значений напряжения был правильным.
 
Добрый день! Проблема в том, что значение pointerADC не обязательно кратно количеству каналов, т.е. после запроса текущего значения pointerADC нужно понять на значение какого из каналов он указывает: 1, 2 или 3. При двух каналах все хорошо, потому что значение pointerADC всегда кратно 2.
 
"После запроса текущего значения pointerADC нужно понять на значение какого из каналов он указывает: 1, 2 или 3". А как это понять? Что нужно сделать в программе?
 
Для реализации этого алгоритма нужно ввести свое значение PointerADC и читать по нему. Такой пример: 1) PointerAdc_Real = 0, PointerAdc_User = 0 2) PointerAdc_Real = 4 => PointerAdc_User = 3. 3) PointerAdc_Real = 8 => PointerAdc_User = 6 4) PointerAdc_Real = 12 => PointerAdc_User = 12 На первом шаге оба указателя равны 0. На всех последующих шагах указатель в буфере изменился, но свой указатель можно изменить только на число, кратное количеству каналов.
 
Я плохо понял Ваше объяснение. Где нужно ввести свое значение pointerADC (в цикле while или где-нибудь еще) и как оно будет связано с получением указателя функцией ZGetPointerADC? Указатель Real - это получение указателя функцией ZGetPointerADC? Почему такие соотношения чисел для real и user? Хорошо бы Вы пояснили это в коде. Я разместил проект на яндекс-диске https://yadi.sk/d/UEpUEY6aeM2A9g
 
В программе происходит чтение значения PointerADC, т.е. того индекса в буфере драйвера, куда будут копироваться драйвером вновь пришедшие данные от АЦП. Соответственно все данные до этого индекса - это те данные, которые от АЦП уже пришли. Буфер циклический, поэтому данные все время будут затираться, но поскольку размер буфера довольно большой, то программа успеет их скопировать и обработать. АЦП присылает данные порциями, которые могут быть не кратны количеству каналов, поэтому в общем случае текущее значение PointerADC может не указывать на отсчет по первому включенному каналу. Именно для этого pointerADC нужно выравнивать на количество включенных каналов. А это значит, что в программе нужно завести еще одну переменную (PointerAdc_User) и в ней хранить это выравненное значение и читать данные именно по нему. В приведенном выше примере PointerAdc_Real - это то, что вернула функция, PointerAdc_User - это пересчитанное значение. После старта АЦП обе переменные (user и real) равны 0, т.е. никаких данных в буфер еще не поступало. Теперь предположим, что Real стал равен 4, а следовательно мы должны пересчитать User относительно того, что у нас включено 3 канала, поэтому User у нас становится равным 3 и читать из буфера мы будем именно относительно User, а не относительно Real. И так далее. Помощь в написании кода программы доступна только при запросе по электронной почте info@zetlab.com при наличии лицензии ZETLAB STUDIO.
 
Из описания я не понял, с помощью ZETLAB STUDIO можно работать с любыми приборами или только с приборами фирмы ZETLAB. Исходя из цены, можно предположить, что только с приборами фирмы ZetLab. Я правильно понял, что студия может работать только с приборами фирмы Zetlab?
 
При использования библиотеки Zadc.dll, ZETLAB STUDIO поддерживает только устройства производства ZETLAB. А любые графические элементы можно использовать с устройствами сторонних производителей.
 
Спасибо за ответ, понятно.
Страницы: 1
Читают тему