Conditional Compilation
CRBasic allows the user to include or exclude code in the program, based on logger type or on some other condition in the datalogger program, such as a user defined constant (see Conditional Compilation Based on Evaluation of Constants). This is called conditional compilation, and it is accomplished using #If, #Else, #ElseIf, #EndIf
, and #UnDef syntax
.
The #If_no_remove
declaration can be used in place of #If
to specify conditional code that should not be removed from the resulting program when a Conditional Compile and Save is performed.
Conditional Compilation Based on Datalogger Type (LoggerType)
Many CRBasic dataloggers use a default file extension that indicates the logger type the program was compiled for (for example, *.CR1X for a CR1000X-series logger).
In addition to data logger-specific file extensions, there are also 2 universal file extensions that allow a program to run on more than one type of data logger:
-
.DLD
-
Original universal file extension
-
Compatible with both retired and current data logger models
-
.CRB
-
New default file extension
-
Not compatible with retired data loggers
-
Will be used for all future data logger models
CR350 dataloggers, as well as all GRANITE dataloggers use the *.CRB extension. This extension is also valid for CR6 dataloggers with OS 11 or later and CR1000X dataloggers with OS 5 or later. See Program File Extensions for more information.
By using conditional compilation with a *.DLD or *.CRB file, you can create a single program that runs on multiple datalogger types.
A common use case is when the same program must run on dataloggers that support different options for a CRBasic instruction. For example, since voltage ranges vary among datalogger types, you can use conditional #If/#ElseIf
statements to assign the correct range codes. The example program below shows this approach:
Public PTemp, TCTemp
'Set the constant "Range" based on
LoggerType
#If LoggerType = CR6
Const Range=mv200C
#ElseIf LoggerType=CR1000
Const Range=mv2_5C
#EndIf
DataTable (TempTab,True,-1)
DataInterval (0,1,Min,10)
Sample (1,TCTemp,FP2)
EndTable
BeginProg
Scan (1,Sec,3,0)
'Range will bet set to mv200C for a CR6 or mv2_5c for a CR1000
TCDiff (TCTemp,1,Range,U1,TypeT,PTemp,True ,0,15000,1.0,0)
CallTable (TempTab)
NextScan
EndProg
NOTE: Beginning with CR1000X OS 8.4.0, a constant named is_CR1000Xe
, can be used within #IF
statements to conditionally compile code that is specific to the CR1000Xe.
For example:
#If LoggerType = CR1000X Then
Const Modem_Power = SW12_1
#ElseIf is_CR1000Xe Then
'SW12_CSIO - CR1000Xe Only
Const Modem_Power = SW12_CSIO
#EndIf
Conditional Compilation Based on Evaluation of Constants
The following example program shows how conditional compilation can be used to include/exclude code that is compiled in the datalogger based on the state of constants in the program. This program also uses the Custom Menu capability.
Using a keyboard display, the user selects which sensors are connected to the datalogger. If a sensor is marked as “true” all the code associated with that sensor (measurements and data table information) is included in the program when compiled.
Public Batt_Volt, Ptemp_C
'Constants for True/False
Const No = False
Const Yes = True
'Constant table for choosing Sensor types
'Set Values to “no” at the beginning of the program
ConstTable
Const Add107 = No
Const Addtc = No
Const Addcs700 = No
Const Addte525 = No
EndConstTable
'MenuRecompile var
Public Recomp
'Create the Custom Menu
DisplayMenu ("CR6 Menu",-3)
DisplayValue ("Compile Msg",status.compileresults)
SubMenu ("Sensor Setup")
MenuItem ("Add Temp107?",Add107)
MenuPick (Add107, Yes, No)
MenuItem ("Add TCTemp?",Addtc)
MenuPick (Addtc, Yes, No)
MenuItem ("Add CS700?",Addcs700)
MenuPick (Addcs700, Yes, No)
MenuItem ("Add TE525?",Addte525)
MenuPick (Addte525, Yes, No)
EndSubMenu
SubMenu ("Save & Compile")
MenuRecompile ("Compile Now", Recomp)
MenuPick (Yes, No)
EndSubMenu
EndMenu
DataTable (TempPrecip,True,1000)
DataInterval (0,1,Min,10)
Sample (1,Batt_Volt,FP2)
#If Add107 Then
Average (1,Temp107,FP2,False)
#EndIf
#If Addtc Then
Average (1,TempTC,FP2,False)
#EndIf
#If Addte525 Then
Totalize (1,RainIn525,FP2,False)
#EndIf
#If Addcs700 Then
Totalize (1,RaininCS700,FP2,False)
#EndIf
EndTable
BeginProg
'Conditionally added
Measurement vars
#If Add107 Then
Public Temp107
#EndIf
#If Addtc Then
Public TempTC
#EndIf
#If Addte525 Then
Public RainIn525
#EndIf
#If Addcs700 Then
Public RaininCS700
#EndIf
Scan (1,Sec,3,0)
'Wiring panel & battery
Battery (Batt_Volt)
'Conditional code for temp sensors
#If Add107 Then
'107 Temperature Probe measurement T107_C
Therm107(Temp107,1,U1,U5,0,15000,1,0)
#EndIf
#If Addtc Then
'Type T (copper-constantan) Thermocouple measurements Temp_C
TCDiff(TempTC,1,mv200C,
#EndIf
'Conditional code for rain gauges
#If Addcs700 Then
'CS700 Rain Gauge measurement Rain_in
PulseCount(RaininCS700,1,U11,2,0,0.01,0)
#EndIf
#If Addte525 Then
'TE525/TE525WS Rain Gauge measurement Rain_in_2
PulseCount(RainIn525,1,U11,2,0,0.01,0)
#EndIf
CallTable (TempPrecip)
NextScan
EndProg
Conditional Compilation Based on Presence of Constants
The following program shows how conditional compilation with #IfDef can be used to determine which Public variables are present in a program based on what constants are defined.
Public Ptemp, Batt_Volt
BeginProg
Scan (1,Sec,0,0)
Battery (batt_volt)
'If Const Final declared, then a Public variable named Testing is present
Const FINAL = 1
#IfDef FINAL Then
Public Testing
#Else
'If Const Final not declared, then a Public variable named Not_Testing is present
Public Not_Testing
#EndIf
NextScan
EndProg
#UnDef
NOTE: Before using #UnDef, consider IncludeSection().
#UnDef is commonly used with Const and #If/EndIf to create and stitch together libraries or sections of code located in Include files. This approach is most commonly used for systems with many components and measurements. These large system programs often use multiple Include files for specific system-component configurations. #If/#UnDef allows conditional declaration of program sections such that multiple Include files can be condensed into one. For example, in the sample code below, #If is used to declare a constant named “Section” twice in a main program. The first Section is used to pull in sensor settings from an Include file named "cpu:Sensor_PT500_Lib.crb", and the second Section is used to configure data storage using the same Include file. Without #UnDef, declaring the same constant twice would result in a compile error. Using #If along with #UnDef increases program efficiency and decreases the number of Include files required for system configuration.
'From Main program:
Const Section = "Section_PT500_Settings"
Include "cpu:Sensor_PT500_Lib.crb"
#UnDef Section
Const Section = "Section_PT500_Storage"
Include "cpu:Sensor_PT500_Lib.crb"
#UnDef Section
'///////////////////////////////////////////////////////////////////////
'From an Include file named "cpu:Sensor_PT500_Lib.crb"
#If Section = "Section_PT500_Settings"
Const AIR_GRASS_TEMP = True
Const GROUND_TEMP = False
#EndIf
#If Section = "Section_PT500_Storage"
DataTable(pt500_12sec, True, -1 )
TableFile("CRD:pt500_12sec", 8, -1, 0, 1, Day, outstat, lastfilename)
DataInterval(0, 12, Sec, 10)
Sample(1, pt500_air, IEEE4, False)
Sample(1, pt500_grass, IEEE4, False)
Sample(1, pt500_t1, IEEE4, False)
EndTable
#EndIf