Programs and Functions
| function endf result constant keep |
load
tload |
list fexists call trace |
The function is the basic unit of PIC32-Basic. What it effectively does is to create another keyword defined by the user. A keyword is a built in word like say ‘print’ or ‘dim’. A program is a collection of user functions that will ultimately lead to the main function which runs the program.
Building a program this way enables each ‘function’ to be tested before being added to the main program. Writing a robot application for example could have functions called arm, leg, wrist etc. each one doing its own particular task and only needing to come together on the main program. A further advantage of this structure is that it is easy to build a library of functions for a particular application and re-use them.
A function only becomes part of a program when it is first called and so the Flash and SD Card may contain thousands of functions but they will only form part of the program when required. Functions always return a value but this can be ignored.
Functions start with the word ‘function’ followed by the functions name, followed by optional parameters. The function must end with the keyword ‘endf’ When a parameter is used brackets must surround this, thus function s1(x). Multiple parameters are separated by commas.
print “Hello World”
print “a$=”, a$
endf
In this example a$ is carried into the function and printed, if it is loaded into the program area then test(“fred”) would produce:
Hello World fred
A function name follows the same postfix convention as variables, to return a value ‘result’ used.
print "x=",x#
result 2*x#
endf
In this example the function will return a float value because the float postfix symbol ‘#’ has been used in the function name. If this is loaded in the program area then print test#(5.1) would produce:
x=5.1
10.2
Result must be the last executed statement in the function, i.e. before endf or before exitf. Also note that result is NOT a variable, it simply tells the function what to return so this: result=result+2 would cause an error. A function is the fundamental unit of PIC32-Basic and all programs consist of functions. A function does not have to be defined before it is used and so the main function can either appear at the top of a program or at the bottom.
In fact a function can appear anywhere in the microcontrollers memory in either RAM or Flash. If two functions exist with the same name the LAST one to be defined is used, i.e. the most current one.
Brackets
To clear up any confusion, brackets are used when a function has parameters, in the above function test#, to call this function, because it has parameters (the x#) brackets are used to call it. Take a look at the following code:
print "s1 with no parameters"
endf
function s2(a)
print "s2 with 1 parameter: ";a
endf
function s3
print "s3 returns a value"
result 10
endf
function s4(a,b)
print "axb=";a*b
result a*b
endf
function s5$(a$)
print "returns this string <Hello ";a$;">"
result "Hello "+a$
endf
function xx
s1
s2(12)
print "s3 has returned ";s3
print "s4 has returned ";s4(4,5)
endf
The output from executing xx is:
s1 with no parameters
s2 with 1 parameter: 12
s3 has returned s3 returns a value
10
s4 has returned axb=20
20
Function s1 has no parameters and so is just called using its name, s2 and s4 have parameters so they are called using brackets to enclose the value of those parameters. In the case of s3 it breaks with the convention that all functions and keywords that return a value are followed by brackets.
| constant |
| constant <name>
<value> constant AG12 0x33440129 constant CAHR97 ‘a’ constant MSG1$ “Hello there” |
Constant definitions are similar in many ways to functions in that they can exist in RAM or Flash. They are also one of the few words that can exist outside of a function and make sense. The name does not need to be in upper case but that is a generally accepted convention.
Writing and Running Functions
A function can be written directly at the console if required. After the functions name when enter is pressed the prompt changes to ‘>’ to indicate that a function is being written and any subsequent text will go into the program buffer. To end the function the word ‘endf’ is entered, that will stop the ‘>’ prompt and go back to the ok prompt. To run a function simply type its name.
As an example:
function hw
print “Hello World”
endf
Type in the above, notice at the end of the first line the prompt changes to ‘>’. Now type hw and the ‘Hello World’ will be printed at the console. Function’s will generally call other function’s and so in this way a full program can be built.
Typing the information in at the console however is a very tedious method. A better way is to have the program reside on the host PC or an SD Card. There are several ways to get the program onto the BV513 and this is fully explained in the File Loading chapter of the Interfacing section.
| load |
| load <filename> load auto |
The load statement is used to transfer a Basic file from SD Card to the program buffer (RAM). A file must have a ‘bas’ extension and it need not be included in the load statement. In the above example the file “auto.bas” will be loaded into the program buffer. The file must of course exist. When this transfer takes place. Note that 'load' calls 'new' before loading.
| tload |
| tload [to filename] tload tload to "welcome.bas" tload to "data.txt" |
Text load: This will load a program into the RAM program area from a simple text download using the ACK (6) line end protocol. This is a protocol that BV-COMM uses (see File Loading chapter of the Interfacing section). After this command is entered PIC32-Basic will wait for a line of text, a line of text is text terminated with either CR or LF. When the line has been received and PIC32-Basic has dealt with it it sends ACK (character 6) which tells BV-COMM to send another line of text, so on and so forth. There is a time out mechanism built in so that when BV-COMM stops sending text the command will finish.
On its own 'tload' expects to receive a Basic file and will treat it as such loading it correctly into the program RAM area. The purpose of this keyword is to allow programs to be loaded and run if no SD Card is available. Programs can subsequently be saved to Flash using 'fsave'.
Using 'tload' with 'to filename' will create a file on the SD Card and load the text to that file. The file is not altered in any way but it does expect text and it is loaded line by line, the maximum length of a string is 128 bytes. For binary transfer see xload.
Function Storage & Search
When defining a function at the console or loading one via, load or tload the function is stored in the program area RAM. When the function is first called a variable pointer is created to it and this is used in subsequent calls. This speeds access to functions which would be particularly noticeable should a function be called within a program loop.
Functions can also be stored in Flash for immediate access using the calling convention described above, i.e. type in the function name. A function that has already been searched for and initialised will stop other functions being defined with the same name. A function that has not been initialised however can have the name duplicated, when a search occurs for the function the following order is implemented: RAM and then Flash (backwards). This means that the latest version will be found first and it will be that version that is used. This is convenient for Flash as it means that redefining a function is simply a matter of re-saving to flash, the older version will be ignored.
Variables and Scope
Variables by default are local to the function and any routine that it calls. This can be useful but possibly dangerous as you may forget this fact and after a few levels of function nesting it would be very difficult to follow a variable unless it has a unique name.
print "in s1 a=";a
endf
function s2
a=2
s1 print "after calling s1 a=";a
endf
This example illustrates that variable ‘a’ is the same ‘a’ that is used in function s1 & s2 because it is called by function s2, it is part of the scope of s2. The output from running s2 is:
in s1 a=2
after calling s1 a=2
In this situation it is always better to use dim, this will keep the variables local to that function, thus:
dim a=55
print "in s1 a=";a
endf
function s2
a=2
s1 print "after calling s1 a=";a
endf
Calling function s4 now has the desired results:
in s1 a=55
after calling s1 a=2
Using the dim statement in function s1 keeps the 'a' local to s1. For more information on the dim statement see the section on variables.
| keep |
| keep |
When a function is run, all variables created in that function is destroyed at the endf statement. There may be a requirement for some variables to remain after the function has ended. A good example of this is an initialisation routine that may create some variable constants.
if vexists("tell")=0 then
print"dim going on"
dim tell, device1=0x33,device2=0x76
keep
endif
endf
function s2
init:keep
endf
In this example device 1 and 2 need to be initialised so that these values can be used in other functions, ignoring ‘vexists’ for the moment, the keep at the end of the dim statement in the function ‘init’ will keep those variables when the function ‘init’ ends. The keep in function 2 will keep anything that s2 creates and don’t forget that s2 created 'init' and all within it.
The statement ‘vexists’ is used so that ‘init’ can be called many times and only create one set of global variables. See vexists in the variables section.
| fexists() |
| fexists([“]<function
name>[“]) a%=fexists(my_func) |
This searches RAM and Flash for the existence of a function. If not found it will return 0, if found it returns the memory address of the start of the function.
| call() |
| call(func_address)[(params)] call(0x9d032000) call(a%) call(a%)(12,"fred") a=call(fun%) |
Call is used to execute (run) a function at a given address,
this address can be found by fexists(). It will return an integer value
provided the called function returns one. Parameters can also be
specified by using a second set of parenthasis.
| trace |
|
trace <param> trace 1 trace 0x21 |
Trace is provided as a simple method of debugging, it is not guaranteed to work every time just yet but could help out if it proves difficult to find out where a problem lays. The current parameter options are available:
0, Turn off trace.
1, This will show the current function and current extracted token, this may not show the results you expect.
2, As above but also displays any variables that have been created at the point in time the trace was evoked.
0x2n (0x21 or 0x22). The above trace results will be shown for each line of BASIC executed (possibly more than once per line) until trace 0 is encountered. Entering a value of 0x2n will stop the process each time a trace is shown, pressing space bar will go onto the next line of BASIC. Any other entry will turn trace off.
As indicated above, this command is in its early stages and is likely to change in time to provide a more useful output.
| list |
| list [ram
[function]][flash [function] list ram list flash list ram func |
Lists the functions in either Flash or RAM. The list followed by just Flash or ram will give a list of the functions. If the word flash or ram is followed by a function name then it will list that functions contents.