Zählereingänge

Mit Hilfe der LIBAD4 Bibliothek ist es sehr einfach, einen Zählereingang auszulesen. Dazu öffnet das Beispiel Messsystem (ad_open), stellt dann die Betriebsart (ad_set_counter_mode) ein und liest den Zählerstand aus (ad_discrete_in). Zuletzt wird das Messsystem wieder geschlossen (ad_close). Natürlich würde in einem realen Programm das Messsystem nur einmal am Beginn des Programms geöffnet und am Ende wieder geschlossen werden. Auch die Betriebsart des Zähler muss nur einmal eingestellt werden und nicht vor jedem Auslesen.

Der Sourcecode des Beispiels befindet sich im LIBAD4 SDK im Verzeichnis examples/counter (und dort jeweils in den Verzeichnissen ccs und vb für C/C++, C# und Visual Basic™ .Net). Wie alle Beispiele, verzichtet auch dieses aus Gründen der Einfachheit auf eine solide Fehlerbehandlung...

Das Beispiel verwendet die Routine do_counter() um den Aufruf der LIBAD4 Funktionen ad_open()ad_set_counter_mode()ad_discrete_in() und ad_close() zu zeigen. An diese Routine wird der Name des Messgeräts (driver), die Betriebsart (mode), ein Flag zum Aktivieren der Resetleitung (enable_rst) und die Nummern der Zählerkanäle (chav) übergeben. Die C/C++ Variante übergibt zusätzlich noch die Anzahl der Kanäle (chac). Alle Argumente werden in main() von der Kommandozeile gewonnen, entsprechend aufbereitet und dann an do_counter() übergeben.

Der erste Parameter auf der Kommandozeile wird in driver übergeben und legt das Messsystem fest. Beispielsweise öffnet "usb-oi16:@100" die USB-OI16 mit der Seriennumer 100. Ausführliche Hinweise zu den notwendigen Namen für die verschiedenen Messsysteme finden Sie im LIBAD4 Handbuch in Kapitel 6, Messsysteme.

Dieser Name wird von do_counter() direkt an ad_open() weitergegeben. Der Rückgabewert von ad_open() ist ein Handle, der das geöffnete Messsystem repräsentiert und an alle Funktionen der LIBAD4 übergeben werden muss. Im Fehlerfall wird -1zurückgegeben.

Der Parameter mode definiert die Betriebsart des Zähler und wird in main() durch das optionale Kommandzeilenargument -counter (AD_CNT_COUNTER), -updown (AD_CNT_UPDOWN) oder -quad (AD_CNT_QUAD_DECODER) bestimmt. Per default steht dieser Wert auf -1 und sorgt so dafür, dass die Betriebsart nicht verändert wird.

Die restlichen Argumente auf der Kommandzeile werden von main() in Zahlen konvertiert und in das Feld chav[] geschrieben. In einer Schleife über alle Kanäle stellt do_counter() dann die Betriebsart des Zählers ein. Dazu wird die Variable par entsprechend belegt und an ad_set_counter_mode übergeben. Dabei definiert par.cha den Kanal und par.mode die Betriebsart. Die Einstellungen in par.mux_a sowie par.mux_b legen fest, mit welchen Digitalleitungen die Zählereingänge verbunden werden (im Beispiel fest Port A/1 und Port A/2). Falls auf der Kommandzeile -rst angegeben worden ist, dann wird der Reseteingang des Zählers aktiviert. Das Beispiel verbindet den Reset (par.mux_rst) fest mit Port A/3.

Danach wird der aktuelle Zählerstand durch Aufruf von ad_discrete_in ermittelt. Dabei spezifiert das erste Argument (adh) das Messsystem (wie von ad_open() geliefert), das zweite Argument den Kanal (bestehend aus dem Kanaltyp AD_CHA_TYPE_COUNTER und der Nummer des Kanals chav[i]) und das dritte Argument den Messbereich (für Zählerlkanäle immer 0). Als letztes Argument wird data] übergeben, das den aktuellen Zählerstand aufnimmt. Die Funktion gibt im Fehlerfall einen Wert ungleich null zurück, wobei diese Fehlernummer immer einer Fehlernummer des Hostrechners entspricht (also z.B. unter Windows wird eine Fehlernummer aus <winerror.h> zurückgegeben).

Nach dem Schleifenende wird das Messsystem mit ad_close() wieder geschlossen.

/* Libad Counter Example
 *
 * Example showing how to setup counter mode and read counter value
 * using bmcm's LIBAD4.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "libad.h"
/* Setup counter and read actual value.
 */
void
do_counter (const char *driver, int mode, int enable_rst, int chac, int chav[])
{
  int32_t adh;
  int i;
  /* Open DAQ system.
   */
  adh = ad_open (driver);
  if (adh == -1)
    {
      printf ("failed to open %s: err = %d\n", driver, errno);
      return;
    }
  /* Set counter mode and read actual value.
   */
  for (i = 0; i < chac; i++)
    {
      struct ad_counter_mode par;
      uint32_t data;
      int rc;
      if (mode != -1)
        {
          /* Setup counter mode, using Port A/1 and Port A/2 as
           * both counter inputs. The counter's reset input
           * gets connected to Port A/3 (if enabled).
           */
          memset (&par, 0, sizeof(par));
          par.cha = AD_CHA_TYPE_COUNTER | chav[i];
          par.mode = mode;
          par.mux_a = 0;
          par.mux_b = 1;
          if (enable_rst)
            {
              par.mux_rst = 2;
              par.flags |= AD_CNT_ENABLE_RST;
            }
          rc = ad_set_counter_mode (adh, &par);
          if (rc != 0)
            {
              printf ("error: failed to setup counter %d: err = %d\n", chav[i], rc);
              return;
            }
        }
      rc = ad_discrete_in (adh, AD_CHA_TYPE_COUNTER|1, 0, &data);
      if (rc == 0)
        printf ("counter %d: %d\n", chav[i], data);
      else
        printf ("error: failed to read counter %d: err = %d\n", chav[i], rc);
    }
  /* Close DAQ system again.
   */
  ad_close (adh);
}
/* Show usage.
 */
void
usage ()
{
  printf ("usage: counter <driver> [-counter|-updown|-quad] [-rst] <cha1> .. <chan>\n"
          "  <driver>     string to pass to ad_open()\n"
          "               - will prompt for name\n"
          "  -counter     configure counter mode\n"
          "  -updown      configure up/down counter mode\n"
          "  -quad        configure quad-decoder counter mode\n"
          "  -rst         enable counter's reset input\n"
          "  <cha1..n>    number of counter channel to (configure and) read\n");
}
/* Main entry point.
 */
int
main (int argc, char *argv[])
{
  if (argc > 1)
    {
      char *name, *p, tmp[80];
      int i, start, mode, enable_rst, chac, chav[16];
      /* First command line argument is the DAQ's name.
       * If "-" is passed, then let's read the name from
       * the console.
       */
      name = argv[1];
      if (strcmp (argv[1], "-") == 0)
        {
          printf ("data acquisition system to open: ");
          fgets (tmp, sizeof(tmp), stdin);
          p = strchr (tmp, '\n');
          if (p)
            *p = 0;
          name = tmp;
        }
      /* Counter mode defaults to -1 (i.e. do not configure), but
       * may get overridden by command line.
       */
      start = 2;
      mode = -1;
      enable_rst = 0;
      while (argc > start)
        {
          if (strcmp (argv[start], "-counter") == 0)
            {
              mode = AD_CNT_COUNTER;
              start++;
            }
          else if (strcmp (argv[start], "-updown") == 0)
            {
              mode = AD_CNT_UPDOWN;
              start++;
            }
          else if (strcmp (argv[start], "-quad") == 0)
            {
              mode = AD_CNT_QUAD_DECODER;
              start++;
            }
          else if (strcmp (argv[start], "-rst") == 0)
            {
              enable_rst = 1;
              start++;
            }
          else
            break;
        }
      /* Convert remaining command line arguments
       * into numbers and add those to the channel array.
       */
      chac = 0;
      for (i = start; i < argc; i++)
        {
          chav[chac] = atoi (argv[i]);
          chac++;
          if (chac >= 16)
            break;
        }
      /* Configure counter and read actual values, printing results
       * to the console.
       */
      do_counter (name, mode, enable_rst, chac, chav);
      if (strcmp (argv[1], "-") == 0)
        {
          printf ("press return to continue...\n");
          fgets (tmp, sizeof(tmp), stdin);
        }
      return 0;
    }
  else
    {
      usage ();
      return 1;
    }
}
// Libad Counter Example
//
// Example showing how to setup counter mode and read counter value
// using bmcm's LIBAD4.
using System;
using LIBAD4;
static class Example
{
  // Setup counter and read actual value.
  static void
  do_counter (string driver, int mode, bool enable_rst, int[] chav)
  {
    // Open DAQ system.
    int adh = LIBAD.ad_open (driver);
    if (adh == -1)
      {
        Console.WriteLine ("failed to open {0}: err = {1}", driver, LIBAD.errno);
        return;
      }
    // Set counter mode and read actual value.
    for (int i = 0; i < chav.Length; i++)
      {
        uint data = 0;
        int rc;
        if (mode >= 0)
          {
            LIBAD.ad_counter_mode par;
            /* Setup counter mode, using Port A/1 and Port A/2 as
             * both counter inputs. The counter's reset input
             * gets connected to Port A/3 (if enabled).
             */
            par = new LIBAD.ad_counter_mode ();
            par.cha = LIBAD.AD_CHA_TYPE_COUNTER | chav[i];
            par.mode = (byte) (mode & 0xff);
            par.mux_a = 0;
            par.mux_b = 1;
            if (enable_rst)
              {
                par.mux_rst = 2;
                par.flags |= LIBAD.AD_CNT_ENABLE_RST;
              }
            rc = LIBAD.ad_set_counter_mode (adh, ref par);
            if (rc != 0)
              {
                Console.WriteLine ("error: failed to setup counter %d: err = %d\n", chav[i], rc);
                return;
              }
          }
        rc = LIBAD.ad_discrete_in (adh, LIBAD.AD_CHA_TYPE_COUNTER | chav[i], 0, ref data);
        if (rc == 0)
          Console.WriteLine ("counter {0,2}: {1}", chav[i], data);
        else
          Console.WriteLine ("error: failed to write cha {0}: err = {1}", chav[i], rc);
      }
    // Close DAQ system again.
    LIBAD.ad_close (adh);
  }
  // Show usage.
  static void
  usage ()
  {
    Console.WriteLine ("usage: counter <driver> [-counter|-updown|-quad] [-rst] <cha1> .. <chan>");
    Console.WriteLine ("  <driver>     string to pass to ad_open()");
    Console.WriteLine ("               - will prompt for name");
    Console.WriteLine ("  -counter     configure counter mode");
    Console.WriteLine ("  -updown      configure up/down counter mode");
    Console.WriteLine ("  -quad        configure quad-decoder counter mode");
    Console.WriteLine ("  -rst         enable counter's reset input");
    Console.WriteLine ("  <cha1..n>    number of counter channel to (configure and) read");
  }
  // Main entry point.
  static int
  Main (string[] argv)
  {
    if (argv.Length > 0)
      {
        // First command line argument is the DAQ's name.
        // If "-" is passed, then let's read the name from
        // the console.
        string name = argv[0];
        if (argv[0] == "-")
          {
            Console.Write ("data acquisition system to open: ");
            name = Console.ReadLine ();
          }
      // Direction defaults to input, but may get overridden by -o
      // on the command line.
      int start = 1;
      int mode = -1;
      bool enable_rst = false;
      while (argv.Length > start)
        {
          if (argv[start] == "-counter")
            {
              mode = LIBAD.AD_CNT_COUNTER;
              start++;
            }
          else if (argv[start] == "-updown")
            {
              mode = LIBAD.AD_CNT_UPDOWN;
              start++;
            }
          else if (argv[start] == "-quad")
            {
              mode = LIBAD.AD_CNT_QUAD_DECODER;
              start++;
            }
          else if (argv[start] == "-rst")
            {
              enable_rst = true;
              start++;
            }
          else
            break;
        }
        // Convert remaining command line arguments into
        // numbers and add those to the channel array.
        int[] chav = new int[argv.Length - start];
        for (int i = start; i < argv.Length; i++)
          {
            chav[i - start] = int.Parse (argv[i]);
          }
        // Configure counter and read actual values, printing results
        // to the console.
        do_counter (name, mode, enable_rst, chav);
        if (argv[0]== "-")
          {
            Console.WriteLine ("press return to continue...");
            Console.ReadLine ();
          }
        return 0;
      }
    else
      {
        usage ();
        return 1;
      }
  }
}
' Libad Counter Example
'
' Example showing how to setup counter mode and read counter value
' using bmcm's LIBAD4.
Imports System
Imports LIBAD4
Module Example
  ' Setup counter and read actual value.
  Sub do_counter (driver As String, mode As Integer, enable_rst As Boolean, ByVal chav As Integer())
    ' Open DAQ system.
    Dim adh As Integer
    adh = LIBAD.ad_open (driver)
    If adh = -1 Then
      Console.WriteLine ("failed to open {0}: err = {1}", driver, LIBAD.errno)
      Exit Sub
    End If
    ' Set counter mode and read actual value.
    For i = 0 To chav.Length-1
      Dim data As Uinteger
      Dim rc As Integer
      If mode >= 0 Then
        Dim par As LIBAD.ad_counter_mode
        ' Setup counter mode, using Port A/1 and Port A/2 as
        ' both counter inputs. The counter's reset input
        ' gets connected to Port A/3 (if enabled).
        par = new LIBAD.ad_counter_mode ()
        par.cha = LIBAD.AD_CHA_TYPE_COUNTER Or chav(i)
        par.mode = mode And &Hff
        par.mux_a = 0
        par.mux_b = 1
        If enable_rst Then
          par.mux_rst = 2
          par.flags = par.Flags Or LIBAD.AD_CNT_ENABLE_RST
        End If
        rc = LIBAD.ad_set_counter_mode (adh, par)
        If rc <> 0 Then
          Console.WriteLine ("error: failed to setup counter %d: err = %d\n", chav(i), rc)
          Exit Sub
        End If
      End If
      rc = LIBAD.ad_discrete_in (adh, LIBAD.AD_CHA_TYPE_COUNTER or chav(i), 0, data)
      If rc = 0 Then
        Console.WriteLine ("counter {0,2}: {1}", chav(i), data)
      Else
        Console.WriteLine ("error: failed to write cha {0}: err = {1}", chav(i), rc)
      End If
    Next
    ' Close DAQ system again.
    LIBAD.ad_close (adh)
  End Sub
  ' Show usage.
  Sub Usage
    Console.WriteLine ("usage: counter <driver> [-counter|-updown|-quad] [-rst] <cha1> .. <chan>")
    Console.WriteLine ("  <driver>     string to pass to ad_open()")
    Console.WriteLine ("               - will prompt for name")
    Console.WriteLine ("  -counter     configure counter mode")
    Console.WriteLine ("  -updown      configure up/down counter mode")
    Console.WriteLine ("  -quad        configure quad-decoder counter mode")
    Console.WriteLine ("  -rst         enable counter's reset input")
    Console.WriteLine ("  <cha1..n>    number of counter channel to (configure and) read")
  End Sub
  ' Main entry point.
  Sub Main (ByVal argv As String())
    If argv.Length > 0 Then
      ' First command line argument is the DAQ's name.
      ' If "-" is passed, then let's read the name from
      ' the console.
      Dim name As String
      name = argv(0)
      If argv(0) = "-" Then
        Console.Write ("data acquisition sytem to open: ")
        name = Console.ReadLine ()
      End If
      ' Direction defaults to input, but may get overridden by -o
      ' on the command line.
      Dim start As Integer
      Dim mode As Integer
      Dim enable_rst As Boolean
      start = 1
      mode = -1
      enable_rst = False
      Do While argv.Length > start
        If argv(start) = "-counter" Then
          mode = LIBAD.AD_CNT_COUNTER
          start = start + 1
        Else If argv(start) = "-updown" Then
          mode = LIBAD.AD_CNT_UPDOWN
          start = start + 1
        Else If argv(start) = "-quad" Then
          mode = LIBAD.AD_CNT_QUAD_DECODER
          start = start + 1
        Else If argv(start) = "-rst" Then
          enable_rst = True
          start = start + 1
        Else
          Exit Do
        End If
      Loop
      ' Convert remaining command line arguments into
      ' numbers and add those to the channel array.
      Dim chav(argv.Length-1 - start) As Integer
      For i = start To argv.Length-1
        chav(i - start) = Int32.Parse (argv(i))
      Next
      ' Configure counter and read actual values, printing results
      ' to the console.
      do_counter (name, mode, enable_rst, chav)
      If argv(0) = "-" Then
        Console.WriteLine ("press return to continue...")
        Console.ReadLine ()
      End If
      Environment.Exit (0)
    Else
      Usage
      Environment.Exit (1)
    End If
  End Sub
End Module