Professional Documents
Culture Documents
1 INTRODUCTION
Novices in electronics usually think that the microcontroller is the same as the
microprocessor. That's not true. They differ from each other in many ways. The first
and most important difference in favour of the microcontroller is its functionality. In
order for the microprocessor to be used, other components, first of all memory, must
be added to it. Even though it is considered a powerful computing machine, it is not
capable of establishing direct communication with the peripherals. Instead, specialized
circuits must be used for this purpose. This is how it was in the beginning and remains
the same today.
On the other hand, the microcontroller is designed to be all of that in one. No other
specialized peripheral components are needed for its operation as all necessary
circuits, which otherwise belong to peripherals, have been already built into it. It saves
both time and space required when designing a device.
Around ten years ago, the process of designing an electronic device controlling an
elevator in a multistory building was extremely difficult, even for a team of experts.
Have you ever thought of what requirements an ordinary elevator has to meet? How to
deal with situation when two or more people call the same elevator at the same time?
Which call has the priority? How to handle the security questions? Loss of electricity?
Operation failure? Misuse? After solving these basic questions, a tough process of
designing an appropriate electronics using a large number of special-purpose chips
comes next. Depending on the device complexity, such process can take weeks, even
months. Then it's time to make a printed circuit board and assemble device. A huge
device! It is another long-lasting and trying work. Finally, when your device is finished
and tested many times, the crucial moment comes. The moment when you take a deep
breath and switch the power supply on. The party is over at this point as electronic
devices almost never start to operate immediately. Get ready for many sleepless
nights, corrections, improvements... and don't forget, we are still talking about running
an ordinary elevator.
When your device finally works perfectly and everybody is satisfied and you get paid
for the work you have done, other constructing companies will become interested in
your work. Of course, if you are lucky, another day will bring you a locking offer from a
new investor. A new building has four stories more. You know what it is all about? You
think you can control destiny? You are going to make a universal device which can be
used in buildings of 4 to 40 stories, a masterpiece of electronics? Even if you manage
to make such an electronic jewel, your investor will wait in front of your door asking for
a camera in the elevator. Or for relaxing music in case of elevator failure. Or for a twodoor elevator. Anyway, Murphy's law is inexorable and you will certainly not be able to
make advantage of all the effort you have made. Unfortunately, everything said so far
is true. This is what 'handling electronics' really means. No, no, wait, let us correct
ourselves, this is how it was until the first microcontrollers were designed - small,
powerful and cheap devices. Since the moment their programming stopped being a
science, everything went in another direction...
Electronics capable of controlling a small submarine, a crane or an elevator are now
built into one single chip. Microcontrollers offer a wide range of applications, but only a
few of them are normally used. It's up to you to decide what you want from the
microcontroller and dump a program accordingly containing appropriate instructions
into it. Prior to turning the device on, its operation should be tested by simulation. If
everything works fine, build the microcontroller into your device. If you ever need to
change, improve or upgrade the program, just do it. Until when? Until you feel
satisfied. That's all.
Did you know that all people can be classified into one out of 10 groups- those who are
familiar with binary number system and those who are not familiar with it. You don't
understand? Then you still belong to the latter group. If you want to change your status
read the following text which briefly describes some of the basic concepts used further
in this book (just to be sure we are on the same page).
It is clearly the same number represented in two different numeric systems. The only
difference between these two formats is the number of digits they consist of. One digit
(2) is used for writing number 2 in decimal system, whereas two digits (1 and 0) are
used for its writing in binary system. Do you now agree that there are 10 groups of
people? Welcome to the world of binary arithmetic! Do you have any idea where it is
used?
Except in strictly controlled laboratory conditions, even the most complex electronic
circuits cannot accurately determine the difference between two sizes (two voltage
values, for example) if they are too small (lower than several volts). The reason for it
lies in the noise and something known as a real working environment (unpredictable
changes of power supply voltage, temperature change, tolerance to values of built-in
components etc.). Imagine a computer which operates upon decimal numbers by
interpreting them as follows: 0=0V, 1=5V, 2=10V, 3=15V, 4=20V...9=45V.
Did anybody say batteries?
A far simpler solution is the binary logic where 0 indicates that there is no voltage and
1 indicates that there is a voltage. It is easier to write 0 or 1 instead of full sentences
there is no voltage or there is a voltage, respectively. It is about a logic zero (0) and a
logic one (1) which electronics perfectly copes with, and easily performs all those
endlessly complex mathematical operations. Obviously, the electronics we are talking
about applied mathematics in which all the numbers are represented by two digits only
and where it is only important to know whether there is a voltage or not. Of course, we
are talking about digital electronics.
The largest number that can be represented by 4 binary digits is the number 1111. It
corresponds to the number 15 in a decimal system, whereas it is represented by letter
F in hexadecimal system. It is the largest 1-digit number in the hexadecimal system.
Do you see how skillfully it is used? The largest number written with eight binary digits
is at the same time the largest 2-digit hexadecimal number. Remember that computers
use 8-digit binary numbers. Coincidence?
BCD CODE
A BCD code is a binary code for decimal numbers only (Binary-Coded Decimal). It
consists of 4-digit binary numbers representing the first ten digits (0, 1, 2, 3 ... 8, 9).
Even though four bits can give 16 possible combinations in total, the BCD code makes
advantage of the first ten only.
In order for decimal numbers from 0 to 3 to be represented, you need only two binary
digits. For larger numbers, extra binary digits must be used. Thus, in order for the
decimal numbers from 0 to 7 to be represented, three binary digits are required, for
numbers from 0 to 15, four digits etc. Simply put, the largest binary number consisting
of n digits is obtained when the base 2 is raised by n and the respective result is
subtracted by 1. For example, if n=4:
24 - 1 = 16 - 1 = 15
Accordingly, 4 binary digits enable you to represent decimal numbers from 0 to 15,
which amounts to 16 different values in total.
A comparative table on the left shows the values of numbers 0-255 represented in
three different number systems. This is probably the easiest way to understand the
common logic applied to all numeric systems.
MARKING NUMBERS
The hexadecimal numeric system is, along with binary and decimal numeric systems,
considered the most important for us. It is easy to convert any hexadecimal number to
binary. It is also easy to remember it. However, such conversions may confuse us. For
example, what does the sentence It is necessary to count up 110 products on the
assembly line actually mean? Depending on whether it is about binary, decimal or
hexadecimal system, the result could be 6, 110 or 272 products, respectively. To avoid
such and similar situations, different prefixes and suffixes are directly added to the
numbers. Prefixes $ and 0x mark hexadecimal numbers. For example, hexadecimal
number 10AF looks either as $10AF or 0x10AF. Similarly, binary numbers usually get
the prefix %. If a number has neither suffix nor prefix it is considered decimal.
Unfortunately, this way of marking numbers is not standardized, yet depends on
specific application.
BIT
In theory, a bit is the basic unit of information... Lets forget this for a moment and take
a look at what it is in practice. The answer is- nothing special- a bit is just a binary digit.
Similar to the decimal numeric system where the same digits of a number do not have
the same value (for example, digits in decimal number 444), the significance of bits
depends on their positions in the binary number. Unlike the decimal numeric system,
binary digits are not referred to as units, tens etc, but zero bit (rightmost bit), first bit
(second from the right) etc. Since the binary system uses only two different digits (0
and 1), the value of one bit can be either 0 or 1.
Dont be confused if you come across a bit having value 4, 16 or 64. It means that its
value is represented in the decimal system. We are simply so much accustomed to the
usage of decimal numbers that such expressions are very common. It would be correct
to say for example, the value of the sixth bit of any binary number is equivalent to
decimal number 64. But we are human and old habits die hard... Besides, how would
it sound number one-one-zero-one-zero...?
BYTE
A byte consists of eight bits grouped together. If a bit is a digit, then bytes represent
numbers. All mathematical operations can be performed upon them, like upon common
decimal numbers. Similar to digits of any number, byte digits do not have the same
significance either. The largest value has the leftmost bit called the most significant bit
(MSB). The rightmost bit has the least value and is therefore called the least significant
bit (LSB). Since eight zeros and ones of one byte can be combined in 256 different
ways, the largest decimal number which can be represented by one byte is 255 (one
combination represents a zero).
A nibble is referred to as half a byte. Depending on which half of the register we are
talking about (left or right), there are high and low nibbles, respectively.
Have you ever wondered what electronics within digital integrated circuits,
microcontrollers or processors look like? What do circuits performing complicated
mathematical operations and making decisions look like? Do you know that their
seemingly complicated schematics comprise only a few different components called
logic circuits or logic gates?
what today is known as AND, OR and NOT logic circuits. The principle of their
operation is known as Boolean algebra.
LOGIC CIRCUITS
Some of the program instructions give the same results as logic gates. The principle of
their operation will be discussed below.
AND Gate
The logic gate AND has two or more inputs and one output. Let us presume that the gate used in this example has only two inputs. A logic
one (1) will appear on its output only if both inputs (A AND B) are driven high (1). Table on the right shows mutual dependence between the
AND gates inputs and output.
The principle of operation is the same even when the gate has more than two inputs: a logic one (1) will appear on its output only when all
inputs are driven high (1). Any other combination of input voltages will result in a logic zero (0) on its output. When used in the program, the
logic AND is performed by a program instruction to be discussed later. Just remember that logic AND in the program refers to the
corresponding bits of two registers.
OR GATE
Similarly, OR gates also have two or more inputs and one output. If the gate has only two inputs the following applies. A logic one (1) will
appear on its output if either input (A OR B) is driven high (1). If the OR gate has more than two inputs then the following applies. A logic one
(1) appears on its output if at least one input is driven high (1). If all inputs are at logic zero (0), the output will be at logic zero (0) as well.
In the program, the peration is performed in the same manner as the logic AND operation.
NOT GATE
The logic gate NOT has only one input and only one output. It operates in an extremely
simple way. When a logic zero (0) appears on its input, a logic one (1) appears on its
output and vice versa. It means that this gate inverts the signal and is therefore often
called inverter.
The logic NOT operation in the program is performed upon one byte. The result is a
byte with inverted bits. If byte bits are considered a number, the inverted value is
actually a complement thereof. The complement of a number is a value which added to
that number makes it reach the largest 8-digit binary number. In other words, the sum
of an 8-digit number and its complement is always 255.
EXCLUSIVE OR GATE
The EXCLUSIVE OR (XOR) gate is a bit complicated compared to other gates. It is a sort of combination of all of them. A logic one (1)
appears on its output only when its inputs have different logic states.
In the program, the appropriate instruction is commonly used to compare two bytes. Subtraction has the same purpose (if the result is 0,
bytes are equal), but the advantage of the EXCLUSIVE OR logic operation is that it never gives negative results.
REGISTER
In short, a register or a memory cell is an electronic circuit which can memorize the
state of one byte.
SFR REGISTERS
In addition to registers which do not have any special and predefined function, every
microcontroller also has a number of special-function registers (SFRs) the function of
which is predefined by the manufacturer. Their bits are connected (literally) to the
integrated circuits within the microcontroller such as timers, A/D converter, oscillators
etc. It means that they are directly in command of the operation of these circuits, i.e.
the microcontroller. Imagine eight switches controlling the operation of a small circuit
within the microcontroller - Special Function Registers do exactly that.
In other words, the state of register bits is changed from within the program, registers run small integrated circuits within the microcontroller,
these circuits are via microcontroller pins connected to peripherals which are used for... Well, its up to you to decide for what.
One of the important features of input/output (I/O) pins is a maximum current they can
handle. For most microcontrollers, current supplied from one pin is sufficient to activate
a LED or some other low-consumption device (10-20 mA).
Another important pin feature is a pull-up resistor it may be provided with. The pull-up
resistor connects the appropriate pin to the positive power supply voltage. It can also
be used when the pin is configured as an input connected to a switch or a push button.
Later versions of microcontrollers have pull-up resistors configurable by software.
Each I/O port is usually under control of one SFR, which means that each bit of that
register determines the state of the corresponding microcontroller pin. For example, by
writing a logic one (1) to some of the register bits, the appropriate microcontroller pin is
automatically configured as an input. The voltage supplied to that pin is visible on its
port as 0 or 1. Otherwise, by writing a logic zero to the SFR, the appropriate port pin is
configured as an output. Voltage provided on such an output pin (0V or 5V) reflects the
state of the appropriate register bit (logic 0 or 1, respectively).
MEMORY UNIT
Memory module is a part of the microcontroller used for data storage. The easiest way
to explain it is by comparing it with a filing cabinet with many drawers. Suppose, the
drawers are clearly marked so that their contents can be easily available by reading
labels on the front of the drawers. In the same way, each memory address
corresponds to one memory location. The contents of any location can be accessed
and read by its address. Memory can either be written to or read from.
One time programmable ROM enables you to download a program into it, but, as its
name states, one time only. If an error is detected after the process of loading a
program, the only thing you can do is to load the program to another chip.
Both the manufacturing process and characteristics of UV EPROM memory are fully identical to OTP ROM. However, the package of the
microcontroller with this memory has a recognizable window on its top side. It enables data to be erased under strong ultraviolet light. After
a few minutes of such sunbathing it is possible to load a new program into it. The installation of this window is complicated, which normally
affects the price. In our opinion, unfortunately negative...
Flash Memory
Flash memory, known as the successor to the UV EPROM, was made in the 80s in the
laboratories of INTEL. Since such memory can be rewritten practically an unlimited
number of times, microcontrollers with Flash ROM are ideal for learning,
experimentation and small-scale production. Due to its great popularity, most
microcontrollers are today manufactured in flash technology. So, if you are going to
buy a microcontroller, the type to look for is definitely Flash!
INTERRUPT
Most programs use interrupts in their regular execution. The purpose of the
microcontroller is mainly to respond to changes in its surrounding. In other words,
when an action takes place, the microcontroller does something... For example, when
you push a button on a television remote control, the microcontroller will register it and
respond by changing a channel, turn the volume up or down etc. As such, the
microcontroller would spend most of its time endlessly checking a few buttons for
hours or days, which is not practical at all.
This is why the microcontroller has learnt a trick during its evolution. Instead of
constant checking each pin or bit, the microcontroller delegates the wait issue to a
specialist which will respond only when something attention worthy happens.
A signal which informs the central processor unit about such action is called an
INTERRUPT.
BUS
A bus consists of 8, 16 or more wires. There are two types of buses: the address bus
and the data bus. The address bus consists of as many lines as necessary for memory
addressing. It is used to tranfer an address from the CPU to the memory. The data bus
is as wide as data, in this case it is 8 bits or wires wide. It is used to connect all the
circuits within the microcontroller.
SERIAL COMMUNICATION
A parallel connection between the microcontroller and peripherals established via
input/output ports is an ideal solution when the distance between them is up to several
meters. Otherwise, when it is necessary to establish communication on longer
distances the parallel connection is out of the question. Serial communication is used
instead.
Today, most microcontrollers have several different modules for serial communication
built into them as a standard equipment. Which of these modules will be used depends
on many factors of which the most important are:
One of the most important things about the serial communication is the Protocol which
should be strictly observed. It is a set of rules which enables devices to correctly
interpret data they exchange. Fortunately, the microcontroller itself takes care of this,
so that the work of the programmer/user boils down to simple writing (data to be sent)
and reading (received data).
DATA RATE
The term data rate is used to denote the number of bits transferred per second [bps].
Note that it refers to bits, not bytes. According to the protocol, each byte is transferred
along with several control bits. It means that one byte in serial data stream may consist
of 11 bits. For example, if the data rate is 300 bps then maximum 37 and minimum 27
bytes may be transferred per second.
The most commonly used serial communication modules are:
OSCILLATOR
Even pulses generated by the oscillator enable a harmonic and synchronous operation of all circuits within the microcontroller. The oscillator
is usually configured so as to use a quartz crystal or ceramic resonator for frequency stabilization, but it can also operate as a stand-alone
circuit (like RC oscillator). It is important to say that instructions are not executed at the rate imposed by the oscillator itself, but several
times slower. It happens because each instruction is executed in several steps. In some microcontrollers, the same number of cycles is
required to execute all instructions, while in others, the number of cycles is different for different instructions. Accordingly, if the
microcontroller uses quartz crystal with a frequency of 20 Mhz, the execution time of an instruction is not 50nS, but 200, 400 or 800 nS,
depending on the microcontroller type.
TIMERS/COUNTERS
The microcontroller oscillator uses quartz crystal for its operation. Even though it is not
the best solution, there are still many reasons to use it. The frequency of such
oscillator is precisely defined and very stable, so that pulses it generates are always
the same width, which makes them ideal for time measurement. Such oscillators are
also used in quartz watches. If it is necessary to measure time between two events, it
is sufficient to count up pulses generated by this oscillator. This is exactly what the
timer does.
Most programs use these miniature electronic stopwatches. Their heart make 8- or
16- bit SFRs, the contents of which is automatically incremented by each coming
pulse. Once a register is fully loaded, an interrupt may be generated.
If the timer uses an internal quartz oscillator for its operation, then it can be used to
measure time between two events (if the value stored in the timer register is T1 at the
moment the measurement starts, and T2 at the moment it terminates, then the time
elapsed is equal to the result of subtraction T2-T1). If registers use pulses supplied
from an external source then such timer is turned into a counter.
This is just a simple explanation of the operation of timer/counter. As you already know,
it is more complicated in practice.
process (except for the interrupt routine) is automatically performed behind the scenes,
which enables the main circuits of the microcontroller to operate normally.
Figure above illustrates the use of an interrupt in timer operation. Delays of arbitrary
duration, having almost no influence on the main program execution, can be easily
obtained by assigning a prescaler to the timer.
COUNTERS
If the timer is supplied with pulses from the microcontroller input pin, then it turns into a
counter. It is clear that the same electronic circuit is able to operate in two different
modes. The only difference is that in this case pulses to be counted come via the
microcontroller input pin and their duration (width) is usually undefined. This is why
they cannot be used for time measurement, but can be used for other purposes such
as counting products on an assembly line, number of axis rotation, passengers etc.
(depending on sensor in use).
WATCHDOG TIMER
A watchdog timer is a timer connected to a stand-alone RC oscillator within the
microcontroller.
If the watchdog timer is enabled, every time it counts up to the maximum value, the
microcontroller reset occurs and the program execution starts from the first instruction.
The point is to prevent this from happening by using a specific command.
Anyway, the whole idea is based on the fact that every program is executed in several
longer or shorter loops. If instructions for the watchdog timer reset are set at the
appropriate program locations, in addition to commands being regularly executed, then
the operation of the watchdog timer will not affect the program execution. If for any
reason, usually due to manufacturing noise, the program counter gets stuck at some
memory location from which there is no return, the watchdog timer will not be cleared,
so the registers value being constantly incremented will reach the maximum et
voila! Reset occurs and the program will be executed from the beginning.
A/D CONVERTER
External signals are usually fundamentally different from those the microcontroller recognizes (0V and 5V only) and therefore have to be
converted into recognizable values. An analog to digital converter is an electronic circuit which converts continuous signals to discrete digital
numbers. In other words, this circuit converts an analogue value into a binary number and forwards it to the CPU for further processing. This
module is thus used for input pin voltage (analogue value) measurement.
The result of measurement is a number (digital value) used and processed later in the
program.
INTERNAL ARCHITECTURE
All upgraded microcontrollers implement one of the two basic design models
called Harvard and von-Neumann architecture.
They represent two different ways of exchanging data between the CPU and memory.
VON-NEUMANN ARCHITECTURE
Microcontrollers using the von-Neumann architecture have only one memory block and one 8-bit data bus. As all data is exchanged through
these 8 lines, the bus is overloaded and communication is slow and inefficient. The CPU can either read an instruction or read/write data
from/to the memory. Both processes cannot be performed at the same time since instructions and data use the same bus. For example, if a
program line reads that a RAM memory register called SUM should be incremented by one (instruction: incf SUM), the microcontroller will
do the following:
1. Read the part of the program instruction specifying WHAT should be done
(in this case the incf instruction for increment is to be performed).
2. Read the other part of the same instruction specifying upon WHICH data i
should be performed (in this case it is the SUM register).
HARVARD ARCHITECTURE
Microcontrollers which implement the Harvard architecture have two different data buses. One is 8 bits wide and connects the CPU to RAM.
The other consists of 12, 14 or 16 lines and connects the CPU to ROM. Accordingly, the CPU can read an instruction and access data
memory at the same time. Since all RAM memory registers are 8 bits wide, all data being exchanged is of the same width. During the writing
process, only 8-bit data is included. In other words, all you can change from within the program and all you can deal with is 8 bits wide. All
the programs written for these microcontrollers will be stored in the microcontroller internal ROM after being compiled to machine code.
However, ROM memory locations are not 8, but 12, 14 or 16 bits wide. The rest of bits 4, 6 or 8, respectively, represents the instruction
alone specifying for the CPU what to do with the 8-bit data.
All data in the program is one byte (8 bits) wide. As the data bus used for
program reading has 12, 14 or 16 lines, both instruction and data can be
read simultaneously using these spare bits. For this reason, all
instructions are single-cycle instructions, except the jump instruction
which is two-cycle.
Owing to the fact that the program (ROM) and temporary data (RAM) use
separate buses, the CPU can execute two instructions at the same time.
In other words, while RAM read or write is in progress (the end of one
instruction), the next program instruction is read via the other bus.
With microcontrollers with the von-Neumann architecture, one never
knows how much memory is to be occupied by the program. Basically,
most program instructions occupy two memory locations (one contains
information on WHAT should be done, while the other contains
information upon WHICH data it should be done). However, it is not a
hard and fast rule, but the most common case. In the Harvard
architecture the program bus is wider than one byte, which allows each
program word to consist of instruction and data, i.e. one memory location
- one program instruction.
INSTRUCTION SET
All instructions recognizable by the microcontroller are colectivelly called the Instruction Set. When you write a program in assembly
language, you actually specify instructions in such order as they should be executed. The main restriction here is the number of available
instructions. The manufacturers usually employ one of the two opposite solutions and design microcontrollers which implement the smallest
or the largest possible number of instructions. In other words - they choose between RISC and CISC instruction sets, respectively.
Before you start designing a microcontroller-based device, think of the following: how
many inputs/outputs does your project require? Should it perform some other
operations than to simply turn relays on/off? Does it need some specialized modules
such as serial communication, A/D converter etc.? When you create a clear picture of
what you need, the selection range is considerably reduced and its time to think of the
price. Are you going to make several such devices? Several hundred? A million?
Anyway, you get the point.
If you think of all these things for the very first time then everything seems a bit
complicated. Make it simple and go step by step. First of all, select the manufacturer,
i.e. the microcontroller family you can easily get. Study one particular model. Learn as
much as you need, dont go into details. Solve a specific problem and something
incredible will happen- you will be able to handle any model belonging to that
microcontroller family.
Remember learning to ride a bicycle. After several bruises you got when you started,
you were able to keep the balance and then easily ride any other bicycle. And of
course, you will never forget programming just as you will never forget riding bicycles!
ROM
[Kbytes]
RAM
[bytes]
Pins
Clock
Freq.
[MHz]
A/D
Inputs
Resolution
of A/D
Converter
Comparators
8/16
bit
Timers
Serial
Comm.
PWM
Outputs
Others
0.375 -
16 - 24
6-8
4-8
0-2
0-1
1x8
0.75
PIC12FXXX
0.75 - 1.5
25 - 38
4-8
0-3
0-1
1x8
EEPROM
PIC16FXXX
0.75 - 3
25 - 134
14 44
20
0-3
0-2
1x8
EEPROM
PIC16HVXXX
1.5
25
18 20
20
1x8
Vdd =
15V
1.75 - 3.5
64 - 128
20
0-4
10
1-2x
81x
16
0-1
EEPROM
PIC12HVXXX
1.75
64
20
0-4
10
1-2x
81x
16
0-1
PIC16FXXX
1.75 - 14
64 - 368
14 64
20
0 - 13
8 or 10
0-2
1-2x
81x
16
USART
I2C SPI
0-3
PIC16HVXXX
1.75 - 3.5
64 - 128
14 20
20
0 - 12
10
2x81
x 16
USART
I2C SPI
0-3
0-2x
82-3
x 16
USB2.0
CAN2.0
USART
I2C SPI
0-5
USB2.0
USART
Ethernet
I2C SPI
2-5
USART
I2C SPI
4 - 128
256 3936
18 80
32 48
PIC18FXXJXX
8 - 128
1024 3936
28 100
40 48
10 - 16
10
0-2x
82-3
x 16
PIC18FXXKXX
8 - 64
768 3936
28 44
64
10 - 13
10
1x83
x 16
PIC18FXXX
4 - 16
10 or 12
All PIC microcontrollers use Harvard architecture, which means that their program
memory is connected to the CPU over more than 8 lines. Depending on the bus width,
there are 12-, 14- and 16-bit microcontrollers. Table above shows the main features of
these three categories.
As can be seen in the table on the previous page, if we disregard 16-bit monstersPIC 24FXXX and PIC 24HXXX for a moment- all PIC microcontrollers have 8-bit
Harvard architecture and belong to one out of three large groups. Accordingly,
depending on the size of the program word there are the first, second and third
microcontroller category, i.e. 12-, 14- or 16-bit microcontrollers. Having similar 8-bit
core, all of them use the same instruction set and the basic hardware skeleton
connected to more or less peripheral units.
PIC microcontrollers with 14-bit program words are most likely the best choice for
beginners. Here is why...
INSTRUCTION SET
The instruction set for the 16F8XX includes 35 instructions in total. The reason for such
a small number of instructions lies in the RISC architecture. Instructions are well
optimized from the operating speed aspect, simplicity in architecture and code
compactness. The drawback to the RISC architecture is that the user is expected to
cope with these instructions. Of course, this is relevant only if you use assembly
DESCRIPTION
O P E R ATI O N
FLAG
CLK
Move constant to W
k -> w
MOVWF f
Move W to f
W -> f
MOVF f,d
Move f to d
f -> d
CLRW
Clear W
0 -> W
CLRF f
Clear f
0 -> f
SWAPF f,d
Swap nibbles in f
1, 2
1, 2
Arithmetic-logic Instructions
ADDLW k
W+k -> W
C, DC, Z
ADDWF f,d
Add W and f
W+f -> d
C, DC ,Z
SUBLW k
k-W -> W
C, DC, Z
SUBWF f,d
Subtract W from f
f-W -> d
C, DC, Z
ANDLW k
W AND k -> W
ANDWF f,d
W AND f -> d
IORLW k
W OR k -> W
IORWF f,d
W OR f -> d
1, 2
XORWF f,d
W XOR k -> W
1, 2
XORLW k
W XOR f -> d
INCF f,d
Increment f by 1
f+1 -> f
1, 2
DECF f,d
Decrement f by 1
f-1 -> f
1, 2
RLF f,d
1, 2
RRF f,d
1, 2
COMF f,d
Complement f
1, 2
f -> d
1, 2
1, 2
1, 2
Bit-oriented Instructions
BCF f,b
Clear bit b in f
0 -> f(b)
1, 2
BSF f,b
Clear bit b in f
1 -> f(b)
1, 2
Skip if f(b) = 0
1 (2)
BTFSS f,b
Skip if f(b) = 1
1 (2)
DECFSZ f,d
1 (2)
1, 2, 3
INCFSZ f,d
1 (2)
1, 2, 3
GOTO k
Go to address
k -> PC
CALL k
Call subroutine
RETURN
TOS -> PC
RETLW k
RETFIE
Other instructions
NOP
No operation
CLRWDT
TO, PD
SLEEP
TO, PD
*1 When an I/O register is modified, the value used will be that value present on the
pins themselves.
*2 If the instruction is executed upon the TMR register and if d=1, the prescaler will be
cleared.
*3 If the PC is modified or test result is a logic one (1), the instruction requires two
cycles. The second cycle is executed as an NOP.
The architecture of 8-bit PIC microcontrollers. Which of these modules are to be built
into the microcontroller depends on the type there
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 microcontrollers 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.
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 doesnt matter
anyway. In case it does, the problem is solved by adding a sequence written in
assembly language to the program.
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:
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.
Identifiers
Comments
Operators
Expressions
Instructions
Constants
Variables
Symbols
Directives
Labels
Procedures and functions
Modules
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...
PROGRAM STRUCTURE
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, dont you? In this case, you need the mikroBasic PRO for
PICcompiler.
Unlike most programs you have already got used to dealing with, the process of writing
programs in the compiler doesnt 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.
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 (microBasicProject 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:
IDENTIFIERS
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.
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
COMMENTS
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
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.
CONSTANTS
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.
F O R M AT
PREFIX
Decimal
EXAMPLE
const MAX = 100
Hexadecimal
0x or $
Binary
Floating point
Constants are declared in the declaration part of the program or routine. The syntax of
constants is:
VARIABLES
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:
SYMBOLS
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.
D ATA T Y P E
DESCRIPTION
R A N G E O F V AL U E S
bit
One bit
0 or 1
sbit
One bit
0 or 1
byte, char
Character
0 ... 255
short
word
Unsigned integer
16
0 ... 65535
integer
Signed integer
16
longword
32-bit word
32
0 ... 4294967295
longint
32
float
Floating point
32
PROMOTION
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
DATA CLIPPING
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 doesnt
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
dim
...
j =
i =
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.
dim a as byte
dim b as short
'...
b = -1
a = byte(b) ' a is 255, not -1
' Data doesnt change its binary representation %11111111
' it is just interpreted differently by the compiler
OPERATORS
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
O P E R ATO R S
A S S O C I ATI V I T Y
High
@ not + -
+ - or xor
Low
ARITHMETIC OPERATORS
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.
O P E R ATO R
O P E R ATI O N
Addition
Subtraction
Multiplication
div
mod
Reminder
DIVISION BY ZERO
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
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...
O P E R ATO R
MEANING
EXAMPLE
TRUTH CONDITION
>
is greater than
b>a
if b is greater than a
>=
a >= 5
<
is less than
a<b
if a Is less than b
<=
a <= 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
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
B=11001100
C = 11000000
or
Bitwise OR
C = A or B
A=11100011
B=11001100
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.
CONDITIONAL STATEMENTS
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.
CONDITIONAL STATEMENT IF
The syntax of a simple form of the if statement is:
if expression then
operations
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
operations1
else
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 STATEMENTS
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:
This program routine converts decimal digits into appropriate binary combination on
the port in order to display them on an LED display.
PROGRAM LOOPS
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.
WHILE 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
statements
wend
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.
FOR LOOP
The for loop is implemented when the number of iterations is specified. The syntax of
the for loop looks as follows:
DO 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:
do
statements
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).
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:
asm
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:
ARRAYS
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:
CONTENTS OF ELEMENT
shelf[0]
shelf[1]
23
shelf[2]
34
shelf[3]
shelf[4]
shelf[5]
12
shelf[6]
...
...
...
...
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:
GOTO STATEMENT
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.
GOSUB STATEMENT
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
...
...
...
label_name:
...
return
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 dont have any better solution.
SBIT TYPE
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:
BIT TYPE
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:
PROCEDURES
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:
FUNCTIONS
Functions must be properly declared in order to be correctly interpreted during the
process of compiling.
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.
PREPROCESSOR
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.
CONDITIONAL COMPILATION
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.
#if constant_expression_1
is not zero,
<section_1>
compiled
[#elif constant_expression_2
is not zero,
<section_2>]
compiled
...
[#elif constant_expression_n
is not zero,
<section_n>]
compiled
[#else
sections are compiled
<final_section>]
compiled
#endif
'If constant_expression_1
'section_1 will be
'If constant_expression_2
'section_2 will be
'If constant_expression_n
'section_n will be
'If none of previous
'final_section will be
'End of #if directive
POINTERS
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.
...
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.
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).
@ OPERATOR
The @ operator returns the address of an object, i.e. creates a pointer upon its
operand. The following rules apply here:
Everything you have read so far about programming in Basic is just a theory. It is
useful to know, of course, but dont 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. Its 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, its 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. Its 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:
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. Thats why you need the PICFLASH programmer. Install it!
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!
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 32bit folder containing the appropriate driver and start up its installation.
Now you are safe, just keep on clicking Next, OK, Next, Next...
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.
PROJECT MANAGER
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 compilers 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.
LIBRARY MANAGER
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 dont 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 readyto-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.
CODE EXPLORER
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.
PROJECT SETTINGS
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 microcontrollers 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 doesnt 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 doesnt require any taget device.
Note that any of these settings can be modified at any time while editing the program.
Dont forget to re-build and re-program your device after modifying any of those
settings.
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.
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 dont know whether your
program behaves as expected or not.
SOFTWARE SIMULATOR
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.
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.
STOPWATCH
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, its 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.
IN-CIRCUIT DEBUGGER
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.
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:
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.
Note that you can re-program your microcontroller as many times as you wish.
COMPILERS TOOLS
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.
USART TERMINAL
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 PCs RS-232
connector over a serial cable. The USART terminal window contains options for setting serial communication and displaying sent/received
data.
EEPROM EDITOR
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.
ASCII CHART
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.
Every code generated using tools for controlling LCD and GLCD displays contains
functions of the Lcd library. If you use them in the program, dont 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.
LIBRARIES
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
Miscellaneous libraries contain some of the general-purpose functions:
LIBRARY
DESCRIPTION
Button Library
Conversions Library
C Type Library
String Library
Time Library
Time library routines usage for time calculations in UNIX time format
Trigon Library
LIBRARY
DESCRIPTION
ADC Library
CAN Library
CANSPI Library
EEPROM Library
Used for operation with graphic LCD module with 128x64 resolution
IC Library
Keypad Library
Lcd Library
OneWire Library
Used for operation with circuits using One Wire serial communication
PS/2 Library
PWM Library
RS-485 Library
Software IC Library
Sound Library
SPI Library
Used for 4-bit SPI communication with LCD display (2x16 characters)
UART Library