Как дождаться запроса на обслуживание (RQS)

** Примечание. Перекрестно размещено на форумах LabVIEW: http://forums.ni.com/t5/LabVIEW/C-VISA-wait-on-RQS/td-p/3122939

Я пытаюсь написать простую программу C # (.NET 4.0) для управления SMU Keithley 2400 через VISA GPIB, и у меня возникают проблемы с тем, чтобы программа ожидала запроса на обслуживание, который Keithley отправляет в конце развертки .

Развертка представляет собой простую линейную развертку напряжения, внутренне управляемую блоком Кейтли. У меня есть устройство, настроенное на отправку сигнала ServiceRequest в конце цикла или при достижении соответствия.

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

Одна проблема, с которой я столкнулся, заключается в том, что я новичок в C # - я использую этот проект (портирую части моего LV-кода), чтобы изучить его.

Вот что у меня есть для моего кода на C #:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using NationalInstruments.VisaNS;

private void OnServiceRequest(object sender, MessageBasedSessionEventArgs e)
{
    Console.WriteLine("Service Request Received!");
}

// The following code is in a class method, but
public double[,] RunSweep()
{
    // Create the session and message-based session
    MessageBasedSession mbSession = null;
    Session mySession = null;
    string responseString = null;

    // open the address
    Console.WriteLine("Sending Commands to Instrument");
    instrAddr = "GPIB0::25::INSTR";
    mySession = ResourceManager.GetLocalManager().Open(instrAddr);

    // Cast to message-based session
    mbSession = (MessageBasedSession)mySession;

    // Here's where things get iffy for me... Enabling the event and whatnot
    mbSession.ServiceRequest += new MessageBasedSessionEventHandler(OnServiceRequest);
    MessageBasedSessionEventType srq = MessageBasedSessionEventType.ServiceRequest;
    mbSession.EnableEvent(srq, EventMechanism.Handler);

    // Start the sweep (SMU was set up earlier)
    Console.WriteLine("Starting Sweep");
    mbSession.Write(":OUTP ON;:INIT");

    int timeout = 10000;             // milliseconds
    // Thread.Sleep(10000);          // using this line works fine, but it means the test always takes 10s even if compliance is hit early

    // This raises error saying that the event is not enabled.
    mbSession.WaitOnEvent(srq, timeout);

    // Turn off the SMU.
    Console.WriteLine("I hope the sweep is done, cause I'm tired of waiting");
    mbSession.Write(":OUTP OFF;:TRAC:FEED:CONT NEV");

    // Get the data 
    string data = mbSession.Query(":TRAC:DATA?");

    // Close session
    mbSession.Dispose();

    // For now, create a dummy array, 3x3, to return. The array after is the starting value.
    double[,] dummyArray = new double[3, 3] {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

    return dummyArray;
}

Все вышеперечисленное должно имитировать этот код LabVIEW: simple Keithley Sweep

Итак, есть идеи, где я ошибаюсь?

Спасибо,

Редактировать:

Немного поигравшись, я обнаружил, что функция запроса на обслуживание OnServiceRequest действительно запускается в нужное время (на консоль выводится сообщение «Запрос на обслуживание получен!»).


person dthor    schedule 21.04.2015    source источник
comment
Я отредактировал ваше название. См. Должны ли вопросы включать «теги» в свои заголовки?, где нет единого мнения, не следует.   -  person John Saunders    schedule 22.04.2015
comment
Спасибо, @JohnSaunders, извините за это.   -  person dthor    schedule 22.04.2015


Ответы (2)


Оказывается, мне нужно включить событие как Очередь, а не как обработчик. Эта строка:

mbSession.EnableEvent(srq, EventMechanism.Handler);

На самом деле должно быть:

mbSession.EnableEvent(srq, EventMechanism.Queue);

Источник: Документация в разделе " Замечания ». Было больно найти на него документацию ... NI нужно упростить :-(.

С этим изменением мне также не нужно создавать MessageBasedSessionEventHandler.

Окончательный рабочий код выглядит так:

rm = ResourceManager.GetLocalManager().Open("GPIB0::25::INSTR");
MessageBasedSession mbSession = (MessageBasedSession)rm;
MessageBasedSessionEventType srq = MessageBasedSessionEventType.ServiceRequest;
mbSession.EnableEvent(srq, EventMechanism.Queue);    // Note QUEUE, not HANDLER
int timeout = 10000;

// Start the sweep
mbSession.Write(":OUTP ON;:INIT");

// This waits for the Service Request
mbSession.WaitOnEvent(srq, timeout);

// After the Service Request, turn off the SMUs and get the data
mbSession.Write(":OUTP OFF;:TRAC:FEED:CONT NEV");
string data = mbSession.Query(":TRAC:DATA?");
mbSession.Dispose();
person dthor    schedule 22.04.2015
comment
Добро пожаловать в C #. Большинство методов сеанса, включая Write, могли вызвать исключение, нарушив поток выполнения. Итак, вы должны поместить вызов Dispose в блок finally. Это такой распространенный шаблон в .NET, в C # есть оператор using так что вам на самом деле не нужно выписывать попытку - наконец, просто позвонить Dispose. - person Tom Blodget; 23.04.2015
comment
Спасибо @TomBlodget. Я буду помещать большинство вещей в блоки try ... catch ... finally, когда закончу код. Я в первую очередь разработчик Python и привык складывать большинство вещей в эти блоки :-). Я не включил их в этот пост, чтобы было легче читать. Но хорошая информация об утверждении using, я этого не знал. - person dthor; 24.04.2015

То, что вы делаете, мне кажется правильным, так что возможно, что есть проблема с библиотекой NI.

Единственное, что я могу придумать, - это дождаться «всех событий», а не просто «ServiceRequest». нравится:

mbSession.WaitOnEvent(MessageBasedSessionEventType.AllEnabledEvents, timeout);

Примечание: похоже, что вы не можете «включить» все события (так что не меняйте эту часть).

Я также поискал несколько примеров того, как другие люди проводят чистки Кейтли, и нашел this и this (например, Matlab). Как я подозревал, в обоих случаях они не используют события для определения того, когда сканирование завершено, а скорее «цикл while, который продолжает опрашивать Кейтли» (первая ссылка фактически использует потоки, но это та же идея). Это заставляет меня думать, что, возможно, это ваш лучший выбор. Итак, вы могли просто сделать это:

        int timeout = 10000;
        int cycleWait = 1000;

        for (int i = 0; i < timeout / cycleWait; i++)
        {
            try
            {
                string data = mbSession.Query(":TRAC:DATA?");
                break;
            }
            catch
            {
                Thread.Sleep(cycleWait); 
            }
        }

(Возможно, вам также придется проверить, являются ли данные нулевыми, но должен быть какой-то способ узнать, когда сканирование завершено).

person Charlie    schedule 22.04.2015
comment
Я бы хотел избежать опроса, если это вообще возможно, но спасибо за информацию. Я воспользуюсь этим как запасной вариант. Я отредактировал сообщение с дополнительной информацией о запросе на обслуживание: обработчик запроса на обслуживание вызывается в нужное время, поэтому, возможно, я смогу использовать его для продолжения программы. - person dthor; 22.04.2015