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 c
, cs
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 -1
zurü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 - Programmierschnittstelle (API)
/* 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