3.2 Your First mikroC Pro for PIC Program

Figure 3.1 shows a very simple mikroC Pro for PIC program. This program turns ON all the 8 LEDs connected to port B of a PIC microcontroller. Then, after a 500 millisecond delay, all the 8 LEDs are turned OFF. Do not worry if you do not understand the operation of this program at this stage, as all will be clear as we progress through this chapter. Some of the elements used in Figure 3.1 are described in detail here.

Figure 3.1 A very simple mikroC Pro for PIC program

img

3.2.1 Comments

Comments are used in programs to clarify the operation of the program. Although the use of comments are optional, it is strongly recommended that you use as many comments as possible in your programs, as comments make your programs readable and easily maintainable. Imagine how hard it would be to write a complex program with no comments and then try to modify the program after several months. All the comment lines are ignored by the compiler.

In mikroC Pro for PIC language, comments can be of two types: long comments and short comments. Long comments start with the character pair:

img

and end with the character pair:

img

Long comments are commonly used at the beginning of a program to describe the program details, such as what the program does, what type of hardware is used, who the author is, the date program was created, filename of the program, version history, and so on. You can see the use of long comments at the beginning of our simple program. Long comments are also used inside a program to describe the operation of part of the program, for example the parameters of functions, the algorithm used, and so on.

Short comments start with the character pair:

img

Short comments are not terminated with a character and they can be used in a single line, starting anywhere in the line. These comments are generally used after program statements and they describe what the statement does. Examples of short comments can be seen in our simple program in Figure 3.1.

3.2.2 Beginning and Ending a Program

In mikroC Pro for PIC language, a program starts with the keywords:

img

After this, a curly opening bracket is used to indicate the start of program body. The program is terminated with a curly closing bracket. Thus, the structure of a program is (see Figure 3.1):

img

The program body consists of program statements. Each program statement must be terminated with a semicolon (‘;’) character to indicate the end of the statement, otherwise an error will be generated by the compiler:

img

3.2.3 White Spaces

White spaces in programs consist of spaces, tabs, newline characters, and blanks. These characters are ignored by the compiler. Thus, the following lines are identical:

img

or

img

or

img

or

img

In some applications, we may have a long string that we may want to extend over several lines. The backspace character (‘’) is used to join strings that extend to several lines. For example:

img

parses into string ‘My new mikroC Compiler’.

3.2.4 Variable Names

In mikroC Pro for PIC language, variable names can begin with a letter or the underscore character (‘_’). Variable names can include any character a to z, A to Z, or 0 to 9. A variable name can be up to 31 characters long. Some examples of valid variable names are:

img

and here are some invalid variable names:

img

The names are case sensitive and thus variables with lowercase names are different to variables with uppercase names. Thus, the following variables are all different:

img

3.2.5 Reserved Names

Some names in mikroC Pro for PIC are reserved for the compiler and these names can not be used as variable names. Table 3.1 gives a list of these reserved names. For example, the following variable names are illegal:

img

Table 3.1 mikroC Pro for PIC reserved names.

asm enum signed
auto extern sizeof
break float static
case for struct
char goto switch
const if typedef
continue int union
default long unsigned
do register void
double return volatile
else short while

3.2.6 Variable Types

mikroC Pro for PIC is a strictly typed language, which means that every object, expression or function must have a defined type before the program is compiled. mikroC Pro for PIC supports many pre-defined and user-defined data types, including signed and unsigned bytes and integers in various sizes, floating point numbers in various precisions, arrays, structures, and so on. The type of a variable defines how much memory space should be allocated for a variable in memory and how the bits of the variable should be manipulated. Types can be divided into two groups: Fundamental types and Derived types. The fundamental types represent types that cannot be split up into smaller parts. These types are void, char, int, float and double, together with short, long, signed and unsigned variants. The derived types are also known as structured types and they include pointers, structures, arrays and unions.

mikroC Pro for PIC language supports the fundamental variable types shown in Table 3.2. Examples of these variable types are given in this section.

Table 3.2 mikroC Pro for PIC variable types.

Type Size (bits) Range
unsigned char 8 0 to 255
unsigned short int 8 0 to 255
unsigned int 16 0 to 65 535
unsigned long int 32 0 to 4 294 967 295
signed char 8 −128 to 127
signed short int 8 −128 to 127
signed int 16 −32 768 to 32 767
signed long int 32 −2 147 483 648 to 2 147 483 647
float 32 ±1.17549435082E-38 to ±6.80564774407E38
double 32 ±1.17549435082E-38 to ±6.80564774407E38
long double 32 ±1.17549435082E-38 to ±6.80564774407E38

unsigned char or unsigned short int are unsigned 8-bit variables, occupying only 1 byte in memory and having values in the range 0 to 255. In the following example, variable Sum is assigned value 225:

img

or

img

unsigned int variables are unsigned 16-bit variables, occupying 2 bytes in memory and having values in the range 0 to 65 535. In the following example, variable Total is assigned value 64 500:

img

unsigned long int variables are unsigned 32-bit variables, occupying 4 bytes in memory and having values in the range 0 to 4 294 967 295. In the following example, variable Sum is assigned value 4 200 000 000:

img

signed char or signed short int variables are signed 8-bit variables, occupying only 1 byte in memory and having values in the range −128 to +127. In the following example, variable Total is assigned value −240:

img

signed int variables are 16-bit variables, occupying 2 bytes in memory and having values in the range −32 768 to +32 767. In the following example, variable Sum is assigned value −31 500:

img

signed long int variables are 32-bit variables, occupying 4 bytes in memory and having values in the range −2 147 483 648 to +2 147 483 647. In the following example, variable Sum is assigned value 2 050 480 000:

img

Floating point number data types are float, double and long double. mikroC Pro for PIC implements the floating point numbers using the Microchip AN575 32-bit format, which is IEEE 754 compliant. The floating point numbers have values in the range ±1.17549435082E-38 to ±6.80564774407E-38. In the following example, variable Volume is assigned value 23.45:

img

or

img

3.2.7 Constants

Constants are very important in mikroC Pro for PIC programs, especially if the RAM data memory has limited size. Constant variables are stored in the microcontroller flash program memory, thus freeing valuable RAM memory space. In mikroC Pro for PIC, constants can be characters, integers, floating point numbers, strings and enumerated variables.

3.2.7.1 Character Constants

A character constant occupies a single byte in the program memory. The constant is declared by specifying the character within a single quote mark. In the following example, variable FirstName is declared as a constant character and is assigned the value ‘D’:

img

3.2.7.2 Integer Constants

Integer constants occupy 2 bytes in memory. These constants can be specified using decimal, hexadecimal, octal or binary bases. The data type of a constant is derived by the compiler automatically, depending upon the value of the constant. For example, a constant with a value 130 is stored as an unsigned char, a constant with a value 12 000 is stored as an unsigned int, and a constant with a value −22 500 is stored as a signed int.

In the following example, MIN and MAX are defined as constants 0 and 200, respectively:

img

Hexadecimal numbers have the range 0 to 9 and A to F. Hexadecimal constants are specified by inserting characters ‘0x’ or ‘0X’ in front of the number. In the following example, constant MAX is defined to have the hexadecimal value FFF:

img

Octal numbers have the range 0 to 7. Octal constants are specified by inserting number ‘0’ in front of the number. In the following example, constant MAX is defined to have the octal value 177:

img

Binary numbers can be 0 or 1. These numbers are specified by inserting characters ‘0b’ or ‘0B’ in front of the number. In the following example, constant MIN is defined to have the binary value 01 101 111:

img

3.2.7.3 Floating Point Constants

Floating point constants are non-integer constants having a decimal part, a dot and the fractional part. In addition, for very large or very small numbers, the exponent part can be specified by inserting characters ‘e’ or ‘E’ with the value of the exponent at the end of the number. In the following example, variable MIN is given the value 0.15E-2, and MAX is given the value 25.5E10:

img

3.2.7.4 String Constants

String constants consist of collections of characters enclosed within double quotes. An example string constant is:

img

As we shall see in later sections, strings are made up of character arrays.

3.2.7.5 Enumerated Constants

An enumeration data type is used for representing an abstract, discreet set of values with appropriate symbolic names. Enumeration makes a program easier to follow.

Variables of the enum type are declared the same as other variables. An example enumeration declaration is given below:

img

img

In the above example, Black = 0, Red = 1, Green = 2, and so on. Identifier clr can take any value of the specified colours, or any integer value:

img

or

img

The order of constants in an enum type can be explicitly re-arranged using specific values. Any names without initialisers will be increased by 1 with respect with the previous value. An example is given below:

img

Another example is given below:

img

3.2.8 Escape Sequences

Some of the control characters in the ASCII table are non-printable and are known as the escape sequences. For example, the character ‘ ’ represents the new-line character, which causes the cursor to jump to the next line. Table 3.3 gives a list of the commonly used escape sequences. Notice that the escape sequence characters can also be obtained by specifying their values. For example, the hexadecimal ‘0×0A’ can be used to specify the new line.

Table 3.3 Commonly used escape sequences.

Escape Sequence Hex Value Character
a 0×07 BEL (bell)
 0×08 BS (backspace)
0×09 HT (horozontal tab)
0×0A LF (linefeed)
v 0×0B VT (vertical feed)
f 0×0C FF (formfeed)
0×0D CR (carriage return)
xH String of hex digits

3.2.9 Volatile Variables

Volatile declaration is particularly important in interrupt based applications. The qualifier volatile implies that a variable may change its value during run time, independent from the main program. Use the volatile modifier to indicate that a variable can be changed by a background routine, an interrupt routine or I/O port. Declaring an object to be volatile warns the compiler not to make assumptions concerning the value of an object while evaluating expressions in which it occurs, because the value could be changed at any moment. In the following example, variable Cnt is declared to be a volatile unsigned character:

img

3.2.10 Accessing Bits of a Variable

There are many cases where we may want to access individual bits of an 8-bit variable. If we wish to access the bit of a microcontroller internal register, and if we know the name of the register to be accessed, then we can simply write the name of the bit and set or reset it as required. An example is given below:

img

We can also use the qualifiers B0, B1, . . . . B7 or F0, F1, . . . . . F7, with ‘0’ being the least significant bit (LSB) and ‘7’ being the most significant bit (MSB). As an example, to set bit 0 of register INTCON we can write:

img

or, to set bit 3 we can write:

img

3.2.11 sbit Type

The mikroC Pro for PIC compiler has sbit data type, which provides access to bit addressable internal registers (SFRs). You can access bits of internal registers, as in the following examples:

img

or, alternatively and equivalently,

img

3.2.12 bit Type

mikroC Pro for PIC compiler also supports a single-bit definition using the bit type. An example is given below:

img

3.2.13 Arrays

3.2.13.1 Numeric Arrays

During program development, there is usually the need to manipulate several related items of data of the same type. For example, a program designed to read the ages of 50 students in a classroom may at first seem to require the use of 50 separate integer type variables. However, such an approach makes the manipulation of data difficult, as we have to access each integer separately. Furthermore, if the class size increases to, say, 70 students, then we have to introduce 20 more integers and 20 more statements to process the new entries.

The solution to this problem is to use an array with an easy way of collecting related items under a single variable name. An array is declared by specifying its name, type and the number of elements it has to store. For example, the following is an unsigned integer array called Average, having five elements:

img

The array is stored in sequential memory locations, as shown below:

Average[0]
Average[1]
Average[2]
Average[3]
Average[4]

In this example, the first array element has index 0 and the last one has index 4. Array elements are addressed by writing the array name followed by a square bracket where the index is specified. For example, to set the third array element to value 120, we have to write:

img

Similarly, for example, to copy the third array element to a variable called MyValue, we can write:

img

Whenever an array definition is encountered by the compiler, a calculation is performed to determine the storage requirements of each element.

The contents of an array can be initialised during the declaration of the array by specifying the array elements, separated by commas and enclosed in curly brackets. An example follows where array numbers have 10 elements and numbers[0] = 0, numbers[1] = 1, and so on:

img

The same array can be declared, without specifying the array size, as follows. Here, the compiler determines the array size and allocates the required number of bytes in memory:

img

Note that it is not necessary to initialise all of the elements of an array. For example, we could pre-initialise just the first three elements of an array and leave the remaining elements un-initialised with a definition of the form:

img

In which case only elements [0], [1] and [2] would be initialised, even though storage will be reserved for 10 elements. Here, any remaining un-initialised elements are implicitly initialised to zero.

Note, however, that it is an error to have more elements than the defined array size. For example, the definition below will generate a compiler error:

img

Whenever an array is initialised, the compiler copies the specified data to the array elements. If this array happens to be inside a function, then each time the function is called, the array elements will be re-loaded, thus causing unnecessary delay. For this reason, the keyword static should be used to force the array elements to be loaded only once at the start of the program:

img

In mikroC Pro for PIC language, we can also declare an array with multiple dimensions. Such arrays are commonly used in mathematical operations, such as vector and matrix calculations. A multi-dimensional array is declared by specifying the data type, name of the array and the size of each dimension. In the following example, a two-dimensional array called MyMatrix is declared, having three rows and two columns:

img

This array will have the following structure. Altogether the array has six elements. The first element of the array is MyMatrix[0][0], and the last element is MyMatrix[2][1]:

MyMatrix[0][0] MyMatrix[0][1]
MyMatrix[1][0] MyMatrix[1][1]
MyMatrix[2][0] MyMatrix[2][1]

Elements of a multi-dimensional array can be initialised as before, by specifying the elements within curly brackets and separated by commas. An example is given below:

img

In the above example, we have 2 rows and 3 columns. The value of each element can be shown as:

0 2 5
6 8 5

The size of the first dimension is optional and can be left blank, as shown below for the above example. The compiler fills in the correct size during compilation:

img

3.2.13.2 Character Arrays

Character arrays are declared similarly to numeric arrays, where each character is separated and enclosed within a pair of curly brackets. In the following example, character array MyName has four elements:

img

As before, we can leave the array size blank:

img

3.2.13.3 Strings

Strings are character arrays terminated with a NULL character (hexadecimal 0×0 or ‘’). In the example below, MyName is a string having five elements, including the string terminator NULL character:

img

As you can see from the above example, we have to separate each character with a comma and terminate the string with a NULL character. An alternative and easier way of declaring the same string would be:

img

Here, the characters are terminated automatically with a NULL character and this second option is more readable, especially when it is required to declare long strings. In addition, the string will not be terminated correctly if we forget to insert the NULL character.

3.2.13.4 Constant Strings

In many applications it may be required to create fixed long strings in the flash program memory of the microcontroller. Such strings can be created as constant strings to save space in the RAM data memory. An example is given below:

img

3.2.13.5 Arrays of Strings

There are many applications where we may want to create arrays of strings in our programs. In the following example, the array Days stores days of the week. Notice that it is optional to specify size of the first dimension:

img

In the above example, the size of the first dimension is set to 7 automatically by the compiler. The second dimension is set to 10, which is the size of the longest word in the array. Notice that each word in the array is a string and as such is terminated with a NULL character. Figure 3.2 shows the structure of this array.

Figure 3.2 Structure of the array of strings

img

3.2.14 Pointers

Pointers are a very important part of the C language, and the subject of pointers is perhaps the most interesting and useful aspect of C. The concept of pointers may sound strange to most students who have been programming in other high-level languages, such as Pascal or BASIC. Pointers are important, especially in microcontroller based applications, since they enable the programmer to directly access the memory locations by using memory addresses.

Pointers hold the addresses of variables in memory. They are declared just like the other variables, but with the character ‘*’ inserted in front of the variable name. Pointers can be created to point (or hold the address of) to character variables, integer variables, long variables, floating point variables, and so on. Because of this generality, we have to specify the type of a pointer at the time of declaring it.

In the following example, ptr is the pointer to a character variable in memory. At this point all we know is that it is a pointer can hold the address of a character variable. But we have not specified yet which variable's address it is holding:

img

We can now specify the name of the variable whose address we wish to hold. This is done using the character ‘&’ in front of the variable name. In the following example, ptr holds the address of character variable Cnt in memory:

img

The value of variable Cnt can be accessed by using the ‘*’ character in front of its pointer. Thus, the following two statements are equivalent:

img

We can also make an assignment of the form shown below, to assign value to a variable:

img

3.2.14.1 Pointer Arithmetic

In C language we can perform various pointer arithmetic, which may involve:

  • adding or subtracting pointers with integer values;
  • adding or subtracting two pointers;
  • comparing two pointers;
  • comparing a pointer to a NULL;
  • assigning one pointer to another.

As an example to pointer arithmetic, assume that six memory locations, starting from address 1000, store the character variables, as shown in Figure 3.3.

Figure 3.3 Memory locations

img

We can now declare a pointer to hold the address of variable A and then perform the following operations:

img

3.2.14.2 Array Pointers

In C language, the name of an array is also a pointer to the first element of the array. Thus, for the array:

img

The name Sum is also a pointer to element Sum[0] of the array, and it holds the address of the array. Similarly, the following statements can also be used to point to the array:

img

The following two statements are equivalent, since Sum is also the address of array Sum:

img

It is interesting to note that the following statement is also true, for the same reason:

img

3.2.14.3 Using Pointers in String Operations

Another useful application of pointers is to create and manipulate string variables. Remember that strings are a collection of character arrays terminated with the NULL character. Using pointers, we can create a string, as shown in the example below:

img

Here, a hidden character array is created at compile time, containing characters ‘JOHN’, terminated with the NULL character. The character pointer p is initialised and loaded with the address of this string in memory. Thus, p holds the address of the first character of the string, that is the address of character ‘J’. The programmer has no control over the size of the created string and therefore should not attempt to alter its contents using the pointer.

In many applications we may want to create long fixed strings. This is easily done using pointers and declaring the strings as constants. An example is given below:

img

It is important to realise the differences between the following two ways of creating strings:

img

In the first statement, a character array called Text is created and is terminated with a NULL character. Individual characters of this array can be accessed by indexing the array. In the second statement, the characters ‘An example text’ and terminator NULL are stored somewhere in memory, and pointer p is loaded with the address of the first character of this text, that is the address of character ‘A’.

We can create arrays of text strings using pointers. In the following example, seven pointers are created with names Days[0] to Days[6] and each pointer is loaded with the corresponding address of the day name. The dimension of the pointer array is set to 7 automatically by the compiler:

img

3.2.15 Structures

Structures are used in programs to group and manipulate related but different types of data as a single object or variable. The elements of a structure can all be of different type, which is in contrast with an array where all elements must be of the same type. For example, a structure can be used to store details of a person, such as the name, age, height and weight as a single object. Here, the elements are of different types. Name is a string, age is an integer, and height and weight are floating point type variables.

A structure is created using the keyword struct, followed by a structure name and a list of the elements (or structure members), enclosed within a pair of curly brackets. As an example, the structure called Person given below could be used to describe details of a person:

img

When a structure, as above, is declared, it is simply a template and no space is reserved in memory for this template. It is only when variables of the same type are declared that the structure takes space in memory. For example, we can create a variable called Me of type Person by the statement:

img

It is important to realise that it is Me that is the variable and not the Person. We can create more than one variable of type Person by separating them with a comma, as shown below:

img

In the above examples, the structure template and variable creation were done in two separate statements. If required, these two statements can be combined into one and the variables can be created during the creation of the template. An example is given below:

img

We can omit the name of the structure if we wish, but if we do this, then all variables based upon that structure template must be defined at the same time as the template is declared, as there is no way to introduce new variables later using the same template.

3.2.15.1 Accessing Structure Members

After a structure variable has been defined, its members (elements within the structure) can be individually accessed using the dot (‘.’) operator. This operator is placed between the structure name and the member name that we wish to access. In the following statement, age member of structure Me above is set to 25:

img

Similarly, for example, the height in the same structure can be assigned to a variable called H with the statement:

img

3.2.15.2 Initialising Structure Members

As with other data types, when a structure is declared, the values of its members are undefined. However, as with arrays, it is often necessary to initialise the member elements to known values during the declaration of a structure. The following example shows how the sides of a rectangle declared as a structure can be initialised to 2.5 and 4.0:

img

Members of a structure can also be assigned values by using structure pointers. For example, in the above example, we can define MyRectangle as a pointer and then assign values to its members using the arrow (‘->’) operator:

img

3.2.15.3 Structure Copying

If two structure are derived from the same template, then it is permissible to assign one structure to the other one (this is not possible in arrays). An example is given below:

img

img

3.2.15.4 Size of a Structure

Sometimes we need to know the size of a structure variable. We can use the sizeof operator to find the number of bytes occupied by a structure variable. In the following example, the size of structure variable R1 is assigned to integer variable S:

img

3.2.15.5 Arrays of Structures

In some applications we may need a collection of structures of similar type. For example, consider the following complex number structure template:

img

We can now create an array of this structure with 10 elements as:

img

Individual structure elements can now be accessed by indexing the structure variable XY. In the example below, index 0 of the structure variable is taken and the real and imaginary parts are set to 2.3 and 5.0, respectively:

img

3.2.15.6 Structure Bit Fields

Bit fields can be defined using structures. With bit fields, we can assign identifiers to individual bits or to collections of bits of a variable. For example, to identify the low byte of a 16-bit unsigned integer Total as LowB and the high byte as HighB, we can write:

img

We can then access the two bytes as:

img

3.2.16 Unions

A union in C is very much like a structure, and is even declared and initialised in the same way. Both are based on templates and members of both are accessed in the same way. Where a union principally differs from a structure is that in a union all members share the same common storage area. Even though the members can be of different type, they all share the same common storage area, and the size of this area is equal to the size of the largest data type amongst the members of the union. An example of a union declaration is:

img

In this example, variables x, y and z all share the same memory area. Variables x and y are mapped to each other, where variable z is mapped to the lower byte of x or y. The size of the common area in this example is 2 bytes. In the following statement, 16-bit hexadecimal number 0×F034 is loaded into union variable V:

img

Now, both variables x and y are loaded with hexadecimal number 0×F034, and variable z is loaded with the lower byte, that is 0×34.

As with the structures, the size of a union variable can be determined using the size of operator, as shown below:

img

3.2.17 Operators in mikroC Pro for PIC

Operators are symbols applied to variables to cause some operations to take place. For example, addition symbol ‘+’ is an operator and causes the value of a variable to change. In mikroC Pro for PIC language, operators are classed as unary or binary. Unary operators require only one variable and they operate on this variable, for example changing the sign of a variable. Binary operators, on the other hand, operate on two variables, for example adding two numbers.

Operators in mikroC Pro for PIC can be arithmetical, logical, bitwise, relational, assignment, conditional and pre-processor. In this section, we shall look at these operators in detail and see how they can be used in programs.

3.2.17.1 Arithmetic Operators

Table 3.4 gives a list of the arithmetical operators. All readers are familiar with the basic operators of addition, subtraction and multiplication. The other arithmetic, operators need some explanation and some understanding before they are used.

Table 3.4 mikroC Pro for PIC arithmetic operators.

Operator Operation
+ Addition
Subtraction
* Multiplication
/ Division
% Remainder (integer division)
++ Auto increment
-- Auto decrement

The division operator ‘/’ divides two numbers. If the numbers are real, then using floating point arithmetic will give correct results. But, if the two numbers are integers, the division can give wrong results, as in the following example:

img

The modulus operator ‘%’ is used to give the remainder after two integer numbers are divided. In the following example, numbers 5 and 7 are divided using the modulus operator and the result is 2, which is the remainder:

img

The auto increment operator (++) is used to increment the value of a variable by 1, without using the assignment operator (‘=’). An example is given below:

img

Similarly, the auto decrement operator (--) is used to decrement the value of a variable by 1, without using the assignment operator. An example is given below:

img

The auto increment and auto decrement operators can be used in assignment operations. The value assigned to a variable changes depends on whether the ‘++’ or ‘--’ symbols are placed to the left or the right of a variable. In the following example, the value of variable Sum is 10 initially. Sum is assigned to variable Total and is then incremented automatically. Thus, at the end, Sum contains 11 and Total contains 10:

img

In the following example, Sum is incremented and is then assigned to Total. Thus, at the end, Sum contains 11 and Total contains 11:

img

A similar thing happens when auto decrement is used. An example is given below:

img

3.2.17.2 Logical Operators

Logical operators are used in logical and arithmetical operations. Table 3.5 gives a list of the mikroC Pro for PIC logical operators.

Table 3.5 mikroC Pro for PIC logical operators.

Operator Operation
&& AND
|| OR
! NOT

An example is given below on the use of logical operators:

img

3.2.17.3 Bitwise Operators

In addition to arithmetical and logical operators, bitwise operators are used to modify individual bits of a variable. Table 3.6 gives a list of the mikroC Pro for PIC bitwise operators. These operators can only be used with integer type variables.

&

Table 3.6 mikroC Pro for PIC bitwise operators.

Operator Operation
& Bitwise AND
| Bitwise OR
^ Bitwise EXOR
img Bitwise complement
<< Shift left
>> Shift right

The ‘&’ operator performs the bitwise AND of its two operands. Each bit of the first operand is ANDed with the corresponding bit of the second operand. The resulting bit is only 1 if both of the two corresponding bits are 1, otherwise the resulting bit is set to 0. An example is given below:

img

In this example, variable z takes the hexadecimal value 0×0060. The bitwise ANDing operation is shown below:

img

|

The ‘|’ operator performs the bitwise OR of its two operands. Each bit of the first operand is Ored with the corresponding bit of the second operand. The resulting bit is 1 if either of the corresponding bits are 1, otherwise the resulting bit is set to 0. An example is given below:

img

In this example, variable z takes the hexadecimal value 0×FFF1. The bitwise ORing operation is shown below:

img

The ‘^’ operator performs the bitwise Exclusive OR of its two operands. Each bit of the first operand is Exclusive Ored with the corresponding bit of the second operand. The resulting bit is 1 if only one of the corresponding bits is 1, otherwise the resulting bit is set 0. An example is given below:

img

In this example, variable z takes the hexadecimal value 0×FF91. The bitwise Exclusive ORing operation is shown below:

img

The ‘img’ operator performs the bitwise complement of its operand. Each bit is complemented, thus a 0 becomes a 1, and a 1 becomes a 0. An example is given below:

img

In this example, variable y takes the hexadecimal value 0×0F1F. The bitwise complement operation is shown below:

img

The ‘<<’ operator performs shift left. The operand is shifted left by n bits, where n is specified by the programmer. The right-hand side of the variable LSB is filled with zeroes, while bits at the left-hand side MSB are lost. Shifting a variable left by 1 bit is the same as multiplying by 2, but the shift operation is much quicker. An example is given below:

img

The actual shift left operation for the above example is shown in Figure 3.4.

>>

Figure 3.4 Shifting left by 2 places

img

The ‘>>’ operator performs shift right. The operand is shifted right by n bits, where n is specified by the programmer. The left-hand side of the variable MSB is filled with zeroes, while bits at the right-hand side LSB are lost. Shifting a variable right by 1 bit is the same as dividing by 2, but the shift operation is much quicker. An example is given below:

img

The actual shift right operation for the above example is shown in Figure 3.5.

Figure 3.5 Shifting right by 2 places

img

3.2.17.4 Relational Operators

Relational operators are used in conditional operations that change the flow of control in a program. A 1 is returned if the relational operation evaluates to TRUE, otherwise 0 is returned. Table 3.7 gives a list of the mikroC relational operators. These operators are common to all programming languages, but the symbols used may change. It is important to note that the equivalence operator ‘= =’ consists of two equal signs. A common mistake is to use a single equal sign in a relational operator, which will be interpreted as an assignment operator.

Table 3.7 microC relational operators.

Operator Operation
= = Equal to
!= Not equal to
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to

A few examples to the use of relational operators are given below:

img

3.2.17.5 Assignment Operator

The assignment operator ‘=’ is used to assign the result of an expression to a variable. The general format of the assignment operation is:

img

In the following example, the sum of a and b are assigned to c:

img

mikroC Pro for PIC also supports complex assignment operations, used when a variable appears both on the left and right of the assignment operator. For example, consider the expression below, where variable a is added to variable b and the result is stored back in variable a:

img

Using complex assignment operator, we can write the above statement as:

img

Other useful assignment operators are:

img

3.2.17.6 The Conditional Operator

The conditional operator (or ternary operator) is useful for evaluating conditional expressions. This operator requires three operands and its general form is given below and is interpreted as follows: if expression1 is TRUE, then evaluate expression2 and assign to the result, otherwise evaluate expression 3 and assign to the result.

img

In the following example, the minimum of x and y is found and is assigned to min. Notice that using brackets simplifies the expression:

img

In the following example, the absolute value of x is assigned to y. We can interpret this expression as: if x is less than zero (i.e. negative) then change its sign (i.e. make it positive) and assign to y, otherwise assign x to y (since it is already positive)

img

3.2.17.7 Preprocessor Operators

Any line in the source code with a leading ‘#’ character is known as a preprocessor operator, or preprocessor directive. Traditionally, the preprocessor has been a separate program, which runs before the main compilation process. However, with modern compilers, the preprocessor is part of the main compiler and is automatically invoked at compilation time.

Preprocessor operators are useful when the programmer wants to insert files into a program, when it is required to replace symbols or values with other symbols, or when it is required to compile part of a program conditionally.

mikroC Pro for PIC supports the following preprocessor operators:

img

img

The #define preprocessor operator is used at the beginning of a program and it is useful when we wish to assign symbols to values. Some examples are given blow:

img

It is important to realise that when the #define preprocessor operator is used, the compiler substitutes the value for the symbol wherever it is used in the program. Also, an identifier that has already been defined cannot be defined again. One way to get round this problem is to un-define a definition using preprocessor operator #undef, as shown below:

img

Alternatively, we can use the existence of a definition using the #ifndef preprocessor operator, as shown below. Here, the definition of symbol PI is checked for existence. If it is not defined, a definition is made, otherwise nothing else is done:

img

The #define preprocessor operator may include a number of optional parameters. An example is given below:

img

When symbol SQR is used in a program, (x) will be replaced with the square of it, that is ((x)*(x)). Thus, the following expression

img

will evaluate into

img

Some other examples are given below:

img

It is important to enclose the definitions on the right-hand side within the parenthesis for the expressions to be expanded correctly. As an example, consider what may happen if parenthesis is not used:

img

Now, suppose we use this definition in a statement such as

img

Now, the compiler will expand the above expression as

img

giving the wrong result 11 instead of the correct result of 9.

#include

The #include preprocessor operator is used to insert a file into the program. It is commonly used at the beginning of a program to insert a header or a definition file into the program. In the following example, file math.h is inserted into the program:

img

or

img

If the #include is used with the ‘< >’ version, the compiler searches the file in each of the following locations, in the given order:

  • the mikroC Pro for PIC installation folder ‘include’;
  • user's custom search path.

The ‘ ’ version searches the file in the following locations, in the given order:

  • user project folder;
  • mikroC Pro for PIC installation folder ‘include’;
  • user's custom search path.

It is also permissible to specify the search path explicitly, as shown in the following example:

img

These are conditional assembly preprocessor operators. Using these operators, the programmer can force parts of a program to be compiled conditionally. For example, depending on the type of microcontroller used, the programmer may wish to not compile part of a program.

In the following example, the code section including variable FLAG is compiled if CPU is 100, otherwise this code section is omitted:

img

Similarly, in the following example, if CLOCK is 1 the first code block is compiled, otherwise the second code block is compiled:

img

We can also use the #elif in conditional compilation, as shown in the following example. Here, if Y_RES is less than 500, then the code X = 200 is compiled, if Y_RES is between 500 and 1024, then the code X = 300 is compiled, if Y_RES is greater than 1024, then the code X = 400 is compiled, otherwise the code X = 500 is compiled:

img

Notice that each #if operator must match with a #endif operator. Any number of #elif operators can be used between #if and #endif, but at most only one #else can be used.

3.2.18 The Flow of Control

Most statements in a program are executed sequentially one after the other. There are many cases where in a program a decision is to be made about the operation that will be performed next. The flow of control in a program can be modified using the flow of control statements. These statements include modification of flow based on selection, unconditional modification of the flow, and iteration statements. In this section, we shall be looking at these statements that modify the flow of control in programs.

3.2.18.1 Selection Statements

The selection statements are based on modifying the flow of control conditionally. For example, if a condition evaluates to TRUE, then a certain part of the program is executed, otherwise a different part is executed.

There are two selection statements: if - else and switch.

if – else Selection Statements

The basic if statement has the following format, where the expression usually includes logical and relational operators:

img

In the following example, if variable p is equal to 10 then k is incremented by 1:

img

Notice that because the white spaces are ignored in the C language, the statement can be on a different line:

img

The if statement can be used together with else, such that if the expression is FALSE, then the statement following else is executed. In the following example, if variable Total is equal to MAX, then Sum is incremented by 1, otherwise Sum is decremented by 1:

img

The above statement is usually written in the following form:

img

In some applications, we may need to execute more than one statement if a condition is TRUE or FALSE. This is done by enclosing such statements inside a pair of curly brackets. An example is given below:

img

or

img

3.2.18.2 switch Selection Statements

There are cases where we may want to do multi-way conditional tests. For example, in a menu type application, the user's choice is compared to a number of options, and a different action is taken with each option. Such a program could normally be written using the if – else type selection statements. However, when there are many options, the use of if – else makes the program unreadable.

The switch statement is generally used in multi-way conditional tests. The general format of this statement is:

img

The switch statement operates as follows: First, the condition is evaluated. If condition is equal to condition 1, then statements following condition 1 are executed. If condition is equal to condition 2, then statements following condition 2 are executed. This process continues until condition n, where if the condition is equal to condition n, then statements following condition n are executed. If condition is not equal to any of the conditions 1 to n, then the statements following the default case are executed. Notice that the break statements in each block make sure that we return to the end of the switch statements (after the closing curly bracket) and jump out of the selection block. Without the break statements, the program will continue to execute those statements associated with the next case. The last break statement is not obligatory, as the switch block closes after this statement. The default case is optional and can be avoided if we are sure that the condition will be equal to one of the conditions 1 to n.

The following example shows part of a program implemented using both if-else and switch selection statements. Functionally, the two codes are equal to each other:

img

An example is given below, which shows how the switch selection statement can be used.

Example 3.1

It is required to write a program code using the switch statement to convert a hexadecimal character A to F to its decimal equivalent. Assume that the input character is stored in a variable called chr, and the output should be stored in variable y.

Solution 3.1

As you will remember, the decimal equivalents of hexadecimal digits are:

Hexadecimal Decimal
A 10
B 11
C 12
D 13
E 14
F 15

The required program code is given below:

img

Example 3.2

The relationship between X and Y variables in an experiment are as follows:

X Y
1 1.5
3 3.5
5 4.0
7 5.0
9 7.5

Write a switch statement that will return the value of Y.

Solution 3.2

The required switch statement is:

img

img

3.2.18.3 Repetition Statements

Another fundamental building block in any programming language is the repetition, or looping construct. Here, one or a group of instructions are executed repeatedly, until some condition is satisfied. Basically, mikroC Pro for PIC language supports three types of repetition statements: while, do – while and for loops.

3.2.18.4 while Statements

The general format of the while statement is:

img

Here, the statement is executed as long as the expression is TRUE. In general, the number of statements are more than one and curly brackets are used to enclose the statements:

img

In the following example, the loop formed using the while statement is repeated 10 times. The loop control variable is i and is initialised to 0 before entering the loop. The statements are executed as long as i is less than 10. Notice that inside the loop, the loop counter i is incremented by 1 at each iteration:

img

Example 3.3

Write a program to initialise an integer array called MyArray to zero. Assume that the array has 10 elements.

Solution 3.3

The required program is given below:

img

When using the while statement, it is important to ensure that the condition that holds the loop is changed inside the loop, otherwise an infinite loop is formed. The following is the above program written in error that never terminates. The program repeatedly initialises element 0 of the array:

img

Sometimes it may be necessary to create infinite loops in our programs. This can easily be achieved using the while statement, as shown below:

img

3.2.18.5 do – while Statements

This is a useful variation of the while statement. The general format of the do – while statement is:

img

Here, the statements are executed as long as the expression is TRUE. The expression usually includes logical and relational statements. An example is given below, where the loop is terminated 10 times:

img

Notice again that the condition that holds the loop is changed inside the loop, so that the loop is terminated after the required number of iterations. There is a difference between the simple while and the do – while statements. The statements inside the while loop may never be executed if the condition is FALSE. On the other hand, the statements inside the do – while loop are executed at least once since the condition is tested at the end of the construct. Some examples are given below, showing how the do – while loop can be constructed and used in programs:

Example 3.4

Write a program to initialise an integer array called MyArray to 1. Assume that the array has 100 elements.

Solution 3.4

The required program is given below:

img

Example 3.5

Write the loop code using do – while statement to copy a string called B to another string called A.

Solution 3.5

Remember that strings are character arrays terminated with a NULL character. The do – while loop below will copy the contents of string B to A, including the NULL terminator. Note that i is incremented after its value has been used as a subscript to B:

img

When using the do – while statement, it is important to make sure that the condition that holds the loop is changed inside the loop, otherwise an infinite loop is formed. The following is the above program written in error that never terminates. The program repeatedly initialises element 0 of the array:

img

Sometimes it may be necessary to create infinite loops. This can easily be achieved using the do – while statements, as shown below:

img

Example 3.6

Write a program to multiply two integer arrays X and Y having 10 elements each, and store the sum in an integer variable called Sum.

Solution 3.6

The required program is given below:

img

img

3.2.18.6 for Statements

The for statement is the most commonly used statement for setting up loops in programs. The general format of this statement is:

img

where expression 1 sets the initial value of the loop count and this variable is evaluated just once on entry into the loop. Expression 2 is the condition that keeps the loop continuing. This expression is evaluated at each iteration, to check whether or not the loop should continue. Expression 2 is usually a logical or relational operator. Expression 3 is also evaluated at the end of each iteration and this expression changes value that is tested for loop termination. Expression 3 is usually an increment of the loop counter value.

The for loop is commonly used with more than one statement. An example is given below, where the loop is repeated 10 times. The initial value of the loop counter i is 0, it is incremented by 1 at each iteration, and the loop continues as long as i is less than 10:

img

Some examples of using the for statement are given below.

Example 3.7

Write a program to calculate the squares of numbers between 1 and 49 and store the results in an integer array called Mult.

Solution 3.7

The required program is given below.

img

The for loops can easily be nested, as shown in the following example. Here, all elements of a two-dimensional array MyArray are initialised to 0 (assuming that the array dimension is 10). In this example, the inner loop is repeated 10 times for each i value of the outer loop, that is the total number of iterations is 100:

img

The parameters in a for loop can be omitted. There are several variations of the for loop, depending upon which parameter is omitted. Some examples are given below:

To create an infinite loop:

img

Setting the initial loop condition outside the loop:

img

To terminate the loop from inside the loop:

img

3.2.18.7 Premature Termination of a Loop

There are cases where we may want to terminate a loop prematurely. This is done using the break statement. When the program encounters this statement, it forces an unconditional jump to outside the loop. The break statement can be used with all repetition statements. An example is given above with the for statement. In the following example, the loop is terminated when variable p becomes 10:

img

3.2.18.8 The goto Statement

The goto statement can be used to alter the normal flow of control in a program. This statement can either be used on its own or with a condition. The general form of using this statement is:

img

or

img

In the first form, the program jumps to the statement just after the label named LOOP. A label can be any valid variable name and it must be terminated with a colon. In the second example, the program jumps to the specified label if a condition is TRUE.

Excessive use of the goto statement is not recommended in programs, as it causes a program to be unstructured and difficult to maintain. Very large and complex programs can be written without the use of the goto statement. Perhaps the most useful application of the goto statement is to prematurely terminate a program.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.19.189