PIC Microcontrollers - Programming in BASIC

Chapter 2: Programming Microcontrollers

You certainly know that it is not enough to simply connect the microcontroller to other components and turn the power supply on to make it work, don’t you? There is more to be done. Microcontrollers need to be programmed to be capable of performing anything useful. This chapter deals with programming in Basic and we are going to describe only the essential things you have to know to write a program. It might seem complicated, especially if you have no experience in this field. Don’t give up, take a deep breath and start...


Programming microcontroller - Machine Code

The microcontroller executes the program loaded in its Flash memory. It is a so called executable code which consists of a seemingly bizarre sequence of zeros and ones. Depending on the microcontroller’s architecture, this binary code is organized in 12-, 14- or 16-bit wide words. Every word is considered by the CPU as an instruction to be executed during the operation of the microcontroller. As it is much easier for us to deal with hexadecimal numeric system, the executable code is usually represented as a sequence of hexadecimal numbers called a Hex code which, long time ago, used to be written by the programmer. All instructions that the microcontroller can recognize and execute are collectively known as the Instruction set. For PIC microcontrollers with 14-bit wide program words, the instruction set includes 35 different instructions.

Programming microcontroller - Assembly

As the writing of executable code was endlessly tiring, the first high-level programming language called assembly language was created. It made the process of programming a bit more complicated, but on the other hand the process of writing program stopped being a nightmare. Assembly instructions consist of meaningful abbreviations which are compiled into executable code by means of a special program installed on a PC called assembler. It compiles instruction by instruction without optimization. The main advantages of assembly language are its simplicity and the fact that each program instruction matches only one memory location. In other words, assembly language enables a complete control of all processes being under way within the microcontroller, which still makes it popular nowadays.

On the other hand, programs are always executed at high speeds and in most cases it is not necessary to know in detail what is going on within the microcontroller. Despite all good attributes of the assembly language, programmers have always needed a programming language similar to the language they use in everyday speech. Finally, high-level programming languages, including Basic, have been created. The main advantage of these languages is a simplicity of program writing. Several assembly instructions are now replaced by one statement in Basic. The programmer is not required to be familiar with the instruction set of the microcontroller in use any more. It is no longer possible to know how each statement is executed, but it doesn’t matter anyway. In case it does, the problem is solved by adding a sequence written in assembly language to the program.

Programming microcontroller - BASIC programming language

Similar to assembly language, a specialized program installed on the PC is in charge of compiling program into machine code. Unlike assembler, compilers for high-level programming languages create an executable code which is not always the shortest possible.

Programming microcontroller process

Figure above gives a rough illustration of what is going on during the process of compiling a program written in Basic into a hex code.

Here is an example of a simple program written in Basic:

Simple program written in BASIC language


If you have any experience in writing programs for PIC microcontrollers in assembly language, then you are probably familiar with the other side of the medal of RISC architecture - the lack of instructions. For example, there is no appropriate instruction for multiplying two numbers. Of course, there is a way to solve this issue owing to mathematics which enables you to perform complex operations by breaking them into a number of simple ones. Accordingly, multiplication can be easily substituted by successive addition (a x b = a + a + a + ... + a). And here we are, just at the beginning of a very long story... Still there is no reason to be worried about as far as you use one of the high-level programming languages, such as Basic, as the compiler will automatically find a solution to these and similar issues. Simply write a*b.



Similar to the use of any language which is not limited to books and magazines only, the Basic programming language is not closely related to any special type of computer, processor or operating system. It is a general-purpose language. This fact can make some problems as the Basic language slightly varies depending on its application (like different dialects of one language). So, we are not going to provide you with a detailed description of all the attributes of Basic in this book. Instead, we are going to describe a concrete application of the Basic programming language, i.e. Basic used by the mikroBasic PRO for PIC compiler.

The Basic programming language is a simple and easy to understand programming language. To use it correctly, it is sufficient to know just a few basic elements that every program consists of. These are:

  • Identifiers
  • Comments
  • Operators
  • Expressions
  • Instructions
  • Constants
  • Variables
  • Symbols
  • Directives
  • Labels
  • Procedures and functions
  • Modules
How you should not write a program

Here is an example of how you should not write a program. No comments are included, labels’ names are meaningless, code sections are not grouped… This program is going to work properly, but its purpose and way of execution will be only known to the programmer who has written it (at least for a day or two).

Figure below illustrates the structure of a simple program written in Basic, pointing out the parts it consists of. This is an example of how you should write a program. Differences are more than obvious...

The structure illustration  of a simple program


Similar to other programming languages, Basic provides a set of strictly defined rules to be observed when writing programs. For a program to be written in Basic, it is necessary to install a software which provides the appropriate work environment and understands these rules on your PC... When you write a letter, you need a word processing program, don’t you? In this case, you need the mikroBasic PRO for PIC compiler.

Unlike most programs you have already got used to dealing with, the process of writing programs in the compiler doesn’t start by selecting the File>New option, but Project>New. Why is that? Well, you write a program in a document with the .mbas extension (mikroBasic). You diligently write, write, write... When you compile it into a HEX code, a new document with the .hex extension will be created. At the same time the compiler will automatically create several documents in addition to it. The purpose of these documents is not important at this point. Of course, there must be something to connect them all. You get it - we are talking about a project. The program you write is just a part of it.

Project in mikroBasic

Just to be sure that we are on the same page... From now on the word module refers to a document with the .mbas extension. The text it contains is referred to as a program. Every project written in the mikroBasic PRO for PIC compiler has the .mbppi extension (microBasic Project for PIC) and consists of at least one module (Main Module).

Every project in mikroBasic PRO for PIC requires a single main module. It is identified by the keyword program and instructs the compiler from where to start the process of compiling. When you successfully create an empty project in Project Wizard, the main module will be automatically displayed in the Code Editor window:

program MyProject ' The main module is called MyProject here
main: ' Main procedure
... '*
... '* Write program code here
... '*

Nothing may precede the program keyword, except comments. As mentioned above, the project may also include other modules which, unlike the main one, start with the module keyword.

module MyModule ' Auxiliary module is called MyModule
... '*
... '* Implements
... '*

To make the compiler familiar with all modules which belong to one project, it is necessary to specify them in the main module using the include keyword followed by a quoted module name. The extension of these files should not be included. Only one module per include clause is allowed. The number of include clauses is not limited, but they all must be specified immediately after the program (main module) name. Here’s an example:

program MyProgram ' Start of program (main module named ‘MyProgram’)
' Other modules included are:

include "utils" ' Module "utils"
include "strings" ' Module "strings"
include "MyUnit" ' Module "MyUnit"


Basically, the main module can be divided in two sections: declarations and program body. What is a declaration in programming? A declaration is a process of defining the properties of identifiers to be used in the program. Like most other programming languages, Basic also requires all identifiers to be declared prior to being used in the program. Otherwise, the compiler may not be able to interpret them correctly. This is how a declaration of a variable called distance looks like:

dim distance as float ' Declare variable distance

As can be seen, it is a floating point variable, i.e. a number with optional decimal places. Two other variables are declared and named speed and time. Now, they can be used in the program as follows:

This is an example of how to write the main module correctly:

Writing the main module correctly


Other modules start with the module keyword. Every module consists of three sections: include, interface and implementation. Only the implementation section is obligatory. It starts with the implements keyword. Follow the example below:

Organization of Module


Identifiers are arbitrary names assigned to the basic language objects such as constants, variables, functions, procedures etc. Somebody just came to an idea to use the word identifier instead of name. As simple as that. Here are a few rules to be observed when using identifiers:

  • Identifiers may contain all the letters of alphabet (both upper and lower case), digits (0-9) and the underscore character ( _ ).
  • The first character of an identifier must not be a digit.
  • No identifier may contain special characters such as ! [{ # $ % & etc.
  • Basic is not case-sensitive, which means that FIRST, first and First will be considered identical.
  • The ^ (caret) symbol is used to denote an exponentiation operator, the * (asterisk) symbol is used to denote multiplication, while other symbols have their usual meanings.
  • Keywords being already used by the compiler must not be used as identifiers The mikroBasic keywords are listed in the following table:
  • Abstract
  • And
  • Array
  • As
  • At
  • Asm
  • Assembler
  • Automated
  • Bdata
  • Begin
  • Bit
  • Case
  • Cdecl
  • Class
  • Code
  • Compact
  • Const
  • Constructor
  • Contains
  • Data
  • Default
  • Deprecated
  • Destructor
  • Dispid
  • Dispinterface
  • Div
  • Do
  • Downto
  • Dynamic
  • Else
  • End
  • Except
  • Export
  • Exports
  • External
  • Far
  • File
  • Finalization
  • Finally
  • For
  • Forward
  • Function
  • Goto
  • Idata
  • If
  • Ilevel
  • Implementation
  • In
  • Index
  • Inherited
  • Initialization
  • Inline
  • Interface
  • Io
  • Is
  • Label
  • Large
  • Library
  • Message
  • Mod
  • Name
  • Near
  • Nil
  • Not
  • Object
  • Of
  • On
  • Or
  • Org
  • Out
  • Overload
  • Override
  • Package
  • Packed
  • Pascal
  • Pdata
  • Platform
  • Private
  • Procedure
  • Program
  • Property
  • Protected
  • Public
  • Published
  • Raise
  • Read
  • Readonly
  • Record
  • Register
  • Reintroduce
  • Repeat
  • Requires
  • Resourcestring
  • Rx
  • Safecall
  • Sbit
  • Set
  • Sfr
  • Shl
  • Shr
  • Small
  • Stdcall
  • Stored
  • String
  • Stringresource
  • Then
  • Threadvar
  • To
  • Try
  • Type
  • Unit
  • Until
  • Uses
  • Var
  • Virtual
  • Volatile
  • While
  • With
  • Write
  • Writeonly
  • Xdata
  • Xor

A list of identifiers which must not be used in the program.


Comments are parts of the program used to provide more information about the program and make it clear to the user. In Basic, any text following a single quotation mark (') is considered a comment. Comments are not compiled into executable code. The compiler is capable of recognizing special characters used to mark where comments start and completely ignores the following text during compilation. Even though comments cannot affect the program execution, they are as important as any other part of the program because almost every program needs to be improved, modified, upgraded or simplified at some point. Without comments, it is almost impossible to understand even the simplest programs.



Labels provide the easiest way of controlling the program flow. They are used to mark particular lines in the program where jump instruction and appropriate subroutine are to be executed. All labels must be terminated by ‘:’ so that the compiler can easily recognize them.



A constant is a number or a character the value of which cannot be changed during the program execution. Unlike variables, constants are stored in ROM memory of the microcontroller in order to save as much memory space of RAM as possible. The compiler recognizes constants by their names and prefix const. Every constant is declared under unique name which must be a valid identifier. Constants are available in decimal, hexadecimal and binary formats. The compiler distinguishes between them according to their prefixes. If a constant has no prefix, it is considered decimal by default.

Format Prefix Example
Decimal const MAX = 100
Hexadecimal 0x or $ const MAX = 0xFF
Binary Floating point const MAX = %11011101

Constants are declared in the declaration part of the program or routine. The syntax of constants is:

const constant_name [as type] = value

Constant names are usually written in capitals. The type of a constant is automatically recognized by its size. In the following example, the constant MINIMUM is considered a signed integer and will be stored within two bytes of Flash memory (16 bits):

const MINIMUM = -1000 ' Declare constant MINIMUM

Type of constant is optionally specified. In the absence of type, the compiler assumes the ‘smallest’ type that can accommodate the constant value.

const MAX as longint = 10000
const MIN = 1000 ' Compiler will assume word type
const SWITCH = "n" ' Compiler will assume char type

In the following example, a constant named T_MAX is declared so as to have a fractional value 32.60. Now, the program can compare the measured temperature to that constant with a meaningful name instead to number 32.60.

const T_MAX = 32.60 ' Declare temperature T_MAX
const T_MAX = 3.260E1 ' Another way of declaring constant T_MAX

A string constant consists of a sequence of characters. They are enclosed within double quotation marks. A blank space may also be included in the string constant as a character. String constants are used to represent non-numeric quantities such as names, addresses, messages etc.

const Message_1 = "Press the START button" ' Message 1 for LCD
const Message_2 = "Press the RIGHT button" ' Message 2 for LCD
const Message_3 = "Press the LEFT button" ' Message 3 for LCD

In this example, sending the Message_1 constant to an LCD will cause the message ‘press the START button’ to be displayed.


A variable is a named object able to contain a data which can be modified during program execution. Every variable is declared under a unique name which must be a valid identifier. For example, to add two numbers (number1 + number2) in the program, it is necessary to have a variable to represent what we in everyday life call the sum. In this case number1, number and sum are variables. The syntax of one single variable declaration is as follows:

dim variable_name as type

Variables in Basic are typed, which means that it is necessary to specify the type of data a variable is to receive. Variables are stored in RAM and the memory space occupied (in bytes) depends on their type. In addition to single declarations, variables of the same type can be declared as a list. Here, identifier_list is a comma-delimited list of valid identifiers, whereas type can be any data type.

dim i, j, k as byte 'Define variables i, j, k
dim counter, temp as word 'Define variables counter and temp


Symbols in Basic allow you to create simple macros without parameters. It means that any code line may be replaced with one single identifier. Symbols, when used properly, can increase code legibility and reusability.

Symbols are declared at the beginning of the module, right after the module name and optional include directive. The scope of a symbol is always limited to the module in which it has been declared.

symbol symbol_name = code

Here, symbol_name must be a valid identifier to be used throughout the code. The code specifier can be any code line (literals, assignments, function calls, etc).

symbol MAXALLOWED = 216        ' Symbol MAXALLOWED for numeric value
symbol OUT = PORTA ' Symbol OUT for SFR
symbol MYDELAY = Delay_ms(762) ' Symbol MYDELAY for procedure call
dim cnt as byte ' Variable cnt
if cnt > MAXALLOWED then ' Program checks whether cnt > 216
cnt = 0 ' If yes,
OUT.1 = 0 ' the following three commands
MYDELAY ' are to be executed
end if
... ' If not, program continues here

No RAM memory space is used for storing symbols being used in the program. The compiler will simply replace all symbols with appropriate code lines assigned to them when declared.


There are several data types that can be used in the Basic programming language. Table below shows the range of values these data may have when used in their basic form.

Data type Description Size (Number of bits) Range of values
bit One bit 1 0 or 1
sbit One bit 1 0 or 1
byte, char Character 8 0 ... 255
short Signed short integer 8 -127 ... 128
word Unsigned integer 16 0 ... 65535
integer Signed integer 16 -32768 ... 32767
longword 32-bit word 32 0 ... 4294967295
longint 32-bit signed word 32 -2147483648 ... 2147483647
float Floating point 32 ±1.17549435082*10-38 ... ±6.80564774407*1038


The compiler automatically performs implicit conversion in the following situations:

  • if a statement requires an expression of particular type, but expression of different type is used;
  • if an operator requires an operand of particular type, but operand of different type is used;
  • if a function requires a formal parameter of particular type, but is assigned an object of different type; and
  • if a function result does not match the declared function return data type.


When operands are of different types, implicit conversion promotes a less complex to a more complex type as follows:

  • bit → byte
  • short, byte/char → integer, word, longint, longword
  • integer, word → longint, longword
  • short, byte/char, integer, word, longint, longword → float


In assignment statements and statements requiring an expression of particular type, the correct value will be stored in destination only if the result of expression doesn’t exceed the destination range. Otherwise, if expression evaluates to a more complex type than expected, the excess data will simply be clipped, i.e. higher bytes will be lost.

dim i as byte ' Variable i occupies one byte of RAM
dim j as word ' Variable j occupies two bytes of RAM
j = $FF0F
i = j ' i becomes $0F, higher byte $FF is lost


Explicit conversion may be executed upon any expression at any point by writing desired type keyword (byte, word, short, integer, longint, float...) before the expression to be converted. The expression must be enclosed in parentheses. Explicit conversion cannot be performed upon the operand to the left of the assignment operator.

a = word(b) ' Explicit conversion of expression b
word(b) = a ' Compiler will report an error

A special case of explicit conversion is a conversion between signed and unsigned data types as it does not affect the binary representation of data.

dim a as byte
b as short
b = -1
a = byte(b) ' a is 255, not -1
' Data doesn’t change its binary representation %11111111
' it is just interpreted differently by the compiler


An operator is a symbol used to denote particular arithmetic, logic or some other operation. Every operation is performed upon one or more operands (variables or constants) in an expression. Besides, every operator features priority execution and associativity. If an expression contains more than one operand, the order of their execution is determined by the level of their priority. There are four priority categories in Basic. Operators belonging to the same category have equal priority. If two or more operators have the same priority level, the operations are performed from left to right. Parenthesis can be used to define the priority of the operation within an expression. Each category is assigned either left-to-right or rightto- left associativity rule. Refer to the table below.

Priority Operators Associativity
High @ not + - from right to left
* / div mod and << >> from left to right
+ - or xor from left to right
Low = <> < > <= >= from left to right


Arithmetic operators are used to perform arithmetic operations. These operations are performed upon numeric operands and always return numerical results. Binary operations are performed upon two operands, whereas unary operations are performed upon one operand. All arithmetic operators associate from left to right.

Operator Operation
+ Addition
- Subtraction
* Multiplication
/ Division - floating point
div Division - round down
mod Reminder


If a zero (0) is used explicitly as the second operand in the division operation (x div 0), the compiler will report an error and will not generate a code. In case of implicit division where the second operand is an object the value of which is 0 (x div y, where y=0), the result will be undefined.


Relational operators are used to compare two variables and determine the validity of their relationship. In mikroBasic, all relational operators return 255 if the expression is true, or zero (0) if it is false. The same applies in expressions such as ‘if the expression is true then...’

Operator Meaning Example Truth condition
> is greater than b > a if b is greater than a
>= is greater than or equal to a >= 5 If a is greater than or equal to 5
< is less than a < b if a Is less than b
<= is less than or equal to a <= b if a Is less than or equal to b
= is equal to a = 6 if a Is equal to 6
<> is not equal to a <> b if a Is not equal to b


Logic bitwise operators are performed upon bits of an operand. They associate from left to right. The only exception is the bitwise complement operator not which associates from right to left. Bitwise operators are listed in the table on the right:

The bitwise operators and, or and xor perform logic operations upon appropriate pairs of bits of operands. The not operator complements each bit of one single operand.

Operand Meaning Example Result
<< Shift left A = B << 2 B = 11110011 A = 11001100
>> Shift right A = B >> 3 B = 11110011 A = 00011110
and Bitwise AND C = A and B A=11100011
C = 11000000
or Bitwise OR C = A or B A=11100011
C = 11101111
not Bitwise NOT A = not B B = 11001100 A = 00110011
xor Bitwise EXOR C = A xor B A = 11100011
B = 11001100
C = 00101111

The bitwise operators and, or and xor perform logic operations upon appropriate pairs of bits of operands. The not operator complements each bit of one single operand.

$1234 and $5678 ' result is $1230 because:
' $1234 : 0001 0010 0011 0100
' $5678 : 0101 0110 0111 1000
' ----------------------------
' and : 0001 0010 0011 0000 ... that is, $1230

$1234 or $5678 ' equals $567C
$1234 xor $5678 ' equals $444C
not $1234 ' equals $EDCB


There are two shift operators in mikroBasic. These are the << operator which moves bits to the left and the >> operator which moves bits to the right. Both operators have two operands each. The left operand is an object to move, whereas the right operand is a number of positions to move the object by. Both operands must be of integral type. The right operand must be a positive value.

By shifting an operand left (<<), the leftmost bits are discarded, whereas ‘new’ bits on the right are assigned zeroes. Shifting unsigned operand to the left by n positions is equivalent to multiplying it with 2n. The same applies to signed operands if all discarded bits are equal to the sign bit.

dim num as word ' declare variable num as word
num = 1 ' asign it decimal value 1 (00000000 00000001 bin.)
num << 5 ' equals 32 (00000000 00100000 bin.)

By shifting operand right (>>), the rightmost bits are discarded, whereas ‘new’ bits on the left are assigned zeroes (in case of unsigned operand) or the sign bit (in case of signed operand). Shifting operand to the right by n positions is equivalent to dividing it by 2n.

dim num as integer ' declare variable num as signed integer
num = 0xFF56 ' asign it hex value FF56 (11111111 01010110 bin.)
num >> 4 ' equals 0xFFF5 (11111111 11110101 bin.)


Conditions are common ingredients of a program. They enable one or a number of statements to be executed depending on the validity of an expression. In other words ‘If the condition is met (...), do (...). Otherwise, do (...)’. A conditional statement can be followed either by a single statement or by a block of statements to execute.


The syntax of a simple form of the if statement is:

if expression then
end if

If the result of expression is true (not 0), operations are performed, then the program proceeds with execution. If the result of expression is false (0), operations are not performed and the program immediately proceeds with execution.

The if operator can also be used in combination with else operators:

if expression then
other operations2
end if

If the result of expression is true (not 0), operations1 are performed, otherwise operations2 are performed. The program proceeds with execution after these operations are performed.


Nested if statement need additional attention. A nested if-statement is a statement used inside the other if-statement. As a rule, they are parsed starting from the most nested ifstatement, whereas each else statement is bound to the nearest available if on its left:



The select case statement is a conditional statement with multiple branching. It consists of a selector expression (condition) and a list of possible values of that expression. The syntax of the select case statement is:

The selector specifier is an expression which should evaluate as integral value.

Specifiers value_1...value_n represent selector’s possible values and can be literals, constants or constant expressions. Specifiers statements_1 ...statements_n can be any statements.

The case else clause is optional.

First, the selector expression is evaluated. It is then compared to all available values. If the match is found, the statements following the match evaluate and the select case statement terminates. If there are multiple matches, statements following the first match will be executed. If none of the values matches the selector, then default_statements in the case else clause (if there is one) are executed.

Here is an example of the select case statement:

select case decimal_digit ' Decimal-digit value is being checked
case 0
mask = %01111110 ' Display "0"
case 1
mask = %00110000 ' Display "1"
case 2
mask = %01101101
case 3
mask = %01111001
case 4
mask = %00110011
case 5
mask = %01011011
case 6
mask = %01011111
case 7
mask = %01110000
case 8
mask = %01111111
case 9
mask = %01111011
end select
Select case statement

This program routine converts decimal digits into appropriate binary combination on the port in order to display them on an LED display.


Some instructions (operations) have to be executed more than once in the program. A set of commands being repeated makes a program loop. How many times it will be executed, i.e. how long the program will stay within a loop, depends on the conditions to leave the loop.


The while loop is implemented when the number of iterations is not specified. It is necessary to check the iteration condition before a loop execution. Simply put, the while loop is executed while all necessary conditions for its execution are met... The syntax of the while loop looks as follows:

while expression

The statements specifier represents a group of statements which are executed repeatedly as long as the value of the expression specifier which represents an expression is true. In other words, the program remains in the loop until expression becomes false. The value of expression is checked before the next iteration is executed. Accordingly, if it is false before entering the loop, no iterations executes, i.e. statements will never be executed. The program will proceed with execution from the end of the while loop (from instructions following the wend instruction).

A special type of the program loop is an endless loop. It is created if the condition to exit loop remains unchanged within the loop.

In this case, the execution is simple as the result in brackets is always true (1 will allways be different from 0), which means that the program remains in the loop.

while 1 ' ‘true’ can be written instead of ‘1’
... ' Expressions will be unceasingly executed (endless loop)


The for loop is implemented when the number of iterations is specified. The syntax of the for loop looks as follows:

for counter = initial_value to final_value [step step_value]
next counter

Here, with each iteration of the loop, the counter variable is incremented by step_value. The step_value parameter is an optional integer value, considered 1 if omitted. Before the first iteration, the counter (counter) is set to its initial value (initial_value) and will be incremented until it reaches or exceeds the final value (final_value). Statements will be executed with each iteration. Iinitial_value and final_value should be expressions compatible with the counter, whereas the statements specifier can be any statement that doesn’t change the counter value. Note that the step_value parameter may be negative, thus enabling a countdown.

for k=1 to 5 ' Increase variable k five times (from 1 to 5) and
operation ' keep on executing "operation" every time
next k

A set of instructions (operation) will be executed five times. After that, it will be determined that the k<5 is false (after 5 iterations k=5) and the program will exit the for loop.


The do loop is implemented when the number of iterations is not specified. The loop is executed repeatedly until the expression evaluates to true. The syntax of the do loop is:

loop until expression

In this case, the statements specifier represents a group of statements which are executed as long as the expression (expression) is true. The loop conditions are checked at the end of the loop, so the loop is executed at least once regardless of whether the condition is true or false. In the following example, the program remains in the do loop until variable a reaches 1E06 (a million iterations).

a = 0 ' Set initial value
a = a+1 ' Operation in progress
loop until a <= 1E06 ' Check condition



Sometimes a program in Basic requires parts of the code to be written in assembly language. In this way some parts of the program can be executed in a precisely defined way for exact period of time. For example, when it is necessary to provide very short pulses (a few microseconds) to appear periodically on a microcontroller pin, the best solution is to write an assembly code for pulse duration control. The asm command is used to introduce one or more assembly instructions to the program written in Basic:

Assembly language instructions
end asm

Assembly instructions may use objects (constants, variables, routines etc.) that must be previously declared in the Basic language. It goes without saying that these objects are declared according to the rules of the Basic language. Refer to the example below:



An array is a finite and arranged list of variables of the same type called elements. This type is called the base type. Each element is assigned a unique index so that different elements may have the same value. An array is declared by specifying the type of its elements (called array type), its name and the number of its elements enclosed within brackets:

dim array_name as component_type [number_of_components]

Elements of an array are identified by their position. Indices go from 0 (the first element of an array) to N-1 (N is the number of elements contained in an array). The compiler must know how many memory locations to allocate when an array is declared and because of that the array size can’t be variable.

Elements of array Contents of element
shelf[0] 7
shelf[1] 23
shelf[2] 34
shelf[3] 0
shelf[4] 0
shelf[5] 12
shelf[6] 9
... ...
... ...
shelf [99] 23

To illustrate it, an array can be thought of as a shorter or longer list of variables of the same type where each of these is assigned an ordinal number always starting from zero. Such an array is called a vector. Table on the right shows an array named shelf which consists of 100 elements.

In this case, the contents of a variable (element) represents a number of products the shelf contains. Elements are accessed by indexing, i.e. by specifying their indices enclosed in square brackets:

dim shelf as byte [100] ' Declare the array "shelf" with 100 elements
shelf [4] = 12 ' 12 items are ‘placed’ on shelf [4]
temp = shelf [1] ' Variable shelf [1] is copied to
' variable temp

In constant arrays, elements can be assigned their contents during array declaration. In the following example, an constant array named CALENDAR is declared and each element is assigned specific number of days:

const CALENDAR as byte [12]= (31,28,31,30,31,30,31,31,30,31,30,31)

The number of assigned values must not exceed the specified array length, but can be less. In this case, the trailing ‘excess’ elements will be assigned zeroes.


The goto statement enables you to make an absolute jump to another point in the program. Be careful when using this statement since its execution causes an unconditional jump ignoring any type of nesting limitations. The destination point is identified by a label, which is used as an argument for the goto statement. A label consists of a valid identifier followed by a colon (:).The syntax of the goto statement is:

goto: label_name

This statement executes a jump to the label_name specifier which represents a label. The goto statement can precede or follow the label. Hence it is not possible to jump into or out of a procedure or function. The goto statement can be used to break out from any level of nested structures. It is not advisable to jump into a loop or other structured statement as it may give unexpected results.


A subroutine is a portion of code within a larger program executed upon demand. It performs a specific task and is relatively independent from the rest of code. The interpreter will jump to the subroutine, execute it, and return to the main program. Keywords gosub and return are used in the Basic language to denote start and end of subroutine.

gosub label_name

Subroutines are considered by many to be hard to maintain, difficult to read and digest, just like the goto statement. Use them just if you don’t have any better solution.


Compiler mikroBasic PRO for PIC, installed on your PC, includes a list of supported PIC microcontrollers with all registers, their accurate addresses and bit names. The compiler allows you to access individual bits of these registers by their names, without specifying their positions (the compiler already ‘knows’ them). There are a number of ways to access and modify one individual bit within a register. Let’s access the GIE bit (Global Interrupt Enable bit) for example. It’s the seventh bit of the INTCON register. One way to access this bit by its name is to write the following:

INTCON.GIE = 0 ' Clear Global Interrupt Enable Bit (GIE)

Instead of a bit name, a variable, constant, function call or an expression enclosed within parentheses may be used to denote the position of bit in a register. In addition, for individual bit access there are predefined global constants B0, B1, … , B7, or 0, 1, … 7, where 7 is considered the most significant bit.

INTCON.B0 = 0 ' Clear bit 0 of the INTCON register
ADCON0.5 = 1 ' Set bit 5 of the ADCON0 register
i = 5
STATUS.(i+1) = 1 ' Set bit 6 of the STATUS register

Finally, a desired bit may be accessed by using its alias name. In this case it’s the GIE_bit:

GIE_bit = 1 ' Set Global Interrupt Enable Bit (GIE)


The mikroBasic PRO for PIC compiler has the sbit data type. This is the shortest data type referring to one single bit. If type sbit is assigned to a variable, the appropriate bit of some register will be changed by changing that variable without specyfing the register name and location. The sbit variable will behave like a pointer. In order to declare the sbit variable, it is sufficient to write:

dim Bit_name as sbit at Register_name.Bit_position
program MyProgram ' Main module
dim Output1 as sbit at PORTB.0 ' Variable Output1 is of sbit type
Output1 = 1 ' Pin PORTB.0 is set (5V)


The mikroBasic PRO for PIC compiler provides the bit data type that may be used for variable declarations.

dim bf as bit

Unlike variables of sbit type, only the bit name is declared here, whereas the compiler stores bit-variable into some of the free registers of RAM. As can be seen, it is not necessary to specify a bit of some specific register. The exact location of the variable of bit type is unknown to the user.

Bit and sbit types are implemented with the following limitations:

  • Cannot be used for argument lists and as function return values
  • Cannot be used as a member of structures
  • Cannot be used as array elements
  • Cannot be initialized
  • Cannot be pointed to
  • Their addresses cannot be red, therefore the unary operator @ cannot be used with variable of this type
dim ptr as ^bit ' invalid
dim arr as array[5] of bit ' invalid


Functions and procedures, collectively referred to as routines, are subprograms (selfcontained statement blocks) which perform a certain task based on a number of input parameters. Functions return a value after execution, while procedures don’t.


A procedure is a named block of code, i.e. a subroutine with some additional features. For example, it can accept parameters. Procedures are declared as follows:

sub procedure procedure_name(parameter_list)
[ local declarations ]
procedure body
end sub
  • The procedure_name specifier represents a procedure name and can be any valid identifier.
  • The parameter_list specifier within parentheses represents a list of formal parameters declared similar to variables. In mikroBasic PRO for PIC, parameters are passed to a procedure by value. To pass parameters by address, it is necessary to add the byref keyword at the beginning of the parameter declaration.
  • Local declarations are optional declarations of variables and constants which refer to the given procedure only.
  • Procedure body is a sequence of statements to be executed upon calling the procedure.

Procedures are called by their name followed by actual parameters placed in the same order as their matching formal parameters. Upon a procedure call, all formal parameters are created as local objects initialized by values of actual arguments.

'Add two numbers
sub procedure add (dim byref sum as word, dim x, y as byte)
sum = x + y ' add numbers x and y and store result into sum variable
end sub ' end of subprocedure

Now, we can call the add procedure to calculate full weight of a cargo for example:

add (gross_weight, net_weight, tare_weight)


Functions must be properly declared in order to be correctly interpreted during the process of compiling.

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

Every declaration contains the following elements:

  • Function name is an identifier by which it will be possible to call a function (function_name in the example).
  • Type of result (returned value) is data type of the returned data (return_type in the example).
  • Declaration of parameters: each parameter consists of a variable, constant, pointer or array preceded by its data type specifier similar to any regular variable declaration (parameter_list in the example). They are used to pass information to the function when it is called.
  • Local declarations are optional declarations of variables and constants which refer only to the given function.
  • Function body is a sequence of statements to be executed upon calling the function.

Here is an example of how to define and use the power function:

'function which calculates xn based on input parameters x and n (n > 0)
sub function power(dim x, n as byte) as longint ' x and n are bytes, result is longint
dim i as byte ' i is a byte
result = 1 ' result = 1 if n = 0
if n > 0 then
i = 1 to n
result = result*x
next i
end if
end sub

Now, we can call the power function to calculate 312 for example:

tmp = power(3, 12) ' Calculate 312


Declarations of all functions and procedures being used in Basic are usually stored in special module files called libraries. Prior to using any of them in the program, it is necessary to specify the appropriate module by means of the include clause at the beginning of the program. It’s just a general rule. But if you write a program in compiler mikroBasic PRO for PIC it is sufficient to check desired library on the list and the appropriate module will be automatically included in the project. This compiler already has a number of such libraries. If the compiler encounters an unknown function or procedure during program execution, first it will look for its declaration in the previously checked libraries.


In addition to function and procedure libraries, the mikroBasic PRO for PIC compiler provides a set of useful built-in functions:

  • Lo
  • Hi
  • Higher
  • Highest
  • Inc
  • Dec
  • Chr
  • Ord
  • SetBit
  • ClearBit
  • TestBit
  • Delay_us
  • Delay_ms
  • Vdelay_Advanded_ms
  • Vdelay_ms
  • Delay_Cyc
  • Clock_KHz
  • Clock_MHz
  • Reset
  • ClrWdt
  • DisableContextSaving
  • SetFuncCall
  • SetOrg
  • GetDateTime
  • GetVersion

The Delay_us and Delay_ms routines are generated in the place of call.

The Vdelay_ms, Delay_Cyc and Get_Fosc_kHz are actual Basic routines. Their sources can be found in the Delays.mbas file located in the uses folder of the compiler.


A preprocessor is an integral part of every compiler. Its function is to recognize and execute preprocessor instructions. What are preprocessor instructions? These are special instructions which do not belong to the Basic language, but are integrated into the compiler. Prior to compiling, the compiler activates the preprocessor which goes through the program in search for these instructions. If any found, the preprocessor will simply replace them by another text which, depending on the type of command, can be a file (command include) or just a short sequence of characters (command define). Then, the process of compiling may start. The preprocessor instructions can be anywhere in the source program and refer only to the part of the program following their appearance up to the end of the program.


Many programs often repeat the same set of commands for several times. In order to speed up the process of writing a program, these commands and declarations are usually grouped in particular modules that can easily be included in the program using the include directive. To be more precise, the include directive imports text from another document, no matter whether it is a set of commands, comments etc., into the program.



Conditional compilation directives are typically used to make source programs easy to modify and compile for different microcontrollers. mikroBasic PRO for PIC supports conditional compilation. All conditional compilation directives must be completed within the module in which they have started.


Conditional directives #if, #elif, #else and #endif are executed similar to the common Basic conditional statements. If an expression you write after #if has a non-zero value, then program lines following the #if directive will be treated as a valid program code and compiled into a hex code. The syntax thereof is:

#if constant_expression_1         'If constant_expression_1 is not zero,
<section_1> 'section_1 will be compiled
[#elif constant_expression_2 'If constant_expression_2 is not zero,
<section_2>] 'section_2 will be compiled
[#elif constant_expression_n 'If constant_expression_n is not zero,
<section_n>] 'section_n will be compiled
[#else 'If none of previous sections are compiled
<final_section>] 'final_section will be compiled
#endif 'End of #if directive
  • Each #if directive in a source file must be matched by a closing #endif directive. Any number of #elif directives can appear between #if and #endif directives, but only one #else directive is allowed. The #else directive, if present, must be the last directive before #endif.
  • Section can be any program code that may be recognized by the compiler or preprocessor. The preprocessor selects a single section by evaluating constant_expression following each #if or #elif directive until it finds a true (non-zero) constant_expression.
  • If all constant-expressions evaluate to false or no #elif directives appear, the preprocessor selects the final_section following the #else clause. If the #else clause is omitted and all instances of constant_expression in the #if block evaluate to false, no section will be selected for further processing.

Finally, the result is that only one code section, even the empty one, will be compiled.


As you know, every object in the program (variable, procedure, subroutine, etc.) is assigned one specific memory address. When declaring a variable in the program, the compiler automatically assigns it a free RAM location. During programming, these addresses are kept hidden from programmers. In other words - addresses are ‘secretly’ used... The possibility to access different objects by their names (identifiers) instead of addresses is one of the main advantages of the high-level programming languages. As a matter of fact it is much easier to deal with words (names) than with numbers. Besides, the compiler takes care of associating objects and their adresses. Addressing objects by specifying their names is called direct addressing.

However, sometimes you have to deal with memory location addresses. Then, pointers are used - variables holding memory address of an object. In this case it is possible to access objects using pointers only. This way of addressing is therefore called indirect addressing.

Prior to using a pointer, it is necessary to declare its data type. Simply, add a caret prefix (^) before the type.

dim pointer_p as ^word ' pointer_p points to data of word type

If it is required to store a variable at some specific RAM memory location, then the absolute directive should be used in the program as follows:

dim variable_a as word absolute 12 ' variable_a will occupy 1 word
' (16 bits) at address 12

Now, if you want to access data at the pointer’s memory location, you need to add a caret after the pointer's name. For example, let’s declare the above mentioned pointer pointer_p which points to a word (in this case, it is previously defined variable_a stored at address 12 in RAM). The pointed variable_a will be assigned value 26:

dim pointer_p as ^word 'Pointer_p points to data of word type
pointer_p = 12 'Pointer_p points to memory adress 12
pointer_p^ = 26 'Variable a at memory address 12 has value 26
'Similar to the absolute directive that is used for variables, the org
'directive specifies the starting address of a routine in ROM. It is
'appended to the routine declaration. For example:

sub procedure proc(dim par as word) org 0x200 ' Procedure will start at
... ' the address 0x200
end sub

In this case, the pointer_p pointer is assigned value 12 (pointer_p =12), which means that the memory address 12 is specified hereby.

Pointers 01

If you want to change the value of a pointed variable, it is sufficient to change the pointer's value and add a caret symbol (^) as a suffix to it. Refer to figure on the right, variable variable_a at address 12 is assigned value 26 by means of the pointer_p pointer.

Pointers can point to data stored in any available memory space and can reside in any available memory space except in program memory space (ROM).


The @ operator returns the address of an object, i.e. creates a pointer upon its operand. The following rules apply here:

  • If X is a variable, @X returns the address of X.
  • If F is a routine (function or procedure), @F creates a pointer to F.
dim temp as word
ptr_b as ^byte
ptr_arr as ^byte[10]
arr as byte[10]
ptr_b = @arr ' @ operator will return ^byte
temp = @arr ' @ operator will return ^byte
ptr_arr = @arr ' @ operator will return ^byte[10]

If variable X is of array type, the @ operator will return pointer to it's first basic element, except when the left side of the statement in which X is used is an array pointer. In this case, the @ operator will return pointer to array, not to it's first basic element.

Program structure in mikroBasic PRO for PIC:

  1. Every program normally starts with a comment which provides information on the purpose of the program, date of program writing, programmer, version, changes made relative to the previous version etc. These comments (header) are not compulsory, but it’s a good habit to write them and have them in the program.
  2. Every program code starts with a program directive followed by the program name.
  3. If the program, apart from the main module, contains other modules as well, their names must be specified using the include directive (one include directive per each module). Accordingly, if the compiler, while compiling the main module, comes to an undeclared object (function, variable etc.), it will first try to find its declaration within declared modules. If no appropriate declaration is found, the compiler will report an error.
  4. The include directive (if there is any) is followed by a code portion intended to declare variables, constants, procedures, subprograms, functions and other objects to be used later in the program. These declarations are used to reserve RAM registers for data storing as well as to instruct the compiler how to execute some function or procedure. For example, a data of byte type occupies only one register, while a data of float type occupies four registers.
  5. The main program starts with the main: directive (always followed by a colon). It is also called a ‘program body’.
  6. Every program is terminated with the end. directive (always followed by a period).


Everything you have read so far about programming in Basic is just a theory. It is useful to know, of course, but don’t forget that this programming language is not much in connection with something concrete and tangible. You will experience many problems with accurate names of registers, their addresses, names of particular control bits and many others when you start writing your first program in Basic. The point is that you need more than theory to make the microcontroller do something useful.

Having in mind a saying ‘Prevention is better than cure’, we have to remind you of all the things you must have settled before you start writing a program for the microcontroller. First of all, you need a program installed on your PC which understands the programming language you are going to use and which provides appropriate working environment for it. There is no such a compiler sutable for only one type of microcontrollers nor for all microcontrollers. It’s about software used for programming similar microcontrollers of one manufacturer. We have previously introduced mikroBasic language which has been especially designed for programming PIC microcontrollers. Now, when you know enough about it, it’s time to present the software you are going to use for developing and editing your projects. This software is called the mikroBasic PRO for PIC compiler. It’s IDE (Integrated Development Environment) includes all the tools you need to develop your projects (editor, compiler debugger etc.)

As its name implies, the mikroBasic PRO for PIC compiler is intended for writing programs for PIC microcontrollers in the Basic language. It contains information about architecture of PIC microcontrollers (registers, their accurate addresses, memory modules, operation of its modules, instruction set, pinout etc.). Moreover, it includes specific tools for PIC microcontroller programming. So, the first thing you have to do when you start up the compiler is to select the chip and operating frequency from the list. This is not the end. This is the beginnig. You can finally start writing your program in Basic.

The process of creating and executing a project can be divided in several parts:

  1. Creation of the project (project name, project settings, file dependancies);
  2. Editing of the program;
  3. Compilation of the program and correction of errors;
  4. Debugging (execute your program step by step to make sure that it performs the operations you expect);
  5. Microcontroller programming (load the .hex file genertaed by the compiler into the microcontroller by using the PICflash programmer).


The installation of mikroBasic PRO for PIC is similar to the installation of any other Windows program and the whole procedure is carried out through Wizard:

Installation of mikroBasic PRO for PIC

You just have to follow the instructions and click on Next, OK, Next, Next... The same old story except for the last option 'Do you want to install PICFLASH v7.11 programmer?'. Does it make you question what to do? As you know, the compiler translates a program written in Basic into a hex code. The next step is to load that code into the microcontroller. That’s why you need the PICFLASH programmer. Install it!

Completing Installation

After completing the PICFLASH installation, you will be asked for the installation of another similar program. It is a software for programming a special family of PIC microcontrollers which operate in low consumption mode (3.3 V). Skip it...

The last step - driver installation!

Driver Installation

A driver is a program which enables the operating system to communicate with a peripheral device. In our case, this device is the hardware programmer of your development system. You definitely need it. Click Yes.

Finding Drivers

A type of driver to be installed depends on the operating system in use. In this case, the PC runs a 32-bit operating system Windows XP. Select the Win 2000, XP, 2003 32-bit folder containing the appropriate driver and start up its installation.

Now you are safe, just keep on clicking Next, OK, Next, Next...

Completing Driver Installation


This is what appears on your screen when you start up mikroBasic PRO for PIC for the very first time:


Unfortunately, a detailed description of all the options available in this IDE would take up too much time, so we are not going into it. We are going to describe only the most important features of the mikroBasic PRO for PIC compiler, instead. Of course, you can always get more information by pressing the Help button [F1]. A detailed explanation on how to create a new project and write a program is given in several practical examples in Chapter 4 of this book.



A program written in the mikroBasic PRO for PIC compiler is not a separate document, but a part of a project that also includes hex code, assembly code, and other files. Some of them are created during the compiler’s operation, while some are imported from other programs. However, the Project Manager window enables you to handle all of the project files. Just right click on any folder and select the option you need for your project.



Libraries contain a large number of ready-to-use functions and provide a lot of facilities when writing programs for PIC MCUs. The compiler must know all dependencies of your mikroBasic source file in order to compile it properly. You should open the Library Manager window and check libraries you want to use in your program. When a library is checked, it is automatically added to the project and linked during the compiling process. Thus, you don’t have to include them manually into your source code files using the #include directive. For example, if your program uses an LCD then there is no need to write new functions because by selecting the Lcd Library you will be able to use ready-to-use LCD functions in your program. If this library is not selected in the Library Manager, every time you try to use any of its functions, the compiler will report an error. A description of each library is available by right clicking on its name and selecting the Help option.



The Code Explorer window enables you to easily locate objects (functions, constants, procedures etc.) within long programs. For example, if you look for a function used in the program, just double click its name in this window, and the cursor will be automatically positioned at the appropriate line in the program.



When compiling a project, the compiler generates files to be loaded into the microcontroller. These files will be different depending on the type of the microcontroller and the purpose of the compilation. Thus, in order to enable the compiler to operate properly, it is necessary to set some project parameters in the Project Settings window:

Device: Selection of the microcontroller to be used enables the compiler to retrieve the associated definition file. The definition file of a microcontroller contain specific information on its SFR registers, their memory addresses and some variables specific to that microcontroller. It is all mandatory for creating a compatible .hex file.

Oscillator: This option is used to specify the operating speed of the microcontroller. Of course this value depends on the oscillator in use. It is retrieved by the compiler for compiling routines which require time information (function Delay_ms( ) for example). Later, this information will also be used by the programmer. The operating speed is set so as to enable the microcontroller’s internal oscillator to operate at selected frequency.

Build/Debugger Type: The whole compiling process is called building and includes parsing, compiling, linking and generation of .hex files. The build type enables you to set up the building mode. Depending on your choice of mode, the generated file to be loaded into the microcontroller will be different.

Build type - release: The program to be loaded into the microcontroller will not contain any complementary information to be debugged later. After completing the compiling process, the compiler has no more influence on the program execution.

Build type - ICD debug: Some information is added to the .hex file in order to allow you to perform hardware debugging. When the compiling process is completed and the microcontroller is programmed, the compiler remains connected to the microcontroller and still can affect its operation. A tool called mikroICD (In Circuit Debugger) enables the program to be executed step by step and provides an access to the current content of all registers of the microcontroller.

For the purpose of debugging, a software simulator can be used in both build type modes. It enables you to simulate your program by reproducing the microcontroller behaviour. The simulator doesn’t use real devices for its operation, so that some operations cannot be reproduced (interrupt, for example). However, it is faster to debug a program by using simulator and it doesn’t require any taget device.

Note that any of these settings can be modified at any time while editing the program. Don’t forget to re-build and re-program your device after modifying any of those settings.



Code Editor is a central part of the compiler window used for writing and editing programs. A large number of options used for setting its functions and layout can be found in the Tools/Options menu [F12]. When you write a program, don’t forget comments. Comments are very important for the program debugging and upgrading. Moreover, even if the compiler doesn’t have formatting restriction, you should always follow the same editing rules (like in the examples provided in this book). As there is no line length limitation, don’t hesitate to use blank spaces in order to make your code more readable.


When you write a program, compile it regularly in order to correct syntax errors as you come along. You can also compile your program every time the redaction of a new function is completed and test its behaviour by using debug mode. In this way, it is much easier to fix compilation errors. Otherwise, you will be compelled to modify the entire program.


To compile your code, you just have to click on the Build option in the Project menu. In fact, the entire project is compiled and, in case the compilation is sucessful, the output files are generated (asm, .hex etc.). A compilation is successful if no error was found. The compilation generates many messages which are displayed in the Messages window. These messages consist of information, warnings and errors. Each error found is associated with its program line and description. As an error in your code can generate many other errors, you should always try to fix the first error on the list and then recompile your program. In other words, it is advisable to fix errors one by one.


In the previous example, the program reports a syntax error in the 80th line. The compilation enables you to correct your program by fixing all mikroBasic errors. When all the errors are fixed, your program is ready to be dumped into the microcontroller. However, your job is not finished yet because you still don’t know whether your program behaves as expected or not.


As we could see before, there are two debug modes: a software debugger which simulates actions of the microcontroller (default mode) and a hardware debugger (mikroICD) which directly reads the content of the microcontroller memory. Whatever mode you choose, the debugging procedure is the same. In case you choose ICD debug make sure you load your program into the microcontroller. Debugging is a very important step as it allows you to test your program after a sucessful compilation, or to fix bugs discovered in a running program.

To start the debugger, click on the Start debugger option from the Run menu. The code editor will automatically be slightly modified and a window called Watch Values will appear. The principle of debugging is based on running a program step by step and following the evolution of the content of registers and variable values. In this way, you will be able to verify the computation and to see if something unexpected has occured. By running the program step by step, you will be able to easily locate where problems occur. As debugging can lead to program modification, you should always re-compile the program after each correction and restart the debugger in order to verify what you have changed.


If you wish to be a programmer and devote yourself to programming microcontrollers, then you have to get used to the fact that programs almost NEVER work on the first try or start using a simulator. The simulator is an integral part of the compiler used to simulate the operation of the microcontroller.


Prior to starting up the simulator, select its operating mode in the Project Settings window (Build type - release), compile the program and click the Run /Start Debugger option.

The compiler will be automatically set to simulation mode. As such, it monitors the state of all register bits and enables you to execute the program step by step while monitoring the operation of the microcontroller on the screen.

A few icons, used only for the operation of this simulator, will appear in the toolbar when the compiler is set to this mode.


These icons have the following meanings:

  • Step Into: Execute the current program line, then halts. If the executed program line calls a subroutine, the debugger steps into the subroutine and halts after executing the first instruction within it.
  • Step Over: Execute the current program line, then halts. If the executed program line calls a subroutine, the debugger will not step into it. The whole subroutine will be executed and the debugger halts at the first instruction following the call. It seems that one program line is skipped even though the whole subroutine is executed. As a result, the state of registers is changed. This command is commonly used when it is necessary to speed up the execution of long program loops.
  • Run To Cursor: Execute all the program lines until the cursor position is reached.
  • Step out: Execute all remaining program lines within the subroutine. The debugger halts immediately after exiting the subroutine.

Breakpoints make the process of debugging programs more efficient by enabling you to stop the program execution at some specific line. This is very useful as you will be able to check only critical parts of the program, not lose your time by testing the whole program line by line. To add or remove a breakpoint you just have to click on the left side of your code editor on the appropriate line or press [F5]. A small window called Breakpoints indicates you where the breakpoints are located. Note that the lines marked by breakpoints are highlighted in red.


The line being currently executed is highlighted in blue. You can read the content of registers and variables you have selected in Watch Values at any time. If you want to jump directly to breakpoints, use the Run/Pause Debugger command.



The software and harware debuggers have the same function to monitor the state of registers during program execution. The difference is that the software debugger simulates the execution of the program on a PC, while the ICD debugger uses the microcontroller. Any change of a pin logic state is reflected on the appropriate register (port). As the Watch Values window enables you to monitor the state of all registers, it is easy to check whether a pin is set or cleared. The latest modifications appears in red in this window. This enables you to easily locate modifications in the list file when debugging. Select View/Windows and click the Watch Values option to activate this window. You can make a list of registers/variables the state of which you want to monitor.



If you want to find out how long it takes for the microcontroller to execute a part of the program, select the Run/View Stopwatch option. A window, as shown in figure on the right, will appear. Do you know how the stopwatch works? Well, it’s as simple as that. The times (time when the program has been started, time of the last step execution etc.) are automatically measured for each action of the debugger (step into, step over, run/pause etc.) and displayed in the Stopwatch window.


Another way to check a program execution is by using mikroICD debugger (in-circuit debugger). The mikroICD is an integral part of the PICflash programmer. It is used for testing and debugging programs. The process of testing and debugging is performed by monitoring the state of all registers within the microcontroller which operates in real time. In order to enable debugging, it is necessary to select options Build Type-ICD Debug and Debugger-mikroICD before the program is loaded into the microcontroller. As soon as the mikroICD debugger starts up, a window, as shown in figure below, appears. The mikroICD debugger communicates with the PIC through its pins used for programming. Therefore, these pins cannot be used as I/O pins while the process of debugging is in progress. During the mikroICD debugger operation, programmer and PC have to be connected using a USB cable.


mikroICD debugger options:

  • Start Debugger [F9]
  • Run/Pause Debugger [F6]
  • Stop Debugger [Ctrl+F2]
  • Step Into [F7]
  • Step Over [F8]
  • Step Out [Ctrl+F8]
  • Toggle Breakpoint [F5]
  • Show/Hide Breakpoints [Shift+F4]
  • Clear Breakpoints [Ctrl+Shift+F4]

Each of these commands is activated via keyboard shortcuts or by clicking appropriate icon within the Watch Values window.

The mikroICD debugger also offers options such as running a program step by step (single stepping), pausing the program execution to examine the state of currently active registers using breakpoints, tracking values of some variables etc. The following example illustrates a step-by-step program execution using the Step Over command.

Running a program step by step

Step 1:

Step 1

In this example the 31st program line is highlighted in blue, which means that it will be executed next. The current state of all registers within the microontroller can be viewed in the mikroICD Watch Values window.

Step 2:

Step 2

After the Step Over command [F8] is executed, the microcontroller will execute the 31st program line. The first next line (32nd) to be executed is highlighted in blue. The state of registers being changed during the execution of this instruction may be viewed now in the Watch Values window.


If you have fixed all errors in your code and you think the program is ready for use, then you should load it into the microcontroller. Use the PICflash programmer for this purpose. PICflash is a tool designed to program all types of PIC microcontrollers. It is composed of two parts:

  • The hardware part buffers a hexadecimal file (the program to be loaded) and programs the microcontroller using specific voltage levels. During the process of programming, a new program is written into the microcontroller’s flash memory. The previous program will be automatically erased from the flash memory.
  • The software part is in charge of sending program (.hex file) to the hardware part of the programmer over a USB cable. It is activated by clicking mE_Programmer from the Tools menu or by pressing [F11]. As a result, you can modify some programming settings and also control the operation of the programmer’s hardware (Load, Write, Verify...).

Note that you can re-program your microcontroller as many times as you wish.


This compiler provides special tools which considerably simplify the process of program writing. All these tools are available from the Tools menu. Here is a brief description for all of them.



The USART terminal is a replacement for the standard Windows Hyper Terminal. It can be used for checking the operation of the microcontroller which uses USART communication. Such microcontrollers are built into the target device and connected to the PC’s RS-232 connector over a serial cable. The USART terminal window contains options for setting serial communication and displaying sent/received data.



By selecting the EEPROM Editor option from the Tools menu, a window, as shown in figure below, will appear. Here you can see how the EEPROM memory of the microcontroller looks like. If you want to change its contents after loading the program into the microcontroller this is the right way to do it. If a new content is a data of specific type (char, int or double), then you should select it, enter the value in the Edit Value field and click Edit. Then click the Save button to save it as a document with the .hex extension. If the Use EEPROM in Project option is active, the data will be automatically loaded into the microcontroller during the programming process.


If you need numerical representation of any ASCII character, just select the ASCII chart option from the Tools menu and the table, as shown in figure below, will appear.


You probably know that every key of your keyboard is associated with one code (ASCII). Numbers have strange equivalents. For this reason, the program instruction for displaying number 7 on an LCD will not display it, but the equivalent of the BEL instruction. If you send the same number as a character, you will get the expected result - number 7. Accordingly, if you want to display a number without previously converting it into appropriate character, then it is necessary to add number 48 to each digit the number to be displayed consists of.


A seven segment editor enables you to easily find out which number is necessary to be set on an output port in order to display a desired symbol. Of course, it goes without saying that port pins must be properly connected to display segments. You just have to place the cursor on any display segment and click it. The number that you should enter into the program will be shown immediately. That’s all.



In addition to the standard characters, the LCD display can also display characters created by the programmer. By selecting the LCD custom character tool you will spare yourself from tedious work of writing functions for sending appropriate code to a display. Just create a symbol by clicking small squares in the LCD custom character window, select position and row and click the GENERATE button. The appropriate code appears in another window. No more clicks are needed. Copy to Clipboard - Paste...



This is another necessary tool in case the microcontroller you are writing program for uses graphic LCD display (GLCD). This tool enables you to display any bitmap easily. In order to take advantage of it, select Tools/Glcd Bitmap Editor and appropriate window appears. Select the type of display to be used and load a bitmap. The bitmap must be monochromatic and in specified resolution (128 x 64 pixels in this case). Further procedure is the same as in the example above. Copy to Clipboard...


Every code generated using tools for controlling LCD and GLCD displays contains functions of the Lcd library. If you use them in the program, don’t forget to check the box next to this library in the Library Manager window so as to enable the compiler to recognize these functions correctly.



One of the most useful features of the mikroBasic PRO for PIC compiler is the Library Manager and surely deserves our attention.

If you need a function or a procedure to perform certain task while writing a program, you just have to find it in one of the libraries included into the compiler and use it. A library is actually a file called header. It contains a group of variables and functions written in mikroBasic. Each library has a specific purpose. For example, if you need a procedure to generate an audio signal on some pin, open the Sound library in the Library Manager window and double click the appropriate procedure Sound_Play. A detailed description of this procedure appears on the screen. Copy it to your program and set appropriate parameters. If this library is checked, its functions will be retrieved during the process of compiling and it will not be necessary to use the include directive.

The mikroBasic PRO for PIC includes miscellaneous and hardware specific libraries.


Miscellaneous libraries contain some of the general-purpose functions:

Library Description
Button Library Function eliminates the influence of contact button flickering
Conversions Library Library routines for numerals to strings and BCD/decimal conversions
C Type Library Library functions for testing and mapping characters
String Library Library which automatizes string related tasks
Time Library Time library routines usage for time calculations in UNIX time format
Trigon Library Library functions for floating point math handling


Hardware specific libraries include functions used to control the operation of hardware modules:

Library Description
ADC Library Used for A/D converter operation
CAN Library Used for operation with CAN module
CANSPI Library Used for operation with external CAN module (MCP2515 or MCP2510)
Compact Flash Library Used for operation with Compact Flash memory cards
EEPROM Library Used for operation with built-in EEPROM memory
Ethernet PIC18FxxJ60 Library Used for operation with built-in Ethernet module
Flash Memory Library Used for operation with built-in Flash memory
Graphic Lcd Library Used for operation with graphic LCD module with 128x64 resolution
I²C Library Used for operation with built-in serial communication module I2C
Keypad Library Used for operation with keyboard (4x4 push buttons)
Lcd Library Used for operation with LCD display (2x16 characters)
Manchester Code Library Used for communication using Manchester code
Multi Media Card library Used for operation with multimedia MMC flash cards
OneWire Library Used for operation with circuits using One Wire serial communication
Port Expander Library Used for operation with port expander MCP23S17
PS/2 Library Used for operation with standard keyboard PS/2
PWM Library Used for operation with built-in PWM module
RS-485 Library Used for operation with modules using RS485 serial communication
Software I²C Library Used for I2C software simulation
Software SPI Library Used for SPI software simulation
Software UART Library Used for UART software simulation
Sound Library Used for audio signal generation
SPI Library Used for operation with built-in SPI module
SPI Ethernet Library Used for SPI communication with ETHERNET module (ENC28J60)
SPI Graphic Lcd Library Used for 4-bit SPI communication with graphic LCD display
SPI Lcd Library Used for 4-bit SPI communication with LCD display (2x16 characters)
SPI Lcd8 Library Used for 8-bit SPI communication with LCD display
SPI T6963C Graphic Lcd Library Used for SPI communication with graphic LCD display
UART Library Used for operation with built-in UART module
USB HID Library Used for operation with built-in USB module

previous chapter | table of contents | next chapter