LabJack MSVC++ v1.4
LabJack MSVC++ v1.4
4
ECE 103 Engineering Programming Portland State University Phillip Wong
Version 1.4
3. The New Project window will pop-up. In the Project types section under the type Visual C++, select Win32. In the Templates section under Visual Studio installed templates, select Win32 Console Application. In the Name input box, enter a name you would like to use for your application. In the Location input box, enter a directory where you would like to save your application. Click [OK].
4. The Win32 Application Wizard window will pop-up. Click [Next]. On the left-side of the wizard window, select Application Settings. Under Application type, select Console application. Under Additional options: o UNCHECK Precompiled header o CHECK Empty project Click [Finish].
Version 1.4
5. The Solution Explorer pane will show your newly created application. There should be three folders visible: Header Files, Resource Files, and Source Files. Right-click the Source Files folder in the solution explorer. A pop-up menu will appear. Select Add > New Item from the pop-up menu.
6. The Add New Item window will pop-up. In the Categories section under Visual C++, select Code. In the Templates section, select C++ File (.cpp). Note: Dont worry that you chose .cpp instead of .c. This is fixed in the next step. In the Name input box, enter a filename with a .c extension (e.g., program.c). Click [Add]
If the file is successfully added, you will see the name of the newly created file inside the Source Files folder. 7. The last step is to add a link to the actual LabJack code library to the project. Right-click the Project name in the solution explorer. A pop-up menu will appear. Select Add > Existing Item from the pop-up menu.
8. The Add Existing Item window will pop-up. Using the pop-up windows browser, navigate to and select the following file:
C:\Program Files\LabJack\Drivers\labjackud.lib
Note: If your Windows profile is configured not to show known filename extensions, then the library file will be displayed as just labjackud in the browser. Click [Add] A message will appear and ask if you want to create a new rule file. Click [No].
If the file is successfully added, you will see its name below (not inside) the Source Files folder.
Once the project and source files have been created, they will exist until you manually delete them. If you want to work on a pre-existing project, just open the project by selecting File > Open > Project/Solution from the menu bar.
Version 1.4
The files contain the declarations needed to access the LabJack system. Add the following function before any other function definition:
void ErrorHandler (LJ_ERROR lngErrorcode, long lngLineNumber) { char err[255]; if (lngErrorcode != LJE_NOERROR) { ErrorToString(lngErrorcode, err); printf("Error # %d: %s\n", lngErrorcode, err); printf("Source line number = %d\n", lngLineNumber); if(lngErrorcode > LJE_MIN_GROUP_ERROR) { getchar(); exit(0); /* Quit if serious error. */ } } }
After calling a LabJack library function, this function is used to display error information. Note: You could add this function after your other function definitions, as long as you remember to insert a prototype for ErrorHandler at the top of the source file. Add the following variable declarations at the start of the main() function:
LJ_ERROR lngErrorcode; /* LabJack error code */ LJ_HANDLE lngHandle = 0; /* ID# assigned to the opened LabJack */
Version 1.4
The purpose of each line is described here: lngErrorcode = OpenLabJack (LJ_dtU3, LJ_ctUSB, "1", 1, &lngHandle); This searches for a LabJack device that may be attached to the computer. If it finds one, then an attempt is made to establish contact with the LabJack hardware. Arguments: LJ_dtU3, LJ_ctUSB, 1, 1 : These values make the function search for a LabJack U3 that is attached to the computer through a USB cable. lngHandle : The unique ID number assigned to the opened LabJack is passed back Returns: lngErrorcode : A numeric error code. Note: Multiple LabJack devices can be attached to the same PC. Each opened LabJack is assigned its own identification number. lngHandle can be passed as an argument to other LabJack functions such as ePut to indicate the specific LabJack you want to control. ErrorHandler (lngErrorcode, __LINE__); This displays an error message that corresponds to the passed error code. If no error occurred, then no message is displayed. If the error is serious enough, then ErrorHandler will terminate the program. Arguments: lngErrorcode : Numeric error code. __LINE__ : This is a pre-defined macro (two underscores, LINE, two underscores). Returns: nothing
Version 1.4
&lngHandle);
/* CONFIGURATION OF I/O CHANNELS GOES HERE */ /* AFTER THAT COMES YOUR OWN LABJACK CODE */
return 0; }
Note: In the rest of this tutorial, the following LabJack library functions are used: ePut() : This sends values to the LabJack device. eGet() : This reads values from the LabJack device.
Version 1.4
U3-LV U3-HV
Bit# 0 1 2 3 4 5 6 7
Add the following lines of code to your C program (e.g., in the main() function):
/* Set all pin assignments to the factory default condition */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__);
The purpose of each line is described here: lngErrorcode = ePut (lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); This resets the I/O channels to their factory default configuration. Arguments: The given values will set all available flexible I/O channels for digital operation. Returns: lngErrorcode : Numeric error code. If all you need are digital I/O channels, then I/O configuration is complete. However, if you require analog input channels, then additional procedures may be needed.
Version 1.4
To set an individual flexible I/O channel for analog input: lngErrorcode = ePut (lngHandle, LJ_ioPUT_ANALOG_ENABLE_BIT, Bit#, State, 0); If State is true (1), the channel corresponding to Bit# is set to analog input. If State is false (0), the channel is set to digital I/O. No other channels are changed. Example: Set FIO0, FIO5, and FIO6 for analog input.
/* For FIO0, set Bit# to 0. To enable analog input, set State to 1. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_ANALOG_ENABLE_BIT, 0, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* For FIO5, set Bit# to 5. To enable analog input, set State to 1. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_ANALOG_ENABLE_BIT, 5, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* For FIO6, set Bit# to 6. To enable analog input, set State to 1. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_ANALOG_ENABLE_BIT, 6, 1, 0); ErrorHandler(lngErrorcode, __LINE__);
To set a group of flexible I/O channels for analog input all at once:
lngErrorcode = ePut (lngHandle, LJ_ioPUT_ANALOG_ENABLE_PORT, StartBit, Settings, NumBits);
For typical programs, set StartBit = 0 and NumBits = 16. Next, define a binary number that represents which channels you want to use for analog input. A bit value of 1 is analog, while a bit value of 0 is digital. The Settings argument is the decimal version of the binary number.
EIO7 15 14 EIO0 FIO7 8 7 FIO0 0 Bit
13
12
11
10
MSB
LSB
Example: Set FIO0, FIO5, and FIO6 for analog input. All other available channels are digital.
/* FIO0 is bit 0, FIO5 is bit 5, FIO6 is bit 6 */ /* Settings = 0000000001100001 (binary) = 97 (decimal) */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_ANALOG_ENABLE_PORT, 0, 97, 16); ErrorHandler(lngErrorcode);
Version 1.4
Writing to an analog output channel (DAC): lngErrorcode = ePut (lngHandle, LJ_ioPUT_DAC, DAC#, WriteVal, 0); The channel corresponding to DAC# outputs a voltage that is an analog representation of the value stored in WriteVal. DAC# is type long int. WriteVal is type double. Allowed ranges: DAC# = 0 or 1, 0 WriteVal 5 (floating point) Reading from an analog input channel (AIN): lngErrorcode = eGet (lngHandle, LJ_ioGET_AIN, AIN#, &ReadVal, 0); The channel corresponding to AIN# is read and the digital representation of the analog input is passed back in ReadVal. AIN# is type long int. ReadVal is type double (&ReadVal is the address of ReadVal). Allowed ranges: AIN# = 0 to 15
Version 1.4
Version 1.4
/* LabJack error code */ /* ID# assigned to the opened LabJack */ /* FIO values */
/* Open the first found LabJack U3 */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, ErrorHandler(lngErrorcode, __LINE__);
&lngHandle);
/* Set all pin assignments to the factory default condition */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* Prompt user for FIO4 output value */ printf("Enter desired FIO4 setting ( 1 for high and 0 for low ): "); scanf("%lf", &WriteVal); /* Write FIO4 value */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_DIGITAL_BIT, 4, WriteVal, 0); ErrorHandler(lngErrorcode, __LINE__); /* Read FIO5 value */ lngErrorcode = eGet(lngHandle, LJ_ioGET_DIGITAL_BIT, 5, ErrorHandler(lngErrorcode, __LINE__); printf("FIO5 value = %lf\n", ReadVal); return 0; }
&ReadVal, 0);
10
Version 1.4
/* LabJack error code */ /* ID# assigned to the opened LabJack */ /* DAC and AIN state values */
/* Open the first found LabJack U3 */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, ErrorHandler(lngErrorcode, __LINE__);
&lngHandle);
/* Set all pin assignments to the factory default condition */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* For FIO2, set Bit# to 2. To enable analog input, set State to 1 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_ANALOG_ENABLE_BIT, 2, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* For DAC0, set DAC# to 0. Set the output voltage at 0.75 V */ WriteVal = 0.75; lngErrorcode = ePut(lngHandle, LJ_ioPUT_DAC, 0, WriteVal, 0); ErrorHandler(lngErrorcode, __LINE__); /* Read AIN2 single-ended voltage */ lngErrorcode = eGet(lngHandle, LJ_ioGET_AIN, 2, ErrorHandler(lngErrorcode, __LINE__); printf("AIN2 value = %lf\n", ReadVal); return 0; }
&ReadVal, 0);
11
Version 1.4
/* main Used for calling LabJack functions that we wrote Parameters: none Returns : execution status */ int main (void) { LJ_HANDLE lngHandle = 0; /* ID# assigned to the opened LabJack */ double WriteVal, ReadVal; /* FIO values */ /* Open LabJack U3 and set it to default config */ Initialize_LJ(&lngHandle); /* Prompt user for FIO4 output value */ printf("Enter desired FIO4 setting ( 1 for high and 0 for low ): "); scanf("%lf", &WriteVal); /* Call LabJack code to set and read FIOs */ ReadVal = Perform_LJ_IO(lngHandle, WriteVal); printf("FIO5 value = %lf\n", ReadVal); return 0; }
12
Version 1.4
/* Initialize_LJ Opens and initializes LabJack hardware Parameters: plngHandle pointer to LabJack ID# variable Returns : none */ void Initialize_LJ (LJ_HANDLE * plngHandle) { LJ_ERROR lngErrorcode; /* LabJack error code */ /* Open the first found LabJack U3 */ /* Note: plngHandle is already a pointer, so no & is needed */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, plngHandle); ErrorHandler(lngErrorcode, __LINE__); /* Set all pin assignments to the factory default condition */ /* Note: *plngHandle is the ID# stored at plngHandle address */ lngErrorcode = ePut(*plngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); }
/* Perform_LJ_IO Sets FIO4 output value and reads FIO5 state Parameters: lngHandle LabJack ID WriteVal - Desired state value for FIO4 Returns : Current state value for FIO5 */ double Perform_LJ_IO (LJ_HANDLE lngHandle, double WriteVal) { LJ_ERROR lngErrorcode; /* LabJack error code */ double ReadVal; /* FIO value */ /* Write FIO4 state */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_DIGITAL_BIT, 4, WriteVal, 0); ErrorHandler(lngErrorcode, __LINE__); /* Read FIO5 state */ lngErrorcode = eGet(lngHandle, LJ_ioGET_DIGITAL_BIT, 5, ErrorHandler(lngErrorcode, __LINE__); return ReadVal; }
&ReadVal, 0);
/* ErrorHandler code was written by the LabJack company */ void ErrorHandler (LJ_ERROR lngErrorcode, long lngLineNumber) { char err[255]; if (lngErrorcode != LJE_NOERROR) { ErrorToString(lngErrorcode, err); printf("Error # %d: %s\n", lngErrorcode, err); printf("Source line number = %d\n", lngLineNumber); if(lngErrorcode > LJE_MIN_GROUP_ERROR) { getchar(); exit(0); /* Quit if serious error. */ } } }
13
Version 1.4
H L
Input signal has three H-to-L transitions
00000000000000000000000000000011 = 310
Figure 1: Sample input signal being counted
Basic Setup
The first four steps of developing a counter program for the LabJack are: 1. Create a new C project file 2. Add startup code to the C program 3. Establish communications with the LabJack 4. Configure the I/O Channels (reset to factory default) These steps are identical to the procedures discussed previously for digital I/O and analog input programs.
14
Version 1.4
Counter Setup
Since there are no dedicated counter channels on the LabJack, a counter needs to be assigned to an available FIO channel. The counter takes over the FIO channel until it is released. Up to two counters can be assigned to channels FIO4 through FIO7 and EIO0 through EIO1. Dual counters are always assigned to consecutive channels. The LabJack utilizes a timer/counter pin offset value (4 to 8) to specify the starting channel for the counters. One Counter Two Counters
Counter Pin Counter0 Counter Pin Counter0 Counter1 Offset Channel Offset Channel Channel
4 5 6 7 8
4 5 6 7 8
TCPO (timer/counter pin offset) specifies the starting channel for counter assignments. TCPO is type double. Allowed range: TCPO = 4 to 8 Example:
/* Put one counter on FIO4 */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,4,0); ErrorHandler(lngErrorcode, __LINE__); /* Put one counter on FIO7 */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,7,0); ErrorHandler(lngErrorcode, __LINE__); /* Put two counters on FIO6 and FIO7 */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,6,0); ErrorHandler(lngErrorcode, __LINE__);
15
Version 1.4
Enabling counters: lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_ENABLE, Counter#, ENA, 0); If ENA is set to true (1), the counter corresponding to Counter# will be enabled. If ENA is set to false (0), the counter will be disabled. Counter# is type long int. ENA is type double. Allowed ranges: Counter# = 0 or 1; ENA = 0 or 1 Example:
/* Enable Counter0 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_ENABLE, 0, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* Enable Counter1 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_ENABLE, 1, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* Disable Counter1 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_ENABLE, 1, 0, 0); ErrorHandler(lngErrorcode, __LINE__);
Resetting counters: lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_RESET, Counter#, 1, 0); The counter corresponding to Counter# will be reset back to a zero count. Counter# is type long int. Allowed ranges: Counter# = 0 or 1 Example:
/* Reset Counter0 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_RESET, 0, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* Reset Counter1 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_RESET, 1, 1, 0); ErrorHandler(lngErrorcode, __LINE__);
16
Version 1.4
Reading from a counter: lngErrorcode = eGet(lngHandle, LJ_ioGET_COUNTER, Counter#, &ReadVal, 0); The counter corresponding to Counter# is read, and the current count is passed back in ReadVal. Counter# is type long int. ReadVal is type double (&ReadVal is the address of ReadVal). Allowed ranges: Counter# = 0 or 1 Example:
/* Read Counter0 */ lngErrorcode = eGet(lngHandle, LJ_ioGET_COUNTER, 0, &cur_count, 0); ErrorHandler(lngErrorcode, __LINE__); /* Read Counter1 */ lngErrorcode = eGet(lngHandle, LJ_ioGET_COUNTER, 1, &Value, 0); ErrorHandler(lngErrorcode, __LINE__);
17
Version 1.4
/* LabJack error code */ /* ID# assigned to the opened LabJack */ /* Current count value */
/* Open the first found LabJack U3. */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, ErrorHandler(lngErrorcode, __LINE__);
&lngHandle);
/* Set all pin assignments to the factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the timer/counter pin offset to 4. The puts Counter0 on FIO4. */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,4,0); ErrorHandler(lngErrorcode, __LINE__); /* Enable Counter0. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_ENABLE, 0, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* Read and display counter value until user presses any key to stop */ while (!_kbhit()) /* _kbhit() is in <conio.h> - not ANSI/ISO compliant */ { /* Request a read from the counter. */ lngErrorcode = eGet(lngHandle, LJ_ioGET_COUNTER, 0, &dblValue, 0); ErrorHandler(lngErrorcode, __LINE__); /* Display the current count value. */ printf("Counter = %.1f\n", dblValue); /* Wait 0.01 second. Sleep() is in <windows.h> - not ANSI/ISO compliant */ /* Argument has units of milliseconds. */ Sleep(10); } /* Reset all pin assignments to factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); return 0; }
18
Version 1.4
INTRODUCTION Timers
A timer is used if an input signal measurement or an output signal generation requires precise, hardware-based timing. Some timer modes include: pulse width modulation output, signal period input, frequency output, and firmware counter input Up to two timers are available. A timer can be assigned to only certain FIO channels.
Basic Setup
The first four steps of developing a timer program for the LabJack are: 1. Create a new C project file 2. Add startup code to C program 3. Establish Communications with the LabJack 4. Configure the I/O Channels (reset to factory default) These steps are identical to the procedures discussed previously for digital I/O and analog input programs.
19
Version 1.4
Timer Pin Timer0 Timer Pin Timer0 Timer1 Offset Channel Offset Channel Channel
4 5 6 7 8
4 5 6 7 8
TCPO (timer/counter pin offset) specifies the starting channel for timer assignments. TCPO is type double. Allowed range: TCPO = 4 to 8 Example:
/* Put one timer on FIO4 */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,4,0); ErrorHandler(lngErrorcode, __LINE__);
20
Version 1.4
TCB (timer clock base) specifies the base frequency for all timer operations. Note: Changing the default 48 MHz base frequency may increase the DAC output noise. TCB is type double. Allowed range: Predefined macros are available for setting TCB. TCB Macro Name
LJ_tc4MHZ LJ_tc12MHZ LJ_tc48MHZ LJ_tc1MHZ_DIV LJ_tc4MHZ_DIV LJ_tc12MHZ_DIV LJ_tc48MHZ_DIV
Description 4 MHz clock base 12 MHz clock base 48 MHz clock base (default) 1 MHz clock base w/ divisor (no Counter0) 4 MHz clock base w/ divisor (no Counter0) 12 MHz clock base w/ divisor (no Counter0) 48 MHz clock base w/ divisor (no Counter0)
Since the LabJack only offers a limited number of base frequencies (1, 4, 12, and 48 MHz), a divisor can be used to divide the chosen frequency down to a smaller value. The divisor is set using a separate ePut() call. If a divisor is used, then Counter0 is no longer available. Example:
/* Use the 4 MHz timer clock with no divisor */ lngErrorcode= ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, LJ_tc4MHZ, 0); ErrorHandler(lngErrorcode, __LINE__);
/* Use the 48 MHz timer clock with a divisor */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, LJ_tc48MHZ_DIV, 0); ErrorHandler(lngErrorcode, __LINE__);
21
Version 1.4
If the chosen timer clock base uses a divisor, then TCD (timer clock divisor) sets the divisor value. The timer frequency is given by fT = timer clock base / timer clock divisor = TCB / TCD. This function should only be used if the timer clock base is LJ_tc1MHz_DIV,
LJ_tc4MHZ_DIV, LJ_tc12MHZ_DIV, or LJ_tc48MHZ_DIV.
TCD is type double. Allowed range: TCD = 0 to 255, where 0 is interpreted as 256. Sample base frequency and divisor combinations TCB Macro Name
LJ_tc1MHz_DIV LJ_tc1MHz_DIV LJ_tc1MHz_DIV LJ_tc1MHz_DIV LJ_tc4MHZ_DIV LJ_tc4MHz_DIV LJ_tc4MHz_DIV LJ_tc4MHz_DIV LJ_tc48MHZ_DIV LJ_tc48MHZ_DIV LJ_tc48MHZ_DIV LJ_tc48MHZ_DIV
TCD 1 4 100 0 (equiv to 256) 1 4 100 0 (equiv to 256) 1 48 128 0 (equiv to 256)
Timer Frequency 1 MHz 250 kHz 10 kHz 3906.25 Hz 4 MHz 1 MHz 40 kHz 15.625 kHz 48 MHz 1 MHz 375 kHz 187.5 kHz
Example:
/* Assume LJ_tc48MHz. Use a divisor of 48 to get a timer frequency of 1 MHz */ lngErrorcode= ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, 48, 0); ErrorHandler(lngErrorcode, __LINE__);
22
Version 1.4
Enabling timers:
lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, #Timers, 0);
#Timers determines the number of timers that should be enabled. Once a timer is enabled (1 or 2), the timer immediately begins operating. Once a timer is disabled (0), the timer immediately stops operating. #Timers is type double. Allowed ranges: #Timers = 0 , 1, or 2 Example:
/* Enable Timer0 only */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* Enable both Timer0 and Timer1 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 2, 0); ErrorHandler(lngErrorcode, __LINE__);
23
Version 1.4
V
A
Duty = 90%
t (ms)
V
A
Duty = 50%
t (ms)
V
A
Duty = 10%
t (ms)
Figure 2: Sample pulse train with f = 1 kHz and varying duty cycles.
24
Version 1.4
The timer corresponding to Timer# will be set to mode Tmode. The mode affects the final pulse width modulation frequency. Timer# is type long int. Tmode is type double. Allowed range: Timer# = 0 or 1. Predefined macros are available for setting Tmode. Macro Name
LJ_tmPWM16 LJ_tmPWM8
The selection of 8-bit or 16-bit PWM output determines the pulse train frequency. The pulse train frequency is fPT = (TCB / TCD) / 2#bits , where #bits = 8 or 16 Timer Clock Base Frequency (TCB) 4 MHz 12 MHz 48 MHz (Default) 1 MHz w/ divisor 4 MHz w/ divisor 12 MHz w/ divisor 48 MHz w/ divisor Example:
/* Set Timer0 to 8-bit pulse width modulation mode */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, 0, LJ_tmPWM8, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set Timer1 to 16-bit pulse width modulation mode */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, 1, LJ_tmPWM16, 0); ErrorHandler(lngErrorcode, __LINE__);
25
Version 1.4
The timer corresponding to Timer# will have its pulse train duty cycle set according to TISL. TISL is the total number of increments out of 65536 that the pulse is in a low state within a single pulse period. To calculate TISL, use TISL = (1 Duty) * 65536, where Duty is the fractional duty cycle. Timer# is type long int. TISL is type double Allowed ranges: Timer# = 0 or 1; TISL = 0 to 65535 (16-bit PWM) or 65280 (8-bit PWM) PWM Type 16-bit 8-bit Resolution (increment size) 65536 / 216 = 1 65536 / 28 = 256 Maximum Duty Cycle 100% 100% Minimum Duty Cycle (1 / 65536) * 100% = 0.0015% (256 / 65536) * 100% = 0.39%
Example:
/* Set Timer0 to a 25% duty cycle (is low 49152 out of 65536 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 49152,0); ErrorHandler(lngErrorcode, __LINE__); /* Set Timer0 to a 50% duty cycle (is low 32768 out of 65536 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 32768,0); ErrorHandler(lngErrorcode, __LINE__); /* Set Timer1 to a 75% duty cycle (is low 16384 out of 65536 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 16384,0); ErrorHandler(lngErrorcode, __LINE__);
26
Version 1.4
List of LabJack functions typically needed for PWM mode: Opening LabJack for I/O
lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, &lngHandle);
Starting channel for timers lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_COUNTER_PIN_OFFSET, TCPO, 0); Timer clock base lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, TCB, 0); Timer clock divisor lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, TCD, 0); Enable/disable timers lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, #Timers, 0); PWM timer mode lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, Timer#, LJ_tmPWM?, 0); PWM duty cycle lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, TISL, 0);
27
Version 1.4
/* ErrorHandler code was written by the LabJack company */ void ErrorHandler (LJ_ERROR lngErrorcode, long lngLineNumber) { char err[255]; if (lngErrorcode != LJE_NOERROR) { ErrorToString(lngErrorcode, err); printf("Error # %d: %s\n", lngErrorcode, err); printf("Source line number = %d\n", lngLineNumber); if(lngErrorcode > LJE_MIN_GROUP_ERROR) { getchar(); exit(0); /* Quit if serious error. */ } } }
/* LabJack error code */ /* ID# assigned to the opened LabJack */ /* Scratch variable */
/* Open the first found LabJack U3. */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, ErrorHandler(lngErrorcode, __LINE__);
&lngHandle);
/* Set all pin assignments to the factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the timer/counter pin offset to 4. This puts Timer0 on FIO4. */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,4,0); ErrorHandler(lngErrorcode, __LINE__); /* Use the 48 MHz timer clock base with divisor. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, LJ_tc48MHZ_DIV, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set divisor to 0 (=256) so the actual timer clock is 187.5 kHz MHz. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* Enable 1 timer. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 1,0); ErrorHandler(lngErrorcode, __LINE__);
28
Version 1.4
/* Configure Timer0 as 16-bit PWM. Frequency is (187.5 kHz / 2^16) = 2.861 Hz. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, 0, LJ_tmPWM16, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the PWM duty cycle to 50%. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 32768, 0); ErrorHandler(lngErrorcode, __LINE__); printf("Press any key to stop the PWM output and reset the LabJack.\n"); while (!_kbhit()) /* _kbhit() is in <conio.h> - not ANSI/ISO compliant */ ; /* Reset all pin assignments to factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* The PWM output sets FIO4 to output, so we do a read */ /* here to set it to input. */ lngErrorcode = eGet(lngHandle, LJ_ioGET_DIGITAL_BIT, 4, &Value, 0); ErrorHandler(lngErrorcode, __LINE__); return 0; }
29
Version 1.4
V
3.5
t (ms)
The timer corresponding to Timer# will be set to mode Tmode. Timer# is type long int. Tmode is type double. Allowed range: Timer# = 0 or 1; A predefined macro is available for setting Tmode. Macro Name
LJ_tmFREQOUT
Example:
/* Set Timer0 to frequency output mode */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, 0, LJ_tmFREQOUT,0); ErrorHandler(lngErrorcode, __LINE__);
30
Version 1.4
The timer corresponding to Timer# will have its output frequency set according to Tvalue. The output frequency is f = (TCB / TCD) / (2 * Tvalue) Timer# is type long int. Tvalue is type double Allowed ranges: Timer# = 0 or 1; Tvalue = 0 to 255, where 0 is interpreted as 256. Timer Clock Base Frequency (TCB) 4 MHz 12 MHz 48 MHz (Default) 1 MHz w/ divisor 4 MHz w/ divisor 12 MHz w/ divisor 48 MHz w/ divisor
Output Frequency Range (Hz) TCD = 1 Tvalue = 1 Tvalue = 256
The table shows only a few sample frequencies. The LabJack can generate many thousands of different frequencies, depending on the values of TCB, TCD, and Tvalue.
The LabJack website has a file that lists all the allowed combinations of TCB, TCD, and Tvalue parameters, along with the frequencies to which they correspond. The file is in CSV format (comma separated values) for easy importing into a spreadsheet program. It can also be opened with a standard text editor. The file can be downloaded from:
http://labjack.com/support/u3/frequency-list-u3-timer-mode-7
Example:
/* Set output frequency to 30.518 Hz (assuming TCB=4 MHz w/divisor, TCD=1 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 256, 0); ErrorHandler(lngErrorcode, __LINE__);
31
Version 1.4
List of LabJack functions typically needed for FREQOUT mode: Opening LabJack for I/O
lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, &lngHandle);
Starting channel for timers lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_COUNTER_PIN_OFFSET, TCPO, 0); Enable/disable timers lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, #Timers, 0); FREQOUT timer mode lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, Timer#, LJ_tmFREQOUT, 0); Timer clock base lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, TCB, 0); Timer clock divisor lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, TCD, 0); PWM duty cycle lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, Tvalue, 0);
32
Version 1.4
/* ErrorHandler code was written by the LabJack company */ void ErrorHandler (LJ_ERROR lngErrorcode, long lngLineNumber) { char err[255]; if (lngErrorcode != LJE_NOERROR) { ErrorToString(lngErrorcode, err); printf("Error # %d: %s\n", lngErrorcode, err); printf("Source line number = %d\n", lngLineNumber); if(lngErrorcode > LJE_MIN_GROUP_ERROR) { getchar(); exit(0); /* Quit if serious error. */ } } }
/* Open the first found LabJack U3. */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, &lngHandle); ErrorHandler(lngErrorcode, __LINE__); /* Set all pin assignments to the factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the timer/counter pin offset to 4. This puts Timer0 on FIO4. */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,4,0); ErrorHandler(lngErrorcode, __LINE__); /* Enable one timer. It will use FIO4 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 1,0); ErrorHandler(lngErrorcode, __LINE__); /* Configure Timer0 as Frequency Output (square wave) */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, 0, LJ_tmFREQOUT, 0); ErrorHandler(lngErrorcode, __LINE__);
33
Version 1.4
/* ----------------------------------------------------------------Desired output frequency = 440 Hz From the LabJack frequency table, the closest matching frequency is 440.044006 Hz, and there are four combinations that will work: Freq (Hz) Clock (Hz) Clock_Divisor 440.044006, 4000000.000000, 45.000000, 440.044006, 4000000.000000, 101.000000, 440.044006, 12000000.000000, 101.000000, 440.044006, 12000000.000000, 135.000000, Timer_Value 101.000000 45.000000 135.000000 101.000000
Choosing the first one, these are the required settings: Clock = 4000000.000000 (i.e., 4 MHz) Clock_Divisor = 45.000000 Timer_Value = 101.000000 -------------------------------------------------------------- */ /* Set the timer clock base to 4 MHz with divisor */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, LJ_tc4MHZ_DIV, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the timer clock divisor to 45 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, 45, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the timer value to 101 */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 101, 0); ErrorHandler(lngErrorcode, __LINE__);
printf("Press any key to stop the square wave output and reset the LabJack.\n"); while (!_kbhit()) /* _kbhit() is in <conio.h> - not ANSI/ISO compliant */ ; /* Disable timer */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 0,0); ErrorHandler(lngErrorcode, __LINE__);
/* Reset all pin assignments to factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); return 0; }
34
Version 1.4
Example: Scenario 1 Timer enabled, LJ_tc48MHz Counter0 disabled, Counter1 disabled TimerCounterPinOffset = 4 1 Timer enabled, LJ_tc48MHz Counter0 enabled, Counter1 disabled TimerCounterPinOffset = 4 1 Timer enabled, LJ_tc48MHz Counter0 disabled, Counter1 enabled TimerCounterPinOffset = 6 1 Timer enabled, LJ_tc48MHz Counter0 enabled, Counter1 enabled TimerCounterPinOffset = 6 2 Timers enabled, LJ_tc48MHz Counter0 enabled, Counter1 disabled TimerCounterPinOffset = 5 2 Timers enabled, LJ_tc48MHz Counter0 enabled, Counter1 enabled TimerCounterPinOffset = 8 1 Timer enabled, LJ_tc48MHz_DIV Counter0 unavailable, Counter1 enabled TimerCounterPinOffset = 4 Channel Assignments Timer0 FIO4
Timer0 FIO4 Counter0 FIO5 Timer0 FIO6 Counter1 FIO7 Timer0 FIO6 Counter0 FIO7 Counter1 EIO0 Timer0 FIO5 Timer1 FIO6 Counter0 FIO7 Timer0 EIO0 Timer1 EIO1 Counter0 EIO2 Counter1 EIO3 Timer0 FIO4 Counter1 FIO5
35
Version 1.4
/* LabJack error code */ /* ID# assigned to the opened LabJack */ /* Counter state value */
/* Open the first found LabJack U3. */ lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, ErrorHandler(lngErrorcode, __LINE__);
&lngHandle);
/* Set all pin assignments to the factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the timer/counter pin offset to 4, which puts */ /* the first timer/counter on FIO4. */ lngErrorcode = ePut(lngHandle,LJ_ioPUT_CONFIG,LJ_chTIMER_COUNTER_PIN_OFFSET,4,0); ErrorHandler(lngErrorcode, __LINE__); /* Use the 48 MHz timer clock base with divider. Since we are */ /* using clock with divisor support, Counter0 is not available. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_BASE, LJ_tc48MHZ_DIV, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the divisor to 48 so the actual timer clock is 1 MHz. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_CLOCK_DIVISOR, 48, 0); ErrorHandler(lngErrorcode, __LINE__); /* Enable 1 timer. It will use FIO4. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_CONFIG, LJ_chNUMBER_TIMERS_ENABLED, 1,0); ErrorHandler(lngErrorcode, __LINE__);
36
Version 1.4
/* Enable Counter1. It will use FIO5 since 1 timer is enabled. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_COUNTER_ENABLE, 1, 1, 0); ErrorHandler(lngErrorcode, __LINE__); /* Configure Timer0 as 8-bit PWM. Frequency is (1 MHz / 256) = 3906.25 Hz. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_MODE, 0, LJ_tmPWM8, 0); ErrorHandler(lngErrorcode, __LINE__); /* Set the PWM duty cycle to 50%. */ lngErrorcode = ePut(lngHandle, LJ_ioPUT_TIMER_VALUE, 0, 32768, 0); ErrorHandler(lngErrorcode, __LINE__); /* Wait 1 second. Sleep() is in <windows.h> - not ANSI/ISO compliant. */ /* Argument has units of milliseconds. */ Sleep(1000); /* Request a read from the counter. */ lngErrorcode = eGet(lngHandle, LJ_ioGET_COUNTER, 1, ErrorHandler(lngErrorcode, __LINE__);
&dblValue, 0);
/* This should read roughly 4k counts if FIO4 is shorted to FIO5. */ printf("Counter = %.1f\n", dblValue); /* Wait 1 second. */ Sleep(1000); /* Request a read from the counter. */ lngErrorcode = eGet(lngHandle, LJ_ioGET_COUNTER, 1, ErrorHandler(lngErrorcode, __LINE__);
&dblValue, 0);
/* This should read about 3906 counts more than the previous read. */ printf("Counter = %.1f\n",dblValue); /* Reset all pin assignments to factory default condition. */ lngErrorcode = ePut(lngHandle, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0); ErrorHandler(lngErrorcode, __LINE__); /* The PWM output sets FIO4 to output, so we do a read */ /* here to set it to input. */ lngErrorcode = eGet(lngHandle, LJ_ioGET_DIGITAL_BIT, 4, &dblValue, 0); ErrorHandler(lngErrorcode, __LINE__); return 0;
37