Data Acquisition in CSharp
Data Acquisition in CSharp
Data Acquisition in C#
HANS-‐PETTER
H ALVORSEN,
2 013.02.18
Faculty of Technology, Postboks 203, Kjølnes ring 56, N-3901 Porsgrunn, Norway. Tel: +47 35 57 50 00 Fax: +47 35 57 54 01
Table of Contents
1
Introduction
......................................................................................................................................
4
2
3
Table
of
Contents
10 Using NI TC-‐01 in Visual Studio and C# ......................................................................................... 52
1 Introduction
In
this
Tutorial
we
will
learn
how
to
create
DAQ
(Data
Acquisition)
applications
in
Visual
Studio
and
C#.
We
will
use
a
USB-‐6008
DAQ
device
from
National
Instruments
as
an
example.
In
order
to
use
DAQ
devices
from
National
Instruments
in
C#
and
Visual
Studio
we
need
to
NI-‐DAQmx
driver
provides
by
National
Instruments.
As
part
of
this
installation
you
can
install
a
.NET
API.
We
will
use
this
API
to
create
a
simple
DAQ
application.
In
addition
we
will
use
Measurement
Studio
which
is
an
add-‐on
to
Visual
Studio
which
makes
it
easier
to
create
more
advanced
DAQ
applications.
In
this
Tutorial
we
end
up
with
a
control
application.
We
will
send
and
read
data
to
a
DAQ
device,
and
we
will
create
our
own
discrete
PID
controller,
low-‐pass
filter
and
a
discrete
model
of
our
system.
We
will
also
read
and
write
data
to
an
OPC
server.
You will find this document and lots of other information in the following web site:
http://home.hit.no/~hansha/?tutorial=csharp_daq
For more information about Visual Studio and C#, visit the following web page:
http://home.hit.no/~hansha/?tutorial=csharp
Below
we
see
the
integrated
development
environment
(IDE)
in
Visual
Studio:
4
5
Introduction
The NI USB-‐6008 is well suited for education purposes due to its small size and easy USB connection.
We
will
give
code
examples
of
how
to
use
this
device
in
C#.
Since
this
is
a
DAQmx
supported
device
from
National
Instruments,
the
programing
structure
will
be
the
same
as
for
NI
USB-‐6008.
We
will
use
the
NI
USB-‐TC01
device
in
Chapter
10
-‐
Using
NI
TC-‐01
in
Visual
Studio
and
C#.
Note!
In
order
to
install
the
DAQmx
API
for
C#,
make
sure
to
select
“.NET
Support”
when
installing
the
DAQmx
driver.
This
application
uses
the
C#
API
included
in
the
NI
DAQmx
driver,
so
make
sure
that
you
have
installed
the
NI
DAQmx
driver
in
advance.
Next,
make
sure
that
you
select
.NET
Framework
X.x
Support
for
the
version
of
.NET
that
yourversion
of
Visual
Studio
id
using:
2 Data Acquisition
2.1 Introduction
The
purpose
of
data
acquisition
is
to
measure
an
electrical
or
physical
phenomenon
such
as
voltage,
current,
temperature,
pressure,
or
sound.
PC-‐based
data
acquisition
uses
a
combination
of
modular
hardware,
application
software,
and
a
computer
to
take
measurements.
While
each
data
acquisition
system
is
defined
by
its
application
requirements,
every
system
shares
a
common
goal
of
acquiring,
analyzing,
and
presenting
information.
Data
acquisition
systems
incorporate
signals,
sensors,
actuators,
signal
conditioning,
data
acquisition
devices,
and
application
software.
The DAQ system has the following parts involved, see Figure:
9
10
Data
Acquisition
• Analog
input
• Analog
output
• Digital
I/O
• Counter/timers
• “Desktop
DAQ
devices”
where
you
need
to
plug
a
PCI
DAQ
board
into
your
computer.
The
software
is
running
on
a
computer.
• “Portable
DAQ
devices”
for
connection
to
the
USB
port,
Wi-‐Fi
connections,
etc.
The
software
is
running
on
a
computer
• “Distributed
DAQ
devices”
where
the
software
is
developed
on
your
computer
and
then
later
downloaded
to
the
distributed
DAQ
device.
• Real-‐time
monitoring
• Data
analysis
• Data
logging
• Control
algorithms
• Human
machine
interface
(HMI)
In
order
to
create
your
DAQ
application
you
need
a
programming
development
tool,
such
as
Visual
Studio/C#,
LabVIEW,
etc..
Measurement
&
Automation
Explorer
(MAX)
provides
access
to
your
National
Instruments
devices
and
systems.
In
addition
to
the
standard
tools,
MAX
can
expose
item-‐specific
tools
you
can
use
to
configure,
diagnose,
or
test
your
system,
depending
on
which
NI
products
you
install.
As
you
navigate
through
MAX,
the
contents
of
the
application
menu
and
toolbar
change
to
reflect
these
new
tools.
2.3.1 NI-DAQmx
National
Instruments
provides
a
native
.NET
API
for
NI-‐DAQmx.
This
is
available
as
a
part
of
the
NI-‐DAQmx
driver
and
does
not
require
Measurement
Studio.
In general, data acquisition programming with DAQmx involves the following steps:
Data
acquisition
in
text
based-‐programming
environment
is
very
similar
to
the
LabVIEW
NI-‐DAQmx
programming
as
the
functions
calls
is
the
same
as
the
NI-‐DAQmx
VI’s.
http://zone.ni.com/devzone/cda/tut/p/id/5409#toc4
Examples:
The
location
of
examples
will
depend
on
the
version
of
Visual
Studio
and
is
listed
in
the
following
Developer
Zone
Article:
Using
NI-‐DAQmx
in
Text
Based
Programming
Environments.
The
most
common
location
is:
Sub-‐folders
named
CS
contain
C#
examples.
These
examples
install
with
NI-‐DAQmx.
Measurement
Studio
is
not
required
to
install
the
class
libraries
or
the
examples.
Note! If the paths above do not exist, be sure you have .NET support installed for NI-‐DAQmx.
3.1 Introduction
This
application
uses
the
C#
API
included
in
the
NI
DAQmx
driver,
so
make
sure
that
you
have
installed
the
NI
DAQmx
driver
in
advance.
You
don’t
need
Measurement
Studio
to
create
this
application.
We will create the following application in Visual Studio 2010 and C#:
14
15
My
First
DAQ
App
We start by connecting the Analog In and Analog Out wires together (a so called Loopback test).
When
we
click
the
“Write
Data”
button,
the
value
entered
in
the
text
box
“Analog
Out”
will
be
written
to
the
DAQ
device.
If
we
have
connected
the
Analog
In
and
Analog
Out
wires
together
we
will
read
the
same
value
in
the
“Analog
In”
textbox
when
we
push
the
“Get
Data”
button.
References:
This
application
uses
the
C#
API
included
in
the
NI
DAQmx
driver,
so
make
sure
that
you
have
installed
the
NI
DAQmx
driver
in
advance.
• NationalInstruments.Common
• NationalInstruments.DAQmx
We add References by right-‐clicking the References node in the Solution Explorer:
When we have added the necessary References, the Solution Explorer will look like this:
Initialization:
using NationalInstruments;
using NationalInstruments.DAQmx;
Analog Out:
We
implement
the
code
for
writing
to
the
Analog
Out
channel
in
the
Event
Handler
for
the
“Write
Data”
button:
AOChannel myAOChannel;
myAOChannel = analogOutTask.AOChannels.CreateVoltageChannel(
"dev1/ao0",
"myAOChannel",
0,
5,
AOVoltageUnits.Volts
);
double analogDataOut;
analogDataOut = Convert.ToDouble(txtAnalogOut.Text);
writer.WriteSingleSample(true, analogDataOut);
Analog In:
We
implement
the
code
for
reading
data
from
the
Analog
In
channel
in
the
Event
Handler
for
the
“Get
Data”
button:
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateVoltageChannel(
"dev1/ai0",
"myAIChannel",
AITerminalConfiguration.Differential,
0,
5,
AIVoltageUnits.Volts
);
txtAnalogIn.Text = analogDataIn.ToString();
4 Temperature Logging
Example
In
this
example
we
will
use
a
NI
TC-‐01
USB
Thermocouple
device.
Add Reference:
• NationalInstruments.Common
• NationalInstruments.DAQmx
We add References by right-‐clicking the References node in the Solution Explorer:
18
19
Temperature
Logging
Example
When we have added the necessary References, the Solution Explorer will look like this:
Initialization:
using NationalInstruments;
using NationalInstruments.DAQmx;
Add Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NationalInstruments;
using NationalInstruments.DAQmx;
namespace TC01_DAQ_Example
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
AIChannel myAIChannel;
myAIChannel = temperatureTask.AIChannels.CreateThermocoupleChannel(
"Dev1/ai0",
"Temperature",
0,
100,
AIThermocoupleType.J,
AITemperatureUnits.DegreesC,
25
);
txtTempData.Text = analogDataIn.ToString();
}
}
}
Run
your
application.
When
clicking
the
button,
you
should
now
retrieve
data
from
the
temoerature
device.
Error?
If your application runs without error that’s fine, but perhaps you get the following error:
In order to fix the problem, open the Properties for your project:
Make sure to select “.NET Framework X” in the “Target framework” drop-‐down menu.
5 Measurement Studio
5.1 Introduction
C#
is
a
powerful
programming
language,
but
has
few
built-‐in
features
for
measurement
and
control
applications.
Measurement
Studio
is
an
add-‐on
to
Visual
Studio
which
makes
it
easier
to
create
such
applications.
With
Measurement
Studio
we
can
implement
Data
Acquisition
and
a
graphical
HMI.
• Managed
.NET
controls
for
creating
rich
Web
and
Windows
GUIs
• Multithreaded
API
for
data
acquisition
• Instrument
control
APIs
• Analysis
libraries
designed
for
engineers
and
scientists
22
23
Measurement
Studio
5.2 Templates
Measurement
Studio
has
several
Templates
that
make
it
easier
to
build
DAQ
applications.
5.3 Toolbox
Below
we
see
the
Toolbox
in
Visual
Studio
that
is
installed
with
Measurement
Studio:
In addition to the Toolbox, Measurement Studio also installs the following menu item:
5.4 Example
In
this
example,
we
will
select
the
“NI
windows
Application”
Template
in
the
“New
Project”
window
.
Next
we
select
the
Class
Libraries
we
want
to
include.
In
our
case
we
need
at
least
to
select
the
“DAQmx
Library”.
When
we
click
“Finish”
an
empty
project
will
be
created
for
us.
We
are
now
ready
to
create
our
own
application.
When
we
click
the
“Read
Temp”
button,
the
Temperature
data
shall
be
shown
in
the
“Temp
Data”
TextBox.
In the event Handler for the “Read Temp” button, we create the following code:
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateThermocoupleChannel(
"Dev1/ai0",
"Temperature",
0,
100,
AIThermocoupleType.J,
AITemperatureUnits.DegreesC,
25
);
txtTempData.Text = analogDataIn.ToString();
Improvements:
We
should
use
a
“Timer”
in
order
to
read
Temperature
data
at
specific
intervals
instead
of
pushing
a
button
each
time
we
need
data.
We drag in a Timer component from the Toolbox. First, we need to start the Timer:
public Form1()
{
InitializeComponent();
timer1.Start();
}
Next, we need to specify the interval. We can do that in the Properties window:
In the Timer Event we write the code for reading the Temperature:
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateThermocoupleChannel(
"Dev1/ai0",
"Temperature",
0,
100,
AIThermocoupleType.J,
AITemperatureUnits.DegreesC,
25
);
txtTempData.Text = analogDataIn.ToString("0.0");
6 Control Application
6.1 Introduction
In
this
example
we
will
use
Measurement
Studio
to
create
a
simple
control
application.
We
will
control
the
level
in
a
water
tank
using
manual
control.
The
process
is
as
follows:
We
want
to
control
the
level
in
the
water
tank
using
a
pump
on
the
inflow.
We
will
read
the
level
using
our
USB-‐6008
DAQ
device
(Analog
In)
and
write
the
control
signal
(Analog
Out)
to
the
DAQ
device.
The
Analog
Out
(control
signal)
will
be
a
signal
between
0 − 5𝑉
and
the
Analog
In
(Level)
will
be
a
0 − 5𝑉
signal
that
we
need
to
scale
to
0 − 20𝑐𝑚.
29
30
Control
Application
We
will
use
a
“Slider”
to
manually
adjust
the
control
signal
and
a
Tank
to
indicate
the
level
in
the
real
process.
In
this
example
we
will
use
the
“Slide”
control
and
“Tank”
control
that
comes
with
Measurement
Studio.
Select the “NI Windows Application” Template in the “Measurement Studio” node.
In the window that appears next, select the Libraries you want to include:
We create the User Interface above in Visual Studio, and it looks like this:
For the read and write operations we have created a simple Class with two methods:
Read Level:
The ReadDaqData() method handles the logic for reading from the DAQ device:
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateVoltageChannel(
"dev1/ai0",
"myAIChannel",
AITerminalConfiguration.Differential,
0,
5,
AIVoltageUnits.Volts
);
return analogDataIn;
}
The WriteDaqData() method handles the logic for writing to the DAQ device:
AOChannel myAOChannel;
myAOChannel = analogOutTask.AOChannels.CreateVoltageChannel(
"dev1/ao0",
"myAOChannel",
0,
5,
AOVoltageUnits.Volts
);
writer.WriteSingleSample(true, analogDataOut);
Timer:
In
the
previous
example
(“My
First
DAQ
App”)
we
was
reading
and
writing
to
the
DAQ
device
when
clicking
a
button,
but
in
an
ordinary
application
this
is
not
a
good
solution.
In
order
to
read
and
write
data
on
regular
intervals
we
will
use
a
“Timer”.
In the Properties window we can specify the Interval (“Sampling Time”) in milliseconds.
public Form1()
{
InitializeComponent();
timer1.Start();
}
In
the
Timer
Event
we
create
the
main
logic
in
our
application.
We
call
the
ReadDaqData()
and
WriteDaqData()
methods,
updates
the
GUI,
etc.
//Read Data
double analogDataIn;
analogDataIn = myDaqData.ReadDaqData();
if (analogDataIn < 0)
analogDataIn = 0;
if (analogDataIn > 5)
analogDataIn = 5;
//Scaling:
analogDataIn = analogDataIn * 4; //0-5V -> 0-20cm
tank.Value = analogDataIn;
txtLevelValue.Text = analogDataIn.ToString("0.00");
//Write Data
double analogDataOut;
analogDataOut = sliderControl.Value;
myDaqData.WriteDaqData(analogDataOut);
7 Trending Data
Now
we
want
to
extend
our
application
with
functionality
for
viewing
historical
data
using
a
trend
plot.
In this example we will use the “WaveformGraph” control in Measurement Studio.
The
source
code
is
the
same
as
in
the
previous
example,
except
for
one
new
line
of
code
in
the
Timer
Event:
waveformGraph.PlotYAppend(analogDataIn);
The
“WaveformGraph”
control
has
lots
of
functionality
you
can
set
in
the
Properties
window
or
clicking
the
Smart
Tag
Anchor
(little
arrow
in
the
upper
right
corner
of
the
control).
Below
we
see
the
Properties
window
(left
side)
and
the
Smart
Tag
Panel
(right
side)
for
the
WaveformGraph
control:
35
36
Trending
Data
8 Discretization
The
next
improvements
to
our
application
would
be
to
implement
a
Low-‐pass
Filter
in
order
to
remove
the
noise
from
the
signal
when
reading
the
level.
Another
improvement
would
be
to
replace
the
manual
control
with
a
PI
controller
that
do
the
job
for
us.
Finally
it
would
be
nice
to
have
a
mathematical
model
of
our
water
tank
so
we
can
simulate
and
test
the
behavior
of
the
real
system
without
connect
to
it.
So
we
need
to
create
discrete
versions
of
the
low-‐pass
filter,
the
PI
controller
and
the
process
model.
We
can,
e.g.,
use
the
Euler
Forward
discretization
method:
𝑥!!! − 𝑥!
𝑥≈
𝑇!
𝑥! − 𝑥!!!
𝑥≈
𝑇!
𝑦(𝑠) 1
𝐻 𝑠 = =
𝑢(𝑠) 𝑇! 𝑠 + 1
Where 𝑇! is the time-‐constant of the filter, 𝑢(𝑠) is the filter input and 𝑦 𝑠 is the filter output.
Discrete version:
It can be shown that a discrete version can be stated as:
𝒚𝒌 = 𝟏 − 𝒂 𝒚𝒌!𝟏 + 𝒂𝒖𝒌
Where
𝑻𝒔
𝒂=
𝑻𝒇 + 𝑻𝒔
It is a golden rule that 𝑇! ≪ 𝑇! and in practice we should use the following rule:
37
38
Discretization
𝑇!
𝑇! ≤
5
Proof:
Given:
𝑦 1
=
𝑢 𝑇! 𝑠 + 1
This gives:
𝑇! 𝑠 + 1 𝑦 = 𝑢
𝑇! 𝑠𝑦 + 𝑦 = 𝑢
𝑇! 𝑦 + 𝑦 = 𝑢
!! !!!!!
We
use
the
Euler
Backward
discretization
method,
𝑥 ≈ ,
which
gives:
!!
𝑦! − 𝑦!!!
𝑇! + 𝑦! = 𝑢!
𝑇!
𝑇! 𝑦! − 𝑦!!! + 𝑦! 𝑇! = 𝑢! 𝑇!
𝑇! 𝑦! − 𝑇! 𝑦!!! + 𝑦! 𝑇! = 𝑢! 𝑇!
𝑦! (𝑇! + 𝑇! ) = 𝑇! 𝑦!!! + 𝑢! 𝑇!
This gives:
𝑇! 𝑇!
𝑦! = 𝑦!!! + 𝑢
𝑇! + 𝑇! 𝑇! + 𝑇! !
𝑇!
≡ 𝑎
𝑇! + 𝑇!
This gives:
𝑦! = (1 − 𝑎)𝑦!!! + 𝑎𝑢!
𝑇!
𝑎=
𝑇! + 𝑇!
8.2 PI Controller
A
PI
controller
may
be
written:
𝐾! !
𝑢 𝑡 = 𝑢! + 𝐾! 𝑒 𝑡 + 𝑒𝑑𝜏
𝑇! !
𝑒 𝑡 = 𝑟 𝑡 − 𝑦(𝑡)
Laplace:
𝐾!
𝑢 𝑠 = 𝐾! 𝑒 𝑠 + 𝑒 𝑠
𝑇! 𝑠
Discrete version:
We start with:
𝐾! !
𝑢 𝑡 = 𝑢! + 𝐾! 𝑒 𝑡 + 𝑒𝑑𝜏
𝑇! !
In order to make a discrete version using, e.g., Euler, we can derive both sides of the equation:
𝐾!
𝑢 = 𝑢! + 𝐾! 𝑒 + 𝑒
𝑇!
𝑲𝒑
𝒖𝒌 = 𝒖𝒌!𝟏 + 𝒖𝟎,𝒌 − 𝒖𝟎,𝒌!𝟏 + 𝑲𝒑 𝒆𝒌 − 𝒆𝒌!𝟏 + 𝑻𝒔 𝒆𝒌
𝑻𝒊
Where
𝑒! = 𝑟! − 𝑦!
We can also split the equation above in 2 different pars by setting:
∆𝑢! = 𝑢! − 𝑢!!!
𝒆𝒌 = 𝒓𝒌 − 𝒚𝒌
𝑲𝒑
∆𝒖𝒌 = 𝒖𝟎,𝒌 − 𝒖𝟎,𝒌!𝟏 + 𝑲𝒑 𝒆𝒌 − 𝒆𝒌!𝟏 + 𝑻𝒔 𝒆𝒌
𝑻𝒊
𝒖𝒌 = 𝒖𝒌!𝟏 + ∆𝒖𝒌
𝐾!
𝑢 𝑠 = 𝐾! 𝑒 𝑠 + 𝑒 𝑠
𝑇! 𝑠
!
We
set
𝑧 = 𝑒 ⇒ 𝑠𝑧 = 𝑒 ⇒ 𝑧 = 𝑒
!
This gives:
𝑧 = 𝑒
𝐾!
𝑢 = 𝐾! 𝑒 + 𝑧
𝑇!
Where
𝑒 = 𝑟 − 𝑦
Discrete version:
Using
Euler:
𝑧!!! − 𝑧!
𝑧≈
𝑇!
This
gives:
𝑧!!! − 𝑧!
= 𝑒!
𝑇!
𝐾!
𝑢! = 𝐾! 𝑒! + 𝑧
𝑇! !
Finally:
𝒆𝒌 = 𝒓𝒌 − 𝒚𝒌
𝑲𝒑
𝒖𝒌 = 𝑲 𝒑 𝒆𝒌 + 𝒛𝒌
𝑻𝒊
𝒛𝒌!𝟏 = 𝒛𝒌 + 𝑻𝒔 𝒆𝒌
𝐴! ℎ = 𝐾! 𝑢−𝐹!"#
or
1
ℎ= 𝐾 𝑢−𝐹!"#
𝐴! !
Where:
We
can
use
the
Euler
Forward
discretization
method
in
order
to
create
a
discrete
model:
𝑥!!! − 𝑥!
𝑥≈
𝑇!
ℎ!!! − ℎ! 1
= 𝐾 𝑢 −𝐹
𝑇! 𝐴! ! ! !"#
Finally:
𝑻𝒔
𝒉𝒌!𝟏 = 𝒉𝒌 + 𝑲 𝒖 −𝑭
𝑨𝒕 𝒑 𝒌 𝒐𝒖𝒕
Below we see the Project and Solution in Visual Studio:
Below we will show and describe the important parts of the code.
PI Controller:
We
create
a
new
Class
for
our
PID
algorithm,
by
right-‐click
in
the
Solution
Explorer
(Add→New
Item…)
class PidController
{
//PID Algoritm
e = r - y;
u = Kp * e + (Kp / Ti) * z;
z = z + Ts * e;
return u;
}
controllerOutput = sliderControl.Value;
}
else // Use PID Control
{
controllerOutput = pidControl.PiController(levelMeasurement);
//Scaling
controllerOutput = controllerOutput / 4; //0-20cm -> 0-5V
//Set boundaries
if (controllerOutput < 0)
controllerOutput = 0;
if (controllerOutput > 5)
controllerOutput = 5;
}
Low-‐pass Filter:
class Filter
{
double a;
double yFiltered;
a = Ts / (Ts + Tf);
yFiltered = (1 - a) * yk + a * yFromDaq;
yk = yFiltered;
return yFiltered;
}
}
Discrete Model:
We have created a Class and a LevelTankModel Method that we use in our simulation:
levelMeasurement = model.LevelTankModel(controllerOutput);
9 OPC
In
order
to
communicate
with
an
OPC
Server
we
can
use
the
DataSocket
API
that
is
part
of
the
Measurement
Studio.
We
use
the
Matrikon
OPC
Simulation
Server.
Code:
string opcUrl;
opcUrl = "opc://localhost/MATRIKON.OPC.Simulation/Bucket Brigade.Real4";
if (dataSocket.IsConnected)
46
47
OPC
dataSocket.Disconnect();
dataSocket.Connect(opcUrl, AccessMode.Read);
txtReadOpcValue.Text = dataSocket.Data.Value.ToString();
}
SelectUrl:
We
can
use
the
SelectUrl
method
if
we
want
to
pick
the
OPC
item
from
a
list
of
available
servers
(both
local
servers
and
network
servers)
and
items.
dataSocket.SelectUrl();
Below
we
will
go
through
a
very
simple
example.
We
will
write
one
value
to
the
OPC
Server
each
time
we
click
a
button.
Code:
string opcUrl;
opcUrl = "opc://localhost/MATRIKON.OPC.Simulation/Bucket Brigade.Real4";
if (dataSocket.IsConnected)
dataSocket.Disconnect();
dataSocket.Connect(opcUrl, AccessMode.Write);
double opcValue = 0;
opcValue = Convert.ToDouble(txtWriteOpcValue.Text);
dataSocket.Data.Value = opcValue;
dataSocket.Update();
}
In the Properties window we can specify the Interval (“Sampling Time”) in milliseconds.
public Form1()
{
InitializeComponent();
timer1.Start();
}
In the Timer Event we create the code in order to read data at this specific interval.
…
…
10 Using NI TC-01 in
Visual Studio and C#
In
order
to
use
the
NI
USB-‐TC01
Thermocouple
Measurement
device
with
C#
we
need
to
have
the
DAQmx
driver
and
the
DAQmx
API
for
C#
installed.
In
order
to
install
the
DAQmx
API
for
C#,
make
sure
to
select
“.NET
Support”
when
installing
the
DAQmx
driver.
C#
is
a
powerful
programming
language,
but
has
few
built-‐in
features
for
measurement
and
control
applications.
Measurement
Studio
is
an
add-‐on
to
Visual
Studio
which
makes
it
easier
to
create
such
applications.
With
Measurement
Studio
we
can
implement
Data
Acquisition
and
a
graphical
HMI.
You
don’t
need
to
use
the
Measurement
Studio
to
create
an
application
where
you
use
the
NI
USB-‐TC01
Thermocouple
Measurement
device,
but
it
is
easier.
Here
we
will
use
Visual
Studio
and
the
Measurement
Studio
Add-‐in
to
create
some
DAQ
examples
where
we
get
temperature
data
from
the
NI
USB-‐TC01
Thermocouple
Measurement
device.
Note!
The
“New
Project”
window
may
look
different
on
your
computer,
it
depends
on
what
features
you
have
installed
and
which
version
or
edition
of
Measurement
Studio
you
are
using.
52
53
Using
NI
TC-‐01
in
Visual
Studio
and
C#
Next
we
select
the
Class
Libraries
we
want
to
include.
In
our
case
we
need
at
least
to
select
the
“DAQmx
Library”.
When
we
click
“Finish”
an
empty
project
will
be
created
for
us.
We
are
now
ready
to
create
our
own
application.
When
we
click
the
“Read
Temp”
button,
the
Temperature
data
shall
be
shown
in
the
“Temp
Data”
TextBox.
In the event Handler for the “Read Temp” button, we create the following code:
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateThermocoupleChannel(
"Dev1/ai0",
"Temperature",
0,
100,
AIThermocoupleType.J,
AITemperatureUnits.DegreesC,
25
);
txtTempData.Text = analogDataIn.ToString();
Improvements:
We
should
use
a
“Timer”
in
order
to
read
Temperature
data
at
specific
intervals
instead
of
pushing
a
button
each
time
we
need
data.
We drag in a Timer component from the Toolbox. First, we need to start the Timer:
public Form1()
{
InitializeComponent();
timer1.Start();
}
Next, we need to specify the interval. We can do that in the Properties window:
In the Timer Event we write the code for reading the Temperature:
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateThermocoupleChannel(
"Dev1/ai0",
"Temperature",
0,
100,
AIThermocoupleType.J,
AITemperatureUnits.DegreesC,
25
);
txtTempData.Text = analogDataIn.ToString("0.0");
We
start
by
creating
a
“New
Project”
from
Visual
Studio.
In
the
“New
Project”
window
we
select
“Visual
C#”
»
“Measurement
Studio”,
and
then
select
the
“NI
DAQ
Windows
Application”
Template
that
is
part
of
the
Measurement
Studio.
Note!
The
“New
Project”
window
may
look
different
on
your
computer,
it
depends
on
what
features
you
have
installed
and
which
version
or
edition
of
Measurement
Studio
you
are
using.
Next, we need to go through different steps in a wizard.
In
the
next
step
we
select
the
measurement
type,
and
since
the
NI
USB-‐TC01
Thermocouple
Measurement
device
is
for
reading
Temperature
values,
we
need
to
select
“Acquire
Signals”.
In the “Acquire Signals” node we first select “Temperature” and then select “Thermocouple”.
Next
we
need
to
select
the
physical
channel(s).
Since
the
NI
USB-‐TC01
Thermocouple
Measurement
device
has
only
one
channel
available,
we
need
to
select
“ai0”
(Analog
In,
Channel
0).
Next
we
can
set
different
Properties,
such
as
“Input
Range”,
“Acquisition
Mode”,
“Thermocouple
Type”,
etc.
Finally
we
see
a
Preview
of
the
User
Interface
before
it
is
automatically
generated
by
the
Measurement
Studio:
When we click “Finish”, the Solution, the Project and User Interface will be automatically created.
Figure
1:
Visual
Studio
Generated
Solution
With
this
approach
we
get
a
“flying
start”
and
we
can
change
the
code
as
we
please.
The
drawback
with
this
approach
is
that
the
code
that
is
automatically
generated
is
a
little
bit
“messy”.
Appendix A: Source
Code
In
this
Appendix
the
complete
source
code
for
all
the
examples
will
be
listed.
using NationalInstruments;
using NationalInstruments.DAQmx;
using NationalInstruments.UI;
using NationalInstruments.UI.WindowsForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyFirstDAQApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateVoltageChannel(
"dev1/ai0",
"myAIChannel",
AITerminalConfiguration.Differential,
0,
5,
AIVoltageUnits.Volts
);
62
63
Appendix
A:
Source
Code
txtAnalogIn.Text = analogDataIn.ToString();
AOChannel myAOChannel;
myAOChannel = analogOutTask.AOChannels.CreateVoltageChannel(
"dev1/ao0",
"myAOChannel",
0,
5,
AOVoltageUnits.Volts
);
double analogDataOut;
analogDataOut = Convert.ToDouble(txtAnalogOut.Text);
writer.WriteSingleSample(true, analogDataOut);
}
}
Control Application
The
code
for
this
application
is
as
follows:
using NationalInstruments;
using NationalInstruments.DAQmx;
using NationalInstruments.UI;
using NationalInstruments.UI.WindowsForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Control_Application
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timer1.Start();
}
//Read Data
double analogDataIn;
analogDataIn = myDaqData.ReadDaqData();
if (analogDataIn < 0)
analogDataIn = 0;
if (analogDataIn > 5)
analogDataIn = 5;
//Scaling:
analogDataIn = analogDataIn * 4; //0-5V -> 0-20cm
tank.Value = analogDataIn;
txtLevelValue.Text = analogDataIn.ToString("0.00");
//Write Data
double analogDataOut;
analogDataOut = sliderControl.Value;
myDaqData.WriteDaqData(analogDataOut);
/// <summary>
/// Reading and Writing Data from DAQ Device
/// </summary>
public class DaqData
{
AIChannel myAIChannel;
myAIChannel = analogInTask.AIChannels.CreateVoltageChannel(
"dev1/ai0",
"myAIChannel",
AITerminalConfiguration.Differential,
0,
5,
AIVoltageUnits.Volts
);
return analogDataIn;
}
AOChannel myAOChannel;
myAOChannel = analogOutTask.AOChannels.CreateVoltageChannel(
"dev1/ao0",
"myAOChannel",
0,
5,
AOVoltageUnits.Volts
);
writer.WriteSingleSample(true, analogDataOut);
}
}
}
namespace OPC_Read
{
public partial class Form1 : Form
{
DataSocket dataSocket = new DataSocket();
public Form1()
{
InitializeComponent();
string opcUrl;
opcUrl = "opc://localhost/MATRIKON.OPC.Simulation/Bucket Brigade.Real4";
if (dataSocket.IsConnected)
dataSocket.Disconnect();
dataSocket.Connect(opcUrl, AccessMode.Read);
}
dataSocket.Update();
txtReadOpcValue.Text = dataSocket.Data.Value.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace OPC_Write
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
string opcUrl;
opcUrl = "opc://localhost/MATRIKON.OPC.Simulation/Bucket Brigade.Real4";
if (dataSocket.IsConnected)
dataSocket.Disconnect();
dataSocket.Connect(opcUrl, AccessMode.Write);
}
double opcValue = 0;
opcValue = Convert.ToDouble(txtWriteOpcValue.Text);
dataSocket.Data.Value = opcValue;
dataSocket.Update();
}
}
}
www.hit.no
E-‐mail: [email protected]
Blog: http://home.hit.no/~hansha/