Functions and Procedures

Functions and procedures, collectively referred to as routines, are subprograms (self-contained statement blocks) which perform a certain task based on a number of input parameters. When executed, a function returns value while procedure does not.

Functions

A function is declared like this:

sub function function_name(parameter_list) as return_type
  [ local declarations ]
  function body
end sub

function_name represents a function’s name and can be any valid identifier. return_type is a type of return value and can be any simple type or complex type. Within parentheses, parameter_list is a formal parameter list very similar to variable declaration. In mikroBasic PRO for AVR, parameters are always passed to a function by the value. To pass an argument by address, add the keyword byref ahead of identifier.

Local declarations are optional declarations of variables and/or constants, local for the given function. Function body is a sequence of statements to be executed upon calling the function.

Calling a function

A function is called by its name, with actual arguments placed in the same sequence as their matching formal parameters. The compiler is able to coerce mismatching arguments to the proper type according to implicit conversion rules. Upon a function call, all formal parameters are created as local objects initialized by values of actual arguments. Upon return from a function, a temporary object is created in the place of the call and it is initialized by the value of the function result. This means that function call as an operand in complex expression is treated as the function result.

In standard Basic, a function_name is automatically created local variable that can be used for returning a value of a function. mikroBasic PRO for AVR also allows you to use the automatically created local variable result to assign the return value of a function if you find function name to be too ponderous. If the return value of a function is not defined the compiler will report an error.

Function calls are considered to be primary expressions and can be used in situations where expression is expected. A function call can also be a self-contained statement and in that case the return value is discarded.

Example

Here’s a simple function which calculates xn based on input parameters x and n (n > 0):

sub function power(dim x, n as byte) as longint
dim i as byte
  result = 1
  if n > 0 then
    for i = 1 to n
      result = result*x
    next i
  end if
end sub

Now we could call it to calculate, say, 312:

tmp = power(3, 12)

Procedures

Procedure is declared like this:

sub procedure procedure_name(parameter_list)
  [ local declarations ]
  procedure body
end sub

procedure_name represents a procedure’s name and can be any valid identifier. Within parentheses, parameter_list is a formal parameter list similar to variable declaration. In mikroBasic PRO for AVR, parameters are always passed to procedure by value; to pass argument by address, add the keyword byref ahead of identifier.

Local declarations are optional declaration of variables and/or constants, local for the given procedure. Procedure body is a sequence of statements to be executed upon calling the procedure.

Calling a procedure

A procedure is called by its name, with actual arguments placed in the same sequence as their matching formal parameters. The compiler is able to coerce mismatching arguments to the proper type according to implicit conversion rules. Upon procedure call, all formal parameters are created as local objects initialized by values of actual arguments.

Procedure call is a self-contained statement.

Example

Here’s an example procedure which transforms its input time parameters, preparing them for output on Lcd:

sub procedure time_prep(dim byref sec, min, hr as byte)
  sec  = ((sec and $F0) >> 4)*10 + (sec and $0F)
  min  = ((min and $F0) >> 4)*10 + (min and $0F)
  hr   = ((hr  and $F0) >> 4)*10 + (hr  and $0F)
end sub

Function Pointers

Function pointers are allowed in mikroBasic PRO for AVR. The example shows how to define and use a function pointer:

Example:

Example demonstrates the usage of function pointers. It is shown how to declare a procedural type, a pointer to function and finally how to call a function via pointer.

program Example;

typedef TMyFunctionType as function (dim param1, param2 as byte, dim param3 as word) as word ' First, define the procedural type

dim MyPtr as ^TMyFunctionType  ' This is a pointer to previously defined type
dim sample as word

sub function Func1(dim p1, p2 as byte, dim p3 as word) as word ' Now, define few functions which will be pointed to. Make sure that parameters match the type definition
  result = p1 and p2 or p3
end sub

sub function Func2(dim abc, def as byte, dim ghi as word) as word  ' Another function of the same kind. Make sure that parameters match the type definition
  result =  abc * def + ghi
end sub

sub function Func3(dim first, yellow as byte, dim monday as word) as word  ' Yet another function. Make sure that parameters match the type definition
  result =  monday - yellow - first
end sub

' main program:
main:
  MyPtr = @Func1            ' MyPtr now points to Func1
  Sample = MyPtr^(1, 2, 3)  ' Perform function call via pointer, call Func1, the return value is 3
  MyPtr = @Func2            ' MyPtr now points to Func2
  Sample = MyPtr^(1, 2, 3)  ' Perform function call via pointer, call Func2, the return value is 5
  MyPtr = @Func3            ' MyPtr now points to Func3
  Sample = MyPtr^(1, 2, 3)  ' Perform function call via pointer, call Func3, the return value is 0
end.

A function can return a complex type. Follow the example bellow to learn how to declare and use a function which returns a complex type.

Example:

This example shows how to declare a function which returns a complex type.

program Example

structure TCircle       ' Structure
  dim CenterX, CenterY as word
  dim Radius as byte
end structure

dim MyCircle as TCircle ' Global variable

sub function DefineCircle(dim x, y as word, dim r as byte) as TCircle ' DefineCircle function returns a Structure
  result.CenterX = x
  result.CenterY = y
  result.Radius = r
end sub

main:
  MyCircle = DefineCircle(100, 200, 30)                       ' Get a Structure via function call
  MyCircle.CenterX = DefineCircle(100, 200, 30).CenterX + 20  ' Access a Structure field via function call
  '                  |------------------------| |-----|
  '                     |                         |
  '                  Function returns TCircle     Access to one field of TCircle
end.

Forward declaration

A function can be declared without having it followed by it's implementation, by having it followed by the forward procedure. The effective implementation of that function must follow later in the module. The function can be used after a forward declaration as if it had been implemented already. The following is an example of a forward declaration:

program Volume

dim Volume as word

sub function First(dim a as word, dim b as word) as word forward

sub function Second(dim c as word) as word
dim tmp as word
  tmp = First(2, 3)
  result = tmp * c
end sub

sub function First(dim a, b as word) as word
  result = a * b
end sub

main:
  Volume = Second(4)
end.

Functions reentrancy

Functions reentrancy is allowed. Remember that the AVR has memory limitations that can vary between MCUs.

Copyright (c) 2002-2012 mikroElektronika. All rights reserved.
What do you think about this topic ? Send us feedback!
Want more examples and libraries? 
Find them on LibStock - A place for the code