'U3Demo in FreeBasic by Alan J. Fridlund, Ph.D., January, 2020. This is just 'a demo of basic U3 code. All code except as noted below is donated to the 'LabJack and FB communities with no restrictions except that you acknowledge 'me within whatever code you use. I make no warranties that the code is error- 'free, so please verify it before relying on it. I'm not a professional coder, 'and any advice on de-glitching or optimizing the code - especially the function 'calls - will be appreciated! ' 'I am indebted to Mr.Swiss on the Freebasic.net forum for demo code for the U12, 'which I expanded and uploaded to the LabJack U12 forum section. Except for the 'DLL-loading code directly below, this U3 code is my extrapolation from his U12 'code, combined with much help from examples LJ provided for VB and PureBasic. 'This code compiled and tested under FB for Windows x64. '-------------------------------------- 'Specific Code for Loading DLL Adapted from U12 Code (c) 2019-10-16, MrSwiss 'from Freebasic.net forum. Dim As Any Ptr LJ_lib ' the DLL's base address # Ifdef __FB_64BIT__ LJ_Lib = DylibLoad("C:\Windows\System32\LabJackUD") ' FBC 64 # Else LJ_Lib = DylibLoad("C:\Windows\SysWOW64\LabJackUD") ' FBC 32 # EndIf If LJ_Lib = 0 Then Print "ERROR: '"; "LabJackUD.dll"; "' load failed!" End If '-------------------------------------- 'Beginning of my U3/FB code. '-------------------------------------- '-------------------------------------- 'Set up variables. Dim as Double ADRate, DelayMsec, StartTime, EndTime Dim As Integer DarkBkgd, LightBkgd, ScrHeight, ScrWidth Dim As Integer GraphCol, LeftGraphCol, RightGraphCol, RightGraph, TopGraph, BottomGraph Dim As Integer BottomTextLine, RightTextCol, TempTextLine Dim As Long ChannelLoop, NumChannels, EOState0, EOState1, EIState2, EIState3 Dim As Single LJ_AdVoltage(16), NumScans, VoltTemp Dim As String AinLabel(16) 'Shared variables for subroutine. Dim Shared Print_LJ_Error As Integer Dim Shared As Long LJ_Error, LJ_Handle Dim Shared St As String 'Sub to show LJ function-call error messages, and success text if print flag is set to -1. Declare Sub LongError '=================================== 'Set parameters for the desired 8-bit graphics mode. 'Uncomment the highest-res screen mode to get the largest graph area. ScrHeight = 480: ScrWidth = 640:BottomTextLine = 60: RightTextCol = 80 'ScrHeight = 600: ScrWidth = 800:BottomTextLine = 75: RightTextCol = 100 'ScrHeight = 768: ScrWidth = 1024:BottomTextLine = 96: RightTextCol = 128 'ScrHeight = 1024: ScrWidth = 1280:BottomTextLine = 128: RightTextCol = 160 '=================================== 'Set the selected mode and clear to a blue screen. SCREENRES ScrWidth,ScrHeight Color 7,1:Cls: Color 15,1 '=================================== 'Display a title. 'Turn on flag to print success strings if no LJ function-call errors. 'Flag turned on for initial demo, and turned off for plot routine to follow. Print_LJ_Error = -1 Locate ,1 : Print String (80,196); St = "U3-HV FreeBasic Function Demo - Alan J. Fridlund, January 2020" Locate , 41 - len(St)/2: Print St Locate ,1 : Print String (80,196); Print St = "Verifying U3-HV Function Calls:" Locate , 41 - len(St)/2: Print St Print '=================================== 'Now set up U3-HV Functions: Open the first found LabJack. Dim LJ_OpenLabJack As Function (ByVal DeviceType As Long, ByVal ConnectionType As Long, ByVal pAddress As String, ByVal FirstFound As Long, ByRef pHandle As Long) As Long LJ_OpenLabJack = DylibSymbol (LJ_Lib, "OpenLabJack") Const LJ_dtU3 = 3: St = "U3" Const LJ_ctUSB = 1 : St = St + " USB" LJ_Error = LJ_OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, LJ_Handle) St = "OpenLabjack Success: " + St LongError '******************************** 'Get the LJ driver version (installed using LJ U3 Windows installer pkg). Dim LJ_GetDriverVersion As Function () As Double LJ_GetDriverVersion = DylibSymbol (LJ_Lib, "GetDriverVersion") St = "GetDriverVersion Success - Vers = " + STR(LJ_GetDriverVersion()) LongError '******************************** 'Get LabJack Serial Number. Dim LJ_eGetSS As Function(ByVal Handle As Long, ByVal IOType As String, ByVal Channel As String, ByRef Value As Double, ByVal x1 As Long) As Long 'Dim LJ_ePut As Function(ByVal Handle As Long, ByVal IOType As Long, ByVal Channel As Long, ByRef Value As Double, ByVal x1 As Long) As Long LJ_eGetSS = DylibSymbol (LJ_Lib, "eGetSS") Const LJ_ioGET_CONFIG = 1001 Const LJ_chSERIAL_NUMBER = 12 Dim LJ_egetSS_Value As Double Dim LJ_eGetSS_x1 As Long LJ_Error = LJ_eGetSS(LJ_Handle, "LJ_ioGET_CONFIG", "LJ_chSERIAL_NUMBER", LJ_eGetSS_Value, LJ_eGetSS_x1) St = "eGetSS Success - Serial Number = " + STR(LJ_eGetSS_Value) LongError '******************************** 'List Parameters of installed LabJack(s). Dim LJ_ListAll As Function (ByVal DeviceType As Long, ByVal ConnectionType As Long, ByRef NumFound As Long, ByRef SerialNumbers As Long, ByRef pIDs As Long, ByRef Addresses As Double) As Long LJ_ListAll = DylibSymbol (LJ_Lib, "ListAll") Dim As Long LJ_Idx, _ ListAllLoop, _ NumDevices Dim As Long LJ_pNumFound(0 to 128), _ LJ_pSerialNumbers(0 to 128), _ LJ_pIDS (0 to 128) Dim As Double LJ_pAddresses (0 to 128) LJ_Error = LJ_ListAll(LJ_dtU3, LJ_ctUSB, LJ_pNumfound(LJ_Idx), LJ_pSerialNumbers(LJ_Idx), LJ_pIDS(LJ_Idx), LJ_pAddresses(LJ_Idx)) NumDevices = LJ_pNumFound(0) St = "ListAll Success - #LJs = " + STR(NumDevices) LongError 'List all LJ devices found by ListAll. For ListAllLoop = 0 to NumDevices - 1 St = "LJ #" + Str(ListAllLoop) + " Ser # = " + STR(LJ_pSerialNumbers(ListAllLoop)) + " ID = " + STR(LJ_pIDS(ListAllLoop)) + " Addr = " + STR(LJ_pAddresses(ListAllLoop)) Print Space(5); St Next '******************************** 'Start by using the pin_configuration_reset IOType so that all 'pin assignments are in the factory default condition. Dim LJ_ePut As Function(ByVal Handle As Long, ByVal IOType As Long, ByVal Channel As Long, ByVal Value As Double, ByVal x1 As Long) As Long LJ_ePut = DylibSymbol (LJ_Lib, "ePut") Const LJ_ioPIN_CONFIGURATION_RESET = 2017 Dim As Long LJ_IOType, LJ_Channel Dim As Double LJ_Value Dim As Long LJ_x1 LJ_Channel = 0 LJ_Value = 0 LJ_x1 = 0 LJ_Error = LJ_ePut(LJ_Handle, LJ_ioPIN_CONFIGURATION_RESET, LJ_Channel, LJ_Value, LJ_x1) St = "ePut Success - Factory Default ioPIN CONF RESET" LongError '******************************** 'Configure and display Quick Sample option. Const LJ_ioPUT_CONFIG = 1000 Const LJ_chAIN_RESOLUTION = 2000 ' Quick Sample On Const LJ_No_chAIN_RESOLUTION = 0 ' Quick Sample Off Dim As Long LJ_chAIN Dim As Double LJ_QuickSample St = "" 'Set Quick Sample On. LJ_chAIN = LJ_chAIN_RESOLUTION: St = "On" 'Set Quick Sample Off by uncommenting next line. 'LJ_Chain = LJ_No_chAIN_RESOLUTION: St = "Off" LJ_Error = LJ_ePut(LJ_Handle, LJ_ioPUT_CONFIG, LJ_chAIN, LJ_QuickSample, 0) St = "ePut Success - Configure A/D Quick Sample Option as: " + St LongError '******************************** 'Configure and display Long Settling Time option. Const LJ_chAIN_SETTLING_TIME = 2001 ' On Const LJ_No_chAIN_SETTLING_TIME = 0 ' Off Dim As Long LJ_SETTLE Dim As Double LJ_LongSettling St = "" 'Set Long Settling Time On. LJ_SETTLE = LJ_chAIN_SETTLING_TIME: St = "On" 'Set Long Settling Time Off by uncommenting next line. 'LJ_SETTLE = LJ_No_chAIN_SETTLING_TIME: St = "Off" LJ_Error = LJ_ePut(LJ_Handle, LJ_ioPUT_CONFIG, LJ_SETTLE, LJ_LongSettling, 0) St = "ePut Success - Configure A/D Long Settling Option as: " + St LongError '******************************** 'Configure the necessary lines as analog. Const LJ_ioPUT_ANALOG_ENABLE_BIT = 2013 Const LJ_ioPUT_ANALOG_ENABLE_PORT = 2015 Const LJ_Analog = 0 Dim As Long AENumChannels Dim as Double LJ_AENumChannels 'Arbitrarily set to 4 for my application, LJ can go 0-15. NumChannels = 4 For ChannelLoop = 0 to NumChannels - 1 LJ_Error = LJ_ePut(LJ_Handle, LJ_ioPUT_ANALOG_ENABLE_BIT, ChannelLoop, LJ_AENumchannels, AENumChannels) St = "ePut Success - A/D Ch " + STR(ChannelLoop) + " Configured as Analog" LongError Next ChannelLoop '******************************** 'Read a Digital I/O Port (0-19). Dim LJ_eDI As Function(ByVal Handle As Long, ByVal Channel As Long, ByRef State As Long) As Long LJ_eDI = DylibSymbol (LJ_Lib, "eDI") Dim As Long LJ_DIChannel, LJ_DIState LJ_DIChannel = 0 'LJ_DIState is 0 for low (False) and 1 for High (True) LJ_Error = LJ_eDI(LJ_Handle, LJ_DIChannel, LJ_DIState) St = "eDI Success - Read Digital I/O Input Bit " + STR(LJ_DIChannel) + " at State: " + STR(LJ_DIState) LongError '******************************** 'Write a Digital I/O Port (0-19). Dim LJ_eDO As Function(ByVal Handle As Long, ByVal Channel As Long, ByRef State As Long) As Long LJ_eDO = DylibSymbol (LJ_Lib, "eDO") Dim As Long LJ_DOChannel, LJ_DOState LJ_DOChannel = 1 'LJ_DOState is 0 for low (False) and 1 for High (True) LJ_DOState = 0 LJ_Error = LJ_eDO(LJ_Handle, LJ_DOChannel, LJ_DOState) St = "eDO Success - Write Digital I/O Outp Bit " + STR(LJ_DOChannel) + " to State:" + Str(LJ_DOState) LongError '******************************** 'Set DACs to arbitary voltages. Dim LJ_AddRequest As Function(ByVal Handle As Long, ByVal IOType As Long, ByVal Channel As Long, ByVal Value As Double, ByVal x1 As Long, ByVal UserData As Double) As Long LJ_AddRequest = DylibSymbol (LJ_Lib, "AddRequest") Const LJ_ioPUT_DAC = 20 Const LJ_DAC0 = 0 Const LJ_DAC1 = 1 'Sample Voltage to send to DAC0. DIM LJ_DAC0Volts As Double: LJ_DAC0Volts = 2.5 'Sample Voltage to send to DAC1. DIM LJ_DAC1Volts As Double: LJ_DAC1Volts = 3.5 LJ_Error = LJ_AddRequest(LJ_Handle, LJ_ioPUT_DAC, LJ_DAC0, LJ_DAC0Volts, 0, 0) St = "AddRequest Success - Setting DAC Ch 0 to " + STR(LJ_DAC0Volts) + " Volts" LongError LJ_Error = LJ_AddRequest(LJ_Handle, LJ_ioPUT_DAC, LJ_DAC1, LJ_DAC1Volts, 0, 0) St = "AddRequest Success - Setting DAC Ch 1 to " + STR(LJ_DAC1Volts) + " Volts" LongError '******************************** 'Read an A/D Channel. Dim LJ_eGet As Function(ByVal Handle As Long, ByVal IOType As Long, ByVal Channel As Long, ByRef Value As Double, ByVal x1 As Long) As Long LJ_eGet = DylibSymbol (LJ_Lib, "eGet") Dim As Double LJ_ADValue Dim As Long LJ_ADChannel, LJ_ADx1 Const LJ_ioGET_AIN = 10 LJ_ADChannel = 0: LJ_ADValue = 0: LJ_ADx1 = 0 LJ_Error = LJ_eGet(LJ_Handle, LJ_ioGET_AIN, LJ_ADChannel, LJ_ADValue, LJ_ADx1) St = "eGet Success - Input at A/D Ch 0 = " + LEFT(STR(LJ_ADValue),6) + " Volts" LongError '******************************** 'Display prompt to proceed to Plotting demo. Print Locate ,1 : Print String (80,196); St = "A/D Plotting Demo " Locate , 41 - len(St)/2: Print St Locate ,1 : Print String (80,196) St = "Press the key to Plot A/D Channels 0-3 and Show Dig I/O Bits 0-3" Locate , 41 - len(St)/2: Print St Print St = "Use the L and R NumPad Arrow Keys to Change Sampling/Plotting Rate" Locate , 41 - len(St)/2: Print St Print:Print St = "Press the key to end program ..." Locate BottomTextLine, RightTextCol - 38: Print St; Do St = Inkey Loop until St = Chr(13) or St = Chr(27) If St = Chr(27) then Goto EndProg 'Turn off flag to Print LJ_Error = 0 Success Strings. Print_LJ_Error = 0 'Color theme for graph screen. LightBkgd = 8: DarkBkgd = 20 Color 0, DarkBkgd: CLS '******************************** 'Initialize graph screen. Color 0,DarkBkgd CLS 'Set up plot axes per variables already set with earlier SCREENRES command. LeftGraphCol = 58 RightGraphCol = ScrWidth - 3 BottomGraph = ScrHeight - 1 'Fill screen with light gray filled box. Line (0, 0) - (RightGraphCol + 2, BottomGraph),LightBkgd, BF 'Make abcissa and ordinate lines with box. Line (LeftGraphCol - 1, BottomGraph - 10) - (RightGraphCol + 2, 1),15, B 'Darken inside plot area with drak gray filled box. Line (LeftGraphCol, BottomGraph - 11) - (RightGraphCol + 1, 2),DarkBkgd, BF 'Initialize values for plot loop. GraphCol = LeftGraphCol + 1: NumScans = 0 'NumChannels = 4 for my application; LJ can go to 16 but will this program 'likely to need new math to place values and plot points. NumChannels = 4 'Start the plotting loop. Do NumScans = NumScans + 1 'Get milliseconds at start of loop to get A/D conversion rate at end of loop. StartTime = Timer 'A/D Channels count from 0 to NumChannels - 1. For ChannelLoop = 0 To NumChannels - 1 'ChannelLoop = I 'Get a reading from analog input I (AINI). LJ_Error = LJ_eGet(LJ_Handle, LJ_ioGET_AIN, ChannelLoop, LJ_ADValue, 0) LongError LJ_ADVoltage (ChannelLoop) = LJ_ADValue 'Place labels on graph only on first scan in loop to save CPU cycles. 'Arbitrary math used to place labels proportionally. IF NumScans = 1 Then Locate (ScrHeight/480)*(44-ChannelLoop*10) ,3: Color 14-ChannelLoop,LightBkgd Print "Ch" + STR(ChannelLoop); TempTextLine = CSRLIN + 2 Color 15,LightBkgd: Locate BottomTextLine, 8: Print "Samp Rate = ms/Ch"; Color 14, LightBkgd Locate , RightTextCol/2 - 4: Print Chr(27) + Space(12) + Chr(26); Color 15,LightBkgd Locate , RightTextCol/2 - 2: Print "Sweep Rate"; Locate ,RightTextCol - 22:Color 7,LightBkgd: Print "O0: O1: I2: I3:" ; End If 'Use same math to place A/D voltage values under channel names. Locate 2 + (ScrHeight/480)*(44-ChannelLoop*10),1: Color 14-ChannelLoop,LightBkgd Print Using "+##.###";LJ_ADVoltage(ChannelLoop); Color 12-ChannelLoop,DarkBkgd 'More arbitrary math to graph A/D values with channel labels. 'Adjust both positions and amplitudes of plotted values for different screen modes than 480. VoltTemp = (ScrHeight/480)* (355- ChannelLoop*80 - LJ_ADvoltage(ChannelLoop)*25*ScrHeight/480) Line (Graphcol, VoltTemp) - (GraphCol, VoltTemp), 14 - ChannelLoop 'Next A/D channel until NumChannels-1. Next ChannelLoop 'All A/D Channels now sampled, do the rest for this pass. 'Just for giggles, read Digital I/O input bits 2-3 with each loop. LJ_DIChannel = 2 LJ_Error = LJ_eDI(LJ_Handle, LJ_DIChannel, LJ_DIState) LongError EIState2 = LJ_DIState LJ_DIChannel = 3 LJ_Error = LJ_eDI(LJ_Handle, LJ_DIChannel, LJ_DIState) LongError EIState3 = LJ_DIState 'Just for giggles toggle Digital I/O output bits 0-1 at beginning and midpoint of graph. If GraphCol = 59 THEN LJ_DOChannel = 0 LJ_DOstate = 1 LJ_Error = LJ_eDO(LJ_Handle, LJ_DOChannel, LJ_DOState) LongError EOState0 = LJ_DOState LJ_DOChannel = 1 LJ_DOstate = 0 LJ_Error = LJ_eDO(LJ_Handle, LJ_DOChannel, LJ_DOState) LongError EOState1 = LJ_DOState End If If GraphCol = 320 THEN LJ_DOChannel = 0 LJ_DOstate = 0 LJ_Error = LJ_eDO(LJ_Handle, LJ_DOChannel, LJ_DOState) LongError EOState0 = LJ_DOState LJ_DOChannel = 1 LJ_DOstate = 1 LJ_Error = LJ_eDO(LJ_Handle, LJ_DOChannel, LJ_DOState) EOState1 = LJ_DOState End IF 'Now display the updated Digital I/O Values. Color 14, DarkBkgd Locate BottomTextLine Locate ,RightTextCol - 19: Print Str(EOState0); Locate ,RightTextCol - 13: Print Str(EOState1); Locate ,RightTextCol - 7: Print Str(EIState2); Locate ,RightTextCol - 1: Print Str(EIState3); 'Poor man's Sweep Rate - Use Numpad Left and Right Arrow Keys to speed or slow plot. If MultiKey (&H4B) Then DelayMSec = DelayMSec + 5: If DelayMSec > 1000 then DelayMSec = 1000 If MultiKey (&H4D) Then DelayMSec = DelayMSec - 5 :If DelayMSec < 0 then DelayMSec = 0 Sleep DelayMSec,1 'Wipe plot points one step ahead to allow overwrites with each new sweep. Line (GraphCol+1, TopGraph + 2) - (GraphCol + 1, BottomGraph - 11),DarkBkgd 'Advance to next X-axis position to plot points. At right of graph, reset to plot left to overwrite. If GraphCol >= RightGraphCol then GraphCol = LeftGraphCol ELSE GraphCol = GraphCol + 1: 'If GraphCol >629 then GraphCol = LeftGraphCol + 1 END IF 'Get elapsed milliseconds for one pass of loop. EndTime = Timer 'Calculate and display the A/D conversion rate for one channel during the loop. 'Affected by Sweep Rate as adjusted by Left and Right Numpad arrow keys. Locate BottomTextLine, 20: Print Left(Str( 1000*(EndTime - StartTime) / (NumChannels)),5); 'Exit the plotting routine by pressing key. Loop WHILE Inkey<> CHR(27) 'Clean up: release loaded DLL to fight another day. EndProg: DylibFree(LJ_lib) Color 7,0 CLS END 'Subroutine to print LJ error codes, or success text if no LJ error & print flag is set. Sub LongError If LJ_Error <> 0 Then Print "ERROR: "; (LJ_Error ) Else If PRINT_LJ_Error = -1 THEN Print "-"; St End If END Sub