251 lines
7.4 KiB
HTML
251 lines
7.4 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
|
|
<TITLE>Comedi Documentation: Writing programs that use comedi and comedilib</TITLE>
|
|
<LINK HREF="comedilib-5.html" REL=next>
|
|
<LINK HREF="comedilib-3.html" REL=previous>
|
|
<LINK HREF="comedilib.html#toc4" REL=contents>
|
|
</HEAD>
|
|
<BODY>
|
|
<A HREF="comedilib-5.html">Next</A>
|
|
<A HREF="comedilib-3.html">Previous</A>
|
|
<A HREF="comedilib.html#toc4">Contents</A>
|
|
<HR>
|
|
<H2><A NAME="s4">4. Writing programs that use comedi and comedilib</A></H2>
|
|
|
|
<P>
|
|
<P>
|
|
<H2><A NAME="ss4.1">4.1 Your first comedi program</A>
|
|
</H2>
|
|
|
|
<P>
|
|
<P>This example requires a card that has analog or
|
|
digital input. Right to the source:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
#include <stdio.h> /* for printf() */
|
|
#include <comedilib.h>
|
|
|
|
int subdev = 0; /* change this to your input subdevice */
|
|
int chan = 0; /* change this to your channel */
|
|
int range = 0; /* more on this later */
|
|
int aref = AREF_GROUND; /* more on this later */
|
|
|
|
int main(int argc,char *argv[])
|
|
{
|
|
comedi_t *it;
|
|
int chan=0;
|
|
lsampl_t data;
|
|
|
|
it=comedi_open("/dev/comedi0");
|
|
|
|
comedi_data_read(it,subdev,chan,range,aref,& data);
|
|
|
|
printf("%d\n",data);
|
|
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>Should be understandable. Open the device, get the data,
|
|
print it out. This is basically the guts of <CODE>demo/inp.c</CODE>,
|
|
without error checking or fancy options. Including all
|
|
the appropriate headers is sometimes a little tricky.
|
|
Compile it using
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
cc tut1.c -lcomedi -o tut1
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>Hopefully it works.
|
|
<P>A few notes: The range variable tells comedi which gain
|
|
to use when measuring an analog voltage. Since we don't
|
|
know (yet) which numbers are valid, or what each means,
|
|
we'll use 0, because it won't cause errors. Likewise with
|
|
aref, which determines the analog reference used.
|
|
<P>
|
|
<P>
|
|
<P>
|
|
<H2><A NAME="ss4.2">4.2 Converting samples to voltages</A>
|
|
</H2>
|
|
|
|
<P>
|
|
<P>If you selected an analog input subdevice, you should notice
|
|
that the output of <CODE>tut1</CODE> is a number between
|
|
0 and 4095, or 0 and 65535, depending on the number of bits
|
|
in the A/D converter. Comedi samples are <B>always</B> unsigned,
|
|
with 0 representing the lowest voltage of the ADC, and 4095
|
|
the highest. Comedi compensates for
|
|
anything else the manual for your device says. However,
|
|
you probably prefer to have this number translated to
|
|
a voltage. Naturally, as a good programmer, your first
|
|
question is: "How do I do this in a device-independent
|
|
manner?"
|
|
<P>For each subdevice, the comedi kernel module keeps a
|
|
'range_type' variable. This variable contains the number
|
|
of available ranges (i.e., gains) that you can select,
|
|
along with an offset in a list of range information
|
|
structures. If you know the range_type variable, you
|
|
can use these macros:
|
|
<P>RANGE_OFFSET(range_type)
|
|
RANGE_LENGTH(range_type)
|
|
<P>to extract such information. However, you want the
|
|
actual voltage information, not some integer offset
|
|
in a table. Rather than messing with the library
|
|
internals, use the function
|
|
<P>ptr=comedi_get_range(comedi_file,subdevice,channel,
|
|
range)
|
|
<P>which returns a pointer to a comedi_range structure.
|
|
The comedi_range structure looks like
|
|
<P>
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
typedef struct{
|
|
double min;
|
|
double max;
|
|
unsigned int unit;
|
|
}comedi_range;
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>As you might expect, ptr[range] is for range 'range',
|
|
which you provided to comedi_data_read() above. 'min' represents
|
|
the voltage corresponding to comedi_data_read() returning 0,
|
|
and 'max' represents comedi_data_read() returning 'maxdata',
|
|
(i.e., 4095 for 12 bit A/C converters, 65535 for 16 bit,
|
|
or, 1 for digital input -- more on this in a bit.) The
|
|
'unit' entry tells you if min and
|
|
max refer to voltage, current, etc.
|
|
<P>"Could it get easier?", you say. Well, yes. Use
|
|
the function comedi_to_phys(), which converts data
|
|
values to physical units. Call it using something like
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
volts=comedi_to_phys(it,data,range,maxdata);
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>and the opposite
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
data=comedi_from_phys(it,volts,range,maxdata);
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>You probably noticed (and were worried) that we haven't
|
|
discussed how to determine maxdata and range_type. Well,
|
|
you could ask the kernel this information each time you need
|
|
it, but since there are other variables, special cases,
|
|
and several subdevices to worry about, it would be nice
|
|
if the library could take care of this... (read on...)
|
|
<P>
|
|
<P>
|
|
<P>
|
|
<H2><A NAME="ss4.3">4.3 Another section</A>
|
|
</H2>
|
|
|
|
<P>
|
|
<P>
|
|
<P>In addition to providing low level routines for data
|
|
access, the comedi library provides higher-level access,
|
|
much like the standard C library provides fopen(), etc.
|
|
as a high-level (and portable) alternative to the direct
|
|
UNIX system calls open(), etc. Similarily to fopen(),
|
|
we have comedi_open():
|
|
<P>
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
file=comedi_open("/dev/comedi0");
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>where file is of type <CODE>(comedi_t *)</CODE>. This function
|
|
calls <CODE>open()</CODE>, like we did explicitly in a previous
|
|
section, but also fills the <CODE>comedi_t</CODE> structure with
|
|
lots of goodies -- information that we will need to use
|
|
soon.
|
|
<P>Specifically, we needed to know maxdata for a specific
|
|
subdevice/channel. How about:
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
maxdata=comedi_get_maxdata(file,subdevice,channel);
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>Wow. How easy. And the range type?
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
range_type=comedi_get_rangetype(file,subdevice,channel);
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>Cool. Other information you need to know about a channel
|
|
can be gotten in a similar way.
|
|
<P>
|
|
<P>
|
|
<P>
|
|
<H2><A NAME="ss4.4">4.4 Your second comedi program</A>
|
|
</H2>
|
|
|
|
<P>
|
|
<P>
|
|
<P>Actually, this is the first comedi program again, just
|
|
that we've added what we've learned.
|
|
<P>
|
|
<P>
|
|
<BLOCKQUOTE><CODE>
|
|
<PRE>
|
|
#include <stdio.h> /* for printf() */
|
|
#include <comedi.h> /* also included by comedilib.h */
|
|
#include <comedilib.h> /* for comedi_get() */
|
|
|
|
int subdev = 0; /* change this to your input subdevice */
|
|
int chan = 0; /* change this to your channel */
|
|
int range = 0; /* more on this later */
|
|
int aref = 0; /* more on this later */
|
|
|
|
int main(int argc,char *argv[])
|
|
{
|
|
comedi_t *cf;
|
|
int chan=0;
|
|
int data;
|
|
int maxdata,rangetype;
|
|
double volts;
|
|
|
|
cf=comedi_open("/dev/comedi0");
|
|
|
|
maxdata=comedi_get_maxdata(cf,subdev,chan);
|
|
|
|
rangetype=comedi_get_rangetype(cf,subdev,chan);
|
|
|
|
data=comedi_get(cf->fd,subdev,chan,range,aref);
|
|
|
|
volts=comedi_to_phys(data,rangetype,range,maxdata);
|
|
|
|
printf("%d %g\n",data,volts);
|
|
|
|
return 0;
|
|
}
|
|
</PRE>
|
|
</CODE></BLOCKQUOTE>
|
|
<P>
|
|
<P>By now, the <CODE>comedi_read_data()</CODE> line looks a little archaic, using
|
|
the UNIX file descriptor cf->fd instead of just cf. (By the
|
|
way, somewhere in the heart of <CODE>comedi_open()</CODE> is the line
|
|
<CODE>cf->fd=open(filename,O_RDWR)</CODE>.) Well, there isn't one good
|
|
replacement, since it highly depends on your application
|
|
what additional features you might want in a <CODE>comedi_get()</CODE>
|
|
replacement. But this is the topic of a different section.
|
|
<P>
|
|
<P>
|
|
<P>
|
|
<HR>
|
|
<A HREF="comedilib-5.html">Next</A>
|
|
<A HREF="comedilib-3.html">Previous</A>
|
|
<A HREF="comedilib.html#toc4">Contents</A>
|
|
</BODY>
|
|
</HTML>
|