AnsweredAssumed Answered

C++ Code for reading voltage data from Agilent34972a

Question asked by adaware on Apr 19, 2015
Latest reply on Apr 20, 2015 by adaware
Hi,
I have Agilent34972a with USB address: USB0::0x0957::0x2007::MY49010602::0::INSTR
I have connected 16 channels: 101 to 116. 
I have written C++ code to read voltage from these channels as follows:
I configure agilent meter first, then I have a thread which kicks in every 100ms to read data from Agilent.
I am observing 1 issue if I scan all channels from 101 to 116, I get zero readings for all channels.
If I read only odd channels (101, 103, etc.) then I am getting non-zero valid data.
What can be the issue?
Also there any programming manual available fro 34972a apart from programmer's reference which lists only all commands?
My code is as follows:

Function to open usb port:
/////////////////////////////////////////////////////////////////////////////
// CMeterAgilent34972A
CMeterAgilent34972A::CMeterAgilent34972A()
{
    m_viDefaultSession = VI_NULL;
    m_viDaq34972A = VI_NULL;
}

CMeterAgilent34972A::~CMeterAgilent34972A()
{
}

bool CMeterAgilent34972A::Init(CDaqParms *pDaqParms)
{
    char viPortAddress[500];

    //
    // First initialize m_pDaqParms and then call
    // CMeterAgilent::Init() to do common stuff.
    //
    CMeterAgilent::Init();

    try
    {
        //
        // Open default session.
        //
        // Default session initializes VISA library and it act as resource manager
        // for all DMMs which uses VISA library for communication.Ideally, we
        // should open default session in CMeterAgilent as it handles multiple
        // Agilent DMM. But opening it in 34972A as we are not using VISA for
        // 34970A.
        //
        if (viOpenDefaultRM(&m_viDefaultSession) != VI_SUCCESS)
        {
            return ERROR_MESSAGE_SYSTEM("ERROR: %s",
                    "Could not find USB driver for Agilent 34972A");
        }

        //
        // viOpen does not accept instrument's address in CString form.
        // So convert it into character array.
        //
        strcpy(viPortAddress, m_pDaqParms->strDaqPort);

        // Open session for Agilent 34972A
        if (viOpen(m_viDefaultSession,             // Default session
                   (ViRsrc)viPortAddress,          // DMM's VISA address
                    VI_NULL,                       // Access Mode
                    VI_NULL,                       // Time out
                    &m_viDaq34972A) != VI_SUCCESS) // Session ID
        {
            return ERROR_MESSAGE_SYSTEM("ERROR: %s",
                    "Failed to communicate with USB port");
        }

        viSetAttribute(m_viDaq34972A, VI_ATTR_TERMCHAR_EN, VI_TRUE);
        viSetAttribute(m_viDaq34972A, VI_ATTR_TMO_VALUE, VI_DEFAULT_TIMEOUT);
    }
    catch(...) // Catch all kinds of exceptions
    {
        return ERROR_MESSAGE_SYSTEM("ERROR: %s",
                "Could not find VISA library for Agilent 34972A");
    }
    return true;
}



//Function to write command to agilent meter:


bool CMeterAgilent34972A::WriteCommand(const char *szCommand)
{
    char viTempCommand[500];

    // Each command should be ended with "\n". So append it explicitly.
    strcpy(viTempCommand,szCommand);
    strcat(viTempCommand,"\n");

    if (viWrite(m_viDaq34972A,              // Session ID
                (ViBuf)viTempCommand,       // VI Command
                strlen(viTempCommand),      // Command Lenght
                VI_NULL) != VI_SUCCESS)     // Return Count
    {
        return ERROR_MESSAGE_SYSTEM("ERROR: %s",
                "Failed to send Command to Agilent 34972A");
    }

    return true;
}

//Initialize meter to start reading
void CMeterAgilent34972A::BeginReading()
{
     CString strCommand;
    int i;
    char buf[512];
    int nBothCh[MAX_NUM_CHANNELS_BOTH];

    CString currentRange, voltRange, bothRange;

    m_nNumReadings = 0;
    m_nDataInTextBuf = 0;

    if (m_nNumChannels == 0)
        return;

    // generate sorted channel maps and sorted channel ranges

    // Copy in the current channels.
    for (i = 0; i < m_nNumChannels; i++)
        nBothCh[i] = m_pDaqParms->rails[i].nCurrentChannel;
    BuildChRange( currentRange, currentChMap, nBothCh, m_nNumChannels );

    // Now the voltage channels.
    for (i = 0; i < m_nNumChannels; i++)
        nBothCh[i + m_nNumChannels] = m_pDaqParms->rails[i].nAgilentVoltChannel;
    BuildChRange( voltRange, voltChMap, nBothCh+m_nNumChannels, m_nNumChannels );

    // when voltage is constant, bothRange and bothChMap is the same as currentRange and currentChMap
    if ( m_pDaqParms->bConstantVoltage )
        BuildChRange(bothRange, bothChMap, nBothCh, m_nNumChannels);
    else
        BuildChRange(bothRange, bothChMap, nBothCh, m_nNumChannelsBoth);

    // Stop multimeter
    StopScanning();

    WriteCommand("*RST");
    WriteCommand("SYST:REM");
    WriteCommand("*CLS");

    if ( m_pDaqParms->bDispOff )
    {
        WriteCommand("DISP OFF");
    }

    if ( m_pDaqParms->bConstantVoltage )
    {
        // Get voltage info
        WriteCommand("ROUT:SCAN " + voltRange);
        WriteCommand("SENSE:VOLT:DC:RANG:AUTO ON," + voltRange);
        WriteCommand("SENSE:VOLT:DC:APER 0.1," + voltRange);
        WriteCommand("TRIG:COUNT 1");
        WriteCommand("READ?");
        ReadLine(m_szTextBuf, sizeof m_szTextBuf);

        for (i = 0; i < m_nNumChannels; i++)
        {
            CRail *pRail = &m_pDaqParms->rails[voltChMap[i]];

            sscanf(m_szTextBuf + (i * 16),"%lf", &pRail->m_fVoltage);

            if ( pRail->m_fVoltage < 0 )
            {
                pRail->m_fVoltage *= -1;
            }
        }
    }

    // Zero the buffer
    for (i = 0; i < m_nMaxReadings * m_nNumChannels; i++)
        m_pBuffer[i] = 0.0;

    // Configure the card for getting reading across the precision resistor.
    //
    WriteCommand("ROUT:SCAN " + bothRange);

    if ( m_pDaqParms->bAutoRange )
    {
        WriteCommand("SENSE:VOLT:DC:RANG:AUTO ON," + bothRange);
    }
    else
    {
        sprintf(buf, "%.1f,", m_pDaqParms->dCurrentVoltRange);
        WriteCommand(CString("SENSE:VOLT:DC:RANG ") + buf + currentRange);

        if ( !m_pDaqParms->bConstantVoltage )
        {
            sprintf(buf, "%.1f,", m_pDaqParms->dVoltageVoltRange);
            WriteCommand(CString("SENSE:VOLT:DC:RANG ") + buf + voltRange);
        }
    }

    if ( m_pDaqParms->bMinNplc )
    {
        WriteCommand(CString("SENSE:VOLT:DC:NPLC MIN,") + bothRange);
    }
    else
    {
        sprintf(buf, "%10.6f,", m_pDaqParms->uSampleInterval * 0.000001);
        WriteCommand(CString("SENSE:VOLT:DC:APER ") + buf + bothRange);
    }

    if ( !( m_pDaqParms->bAutoZero ) )
    {
        WriteCommand("SENSE:ZERO:AUTO OFF," + bothRange);
    }

    WriteCommand("TRIG:COUNT INF");
    WriteCommand("READ?");

    m_bReading = true;


//Now polling threads call below function to get data from agilent meter
//
// ViRead returns if one or more of the following conditions were met -
// 1) Termination character received
// 2) Number of bytes read is equal to nLen
// 3) On timout
// So set VISA TIMOUT VI_READ_DATA_TIMEOUT at start of function.
//
bool CMeterAgilent34972A::ReadData(char *pBuf, int nLen)
{
    FILE *fp = NULL;

    ViStatus viStatus;
    ViUInt32 actualCnt;

    viSetAttribute(m_viDaq34972A, VI_ATTR_TMO_VALUE, VI_READ_DATA_TIMEOUT);

    viStatus = viRead(m_viDaq34972A,    // Session ID
                    (ViPBuf)pBuf,       // Buffer to store data
                    nLen,               // Number of bytes to be read
                    &actualCnt);        // Bytes actually transfered
    if ((viStatus != VI_SUCCESS) && (viStatus != VI_ERROR_TMO))
    {
        return ERROR_MESSAGE_SYSTEM("ERROR: %s",
                "Failed to read data from Agilent 34972A");
    }

    pBuf[actualCnt] = 0;

    viSetAttribute(m_viDaq34972A, VI_ATTR_TMO_VALUE, VI_DEFAULT_TIMEOUT);

    return true;
}


Please help me.
Thanks in advance.  

Outcomes