You are on page 1of 25

Arithmetic Operator

Different arithmetic operators of a system are selected from the built-in blocks
of the system generator toolbox, such as Add/Sub and multiplier blocks with zero
latency, and configured using 32/16-bit fixed point settings according to the IEEE
754 standard.

From: Fractional-Order Design, 2022

Related terms:

Transfer Function, Command Window, Logical Expression, Logical Operator, Mag-


nitude Spectrum

View all Topics

C Programming for 32-Bit PIC Micro-


controllers
Dogan Ibrahim, in Designing Embedded Systems with 32-Bit PIC Microcontrollers
and MikroC, 2014

Arithmetic Operators
Arithmetic operators are used in mathematical expressions. Table 3.3 gives a list
of the arithmetic operators. All these operators, except the autoincrement and
autodecrement, require at least two operands. Autoincrement and autodecrement
operators are unary as they require only one operand.

Table 3.3. Arithmetic Operators

Operator Operation
+ Addition
− Subtraction
Multiplication
/ Division
% Remainder (integer division only)
++ Autoincrement
−− Autodecrement
The arithmetic operators “+, −, , and /” are obvious and require no explanation.
Operator “%” gives the remainder after an integer division is performed. Some
examples are given below:

12 % 3     gives 0 (no remainder)

12 % 5     gives 2 (remainder is 2)

−10 % 3     gives −1 (remainder is −1)

The autoincrement operator is used to increment the value of a variable by one.


Depending on how this operator is used, the value is incremented before (preincre-
ment) or after (postincrement) an assignment. Some examples are given below:

i = 5;                        // i is equal to 5

i++;                         // i is equal to 6

i = 5;                        // i = 5

j = i++;                       // i = 6 and j = 5

i = 5;                        // i = 5

j = ++i;                      // i = 6 and j = 6

Similarly, the autodecrement operator is used to decrement the value of a variable


by one. Depending on how this operator is used, the value is decremented before
(predecrement) or after (postdecrement) an assignment. Some examples are given
below:

i = 5;                         // i is equal to 5

i−−;                          // i is equal to 4

i = 5;                         // i  = 5

j = i−−;                       // i = 4 and j = 5

i = 5;                        // i = 5

j = −−i;                      // i = 4 and j = 4

> Read full chapter

Optimum Design with MATLAB®


Jasbir Singh Arora, in Introduction to Optimum Design (Fourth Edition), 2017

7.1.2 Scalar, Array, and Matrix Operations


The arithmetic operators for scalars in MATALB are: addition (+), subtraction (−),
multiplication (*), division (/), and exponentiation (^). Vector and matrix calculations
can also be organized in a simple way using these operators. For example, multi-
plication of two matrices A and B is expressed as A.*B. Slight modification of the
standard operators with a “dot” prefix is used for element-by-element operations
between vectors and matrices: (.*) for multiplication, (./) for division, and (.^) for
exponentiation.

For example, element-by-element multiplication of vectors of the same dimension


is accomplished using the operator“.*” (dot star):

(7.3)

Here a, b, and c are column vectors with three elements. For addition and subtrac-
tion, element-by-element and usual matrix operations are the same. Other useful
matrix operators are: A2 = A.*A, A−1 = inv(A), determinant as det(A), and transpose as
A .

> Read full chapter

MATLAB Fundamentals
Brian H. Hahn, Daniel T. Valentine, in Essential MATLAB for Engineers and Scien-
tists (Sixth Edition), 2017

2.5.7 Arithmetic operations on arrays


Enter the following statements at the command line:

a = [2 4 5];b = [6 2 2];a .* ba ./ b

MATLAB has four additional arithmetic operators, as shown in Table 2.3 that work
on corresponding elements of arrays with equal dimensions. They are sometimes
called array or element-by-element operations because they are performed element
by element. For example, a .* b results in the following vector (sometimes called the
array product):

Table 2.3. Arithmetic Operators That Operate Element-by-Element on Arrays

Operator Description
.* Multiplication

./ Right division

.\ Left division
.̂ Power

[a(1)*b(1) a(2)*b(2) a(3)*b(3)]

that is, [12 8 10].

You will have seen that a ./ b gives element-by-element division. Now try [2 3 4] .^ [4
3 1]. The ith element of the first vector is raised to the power of the ith element of the
second vector. The period (dot) is necessary for the array operations of multiplication,
division, and exponentiation because these operations are defined differently for
matrices; they are then called matrix operations (see Chapter 6). With a and b as
defined above, try a + b and a - b. For addition and subtraction, array operations and
matrix operations are the same, so we don't need the period to distinguish them.

When array operations are applied to two vectors, both vectors must be the same
size!

Array operations also apply between a scalar and a nonscalar. Check this with 3
.* a and a .^ 2. This property is called scalar expansion. Multiplication and division
operations between scalars and nonscalars can be written with or without the period
(i.e., if a is a vector, 3 .* a is the same as 3 * a).

A common application of element-by-element multiplication is finding the scalar


product (also called the dot product) of two vectors x and y, which is defined as

The MATLAB function sum(z) finds the sum of the elements of the vector z, so the
statement sum(a .* b) will find the scalar product of a and b (30 for a and b defined
above).

Exercises

Use MATLAB array operations to do the following:2.1.Add 1 to each element of the


vector [2 3 -1].2.2.Multiply each element of the vector [1 4 8] by 3.2.3.Find the array
product of the two vectors [1 2 3] and [0 -1 1]. (Answer: [0 -2 3])2.4.Square each
element of the vector [2 3 1].

> Read full chapter

Scalar Data Types, Natures and Opera-


tions
Peter J. Ashenden, ... Darrell A. Teegarden, in The System Designer's Guide to
VHDL-AMS, 2003
Type Conversion
When we introduced the arithmetic operators in previous sections, we stated that the
operands must be of the same type. This precludes mixing integer and floating-point
values in arithmetic expressions. Where we need to do mixed arithmetic, we can use
type conversions to convert between integer and floating-point values. The form of a
type conversion is the name of the type we want to convert to, followed by a value in
parentheses. For example, to convert between the types integer and real, we could
write

Converting an integer to a floating-point value is simply a change in representation,


although some loss of precision may occur. Converting from a floating-point value
to an integer involves rounding to the nearest integer. Numeric type conversions
are not the only conversion allowed. In general, we can convert between any closely
related types. Other examples of closely related types are certain array types, dis-
cussed in Chapter 4.

One thing to watch out for is the distinction between type qualification and type
conversion. The former simply states the type of a value, whereas the latter changes
the value, possibly to a different type. One way to remember this distinction is to
think of “quote for qualification.”

> Read full chapter

Scalar Data Types and Operations


Peter J. Ashenden, in The Designer's Guide to VHDL (Third Edition), 2008

2.3.3 Type Conversion


When we introduced the arithmetic operators in previous sections, we stated that the
operands must be of the same type. This precludes mixing integer and floating-point
values in arithmetic expressions. Where we need to do mixed arithmetic, we can use
type conversions to convert between integer and floating-point values. The form of a
type conversion is the name of the type we want to convert to, followed by a value in
parentheses. For example, to convert between the types integer and real, we could
write

real(123) integer(3.6)

Converting an integer to a floating-point value is simply a change in representation,


although some loss of precision may occur. Converting from a floating-point value
to an integer involves rounding to the nearest integer. Numeric type conversions
are not the only conversion allowed. In general, we can convert between any closely
related types. Other examples of closely related types are certain array types, dis-
cussed in Chapter 4.

One thing to watch out for is the distinction between type qualification and type
conversion. The former simply states the type of a value, whereas the latter changes
the value, possibly to a different type. One way to remember this distinction is to
think of “quote for qualification.”

> Read full chapter

A VHDL Primer
Peter Wilson, in Design Recipes for FPGAs (Second Edition), 2016

3.5.5 Arithmetic Operators


There are a set of arithmetic operators built into VHDL which again are self explana-
tory and these are described and examples provided as follows:

Operator Description Example


+ Addition out1 <= in1 + in2;
- Subtraction out1 <= in1 - in2;
* Multiplication out1 <= in1 * in2;
/ Division out1 <= in1/in2;
abs Absolute Value absin1 <= abs(in1);
mod Modulus modin1 <= mod(in1);
rem Remainder remin1 <= rem(in1);
** Exponent out1 <= in1 ** 3;

> Read full chapter

12th International Symposium on


Process Systems Engineering and 25th
European Symposium on Computer
Aided Process Engineering
Vassilios S. Vassiliadis, ... Ye Yuan, in Computer Aided Chemical Engineering, 2015
2.1 Bivariate operations
The bivariate operations correspond to arithmetic operators and are summarized in
Table 1 below. These are sufficient for the description of a DAG representing the
evaluation of an analytical function by assigning appropriately what the left offspring,
Vl+1,2n−1, and right offspring, Vl+1,2n, are for each node, respectively. It is noted that the
division and power operations have to be safeguarded against evaluations outside
their domain of definition. It is also noted that the first to operations are simply
assignment of either the left or right node value to the current node, thus bypassing
this node without any function description.

Table 1. Arithmetic bivariate tree operations

# fk(·)
1 Vl+1,2n−1
2 Vl+1,2n
3 Vl+1,2n−1 + Vl+1,2n
4 Vl+1,2n−1 − Vl+1,2n
5 Vl+1,2n−1 × Vl+1,2n
6 Vl+1,2n−1 ÷ Vl+1,2n
7 Vl+1,2n−1 ^ Vl+1,2n

The nodal value can be represented by the inclusion of bivariate operations weighted
by binary parameters, by the combination of both the left offspring Vl+1,2n−1 and right
offspring Vl+1,2n as input:

(1)

This equation will be the same as the one presented generally in the next section,
with the latter being the more general description.

> Read full chapter

Packages and Use Clauses


Peter J. Ashenden, in The Designer's Guide to VHDL (Third Edition), 2008

7.2 Package Bodies


Now that we have seen how to define the interface to a package, we can turn to the
package body. Each package declaration that includes subprogram declarations or
deferred constant declarations must have a corresponding package body to fill in
the missing details. However, if a package declaration only includes other kinds of
declarations, such as types, signals or fully specified constants, no package body is
necessary. The syntax rule for a package body is similar to that for the interface, but
with the inclusion of the keyword body:

package_body

    package body identifier is

         package_body_declarative_item

    end package body identifier ;

The items declared in a package body must include the full declarations of all
subprograms defined in the corresponding package declaration. These full decla-
rations must include the subprogram headers exactly as they are written in the
package declaration, to ensure that the implementation conforms with the interface.
This means that the names, types, modes and default values of each of the formal
parameters must be repeated exactly. There are only two variations allowed. First, a
numeric literal may be written differently, for example, in a different base, provided
it has the same value. Second, a simple name consisting just of an identifier may
be replaced by a selected name, provided it refers to the same item. While this
conformance requirement might seem an imposition at first, in practice it is not.
Any reasonable text editor used to create a VHDL model allows the header to be
copied from the package declaration with little difficulty. Similarly, a deferred
constant defined in a package declaration must have its value specified by repeating
the declaration in the package body, this time filling in the initialization expression
as in a full constant declaration.

In addition to the full declarations of items deferred from the package declaration, a
package body may include declarations of additional types, subtypes, constants and
subprograms. These items are used to implement the subprograms defined in the
package declaration. Note that the items declared in the package declaration cannot
be declared again in the body (apart from subprograms and deferred constants, as
described above), since they are automatically visible in the body. Furthermore, the
package body cannot include declarations of additional signals. Signal declarations
may only be included in the interface declaration of a package.

Example 7.5 A package of overloaded arithmetic operators


The package declaration outlined below declares overloaded versions of arithmetic
operators for bit-vector values. The functions treat bit vectors as representing signed
integers in binary form. Only the function headers are included in the package
declaration.

package bit_vector_signed_arithmetic is

  function “+” ( bv1, bv2 : bit_vector )

    return bit_vector;

  function “-” ( bv : bit_vector )

    return bit_vector;

  function “*” ( bv1, bv2 : bit_vector )

    return bit_vector;

  …

end package bit_vector_signed_arithmetic;

The package body contains the full function bodies. It also includes a function,
mult_unsigned, not defined in the package declaration. It is used internally in the
package body to implement the signed multiplication operator.

package body bit_vector_signed_arithmetic is

  function “+” ( bv1, bv2 : bit_vector )

    return bit_vector is …

  function “-” ( bv : bit_vector )

    return bit_vector is …

  function mult_unsigned ( bv1, bv2 : bit_vector )

    return bit_vector is

    …

  begin

    …

  end function mult_unsigned;

  function “*” ( bv1, bv2 : bit_vector )

    return bit_vector is

  begin

    if not bv1(bv1‘left) and not bv2(bv2‘left) then

      return mult_unsigned(bv1, bv2);


    elsif not bv1(bv1‘left) and bv2(bv2‘left) then

      return -mult_unsigned(bv1, -bv2);

    elsif bv1(bv1‘left) and not bv2(bv2‘left) then

      return -mult_unsigned(-bv1, bv2);

    else

      return mult_unsigned(-bv1, -bv2);

    end if;

  end function “*”;

  …

end package body bit_vector_signed_arithmetic;

One further point to mention on the topic of packages relates to the order of analysis.
We mentioned before that a package is usually a separate design unit that is analyzed
separately from other design units, such as entity declarations and architecture
bodies. (We will return to the case of a package not being a design unit shortly.)
In most cases, a package declaration and its corresponding package body are each
separate design units; hence they may be analyzed separately. A package declaration
is a primary design unit, and a package body is a secondary design unit. The package
body depends on information defined in the package declaration, so the declaration
must be analyzed first. Furthermore, the declaration must be analyzed before any
other design unit that refers to an item defined by the package. Once the declaration
has been analyzed, it does not matter when the body is analyzed in relation to units
that use the package, provided it is analyzed before the model is elaborated. In a
large suite of models, the dependency relationships can get quite complex, and a
correct order of analysis can be difficult to find. A good VHDL tool suite will
provide some degree of automating this process by working out the dependency
relationships and analyzing those units needed to build a particular target unit to
simulate or synthesize.

VHDL-87
The keywords package body may not be included at the end of a package body in
VHDL-87.

7.2.1 Local Packages


We have mentioned that package declarations and package bodies are usually
separate design units, but that there are cases where that is not so. VHDL allows us
to declare a package locally within the declarative part of an entity, architecture body,
process, or subprogram. This allows the visibility of the package to be contained
to just the enclosing declarative part and the corresponding statement part. If the
package declaration requires a package body, we must write the package body in
the same declarative part after the package declaration. Since declarations written
in a package body are not visible outside the package, we can use a local package to
provide controlled access to locally declared items.

Example 7.6 A package to manage unique identification numbers


Suppose we need to generate test cases in a design, with each test case having
a unique identification number. We can declare a package locally within a stim-
ulus-generator process. The package encapsulates a variable that tracks the next
identification number to be assigned, and provides an operation to yield the next
number. The process outline is:

stim_gen : process is

  package ID_manager is

    impure function get_ID return natural;

  end package ID_manager;

  package body ID_manager is

    variable next_ID : natural := 0;

    impure function get_ID return natural is

      variable result : natural;

    begin

      result := next_ID;

      next_ID := next_ID + 1;

      return result;

    end function get_ID;

  end package body ID_manager;

  …

  type test_case is record

      …

      ID : natural;
    end record test_case;

  variable next_test_case : test_case;

begin

  …

  next_test_case.ID := ID_manager.get_ID;

  ID_manager.next_ID := 0;  -- Illegal

  …

end process stim_gen;

The variable next_ID is declared in the package body, and so is not visible outside
the package. The only way to access it is using the get_ID function provided by
the package declaration. This is shown in the first assignment statement within
the process body. The package name is used as a prefix in the selected name for
the function. The second assignment statement is illegal, since the variable is not
visible at that point. The package provides a measure of safety against inadvertent
corruption of the data state.

By writing the package locally within the process, it is only available in the process.
Thus, we have achieved greater separation of concerns than if we had written the
package as a design unit, making it globally visible. Moreover, since the package is
local to a process, there can be no concurrent access by multiple processes. Thus,
the encapsulated variable can be an ordinary non-shared variable. If the package
were declared as a global design unit, there could be concurrent calls to the get_ID
function. As a consequence, the variable would have to be declared as a shared
variable, which would significantly complicate the design. (We describe shared
variables in Chapter 23.)

We can also declare a local package within an enclosing package declaration, whether
that enclosing package be a design unit or itself a local package. If the nested package
is to be accessible outside the enclosing package, the nested package declaration
must occur within the enclosing package declaration. The nested package body, if
required, must then occur within the body of the enclosing package. As an example,
the following outline shows an enclosing package outer with a nested package inner
that declares a function f:

package outer is

  …

  package inner is

    impure function f ( … ) return natural;


  end package inner;

  …

end package outer;

package body outer is

  …

  package body inner is

    …

    impure function f ( … ) return natural is

      …

    end function f;

  end package body inner;

  …

end package body outer;

Outside the packages, we can refer to the function f with the name outer.inner.f.

If the enclosing package only requires a local package for private use, we can write
both the nested package declaration and nested package body in the body of the
enclosing package. The outline is:

package outer is

  …

end package outer;

package body outer is

  …

  package inner is

    …

  end package inner;

  package body inner is

    …

  end package body inner;

  …
end package body outer;

In this case, items in the nested package are only accessible within the enclosing
package body. While this scheme would not commonly arise in practice, it does
serve to illustrate the consistency and general applicability of the visibility rules we
introduced in Section 6.6.

VHDL-87, -93, and -2002


These versions of VHDL do not allow declaration of local packages. A package can
only be declared as a design unit.

> Read full chapter

Programming with the MPLAB C18


Compiler
Dogan Ibrahim, in SD Card Projects Using the PIC Microcontroller, 2010

4.5.17 Operators in C
Operators are applied to variables and other objects in expressions, and they cause
some conditions or some computations to occur.

C18 language supports the following operators:

• Arithmetic operators

• Logical operators

• Bitwise operators

• Conditional operators

• Assignment operators

• Relational operators

• Preprocessor operators

Arithmetic Operators
Arithmetic operators are used in arithmetic computations. Arithmetic operators
associate from left to right, and they return numerical results. A list of the C18
arithmetic operators is given in Table 4.3.
Table 4.3. C18 arithmetic operators

Operators Operations
+ Addition
− Subtraction
* Multiplication
/ Division
% Remainder (integer division)
++ Autoincrement
−− Autodecrement

Example for use of arithmetic operators is given below:

/* Adding two integers */

5 + 12 // equals 17

/* Subtracting two integers */

120 − 5 // equals 115

10 − 15 // equals −5

/* Dividing two integers */

5 / 3 // equals 1

12 / 3 // equals 4

/* Multiplying two integers */

3 * 12 // equals 36

/* Adding two floating point numbers */

3.1 + 2.4 // equals 5.5

/* Multiplying two floating point numbers */

2.5 * 5.0 // equals 12.5

/* Dividing two floating point numbers */

25.0 / 4.0 // equals 6.25

/* Remainder (not for float) */

7 % 3 // equals 1

/* Post-increment operator */

j = 4;

k = j++; // k = 4, j = 5
/* Pre-increment operator */

j = 4;

k = ++j; // k = 5, j = 5

/* Post-decrement operator */

j = 12;

k = j−−; // k = 12, j = 11

/* Pre-decrement operator */

j = 12;

k = −−j; // k = 11, j = 11

Relational Operators
Relational operators are used in comparisons. If the expression evaluates to TRUE,
1 is returned otherwise 0 is returned.

All relational operators associate from left to right, and a list of mikroC relational
operators is given in Table 4.4.

Table 4.4. C18 relational operators

Operators Operations
== Equal to
!= Not equal to
&gt; Greater than
&lt; Less than
&gt;= Greater than or equal to
&lt;= Less than or equal to

Example for use of relational operators is given below:

x = 10

x > 8 // returns 1

x == 10 // returns 1

x < 100 // returns 1

x > 20 // returns 0

x != 10 // returns 0

x >= 10 // returns 1

x <= 10 // returns 1


Logical Operators
Logical operators are used in logical and arithmetic comparisons, and they return
TRUE (i.e., logical 1) if the expression evaluates to nonzero or FALSE (i.e., logical 0)
if the expression evaluates to zero. If more than one logical operator is used in a
statement and if the first condition evaluates to false, the second expression is not
evaluated.

A list of the C18 logical operators is given in Table 4.5.

Table 4.5. C18 logical operators

Operators Operations
&amp;&amp; AND
|| OR
! NOT

Example for use of logical operators is given below:

x = 7;

x > 0 && x < 10 // returns 1

x > 0 || x < 10 // returns 1

x >=0 && x <=10 // return 1

x >=0 && x < 5 // returns 0

a = 10; b = 20; c = 30; d = 40;

a > b && c > d // returns 0

b > a && d > c // returns 1

a > b || d > c // returns 1

Bitwise Operators
Bitwise operators are used to modify the bits of a variable. A list of the C18 bitwise
operators is given in Table 4.6.

Table 4.6. C18 bitwise operators

Operators Operations
&amp; Bitwise AND
| Bitwise OR
^ Bitwise EXOR
~ Bitwise complement
&lt;&lt; Shift left
&gt;&gt; Shift right

Bitwise AND returns 1 if both bits are 1, else it returns 0.


Bitwise OR returns 0 if both bits are 0, otherwise it returns 1.
Bitwise XOR returns 1 if both bits are complementary, otherwise it returns 0.
Bitwise complement inverts each bit.
Bitwise shift left and shift right move the bits to the left or right, respectively.

Example for use of bitwise operators is given below:

i.  0xFA & 0xEE returns 0xEA

 0xFA: 1111 1010

 0xEE: 1110 1110

 -----------------

 0xEA: 1110 1010

ii.  0x01 | 0xFE returns 0xFF

 0x08: 0000 0001

 0xFE: 1111 1110

 -----------------

 0xFE: 1111 1111

iii.  0xAA ^ 0x1F returns 0xB5

 0xAA: 1010 1010

 0x1F: 0001 1111

 -----------------

 0xB5: 1011 0101

iv.  ~0xAA returns 0x55

 0xAA: 1010 1010

 ~ : 0101 0101

 -----------------

 0x55: 0101 0101

v.  0x14 >> 1 returns 0x08 (shift 0x14 right by 1 digit)

 0x14: 0001 0100


 >> 1: 0000 1010

 -----------------

 0x0A: 0000 1010

vi.  0x14 >> 2 returns 0x05 (shift 0x14 right by 2 digits)

 0x14: 0001 0100

 >> 2: 0000 0101

 -----------------

 0x05: 0000 0101

vii.  0x235A << 1 returns 0x46B4 (shift left 0x235A left by 1 digit)

 0x235A: 0010 0011 0101 1010

 <<1 : 0100 0110 1011 0100

 -------------------------------------

 0x46B4 : 0100 0110 1011 0100

viii.  0x1A << 3 returns 0xD0 (shift left 0x1A by 3 digits)

 0x1A: 0001 1010

 <<3 : 1101 0000

 ---------------------

 0xD0: 1101 0000

Assignment Operators
In C language, there are two types of assignments: simple assignments and com-
pound assignments. In simple assignments, an expression is simply assigned to
another expression or an operation is performed using an expression and the result
is assigned to another expression:

Expression1 = Expression2

or

Result = Expression1 operation Expression2

Examples of simple assignments are

Temp = 10;

Cnt = Cnt + Temp;


Compound assignments have the general format:

Result operation = Expression1

Here, the specified operation is performed on Expression1 and the result is stored
in Result. For example,

also,

The following compound operators can be used in C18 programs:

Conditional Operator
The syntax of the conditional operator is

Expression1 is evaluated first and if its value is true, Expression2 is assigned to


Result, otherwise Expression3 is assigned to Result. In the following example,
maximum of x and y is found, where x is compared with y, and if x > y, then max =
x, otherwise max = y

In the following example, lowercase characters are converted to uppercase. If the


character is lowercase (between “a” and “z”), then by subtracting 32 from the
character, we obtain the equivalent uppercase character:

Preprocessor Operators
The preprocessor allows a programmer to

• Compile a program conditionally such that parts of the code are not compiled

• Replace symbols with other symbols or values

• Insert text files into a program

The preprocessor operator is the (“#”) character, and any line of code with a leading
(“#”) is assumed to be a preprocessor command. Semicolon character (“;”) is not
needed to terminate a preprocessor command.

C compiler supports the following preprocessor commands:

#define #undef

#if #elif #endif

#ifdef #ifndef

#error
#line

#pragma

#define, #undef, #ifdef, #ifndef

#define preprocessor command provides Macro expansion where every occurrence


of an identifier in the program is replaced with the value of the identifier. For
example, to replace every occurrence of MAX with value 100, we can write

#define MAX 100

An identifier that has already been defined cannot be defined again unless both
definitions have the same values. One way to get round this problem is to remove
the Macro definition:

#undef MAX

or the existence of a Macro definition can be checked. In the following example, if


MAX has not already been defined, then it is given value 100, otherwise the #define
line is skipped:

#ifndef MAX

 #define MAX 100

#endif

Note that the #define preprocessor command does not occupy any space in memory.

We can pass parameters to a Macro definition by specifying the parameters in


parenthesis after the Macro name. For example, consider the Macro definition

#define ADD(a, b) (a + b)

When this Macro is used in a program, (a,b) will be replaced with (a + b) as shown
below:

p = ADD(x, y) will be transformed into p = (x + y)

Similarly, we can define a Macro to calculate the square of two numbers:

#define SQUARE(a) (a * a)

When we now use this Macro in a program,

p = SQUARE(x) will be transformed into p = (x * x)

#include
The preprocessor directive #include is used to include a source file in our program.
Usually, header files with extension “.h” are used with #include. There are two
formats for using the #include:

#include <file>

and

#include “file”

In the first option, the file is searched in the C18 installation directory first and then
in the user search paths. In the second option, the specified file is searched in the
C18 project folder, then in the C18 installation folder, and then in the user search
paths. It is also possible to specify a complete directory path as

#include “C:\temp\last.h”

The file is then searched only in the specified directory path.

#if, #elif, #else, #endif

The above preprocessor commands are used for conditional compilation where
parts of the source code can be compiled only if certain conditions are met. In the
following example, the code section where variables A and B are cleared to zero is
compiled if M has a nonzero value, otherwise the code section where A and B are
both set to 1 is compiled. Notice that the #if must be terminated with #endif:

#if M

 A = 0;

 B = 0;

#else

 A = 1;

 B = 1;

#endif

We can also use the #elif condition that tests for a new condition if the earlier
condition was false:

#if M

 A = 0;

 B = 0;

#elif N
 A = 1;

 B = 1;

#else

 A = 2;

 B = 2;

#endif

In the above example, if M has a nonzero value code section, then A = 0; B = 0; is


compiled. If N has a nonzero value, then code section A = 1; B = 1; is compiled.
Finally, if both M and N are zero, then code section A = 2; B = 2; is compiled. Notice
that only one code section is compiled between #if and #endif and a code section
can contain any number of statements.

#pragma

The #pragma directive is used to define device-specific constructs. This directive is


used with the key words as shown below:

• #pragma code

• #pragma romdata

• #pragma idata

• #pragma config

• #pragma interrupt

• #pragma interruptflow

• #pragma varlocate

#pragma code is used to instruct the compiler to compile all subsequent


instructions into the program memory section of the target processor.
#pragma romdata is used to instruct the compiler to compile the subsequent
static data into the program memory of the target processor.
#pragma udata is used to locate the uninitialized user variables in data mem-
ory.
#pragma idata is used to locate the initialized user variables in data memory.
#pragma interrupt is used to instruct the compiler to compile the code from
the named C function as a high-priority interrupt service routine.
#pragma interruptflow is used to instruct the compiler to compile the named
C function as a low-priority interrupt service routine.
#pragma varlocate is used to specify where the variables will be located so that
the compiler will not generate extraneous instructions to set the bank when
accessing the variables.
#pragma config is used to define the processor Configuration bits. Document
“PIC18 Configuration Settings Addendum” of Microchip Inc. gives tables of all
the configuration bits available for any member of the PIC18 family. Some
of the widely used configuration bit definitions for the popular PIC18F452
microcontroller are shown in Table 4.7. As an example, to disable the watchdog
and set the oscillator to XT type crystal operation, we can use the following
statement:#pragma config WDT = OFF#pragma config OSC = XT

Table 4.7. Widely Used PIC18F452 Microcontroller Configuration Bits

Oscillator Selection
OSC = LP LP
OSC = XT XT
OSC = HS HS
OSC = RC RC
OSC = EC EC and OSC2 as clock out
OSC = ECIO EC and OSC2 as port RA6
OSC = HSPLL HS–PLL enabled
OSC = RCIO RC and OSC2 as port RA6
Power-up Timer
PWRT = ON Timer enabled
PWRT = OFF Timer disabled
Watchdog Timer
WDT = OFF Watchdog disabled
WDT = ON Watchdog enabled
Watchdog Postscaler
WDTPS = 1 1:1
WDTPS = 2 1:2
WDTPS = 4 1:4
WDTPS = 8 1:8
WDTPS = 16 1:16
WDTPS = 32 1:32
WDTPS = 64 1:64
WDTPS = 128 1:128

It is permissible to combine the various settings on a single line, i.e.,

#pragma config WDT = OFF, OSC = XT

> Read full chapter

ScienceDirect is Elsevier’s leading information solution for researchers.


Copyright © 2018 Elsevier B.V. or its licensors or contributors. ScienceDirect ® is a registered trademark of Elsevier B.V. Terms and conditions apply.

You might also like