mikroElektronika Sensory RSC-4x Microcontrollers User Manual
বিজ্ঞাপন
বিজ্ঞাপন
mikroElektronika
Development tools - Books - Compilers w w w . m i k r o e l e k t r o n i k a . c o . y u
C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC
M a k i n g i t s i m p l e
Develop your applications quickly and easily with the world's most intuitive C compiler for Sensory RSC-4x microcontrollers.
Highly sophisticated IDE provides the power you need with the simplicity of a Windows based point-and-click environment.
With useful implemented tools, many practical code examples, broad set of built-in routines, and a comprehensive Help, RSC-4x mikroC makes a fast and reliable tool, which can satisfy needs of experienced engineers and beginners alike.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Reader’s note
DISCLAIMER:
RSC-4x mikroC and this manual are owned by mikroElektronika and are protected by copyright law and international copyright treaty. Therefore, you should treat this manual like any other copyrighted material (e.g., a book). The manual and the compiler may not be copied, partially or as a whole without the written consent from the mikroElektronika. The PDF-edition of the manual can be printed for private or local use, but not for distribution. Modifying the manual or the compiler is strictly prohibited.
HIGH RISK ACTIVITIES
The mikroC compiler is not fault-tolerant and is not designed, manufactured or intended for use or resale as on-line control equipment in hazardous environments requiring fail-safe performance, such as in the operation of nuclear facilities, aircraft navigation or communication systems, air traffic control, direct life support machines, or weapons systems, in which the failure of the Software could lead directly to death, personal injury, or severe physical or environmental damage ("High Risk Activities"). mikroElektronika and its suppliers specifically disclaim any express or implied warranty of fitness for High Risk Activities.
LICENSE AGREEMENT:
By using the RSC-4x mikroC compiler, you agree to the terms of this agreement. Only one person may use licensed version of RSC-4x mikroC compiler at a time.
Copyright © mikroElektronika 2003 - 2006.
This manual covers mikroC version 1.0.0.7 and the related topics. Newer versions may contain changes without prior notice.
COMPILER BUG REPORTS:
The compiler has been carefully tested and debugged. It is, however, not possible to guarantee a 100 % error free product. If you would like to report a bug, please contact us at the address [email protected]. Please include next information in your bug report:
- Your operating system
- Version of RSC-4x mikroC
- Code sample
- Description of a bug
CONTACT US:
mikroElektronika
Voice: + 381 (11) 30 66 377, + 381 (11) 30 66 378
Fax: + 381 (11) 30 66 379
Web: www.mikroe.com
E-mail: [email protected]
RSC, RSC-4x is a Registered trademark of Sensory company. Windows is a Registered trademark of Microsoft Corp. All other trade and/or services marks are the property of the respective owners.
page ii
RRSSCC-44xx mmiikkrrooCC UUsseerr’’ss mmaannuu
al
Table of Contents
CHAPTER 1
CHAPTER 2
CHAPTER 3
CHAPTER 4
CHAPTER 5
RSC-4x mikroC IDE
Building Applications
RSC-4x mikroC Specifics
RSC-4x mikroC Reference
RSC-4x mikroC Libraries
mikroC - C Compiler for Sensory RSC-4x microcontrollers
CHAPTER 1: RSC-4x mikroC IDE
Quick Overview
Code Editor
Code Explorer
Error Window
Integrated Tools
Keyboard Shortcuts
CHAPTER 2: Building Applications
Projects
Search and Include Paths
Source Files
Compilation
Output Files
Error Messages
CHAPTER 3: mikroC Specifics
Memory Types
On-Chip SRAM
On-Chip Technology RAM
ROM
External RAM
Memory Models
Address Spaces
Absolute Memory Locations
Language Extension
ANSI Compilance
Types Specifics
Memory Type Specifiers and Modifiers
Variables Allocation
Pointer Types
Qualifier const
Pointer Specifics
Strings Specifics
Specialized Types Conversions
Function Specifics
Interrupt Handlers
Reentrant Functions
Indirect Function Calls page iv
RSC-4x mikroC
making it simple...
14
16
19
21
22
23
25
36
37
37
38
33
33
35
35
29
30
31
32
26
26
28
28
38
39
40
40
42
43
1
6
7
2
3
8
10
13
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Startup Functions
Monitor Functions
Prologue/Epilogue Functions
Inline Assembler
Implementation Details
Compiled Stack
Passing Return Value
Interrupt Handling
MEDIUM and LARGE Memory Models
Runtime Library
CSTARTUP and SYSLIB Modules
Usage of Modules Written in Assembler
CHAPTER 4: mikroC RSC-4x Language Reference
Lexical Elements Overview
Whitespace
Whitespace in strings
Standard C Comments
C++ Style Comments
Nested Comments
Constants
Integer Constants
Long and Unsigned Suffixes
Decimal
Hexadecimal
Binary
Octal
Floating point constants
Character constants
Disambiguation
String Constants
Enumeration Constants
Pointer Constants
Constant Expression
Concepts
Objects and declarations
Scope and Visibility
Name Spaces
Duration
Types
Type Categories
Arithmetic Types
Floating-point Types
48
48
49
50
43
44
45
46
50
51
52
53
55
70
70
72
73
66
68
68
69
74
76
77
77
78
62
63
64
66
61
61
62
62
58
59
60
61
56
56
57
58 page v
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Enumerations
Anonymous Enum Type
Enumeration Scope
Void Type
Derived Types
Arrays
Array Initialization
Arrays in Expressions
Multi-Dimensional Arrays
Pointers
Pointers Declaration
Null Pointers
Pointer Arithmetic
Pointer Addition
Pointer Substraction
Structures
Structures Initialization and Declaration
Working with Structures
Structure Member Access
Accesing Nested Structures
Structure Uniqueness
Unions
Union Declaration
Bitfields
Fuction Calls
Bit Fields Access
Types Conversions
Standard Conversions
Arithmetic Conversions
Pointer Conversions
Explicit Types Conversions (Typecasting)
Declarations
Declarations And Definitions
Declarations And Declarators
Linkage
Storage Classes
Type Qualifiers
Typedef Specifier
Inline Assembler
Initialization
Functions
Function Declaration
Function Prototypes
Function Definition
Function Calls and Argument Conversions page vi
RSC-4x mikroC
making it simple...
99
99
100
100
101
102
103
104
96
97
97
98
91
93
94
95
87
89
90
91
84
85
85
86
82
82
83
83
79
80
81
81
104
105
106
107
109
110
111
112
113
113
114
115
116
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Operators
Operators Precedence and Associativity
Arithmetic Operators
Binary Arithmetic Operators
Unary Arithmetic Operators
Relational Operators
Relational Operators in Expressrions
Bitwise Operators
Bitwise Shift Operators
Bitwise vs. Logical
Logical Operators
Conditional Operator ?
Conditional Operator Rules
Assigment Operators
Sizeof Operators
Expressions
Comma Expressions
Statements
Labeled Statements
Expression Statements
Iteration Statements
Jump Statements
Break And Continue Statements
Compound Statements (Blocks)
Preprocessor
Preprocessor Directives
Line Continuation with Backslash (\)
Macros
Conditional Compilation
Directives #ifdef and #ifndef
CHAPTER 5: RSC-4x mikroC Libraries
RSC-4x mikroC Libraries
C Ctype Library
C Math Library
C stdio.h Library
C Stdlib Library
C String Library
Built-in Routines
Compact Flash Library
LCD Library (4-bit interface)
Software I2C Library
Software SPI Library
Concat Us
151
152
153
157
163
170
175
183
186
190
196
203
206
140
141
141
142
148
149
128
130
130
131
134
137
137
140
122
123
123
125
126
126
127
128
117
117
118
119
119
120
120
121 page vii
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC
making it simple...
page viii
CHAPTER
1
RSC-4x mikroC IDE
QUICK OVERVIEW
RSC-4x mikroC is a powerful, feature rich development tool for Sensory RSC-4x micros. It is designed to provide the customer with the easiest possible solution for developing applications for embedded systems, without compromising performance or control.
RSC-4x mikroC provides a successful match featuring highly advanced IDE,
ANSI compliant compiler, broad set of hardware libraries, comprehensive documentation, and plenty of ready-to-run examples.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Code
Explorer
Code
Editor
Project
Summary
Error
Window
Code
Assistant
RSC-4x mikroC allows you to quickly develop and deploy complex applications:
- Write your C source code using the highly advanced Code Editor
- Use the included RSC-4x mikroC libraries to dramatically speed up the development: data acquisition, memory, displays, conversions, communications…
- Monitor your program structure, variables, and functions in the Code Explorer.
Generate commented, human-readable assembly, and standard HEX compatible with all programmers.
- We have provided plenty of examples for you to expand, develop, and use as building bricks in your projects.
page
2
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
CODE EDITOR
The Code Editor is an advanced text editor fashioned to satisfy the needs of professionals. General code editing is same as working with any standard text-editor, including familiar Copy, Paste, and Undo actions, common for Windows environment.
Advanced Editor features include:
- Adjustable Syntax Highlighting
- Code Assistant
- Parameter Assistant
- Code Templates (Auto Complete)
- Auto Correct for common typos
- Bookmarks and Goto Line
Tools Icon.
You can customize these options from the Editor Settings dialog. To access the settings, choose Tools > Options from the drop-down menu, or click the Tools icon.
page
3
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Code Assistant [CTRL+SPACE]
If you type a first few letter of a word and then press CTRL+SPACE, all the valid identifiers matching the letters you typed will be prompted in a floating panel (see the image). Now you can keep typing to narrow the choice, or you can select one from the list using the keyboard arrows and Enter.
Parameter Assistant [CTRL+SHIFT+SPACE]
The Parameter Assistant will be automatically invoked when you open a parenthesis "(" or press CTRL+SHIFT+SPACE. If name of a valid function precedes the parenthesis, then the expected parameters will be prompted in a floating panel. As you type the actual parameter, the next expected parameter will become bold.
page
4
Code Template [CTRL+J]
You can insert the Code Template by typing the name of the template (for instance, whileb), then press CTRL+J, and the Code Editor will automatically generate the code. Or you can click a button from the Code toolbar and select a template from the list.
You can add your own templates to the list. Just select Tools > Options from the drop-down menu, or click the Tools Icon from Settings Toolbar, and then select the Auto Complete Tab. Here you can enter the appropriate keyword, description, and code of your template.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Auto Correct
The Auto Correct feature corrects common typing mistakes. To access the list of recognized typos, select Tools > Options from the drop-down menu, or click the
Tools Icon, and then select the Auto Correct Tab. You can also add your own preferences to the list.
Comment/Uncomment
Comment /
Uncomment Icon.
The Code Editor allows you to comment or uncomment selected block of code by a simple click of a mouse, using the Comment/Uncomment icons from the Code
Toolbar.
Bookmarks
Bookmarks make navigation through large code easier.
CTRL+<number> : Go to a bookmark
CTRL+SHIFT+<number> : Set a bookmark
Goto Line
Goto Line option makes navigation through large code easier. Select Search >
Goto Line from the drop-down menu, or use the shortcut CTRL+G.
page
5
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
CODE EXPLORER
The Code Explorer is placed to the left of the main window by default, and gives a clear view of every declared item in the source code. You can jump to a declaration of any item by clicking it, or by clicking the Find Declaration icon. To expand or collapse treeview in Code Explorer, use the Collapse/Expand All icon.
Collapse/Expand
All Icon.
Also, two more tabs are available in Code Explorer. QHelp Tab lists all the available built-in and library functions, for a quick reference. Double-clicking a routine in QHelp Tab opens the relevant Help topic. Keyboard Tab lists all the available keyboard shortcuts in RSC-4x mikroC.
page
6
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Simulator
Start Debugger
The source-level Debugger is not an integral component of RSC-4x mikroC development environment. RSC-4x mikroC compiler uses The PDS-SE simulator and
PICE-SE emulator that have the same user interface and the same program developing and debugging capabilities.
After you have successfully compiled your project, you can simulate and debug the code in the external PDS-SE Phyton Simulator. To select the Simulator, select
Debugger › Select Tool › External Simulator from the drop-down menu.
Beside external simulator, you can emulate the code.To choose external emulator from Debugger › Select Tool › External Emulator.
For more info refer to The PDS-SE simulator and PICE-SE emulator help or go to http://www.phyton.com/
ERROR WINDOW
In case that errors were encountered during compiling, the compiler will report them and won't generate a hex file. The Error Window will be prompted at the bottom of the main window by default.
The Error Window is located under the message tab, and displays location and type of errors compiler has encountered. The compiler also reports warnings, but these do not affect the output; only errors can interefere with generation of hex.
Double click the message line in the Error Window to highlight the line where the error was encountered.
Consult the Error Messages for more information about errors recognized by the compiler.
page
7
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
INTEGRATED TOOLS
USART Terminal
RSC-4x mikroC includes the USART (Universal Synchronous Asynchronous
Receiver Transmitter) communication terminal for RS232 communication. You can launch it from the drop-down menu Tools > Terminal or by clicking the
Terminal icon.
ASCII Chart
The ASCII Chart is a handy tool, particularly useful when working with LCD display. You can launch it from the drop-down menu Tools > ASCII chart.
page
8
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
7 Segment Display Decoder
The 7seg Display Decoder is a convenient visual panel which returns decimal/hex value for any viable combination you would like to display on 7seg. Click on the parts of 7 segment image to get the desired value in the edit boxes. You can launch it from the drop-down menu Tools > 7 Segment Display.
page
9
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
KEYBOARD SHORTCUTS
Below is the complete list of keyboard shortcuts available in RSC-4x mikroC IDE.
You can also view keyboard shortcuts in Code Explorer window, tab Keyboard.
IDE Shortcuts
F1
CTRL+N
Help
New Unit
CTRL+O Open
CTRL+F9 Compile
CTRL+F11
CTRL+SHIFT+F5
Code Explorer on/off
View breakpoints
Basic Editor shortcuts
F3
CTRL+A
CTRL+C
CTRL+F
CTRL+H
CTRL+P
CTRL+R
CTRL+S
CTRL+SHIFT+S
CTRL+V
CTRL+X
CTRL+Y
CTRL+Z
Advanced Editor shortcuts
Find, Find Next
Select All
Copy
Find
Replace
Replace
Save unit
Save As
Paste
Cut
Redo
Undo
CTRL+SPACE
CTRL+SHIFT+SPACE
CTRL+D
CTRL+G
Code Assistant
Parameters Assistant
Find declaration
Goto line
CTRL+J Insert Code Template
CTRL+<number> Goto bookmark
CTRL+SHIFT+<number> Set bookmark
CTRL+SHIFT+I
CTRL+SHIFT+U
Indent selection
Unindent selection page
10
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
ALT+SELECT Select columns
Debugger Shortcuts
F9 Debug
For other debugger shortcuts refer to the Phyton PDS-SE documentation.
page
11
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC
making it simple...
page
12
CHAPTER
2
Building
Applications
Creating applications in RSC-4x mikroC is easy and intuitive. Project Wizard allows you to set up your project in just few clicks: name your application, select chip, set flags, and get going.
RSC-4x mikroC allows you to distribute your projects in as many files as you find appropriate. You can then share your RSC-4x mikroC compiled Libraries ( .mcl
files) with other developers without disclosing the source code.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
PROJECTS
RSC-4x mikroC organizes applications into projects which consist of a single project file, with extension .psc, and one or more added files (C, assembler, and object/library files, with extensions .c, .mca, .mco/.mcl respectively). You can compile source files only if they are part of a project.
Before we start managing projects, we should introduce some terms that we’ll be using throughout the documentation:
Source file
Source file is either C file with extension c or assembler file with the extension mca. Source files can be compiled/assembled only if they are part of a project. See
Source Files for more information.
Project file
Project file is a file with extension psc which holds all the information regarding your project. The project file carries the following data:
- project name and optional description,
- project path,
- target device,
- memory model,
- device clock,
- wait states,
- memory address area settings,
- list of project files,
- search paths,
- include paths.
Project folder
Project folder is the folder in which the project file is stored. This folder is automatically added to the project’s search path list.
Project
Project is a collection of all source files (C files, MCA files, header files) and object/library files (MCO/MCL files) relevant to the project. The project file binds them all together. Note that project added files have nothing to do with the preprocessor; see Add/Remove Files from Project below. page
14
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
New Project.
New Project
The easiest way to create project is by means of New Project Wizard, drop-down menu Project > New Project. Just fill the dialog with desired values (project name and description, location, device, clock, config word) and RSC-4x mikroC will create the appropriate project file. Also, an empty source file named after the project will be created by default.
In the following dialog, enter the project name and optional description.
page
15
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Edit Project.
Editing Project
Later, you can change project settings from drop-down menu Project > Edit
Project. You can rename the project, modify its description, change chip, clock, config word, etc. To delete a project, simply delete the folder in which the project file is stored.
Add/Remove Files from Project
Add to Project.
Remove from
Project.
Project can contain any number of source files (extension
.c
) or or assembler files with extension .mca. The list of relevant source files is stored in the project file
(extension
.psc
). To add source file to your project, select Project > Add to
Project from drop-down menu. Each added source file must be self-contained, i.e.
it must have all the necessary definitions after preprocessing. To remove file(s) from your project, select Project > Remove from Project from drop-down menu.
Note: For inclusion of header files, use the preprocessor directive
#include
.
Search and Include Paths
Search paths are absolute or relative paths which tell the compiler where to look for files added to the project. Search paths are specific for each project and are stored in the project file.
Include paths are absolute or relative paths which tell the compiler where to look for header files included by the preprocessor. Include paths are specific for each project and are stored in the project file.
Do not confuse search paths and include paths. Although both lists are managed from the same window, they are totally separate categories. Search paths cover all files in the project, whereas include paths deal only with header files included by the preprocessor. There is a dropdown menu for choosing between absolute or relative paths for search and include paths.
page
16
RSC-4x mikroC
making it simple...
Search Paths
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Search paths (paths to source files) are specific for each project and are stored in the project file (.psc). To manage search paths, open Tools › Options from the drop-down menu and then select Search Path. The upper box in the dialog contains the list of project’s search paths.
To add search path, click Add and browse to the location of the file that you wish to add. Click OK and you’ll see your path added to the list. To remove the path, select it and click Remove.
The default search path is the folder in which the project is stored. Greyed out items represent invalid paths (i.e. non-existent folders). You can purge invalid paths with the Purge Invalid Paths button, which is useful when porting your projects to another computer.
The order of specified paths is important and determines the order in which the compiler looks for files. It will scan the list of locations from the top, and will stop as soon as the requested file is found.
Include Paths
Header files are included by means of preprocessor directive #include . Do not use the preprocessor to include source files other than headers; instead, see
Add/Remove Files from Project.
Include paths tell the compiler where to look for header files, when they are requested with the preprocessor directive #include . Include paths are specific for each project and are stored in the project file (.psc). To manage include paths, open Tools › Options from the drop-down menu and then select Search Path. The lower box in the dialog contains the list of project’s include paths.
By default, the compiler looks for specified header files in RSC-4x mikroC installation folder › “include” folder. This is the default include path which cannot be changed. You can purge invalid paths with the Purge Invalid Paths button, which is useful when porting your projects to another computer.
page
17
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Extended functionality of the Project Files tab
By using the Project Files' new features, you can reach all the output files (.lst,
.asm) by a single click. You can also include in project the library files (.mcl), for libraries, either your own or compiler default, that are project-specific.
page
18
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
SOURCE FILES
In RSC-4x mikroC, source file is either C file with extension .c or assembler file with extension .mca. The list of source files relevant to your application is stored in the project file (extension .psc), along with other project information. A source file can only be compiled if it’s a part of a project.
Use the preprocessor directive
#include to include headers. Do not rely on preprocessor to include other source files — see Projects for more information.
Managing Source Files
New File.
Creating a new source file
To create a new source file, do the following:
Select File > New from drop-down menu, or press CTRL+N, or click the New
File icon. A new tab will open, named “Untitled1”. This is your new source file.
Select File > Save As from drop-down menu to name it the way you want.
If you have used New Project Wizard, an empty source file, named after the project with extension
.c
, is created automatically. RSC-4x mikroC does not require you to have source file named same as the project, it’s just a matter of convenience.
Open File Icon.
Opening an Existing File
Select File > Open from drop-down menu, or press CTRL+O, or click the Open
File icon. The Select Input File dialog opens. In the dialog, browse to the location of the file you want to open and select it. Click the Open button.
The selected file is displayed in its own tab. If the selected file is already open, its current Editor tab will become active.
Print File Icon.
Printing an Open File
Make sure that window containing the file you want to print is the active window.
Select File > Print from drop-down menu, or press CTRL+P, or click the Print icon. In the Print Preview Window, set the desired layout of the document and click the OK button. The file will be printed on the selected printer.
page
19
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Saving File
Save File Icon.
Make sure that window containing the file you want to save is the active window.
Select File > Save from drop-down menu, or press CTRL+S, or click the Save icon. The file will be saved under the name on its window.
Saving File Under a Different Name
Save File As.
Make sure that window containing the file you want to save is the active window.
Select File > Save As from drop-down menu, or press SHIFT+CTRL+S. The New
File Name dialog will be displayed. In the dialog, browse to the folder where you want to save the file. In the File Name field, modify the name of the file you want to save. Click the Save button.
Closing a File
Close File.
Make sure that tab containing the file you want to close is the active tab. Select
File > Close from drop-down menu, or right click the tab of the file you want to close in Code Editor. If the file has been changed since it was last saved, you will be prompted to save your changes. page
20
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
COMPILATION
Compile Icon.
When you have created the project and written the source code, you will want to compile it. Select Project > Build from drop-down menu, or click Build Icon, or simply hit CTRL+F9.
Progress bar will appear to inform you about the status of compiling. If there are errors, you will be notified in the Error Window. If no errors are encountered,
RSC-4x mikroC will generate output files.
Upon successful compilation, RSC-4x mikroC will generate an assembler file for each C source file. These output files will be created in the approprate folder
(folder which contains the original C source file).
View Assembly
Icon.
After compiling your project in RSC-4x mikroC, you can click the View
Assembler icon (View › View Assembler) to review the generated assembly code in a new tab. The option will display the assembler file (.
mca ) corresponding to the currently active C file in IDE. More information can be found in in the list file
(.
lst ).
Then, the created assembler files and other assembler files you included in the project will be fed to the external assembler MCA-SE. Upon succesful assembling, an object file (extension .
mco ) will be created for each assembler file.
These object files together with object/library files you included in the project and default libraries will be fed to the external MCLINK linker, which will produce the hex file and the debug MCE file.
See Output Files for more information.
Compilation Options
You should check the compilation options before building your projects. Open
Project › Build from the drop-down menu and then select Cross Tools.
page
21
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Output Files
Output files are summarized in the table below:
.mcl
.hex
.dat
.mce
Filetype
.cp
.mca
.mco
.lst
Filetype
File containing the preprocessor output. Preprocessor output files are helpful for debugging complex macros.
Assembler source file generated from C source code. These files can be assembled with the MCA-SE assembler.
Created By
Preprocessor
Relocatable object file that contains relocatable object code.
Relocatable object files may be linked to an absolute object file using the MCLINK linker.
Listing file that contains the source text, generated assembler code, and all errors and warnings that were produced by the compiler. Listing file is optional, see Compilation Options.
Library file generated by the MCLIB Librarian from the relocatable object files.
Absolute Intel HEX file for CODE and CONST memory.
Absolute Intel HEX file for DATA memory.
Executable MCE-file in MicroCOSM-ST/Phyton format. This file contains executable code and debugging information and can be used for debugging with the Phyton IDE.
RSC-4x mikroC
Compiler
MCA-SE
Assembler
MCA-SE
Assembler
MCLIB
Librarian
MCLINK linker
MCLINK linker
MCLINK linker page
22
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
ERROR MESSAGES
Error Messages
- Specifier needed
- Invalid declarator
- Expected '(' or identifier
- Integer const expected
- Array dimension must be greater then 0
- Local objects cannot be extern
- Declarator error
- Bad storage class
- Arguments cannot be of void type
- Specifer/qualifier list expected
- Address must be greater than 0
- Identifier redefined
- case out of switch
- default label out of switch
- switch exp. must evaluate to integral type
- continue outside of loop
- break outside of loop or switch
- void func cannot return values
- Unreachable code
- Illegal expression with void
- Left operand must be pointer
- Function required
- Too many chars
- Undefined struct
- Nonexistent field
- Aggregate init error
- Incompatible types
- Identifier redefined
- Function definition not found
- Signature does not match
- Cannot generate code for expression
- Too many initializers of subaggregate
- Nonexistent subaggregate
- Stack Overflow: func call in complex expression
- Syntax Error: expected %s but %s found
- Array element cannot be function
- Function cannot return array page
23
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
- Inconsistent storage class
- Inconsistent type
- %s tag redefined
- Illegal typecast
- %s is not a valid identifier
- Invalid statement
- Constant expression required
- Internal error %s
- Too many arguments
- Not enough parameters
- Invalid expresion
- Identifier expected, but %s found
- Operator [%s] not applicable to this operands [%s]
- Assigning to non-lvalue [%s]
- Cannot cast [%s] to [%s]
- Cannot assign [%s] to [%s]
- lvalue required
- Pointer required
- Argument is out of range
- Undeclared identifier [%s] in expression
- Too many initializers
- Cannot establish this baud rate at %s MHz clock
Compiler Warning Messages
- Highly inefficent code: func call in complex expression
- Inefficent code: func call in complex expression page
24
CHAPTER
3
RSC-4x mikroC
Specifics
RSC-4x mikroC is a powerful, feature rich development tool for Sensory RSC-4x microcontrollers. It is designed to provide the programmer with the easiest possible solution for developing applications for embedded systems, without compromising performance or control.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Memory Types
RSC-4x mikroC compiler provides effective access to all RSC-4x chip memory types except the on-chip technology RAM:
On-chip SRAM. This is the register file consisting of the non-banked area and several memory banks. The 64 byte “window” is used to access the banked area.
Only a part of the on-chip SRAM is available for the user’s program; the rest is reserved for the Sensory technology library.
ROM. Read-only or flash memory accessed with the RDR/WRC signals. On the logical level, ROM can contain executable code (code area) and constant data
(data area). On the physical layer, ROM can be ether all internal or all external, but not both. The access methods for both external and internal ROM are the same.
External RAM. RSC-4x chips can be equipped with external memory of various physical types. Moreover, some applications have no external memory at all. The compiler distinguishes three types of external memory: non-persistent data memory (RAM), persistent writeable memory without predefined values (e.g. nonvolatile RAM) and persistent writeable memory (e.g. flash).
On-chip SRAM
The following areas are available for the user’s C program:
0h – 0Bh (Global Register Area);
3Ah – 7Fh (Non-Banked Area);
80h – BFh (Banks 0h, 0Ah, 0Bh).
Other on-chip SRAM memory locations are reserved for using by the Sensory technology library.
The locations 3Ah – 7Fh and 80h – BFh (Bank 0h) are treated as a contiguous region used for allocation of C program data: static variables and statically placed in the compiled stack automatic variables, function parameters and temporaries.
Note that functions written in assembler should always clear the lower four bits of register BANK before passing control to a C function – either by call or return.
page
26
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Banks 0Ah and 0Bh hold the dynamic stack. The dynamic stack is used as a call stack (i.e. holds return addresses of C functions); also it is used to hold the frames of previously invoked reentrant functions and contents of temporary registers during interrupt handling.
Global Register Area locations are used to pass the return address to the called C function, to return the function return value to the caller, and serve as temporaries for expression evaluation.
_tempArea
_returnAddress
_returnValue
?R11
?R10
?R9
?R8
?R7
?R6
?R5
?R4
?R3
?R2
?R1
?R0
page
27
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
On-chip Technology RAM
On-chip technology RAM is used by Sensory technology library only. C program variables can not be allocated in this memory.
ROM
On the logical level, ROM can contain executable code (code area) and constant data (data area). On the physical layer, ROM can be ether all internal or all external, but not both. The access methods for both external and internal ROM are the same. Application may contain either one 64K ROM page (page 0), or several
64K pages up to 1M.
Static constant variables can be placed in ROM (read-only or flash memory) accessed with the RDR/WRC signals, i.e. CONST address space. The declaration of such variables should contain either memory type specifier cdata or qualifier const with the compilation option “const vars in CDATA area”.
Compiler distinguishes two types of cdata memory:
1. Located on page 0, i.e. in the range 0..0FFFFh
2. Located anywhere in the range 0..0FFFFFh
Memory type modifiers near and far can be used in cdata variable declarations.
The allocation of a cdata variable declared without a memory type modifier will depend on the memory model. The size of a pointer to near cdata object is 2 bytes and the size of pointer to far cdata object is 3 bytes.
The near cdata objects are accessed by MOVC instruction. The far cdata objects are accessed by MOVX instruction with setting bits 0..3 of the ExtAddr register. The bit RW (bit 4 of ExtAddr) should be cleared when any C function is executed.
Note: The driver functions should restore the initial ExtAddr value upon return.
You can use the compilation option “constant CDATA variables” (Cross Tools) which will consider each variable declared with cdata memory type specifier to be const also (i.e. on any attempt to modify it the compiler will generate the error message).
If the CONST address space represents writeable flash memory, uncheck the option “constant CDATA variables” to place non-constant objects there.
page
28
RSC-4x mikroC
making it simple...
External RAM
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x chips can be equipped with external memory of various physical types.
Moreover, some applications have no external memory at all.
The compiler distinguishes three types of external memory:
- Non-persistent data memory (RAM) represented by address space DATA.
Variables located in this memory are initialized during C program startup.
- Persistent writeable memory without predefined values (e.g. non-volatile RAM) represented by address space NDATA. Variables located in this memory are not initialized at startup; no initializers are allowed with ndata variable declarations.
- Persistent writeable memory with predefined values (e.g. flash) represented by address space FDATA. Variables located in this memory are not initialized at startup, instead, the initial values are put directly into the memory locations for fdata variables. The linker creates a separate HEX file for address space FDATA.
To allocate a variable in the external memory the user should declare this variable with one of the memory type specifiers – data, ndata or fdata. Variables declared with such specifiers are put in the corresponding relocatable segments. Their address size is 3 bytes.
Since the compiler does not know what specific method should be implemented to
access data/ndata/fdata external memory, three sets of special driver functions are used to access the external memory locations. Templates of the special driver functions written in assembler are included in the compiler distribution package.
The user can modify their implementation, if necessary.
If fdata represents memory with no write access then the user should set the option “fdata variables are read only” in the Edit Project dialog (drop-down menu
Project › Edit Project). In this case, the compiler will treat any fdata variable as if declared with the type qualifier const, and will generate the error message on any attempt to modify it. Individual fdata variables can be declared as const explicitly.
page
29
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Memory Models
The memory model determines the following C program features:
- Maximum code size (and code generated for the function calls).
- Availability of external RAM.
Memory model
Code placed on page 0 only
SMALL yes
COMPACT yes
MEDIUM
LARGE no no
cdata modifier by default
near near far far
data / ndata / fdata allowed
no yes no yes
The memory model is specified in the Edit Project dialog (drop-down menu
Project › Edit Project).
page
30
RSC-4x mikroC
making it simple...
Address Spaces
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Address space Allocation Description
CODE
CONST
REG
DATA
NDATA
FDATA code const reg data ndata fdata
Instructions
Constants, string literals and initializers
Static register variables, compiled stack
Static data variables
Static ndata variables
Static fdata variables
The address range of CODE address space for SMALL and COMPACT memory models is 0..0FFFFh, for MEDIUM and LARGE memory models is 0..1FFFFh.
By default, DATA address space range is 0..0FFFFFh. You can set the appropriate address range from the Edit Project dialog (drop-down menu Project › Edit
Project).
If there is no FDATA (or NDATA) memory, this should be specified in the Edit
Project dialog (drop-down menu Project › Edit Project). In this case, the compiler will check that there are no fdata (or ndata) variables in the C program.
Otherwise, the user should define the address space FDATA (with allocation data) and set the appropriate address range, again from the Edit Project dialog. The same must be done for NDATA when non-volatile RAM is used.
page
31
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Absolute Memory Locations
There are built-in definitions for several function-like macros to access absolute memory locations.
Accessing Absolute Memory Locations
__BYTE_AT__
__WORD_AT__
__DWORD_AT__
These macros allow the developer to access individual bytes, words and double words in the on-chip SRAM and SFR’s. The main purpose of using these macros is to provide access to the on-chip SRAM memory locations defined outside the
C-written modules.
These built-in macros can be considered as if the following macros were defined in the program source text:
#define __BYTE_AT__(addr) (*(volatile unsigned char *)(addr))
#define __WORD_AT__(addr) (*(volatile unsigned int *)(addr))
#define __DWORD_AT__(addr) (*(volatile unsigned long *)(addr))
Note: The volatile keyword prevents the compiler from making any optimizations.
Example:
#define MyByte (__BYTE_AT__(0x49))
#define MyWord (__WORD_AT__(0x4A))
#define MyDword (__DWORD_AT__(0x4C)) int a; void main(void) { /* some meaningless actions */
/* only for illustration */ a = MyByte * 10;
MyWord = a;
MyDword = a + 1;
}
If the built-in macros __BYTE_AT__ , __WORD_AT__ and __DWORD_AT__ are used inside inline assembler blocks, these macros are directly expanded as the values of their arguments (the typecast-containing expressions may not be used inside builtin assembler blocks).
page
32
RSC-4x mikroC
making it simple...
Language Extensions
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The following topics provide details of the RSC-4x mikroC language extensions:
ANSI Compliance
Types Specifics
Functions Specifics
Linker Directives
Inline Assembler
Pragma Directives
ANSI Compilance
RSC-4x mikroC compiler was built according to ISO/IEC 9899-1990 and
ANSI/ISO 98991990 standards (except for the extensions and restrictions described below). These standards are practically identical, therefore the word
“standard” will be used for referencing them both.
The standard defines two forms of conforming compiler implementations:
1. A conforming hosted implementation must correctly compile any program, which strictly conforms to the language standard.
2. A conforming freestanding implementation must correctly compile any strictly conforming program, in which the use of the standard C library features is confined to the contents of the standard headers: <float.h>, <limits.h>, <stdarg.h>,
<stddef.h>.
It is impossible to create a strictly conforming library for single-chip microcontrollers. For example, it is not possible to implement all file access functions.
Thus, the RSC-4x mikroC is not a conforming hosted implementation.
However, as the standard headers <float.h>, <limits.h>, <stdarg.h>, <stddef.h> and related library functions are fully implemented in accordance with the standard, the RSC-4x mikroC is a conforming freestanding implementation with the exception for a few hardware-specific restrictions.
page
33
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Extensions
The standard extensions implemented in RSC-4x mikroC can be divided in two groups:
- Hardware-specific extensions. This includes memory type specifiers and modifiers.
- Common extensions, such as integer binary constants and C++ style comments.
Restrictions
RSC-4x mikroC has the following restrictions compared to the standard:
- double and long double types representation;
- Function reentrancy support. Functions are not considered as reentrant, by default. A function can be declared reentrant (called either by recursion or both from the main thread and interrupt handler) by the special #pragma reentrant .
Some additional restrictions are applied to functionality of reentrant functions. page
34
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Types Specifics
Memory Type Specifiers and Modifiers
The user can select the memory type for placing a variable using a memory type specifier. Also, memory type specifier can be used in pointer type declaration if the pointer holds addresses in the specific memory.
Additionally, memory type modifiers can be used to specify the memory range where cdata variables are to be placed in.
The memory type specifiers and modifiers can be used in variable declarations, pointer type declarations of variables, pointers and type definitions (with typedef).
Type constructed using a memory type specifier/modifier is called a specialized
type.
Note: The memory type specifiers and modifiers are additional keywords.
Note: For standard type modifiers see Storage Classes and Type Qualifiers.
Specifiers
Specifier data
Description
Variables in the external RAM initialized during startup.
Special driver functions are used to access these variables.
ndata fdata cdata
Variables in the external RAM not initialized during startup.
Special driver functions are used to access these variables.
Variables in the external FLASH not initialized during startup.
Instead, the initial values are put in memory locations
“directly” - the linker creates a separate HEX file with initial values. zero is used. Special driver functions are used to access these variables.
Constants placed in ROM. These constants are accessed by the
MOVC or MOVX instructions in accordance with the given memory type modifier (see below). zero is used.
page
35
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Modifiers
Modifier near
Description
A cdata variable that will be placed in the page 0 of ROM; it has a 16-bit address.
far
A cdata variable that will be placed in any ROM page; it has a
20-bit address.
Variables Allocation
Memory type specifiers can be used in declaration of variables with static storage duration only. It is not allowed to use specifiers in declaration of automatic variables, functions, function parameters, structure and union members.
If a static or external variable is declared as const with no explicit memory type specifier and the compiler option “const vars in CDATA area” (Cross Tools) is checked, the variable is deemed to have the cdata specifier. Variables without explicit memory type specifiers are allocated in the on-chip SRAM. Therefore the
register keyword in declaration of an automatic variable or a function parameter is unnecessary and is ignored.
Memory type modifiers can be used with cdata variables only. The allocation of a
cdata variable declared with the cdata specifier and without any memory type modifiers will depend on the memory model.
Examples – Using the memory type specifiers: data int n; /* variable allocated in "data" memory */ ndata char c; /* variable allocated in "ndata" memory */ long k; /* variable allocated in on-chip SRAM */ page
36
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Pointer Types
Memory type specifier can be used in a pointer type declaration. In this case, the compiler will treat the pointer value as an address in the specific memory and will generate an appropriate instruction sequence when the pointer needs to be dereferenced. A pointer declared without a memory type specifier is treated as the pointer to the on-chip SRAM. The size of pointer type is determined by the memory type specifier (or absence of the specifier).
Note the difference between two pointer declarations:
/* variable allocated in the on-chip SRAM and points into "data" */ data int * p;
/* variable allocated in "data" and points into on-chip SRAM */ int * data q;
Qualifier
const
If a static or external variable is declared as const with no explicit memory type specifier and the compiler option “const vars in CDATA area” is checked, the variable is deemed to have the cdata specifier. If this option is unchecked, such variables are allocated in the on-chip RAM (as variables without explicit memory type specifiers).
page
37
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Pointer Specifics
This topic is an overview of specialized pointer types, constructed with memory type specifiers and modifiers. For more details on pointers syntax and usage see
Pointers.
Data type Bytes Aligment Comment
*
1
data * fdata * ndata * near cdata *
3
3
3
2 none Pointer to the on-chip SRAM none none none
Pointer to the external RAM. If dereferenced the special driver function call is generated.
Pointer to the external RAM. If dereferenced the special driver function call is generated.
Pointer to the external RAM. If dereferenced the special driver function call is generated.
word Pointer to ROM page 0.
far cdata *
3 word
Pointer to ROM. The third byte contains 4 higher bits of the address.
pointer to function,
SMALL/COMPACT memory model pointer to function,
MEDIUM/LARGE memory model
Strings Specifics
3
4 word word
Pointer to ROM. The third byte contains 4 higher bits of the address; the highest byte is not used.
Pointer to ROM. The third byte contains 4 higher bits of the address; the highest byte is not used.
By default, the compiler will store string constants (string literals) according to the destination’s type. See Memory Type Specifiers and Modifiers and Memory
Models.
If the option “store string literals in CDATA area” in Cross Tools (Tools ›
Options) is enabled, all string constants will be linked in the CDATA area.
page
38
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Specialized Types Conversions
Two specialized types are compatible if their memory type specifiers (and modifiers) are equivalent and they are compatible in terms of ANSI standard.
The implicit conversion from a specialized type to a corresponding non-specialized type is always allowed. Backward conversion (from a non-specialized to a specialized version) is not allowed because only lvalue have the specialized type
(the result of type conversion is rvalue).
Pointers to Specialized Types
The following explicit and implicit conversions of pointers to specialized types are allowed (if the corresponding conversion of pointers to non-specialized types is allowed by C standard):
Implicit conversion of pointers to specialized types:
Data Type fdata * ndata * near cdata * ndata *
Result Type data * far cdata *
Explicit conversion of pointers to specialized types:
Data Type fdata * fdata * data * ndata * far cdata *
Result Type data * ndata * fdata * fdata * near cdata *
page
39
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers page
40
Since any pointer declared without an explicit memory type specifier is considered to be a pointer into the on-chip SRAM, any explicit or implicit conversion of a pointer to specialized type into a pointer to non-specialized type is not allowed.
All reverse conversions (from pointer to non-specialized type into pointer to specialized type) are not allowed as well.
If some implicit conversion is allowed, it can be written in the explicit form also.
The pointer to a function may not be converted to void* and back (neither explicitly, nor implicitly).
Functions Specifics
Following topics cover the implementation specifics of functions:
- Interrupt Handlers
- Reentrant Functions
- Indirect Function Calls
- Startup Functions
- Prologue/Epilogue Functions
- Monitor Functions
Interrupt Handlers
The following directive
#pragma interrupt <interrupt_number> <function_name> lets the compiler know that the function function_name is an interrupt handler for the interrupt with interrupt_number.
The interrupt handler must be declared as void, have no parameters, and must be defined in the same source file where the corresponding #pragma interrupt directive appears.
The compiler uses a special mechanism to set the interrupt handler vector for the declared interrupt handler. Also, compiler adds a special prolog and epilog to the interrupt handler code (the prolog saves the necessary registers on the dynamic stack, the epilog restores them). See Interrupt Handling for the implementation details.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Note: Two or more interrupt handlers may not be assigned to one interrupt.
However, a function may be used as a handler for several interrupts.
The function declared as an interrupt handler should not be called in the user’s program, either directly or indirectly (by a pointer to function). The compiler generates the warning message if an interrupt handling function is called or its address is taken.
Example:
#pragma interrupt 00 timer1_isr
...
void timer1_isr(void) {
/* user code */
}
Interrupt numbers and associated vectors:
Interrupt #
0
1
2
3
4
5
6
Address
04h
08h
0Ch
10h
14h
18h
1Ch
Interrupt source
Timer 1 overflow
Timer 2 overflow
Positive edge of Filter End Marker
Positive edge of P00
Timer 3 overflow
Block End
Positive edge of P02
Note: SFR definition files RSC4xxx.h
contain definitions for SFR bits. Thus, the developer can access particular bits in SFR. For example, to disable Interrupt #1
(Timer 2 overflow) you can write the following:
IMR1 = 0; /* produces code: AND IMR, #0FDh */
You should not clear the bits in the IRQ register using bit names defined in
RSC4xxx.h (the IRQ bits should be cleared by an explicit MOV only rather than
AND ). For example, in order to clear the Interrupt #1 request bit, you should write the following:
IRQ = 0xFD; /* produces code: MOV IRQ, #0FDh */ page
41
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Reentrant Functions
The function is reentrant if it may be called either recursively or both from the main thread and from an interrupt handler. Functions are not considered reentrant, by default. The function can be declared reentrant with the special #pragma directive:
#pragma reentrant <func_name>
If the function is reentrant, the corresponding #pragma must be placed in all source modules where this function is implemented, declared or called (the easiest is to place #pragma reentrant in the header file containing the function declaration).
The reentrant function call requires additional overhead. Moreover, the support for reentrant functions results in the following restrictions that violate the C standard:
- Total size of reentrant function parameters must not exceed 4 bytes, since the
_tempArea field of GlobalRegisterArea is used for passing the reentrant function parameters.
- Reentrant functions with ellipsis (variable number of arguments) are not supported.
A reentrant function return value cannot have a structure type, i.e. reentrant function cannot return a structure (but can return a pointer to structure).
- Local objects (automatic variables and actual function parameters) of the previous invocations of reentrant functions are inaccessible from the current reentrant function invocation (because they can be overwritten by the current reentrant function frame, see Compiled Stack for details). Also, only local objects of the last invocation of reentrant function can be accessed from non-reentrant functions.
Example:
#pragma reentrant func
...
void func(char counter) {
...
if (++counter < 10) func(counter);
...
}
Note: Local objects of all non-reentrant functions’ previous invocations can be accessed from both reentrant and non-reentrant function invocations.
page
42
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The linker checks if a function may possibly be activated two or more times simultaneously in the user's program. If it encounters such a function with a nonempty frame (the function has automatic variables or parameters) and the function is not declared as reentrant, the linker generates the error message.
Indirect Function Calls
If the linker encounters an indirect function call (by a pointer to function), it assumes that any one of the functions, addresses of which were taken anywhere in the program, can be called at that point. Use the #pragma funcall directive to instruct the linker which functions can be called indirectly from the current function:
#pragma funcall <func_name> <called_func>[, <called_func>,...]
A corresponding pragma must be placed in the source module where function func_name is implemented. This module must also include declarations of all functions listed in the called_func list.
Note: The #pragma funcall directive can help the linker to optimize function frame allocation in the compiled stack.
Startup Functions
The user is enabled to execute several custom initialization functions at startup.
These functions are executed after running the service startup code and before calling the main() function. The order of startup function invocation is based on the user-defined priorities.
The following special directive:
#pragma startup <priority> <function_name> can be used to inform the RSC-4x mikroC compiler that the function function_name must be executed during startup with the specified priority.
page
43
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The function function_name should return no value and have no parameters.
Declaration of the function should be placed before the #pragma startup directive for that function. External function declaration is allowed.
Priority must be a constant expression ranging from 0 to 255. Smaller values correspond to higher priorities and sooner execution. The value 0 sets the highest priority level (the earliest execution), the value 255 sets the lowest priority (the latest execution).
Note: If the same priority value is used in several #pragma startup directives, the corresponding functions will be executed in an arbitrary order.
Priority levels from 0 to 15 and from 241 to 255 are reserved for using in the
RSC-4x mikroC libraries, so it is not recommended to use them.
Example: extern void ExtFunc(void); /* an external function declaration */ static void LocalFunc(void);/* a local function prototype declaration */
/* then #pragma startup can be used */
#pragma startup 20 ExtFunc
#pragma startup 21 LocalFunc
/* the local function definition */ static void LocalFunc(void) {
/* function body */
}
Monitor Functions
The following directive:
#pragma monitor <function_name> declares the function function_name as monitor function. All interrupts are disabled when this function is executed.
page
44
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Prologue/Epilogue Functions
The #pragma directives
#pragma prolog
#pragma epilog enable the user to customize prologs and epilogs of the functions in a translation unit. This is useful primarily for debugging.
#pragma prolog informs RSC-4x mikroC that the function prolog_function should be called from the prologs of all functions in the file (except any prolog and epilog functions). Call is performed immediately after saving the return address on the dynamic stack.
#pragma epilog informs the compiler that the function epilog_function should be called from the epilogs of all functions in the file (except any prolog and epilog functions). Call is performed immediately before restoring the return address from the dynamic stack.
#pragma prolog can appear more than once in a given file. In this case, the order of the prolog function calls is determined by the arrangement of the #pragma prolog directives in source file.
Function prolog_function should return no value and have no parameters. The declaration of the function should be placed before the #pragma prolog directive for that function. External function declaration is allowed.
The same rules apply to epilog_function and #pragma epilog .
Example: extern void ExtPrologFunc(void);
#pragma prolog ExtPrologFunc; int MyFunction(int a) {
/* call to ExtPrologFunc here */ return a + 1;
} /* call to LocalEpilogFunc here */ static void LocalEpilogFunc(void) {
/* function body */
}
#pragma epilog LocalEpilogFunc page
45
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Inline Assembler
According to standard, C should allow embedding assembler in the source code by means of asm declaration. In addition, RSC-4x mikroC also supports declarations
_asm and __asm which have the same meaning.
Group assembler instructions by the asm keyword (or _asm or __asm):
asm { block of assembler instructions
}
Assembler one-line comments starting with semicolon are allowed in the embedded assembly code; C/C++ style comments are also allowed.
Embedding assembler with pragma
For the sake of backward compatibility, RSC-4x mikroC compiler supports another method for embedding assembler in C source code.
Note: Preferred method is using the asm declaration as described above.
/* Single-line format: */
#pragma asm <machine_instruction0> [; <machine_instruction1> ] ...
or:
/* Block format: */
#pragma asm
<machine_instruction0> [; <machine_instruction1> ] ...
...
#pragma endasm
In the single-line format, instructions should follow the #pragma asm directive in the same line. You can specify more than one instruction in one directive.
Instructions should be separated by semicolons.
In the block format, the #pragma asm directive indicates the beginning of assembler block, and #pragma endasm directive indicates the end of the block. You can write one or more instructions in each line of the block. Multiple instructions in one line should be separated by semicolons.
You can also use function-like macros in the assembly language blocks and lines.
Inside an assembler block, the preprocessor acts in a regular way and processes the assembler block properly. Therefore, in the built-in assembler you can use Cstyle macros and other preprocessing directives. The # and ## operators may not be used.
page
46
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Pragma Directives
Data Type Result Type
#pragma asm/endasm
Built-in assembler
#pragma funcall
#pragma interrupt
#pragma monitor
Enumerate indirectly called functions
Writing interrupt service routines in C
Declaration of a monitor function
#pragma prolog/epilog
Customizing prolog and epilog
Declare a reentrant fuction
#pragma reentrant
#pragma startup
Execution of a function at startup page
47
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Implementation Details
Compiled Stack
The RSC-4x architecture has no indexed addressing mode. For this reason, allocation of C-function arguments and local variables at fixed absolute memory locations is much more effective than simulation of a runtime stack.
The linker can overlay function parameters and local variables for functions that cannot be activated simultaneously to extend the amount of available REG address space. This scheme is called compiled stack.
The size of function frame that consists of the local variable and parameter sections is evaluated by the compiler. The linker analyzes all direct and indirect function calls and builds the call graph. Then the linker places the function frames at fixed addresses in such a way that frames of functions which cannot be activated simultaneously overlay.
The linker places the frames of non-reentrant functions in the non-banked area and
Bank 0 of on-chip SRAM as it was described above. The frames of reentrant function are placed by the linker beginning from the same start address in the nonbanked area of on-chip SRAM.
Reentrant function, in its prolog, pushes on the dynamic stack the contents of memory locations to be used as the frame of that function (locations which hold locals from the previous invocation of another or the same reentrant function).
Before returning, the reentrant function epilog restores the contents of memory locations saved in the prolog.
Because all reentrant function frames are allocated starting from the same address and overlap, the local objects of the previous reentrant functions calls are inaccessible in the current reentrant function invocation.
Note: The RSC-4x mikroC compiler does not support automatic variables and function parameters allocation in ROM or external RAM (see also memory type specifiers).
page
48
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
In the SMALL and COMPACT memory models, the called function returns control to the caller by:
JMPR @?R6
in the MEDIUM and LARGE memory models – through a jump to the __RETURN label:
JMP .LWRD(__RETURN) where the CB1 bit value of ExtAdd is restored and control returns to the caller by
JMPR instruction in the same way as for the SMALL and COMPACT models.
That code is duplicated in both program memory banks.
Passing Return Value
Value returned by a function is loaded into the _ returnValue field of the
GlobalRegisterArea. The number of bytes occupied by the return value depends on its type.
If a called function returns a value of structure (or union) type, the caller reserves a memory location in its frame for the structure and passes the pointer to that location to the called function as the first parameter (before all explicit parameters).
The called function stores the structure to be returned in the reserved memory location and returns the pointer to the structure through the _ returnValue field.
Note: Reentrant function may not return values of structure types.
page
49
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Interrupt Handling
Runtime library contains six library modules with code for default interrupt vectors. If there is a C-written interrupt handler for interrupt #N, the compiler will generate code for such interrupt vector (jump to interrupt handler code). If there is no C-written interrupt handler for an interrupt then a corresponding default interrupt vector will be linked.
In its prolog, the function declared as an interrupt handler copies the state of the register ExtAdd to the special location ?ExtAddSav
, pushes on the dynamic stack: contents of GlobalRegisterArea, variable ?CurRegBank, variable ?ExtAddSav
, value of register BANK , variable ?ExtAdd
(only for MEDIUM and LARGE memory models); and then sets the value of ?CurRegBank
to 0Bh.
The interrupt handler epilog pops the saved values from the dynamic stack.
MEDIUM and LARGE Memory Models
In the MEDIUM and LARGE memory models the code for functions declared as interrupt handlers is always placed in bank 0 of the program memory. Thus, if there is at least one C-written interrupt handler, the interrupt handling dispatcher will be linked. The dispatcher copies ExtAdd to ?ExtAddSav
, sets ExtAdd to 0
(bank 0 of program memory) and transfers control to C-written interrupt handler.
C-written interrupt handler returns control to the dispatcher by JMP instruction, the dispatcher restores ExtAdd from ?ExtAddSav
and returns control by IRET . If there are no C-written interrupt handlers, the dispatcher module will not be linked.
In the MEDIUM and LARGE memory models, interrupt vectors and interrupt handling dispatcher will be placed in both code pages.
Note: Although the dispatcher contains entry points for all interrupts, if there is no
C-written interrupt handler for an interrupt then the dispatcher will not be used for that interrupt because the default interrupt vector will be linked.
page
50
RSC-4x mikroC
making it simple...
Runtime Library
mikroC - C Compiler for Sensory RSC-4x microcontrollers
This chapter gives an overview of the runtime library functions implementation details.
The runtime library contains the following code that is implicitly called in code generated by the compiler:
- Driver functions for external data memory access
- Functions for integer multiplication/division operations
- Floating point library functions
- Code for calling support in MEDIUM and LARGE memory models (see Calling
Convention)
- Functions for dynamic stack operations (return address, GlobalRegisterArea and reentrant function frame save/restore functions)
- Interrupt handling support
In SMALL and COMPACT memory models, the CALL instruction is used to pass control to all the runtime library code. In MEDIUM and LARGE memory models, the control is transferred to driver functions, integer and floating point functions through the resident code; the code for other functions is placed in both code pages. The resident code copies the ExtAdd register value to the ?ExtAdd
variable and sets/clears CB bit of ExtAdd to the number of runtime library code page. By default, the runtime library code is placed in page 0. Change the page number in startup module to relocate the runtime library code to the other page.
The arguments and return value are passed through the _tempArea and
_returnValue fields of GlobalRegisterArea respectively. The runtime library code does not modify the 3-byte field _returnAddress of GlobalRegisterArea
(except for the function that restore the return address from the dynamic stack).
Some of the runtime library functions (floating point library, integer multiplication/division) use up to 8 bytes of temporary variables. Because each of these functions can be called both from the main thread and an interrupt handler, there are two copies of temporary registers allocated in banks 0Ah and 0Bh of the onchip SRAM.
page
51
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The area in Bank 0Ah is used for main thread, the area in Bank 0Bh – for interrupt handlers. The 1-byte variable ?CurRegBank
is allocated in non-banked area of the on-chip SRAM, and each of the system functions that use temporary variables sets the lowest 4 bits of BANK register from ?CurRegBank
before executing and clears the bits before returning. ?CurRegBank
is initialized with value 0Ah at startup.
Interrupt handler writes the value 0Bh to ?CurRegBank
in its prologue and restores the original value of ?CurRegBank
in its epilogue.
Note: if an interrupt handler invokes a system function that uses temporary variables (e.g., a floating point function) and then it is interrupted by another interrupt handler, which, in turn, invokes a system function that also uses temporary variables, the behavior is undefined.
CSTARTUP and SYSLIB Modules
These modules contain segment declarations (and segment allocation directives for linker), interrupt vector declarations, special register declarations
(GlobalRegisterArea, service registers for integer and floating point system libraries, dynamic stack support) and startup code. The C startup code is invoked when the user application is started. This code includes the following operations:
- Initialization of: dynamic stack, special registers, external memory access
- Initialization of the static variables allocated in the on-chip SRAM and external
RAM
- Invocation of the startup functions in the order based on the priorities;
- Calling the user main() function. page
52
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Usage of Modules Written in Assembler
The functions in modules written in assembler and then linked to a C program can be called from C functions. These assembler functions must comply with the C function calling convention. To declare an assembler function that will be included into the compiled stack, special assembler directives and operators can be used
(check the MCASE documentation).
Note: When an assembler function returns control, the BANK register must contain the value of Bank 0 and the ExtAdd register value must be retained ( ExtAdd must contain the original value after return from an assembler function).
In assembler modules, you can use the file “ include\tmpreg_mikro.inc
” which contains definitions for all symbolic names of GlobalRegisterArea registers.
page
53
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC
making it simple...
page
54
CHAPTER
4
RSC-4x Language
Reference
C offers unmatched power and flexibility in programming microcontrollers. RSC-
4x mikroC adds even more power with an array of libraries, specialized for RSC-
4x modules and communications. This chapter should help you learn or recollect
C syntax, along with the specifics of programming RSC-4x modules. If you are experienced in C programming, you will probably want to consult mikroC
Specifics first.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Lexical Elements Overview
These topics provide a formal definition of the RSC-4x mikroC lexical elements.
They describe the different categories of word-like units (tokens) recognized by a language.
In the tokenizing phase of compilation, the source code file is parsed (that is, broken down) into tokens and whitespace. The tokens in RSC-4x mikroC are derived from a series of operations performed on your programs by the compiler and its built-in preprocessor.
C program starts as a sequence of ASCII characters representing the source code, created by keystrokes using a suitable text editor (such as the RSC-4x mikroC
Code Editor). The basic program unit in RSC-4x mikroC is the file. This usually corresponds to a named file located in RAM or on disk and having the extension
.c.
Whitespace
Whitespace is the collective name given to spaces (blanks), horizontal and vertical tabs, newline characters, and comments. Whitespace can serve to indicate where tokens start and end, but beyond this function, any surplus whitespace is discarded. For example, the two sequences int i; float f; and int i; float f; are lexically equivalent and parse identically to give the six tokens: int i f
;
; float page
56
RSC-4x mikroC
making it simple...
Whitespace in Strings
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The ASCII characters representing whitespace can occur within string literals, in which case they are protected from the normal parsing process (they remain as part of the string). For example, char name[] = "mikro foo"; parses to seven tokens, including the single string literal token: char name
[
]
=
"mikro foo" /* just one token here! */
;
Line Splicing with Backslash (\)
A special case occurs if the line ends by a backslash ( \ ). The backslash and new line character are both discarded, allowing two physical lines of text to be treated as one unit. So,
"mikroC \
Compiler" parses as " mikroC Compiler ". Refer to String Constants for more information.
Comments
Comments are pieces of text used to annotate a program, and are technically another form of whitespace. Comments are for the programmer’s use only; they are stripped from the source text before parsing. There are two ways to delineate comments: the C method and the C++ method. Both are supported by RSC-4x mikroC.
You should also follow the guidelines on the use of whitespace and delimiters in comments discussed later in this topic to avoid other portability problems.
page
57
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Standard C comments
A C comment is any sequence of characters placed after the symbol pair /* . The comment terminates at the first occurrence of the pair */ following the initial /* .
The sequence may span multiple lines. After macro expansion, the entire sequence, including the four comment-delimiter symbols, is replaced by one space.
The following code int /* type */ i /* identifier */; parses as: int i;
Note that RSC-4x mikroC does not support the nonportable token pasting strategy using /**/ . For more on token pasting, refer to Preprocessor Operators.
C++ style comments
The RSC-4x mikroC compiler allows C++ style comments – a single-line comment starting with two adjacent slashes (//). The comment can start at any position, and extends until the beginning of new line.
The following code int i; // this is a comment int j; parses as: int i; int j; page
58
RSC-4x mikroC
making it simple...
Nested comments
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC as ANSI C doesn’t allow nested comments. The attempt to nest a comment like this
/* int /* declaration */ i; * fails, because the scope of the first /* ends at the first */. This gives us i ; */ which would generate a syntax error.
TokenToken is the smallest element of a C program that is meaningful to the compiler. The parser separates tokens from the input stream by creating the longest token possible using the input characters in a left–to–right scan.
RSC-4x mikroC recognizes following kinds of tokens: keywords identifiers constants operators punctuators (also known as separators)
Tokens can be concatenated (pasted) by means of preprocessor operator ## . See
Preprocessor Operators for details.
Token Extraction Example
Here is an example of token extraction. Let’s have the following code sequence: inter = a+++b;
First, note that inter would be parsed as a single identifier, rather than as the keyword int followed by the identifier er .
page
59
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The programmer who wrote the code might have intended to write inter = a +
(++b) , but it won’t work that way. The compiler would parse it as the following seven tokens: inter // variable identifier
= // assignment operator a // variable identifier
++ // postincrement operator
+ // addition operator b // variable identifier
; // statement terminator
Note that +++ parses as ++ (the longest token possible) followed by + .
According to the operator precedence rules, our code sequence is actually: inter (a++)+b;
Constants
Constants or literals are tokens representing fixed numeric or character values.
RSC-4x mikroC supports:
- integer constants
- floating point constants
- character constants
- string constants (strings literals)
- enumeration constants
The data type of a constant is deduced by the compiler using such clues as numeric value and the format used in the source code.
page
60
RSC-4x mikroC
making it simple...
Integer Constants
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Integer constants can be decimal (base 10), hexadecimal (base 16), binary (base
2), or octal (base 8). In the absence of any overriding suffixes, the data type of an integer constant is derived from its value.
Long and Unsigned Suffixes
The suffix L (or l ) attached to any constant forces the constant to be represented as a long. Similarly, the suffix U (or u ) forces the constant to be unsigned. You can use both L and U suffixes on the same constant in any order or case: ul, Lu, UL, etc.
In the absence of any suffix ( U, u, L, or l ), constant is assigned the “smallest” of the following types that can accommodate its value: short, unsigned short, int, unsigned int, long int, unsigned long int .
Otherwise:
- If the constant has the U suffix, its data type will be the first of the following that can accommodate its value: unsigned short, unsigned int, unsigned long int .
- If the constant has the L suffix, its data type will be the first of the following that can accommodate its value: long int, unsigned long int .
- If the constant has both L and U suffixes, ( LU or UL ), its data type will be unsigned long int .
Decimal
Decimal constants from -2147483648 to 4294967295 are allowed. Constants exceeding these bounds will produce an “Out of range” error. Decimal constants must not use an initial zero. An integer constant that has an initial zero is interpreted as an octal constant. Thus, int i = 10; /* decimal 10 */ int i = 010; /* decimal 8 */ int i = 0; /* decimal 0 = octal 0 */
In the absence of any overriding suffixes, the data type of a decimal constant is derived from its value, as shown on a next page.
page
61
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Value Assigned to Constant
< -2147483648
-2147483648 – -32769
-32768 – -129
-128 – 127
128 – 255
256 – 32767
32768 – 65535
65536 – 2147483647
2147483648 – 4294967295
> 4294967295
Assumed Type
Error: Out of range!
long int short unsigned short int unsigned int long unsigned long
Error: Out of range!
Hexadecimal
All constants starting with 0x (or 0X) are taken to be hexadecimal. In the absence of any overriding suffixes, the data type of an hexadecimal constant is derived from its value, according to the rules presented above. For example, 0xC367 will be treated as unsigned int.
Binary
The RSC-4x mikroC compiler allows integer binary constants to be used.
All constants starting with 0b (or 0B) are taken to be binary. In the absence of any overriding suffixes, the data type of an binary constant is derived from its value, according to the rules presented above. For example, 0b11101 will be treated as short.
Octal
All constants with an initial zero are taken to be octal. If an octal constant contains illegal digits 8 or 9, the compiler will report an error. In the absence of any overriding suffixes, the data type of an octal constant is derived from its value, according to the rules presented above. For example, 0777 will be treated as int.
page
62
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Floating Point Constants
A floating-point constant consists of:
- Decimal integer
- Decimal point
- Decimal fraction
- e or E and a signed integer exponent (optional)
- Type suffix: f or F or l or L (optional)
You can omit either the decimal integer or the decimal fraction (but not both). You can omit either the decimal point or the letter e (or E ) and the signed integer exponent (but not both). These rules allow for conventional and scientific (exponent) notations.
Negative floating constants are taken as positive constants with the unary operator minus (-) prefixed.
RSC-4x mikroC limits floating-point constants to range ±1.17549435082 * 10-38
.. ±6.80564774407 * 1038.
Here are some examples:
0. // = 0.0
-1.23 // = -1.23
23.45e6 // = 23.45 * 10^6
2e-5 // = 2.0 * 10^-5
3E+10 // = 3.0 * 10^10
.09E34 // = 0.09 * 10^34
RSC-4x mikroC floating-point constants are of type double . Note that mikroC’s implementation of ANSI Standard considers float and double (together with the long double variant) to be the same type.
page
63
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Character Constants
A character constant is one or more characters enclosed in single quotes, such as
' A ', ' +' , or ' \n '. In C, single-character constants have data type int . Multi-character constants are referred to as string constants or string literals. For more information refer to String Constants.
Escape Sequences
The backslash character ( \ ) is used to introduce an escape sequence, which allows the visual representation of certain nongraphic characters. One of the most common escape constants is the newline character ( \n ).
A backslash is used with octal or hexadecimal numbers to represent the ASCII symbol or control code corresponding to that value; for example, ' \x3F ' for the question mark. You can use any string of up to three octal or any number of hexadecimal numbers in an escape sequence, provided that the value is within legal range for data type char ( 0 to 0xFF for RSC-4x mikroC). Larger numbers will generate the compiler error “Out of range”.
For example, the octal number \777 is larger than the maximum value allowed
( \377 ) and will generate an error. The first nonoctal or nonhexadecimal character encountered in an octal or hexadecimal escape sequence marks the end of the sequence.
Note: You must use the sequence \\ to represent an ASCII backslash, as used in operating system paths.
page
64
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The following table shows the available escape sequences:
\t
\v
\\
\'
\"
\?
\O
\xH
\XH
Sequence Value Char
\a
\b
\f
\n
\r
0x07
BEL
0x08
BS
0x0C
FF
0x0A
LF
0x0D CR
0x09 HT
0x0B VT
0x5C
0x27
0x22
0x3F
'
\
"
?
any any any
What it does
Audible bell
Backspace
Formfeed
Newline (Linefeed)
Carriage Return
Tab (horizontal)
Vertical Tab
Backslash
Single quote (Apostrophe)
Double quote
Question mark
O = string of up to 3 octal digits
H = string of hex digits
H = string of hex digits
page
65
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Disambiguation
There are situations when ambiguities might arise when using escape sequences.
Let’s have an example:
Lcd_Out_Cp("\x091.0 Intro");
This is intended to be interpreted as \x09 and " 1.0 Intro ". However, RSC-4x mikroC compiles it as the hexadecimal number \x091 and the literal string " .0
Intro ". To avoid such problems, we could rewrite the code like this:
Lcd_Out_Cp("\x09" "1.0 Intro");
For more information on the previous line, refer to String Constants.
Ambiguities might also arise if an octal escape sequence is followed by a nonoctal digit. For example, the following constant:
"\118" would be interpreted as a two-character constant made up of the characters \11 and 8 , because 8 is not a legal octal digit.
String Constants
Note: This topic discusses the syntax of string constants according to ANSI C
Standard; for the implemenatation specifics and storage see Strings Specifics.
String constants, also known as string literals, are a special type of constants which store fixed sequences of characters. A string literal is a sequence of any number of characters surrounded by double quotes:
"This is a string."
The null string, or empty string, is written like "" . A literal string is stored internally as the given sequence of characters plus a final null character. A null string is stored as a single null character.
page
66
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The characters inside the double quotes can include escape sequences. This code, for example:
"\t\"Name\"\\\tAddress\n\n" prints like this:
"Name"\ Address
"Name" is preceded by two tabs; Address is preceded by one tab. The line is followed by two new lines. The \" provides interior double quotes. The escape character sequence \\ is translated to \ by the compiler.
Adjacent string literals separated only by whitespace are concatenated during the parsing phase. For example:
"This is " "just"
" an example." is equivalent to
"This is just an example."
Line Continuation with Backslash
You can also use the backslash ( \ ) as a continuation character to extend a string constant across line boundaries:
"This is really \ a one-line string." page
67
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Enumeration Constants
Enumeration constants are identifiers defined in enum type declarations. The identifiers are usually chosen as mnemonics to assist legibility. Enumeration constants are of int type. They can be used in any expression where integer constants are valid.
For example: enum weekdays { SUN = 0, MON, TUE, WED, THU, FRI, SAT };
The identifiers (enumerators) used must be unique within the scope of the enum declaration. Negative initializers are allowed. See Enumerations for details of enum declarations.
Pointer Constants
A pointer or the pointed-at object can be declared with the const modifier.
Anything declared as a const cannot be have its value changed. It is also illegal to create a pointer that might violate the nonassignability of a constant object.
Consider the following examples: int i; // i is an int int * pi; // pi is a pointer to int (uninitialized) int * const cp = &i; // cp is a constant pointer to int const int ci = 7; // ci is a constant int const int * pci; // pci is a pointer to constant int const int * const cpc = &ci; // cpc is a constant pointer to a
// constant int
The following assignments are legal: i = ci; // Assign const-int to int
*cp = ci; // Assign const-int to
// object-pointed-at-by-aconst-pointer
++pci; // Increment a pointer-to-const pci = cpc; // Assign a const-pointer-to-aconst to a
// pointer-to-const page
68
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The following assignments are illegal: ci = 0; // NO--cannot assign to a const-int ci--; // NO--cannot change a const-int
*pci = 3; // NO--cannot assign to an object
// pointed at by pointer-to-const.
cp = &ci; // NO--cannot assign to a const-pointer,
// even if value would be unchanged.
cpc++; // NO--cannot change const-pointer pi = pci; // NO--if this assignment were allowed,
// you would be able to assign to *pci
// (a const value) by assigning to *pi.
Similar rules apply to the volatile modifier. Note that const and volatile can both appear as modifiers to the same identifier.
Constant Expressions
A constant expression is an expression that always evaluates to a constant and consists only of constants (literals) or symbolic constants. It is evaluated at compile-time and it must evaluate to a constant that is in the range of representable values for its type. Constant expressions are evaluated just as regular expressions are.
Constant expressions can consist only of the following:
- literals,
- enumeration constants,
- simple constants (no constant arrays or structures),
-
sizeof operators.
Constant expressions cannot contain any of the following operators, unless the operators are contained within the operand of a sizeof operator: assignment, comma, decrement, function call, increment.
You can use a constant expression anywhere that a constant is legal.
page
69
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Concepts
This section covers some basic concepts of the language, essential for understanding how C programs work. First, we need to establish the following terms that will be used throughout the manual:
- Objects and lvalues
- Scope and Visibility
- Name Spaces
- Duration
Objects
An object is a specific region of memory that can hold a fixed or variable value
(or set of values). To prevent confusion, this use of the word object is different from the more general term used in object-oriented languages. Our definiton of the word would encompass functions, variables, symbolic constants, user-defined data types, and labels.
Each value has an associated name and type (also known as a data type). The name is used to access the object. This name can be a simple identifier, or it can be a complex expression that uniquely references the object.
Objects and Declarations
Declarations establish the necessary mapping between identifiers and objects.
Each declaration associates an identifier with a data type.
Associating identifiers with objects requires each identifier to have at least two attributes: storage class and type (sometimes referred to as data type). The RSC-4x mikroC compiler deduces these attributes from implicit or explicit declarations in the source code. Commonly, only the type is explicitly specified and the storage class specifier assumes automatic value auto .
Generally speaking, an identifier cannot be legally used in a program before its declaration point in the source code. Legal exceptions to this rule (known as forward references) are labels, calls to undeclared functions, and struct or union tags.
page
70
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The range of objects that can be declared includes:
- Variables
- Functions
- Types
- Arrays of other types
- Structure, union, and enumeration tags
- Structure members
- Union members
- Enumeration constants
- Statement labels
- Preprocessor macros
The recursive nature of the declarator syntax allows complex declarators. You’ll probably want to use typedefs to improve legibility if constructing complex objects.
Lvalues
An lvalue is an object locator: an expression that designates an object. An example of an lvalue expression is *P , where P is any expression evaluating to a non-null pointer. A modifiable lvalue is an identifier or expression that relates to an object that can be accessed and legally changed in memory. A const pointer to a constant, for example, is not a modifiable lvalue. A pointer to a constant can be changed
(but its dereferenced value cannot).
Historically, the l stood for “left”, meaning that an lvalue could legally stand on the left (the receiving end) of an assignment statement. Now only modifiable lvalues can legally stand to the left of an assignment operator. For example, if a and b are nonconstant integer identifiers with properly allocated memory storage, they are both modifiable lvalues, and assignments such as a = 1 and b = a + b are legal.
Rvalues
The expression a + b is not an lvalue: a + b = a is illegal because the expression on the left is not related to an object. Such expressions are sometimes called
rvalues (short for right values).
page
71
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Scope and Visibility
Scope
The scope of identifier is the part of the program in which the identifier can be used to access its object. There are different categories of scope: block (or local), function, function prototype, and file. These depend on how and where identifiers are declared.
- Block: The scope of an identifier with block (or local) scope starts at the declaration point and ends at the end of the block containing the declaration (such a block is known as the enclosing block). Parameter declarations with a function definition also have block scope, limited to the scope of the function body.
- File: File scope identifiers, also known as globals, are declared outside of all blocks; their scope is from the point of declaration to the end of the source file.
- Function: The only identifiers having function scope are statement labels. Label names can be used with goto statements anywhere in the function in which the label is declared. Labels are declared implicitly by writing label_name : followed by a statement. Label names must be unique within a function.
- Function prototype: Identifiers declared within the list of parameter declarations in a function prototype (not part of a function definition) have function prototype scope. This scope ends at the end of the function prototype.
Visibility
The visibility of an identifier is that region of the program source code from which legal access can be made to the identifier’s associated object.
Scope and visibility usually coincide, though there are circumstances under which an object becomes temporarily hidden by the appearance of a duplicate identifier: the object still exists but the original identifier cannot be used to access it until the scope of the duplicate identifier is ended.
Technically, visibility cannot exceed scope, but scope can exceed visibility. page
72
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Name Spaces
Name space is the scope within which an identifier must be unique. C uses four distinct categories of identifiers:
1.
goto label names. These must be unique within the function in which they are declared.
2. Structure, union, and enumeration tags. These must be unique within the block in which they are defined. Tags declared outside of any function must be unique.
3. Structure and union member names. These must be unique within the structure or union in which they are defined. There is no restriction on the type or offset of members with the same member name in different structures.
4. Variables, typedefs, functions, and enumeration members. These must be unique within the scope in which they are defined. Externally declared identifiers must be unique among externally declared variables.
5. Duplicate names are legal for different name spaces regardless of scope rules.
For example:
int blue = 73;
{ // open a block
enum colors { black, red, green, blue, violet, white } c;
/* enumerator blue = 3 now hides outer declaration of int blue */
struct colors { int i, j; }; // ILLEGAL: colors duplicate tag
double red = 2; // ILLEGAL: redefinition of red
} blue = 37; // back in int blue scope page
73
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Duration
Duration, closely related to storage class, defines the period during which the declared identifiers have real, physical objects allocated in memory. We also distinguish between compile-time and run-time objects. Variables, for instance, unlike typedefs and types, have real memory allocated during run time. There are two kinds of duration: static and local.
Static Duration
Memory is allocated to objects with static duration as soon as execution is underway; this storage allocation lasts until the program terminates. Static duration objects usually reside in fixed data segments allocated according to the memory model in force. All globals have static duration. All functions, wherever defined, are objects with static duration. Other variables can be given static duration by using the explicit static or extern storage class specifiers.
In RSC-4x mikroC, static duration objects are not initialized to zero (or null) in the absence of any explicit initializer.
Don’t confuse static duration with file or global scope. An object can have static duration and local scope – see the example below.
Local Duration
Local duration objects are also known as automatic objects. They are created on the stack (or in a register) when the enclosing block or function is entered. They are deallocated when the program exits that block or function. Local duration objects must be explicitly initialized; otherwise, their contents are unpredictable.
The storage class specifier auto can be used when declaring local duration variables, but is usually redundant, because auto is the default for variables declared within a block.
page
74
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
An object with local duration also has local scope, because it does not exist outside of its enclosing block. The converse is not true: a local scope object can have static duration. For example:
void f() {
/* local duration variable; init a upon every call to f */
int a = 1;
/* static duration variable; init b only upon first call to f */
static int b = 1;
/* checkpoint! */
a++; b++;
}
void main() {
/* At checkpoint, we will have: */
f(); // a=1, b=1, after first call, f(); // a=1, b=2, after second call, f(); // a=1, b=3, after third call,
// etc.
} page
75
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Types
Note: This topic discusses the concept of types and covers standard C types. For specialized types and implemenation details see Types Specifics.
C is a strictly typed language, which means that every object, function, and expression need to have a strictly defined type, known in the time of compilation.
Note that C works exclusively with numeric types.
The type serves:
- to determine the correct memory allocation required initially.
- to interpret the bit patterns found in the object during subsequent access.
- in many type-checking situations, to ensure that illegal assignments are trapped.
RSC-4x mikroC supports many standard (predefined) and user-defined data types, including signed and unsigned integers in various sizes, floating-point numbers in various precisions, arrays, structures, and unions. In addition, pointers to most of these objects can be established and manipulated in memory.
The type determines how much memory is allocated to an object and how the program will interpret the bit patterns found in the object’s storage allocation. A given data type can be viewed as a set of values (often implementation-dependent) that identifiers of that type can assume, together with a set of operations allowed on those values. The compile-time operator, sizeof, lets you determine the size in bytes of any standard or user-defined type.
The RSC-4x mikroC standard libraries and your own program and header files must provide unambiguous identifiers (or expressions derived from them) and types so that RSC-4x mikroC can consistently access, interpret, and (possibly) change the bit patterns in memory corresponding to each active object in your program.
page
76
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Type Categories
Common way to categorize types is to divide them into:
- fundamental
- derived
The fudamental types represent types that cannot be separated into smaller parts.
They are sometimes referred to as unstructured types. The fundamental types are void, char, int, float, and double , together with short, long, signed , and unsigned variants of some of these. For more information on fundamental types, refer to the topic Fundamental Types.
The derived types are also known as structured types . The derived types include pointers to other types, arrays of other types, function types, structures, and unions. For more information on derived types, refer to the topic Derived
Types.
Arithmetic Types
The arithmetic type specifiers are built from the following keywords: void, char, int, float, and double, together with prefixes short, long, signed, and unsigned.
From these keywords you can build the integral and floating-point types.
Integral Types
Types char and int , together with their variants, are considered integral data types. Variants are created by using one of the prefix modifiers short, long, signed , and unsigned .
The table below is the overview of the integral types – keywords in parentheses can be (and often are) omitted.
The modifiers signed and unsigned can be applied to both char and int . In the absence of unsigned prefix, signed is automatically assumed for integral types.
The only exception is the char , which is unsigned by default. The keywords signed and unsigned , when used on their own, mean signed int and unsigned int , respectively.
The modifiers short and long can be applied only to the int . The keywords short and long used on their own mean short int and long int , respectively.
page
77
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Note: The integral type values are stored in the little-endian byte order.
Type
(unsigned) char signed char
(signed) short (int) unsigned short (int)
(signed) int unsigned (int)
(signed) long (int) unsigned long (int)
Size in bytes
1
1
1
1
4
4
2
2
Range
0 .. 255
- 128 .. 127
- 128 .. 127
0 .. 255
-32768 .. 32767
0 .. 65535
-2147483648 .. 2147483647
0 .. 4294967295
Floating-point Types
All floating types ( float, double, long double ) use 32-bit IEEE real format
(ANSI/IEEE 754-1985) of single-precision normalized numbers. The three types are of the same size and entirely compatible (casting would not produce any code), though their types are different.
Here is the overview of the floating-point types:
Type
float double long double
Size in bytes
4
4
4
Range
±1.17549435 * 10-38 .. ±3.40282347 * 10^38
±1.17549435 * 10-38 .. ±3.40282347 * 10^38
±1.17549435 * 10-38 .. ±3.40282347 * 10^38
page
78
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Some features of the double and long double types do not comply with the standard:
Macro defined in
<float.h>
DBL_DIG
LDBL_DIG
DBL_EPSILON
LDBL_EPSILON
Value in this implementation
6
6
1.19209290 * 10-7
1.19209290 * 10-7
ANSI C Standard requirements
>=10
>=10
<=10-9
<=10-9
Enumerations
An enumeration data type is used for representing an abstract, discreet set of values with appropriate symbolic names.
Enumeration Declaration
Enumeration is declared like this:
enum tag {enumeration-list};
Here, tag is an optional name of the enumeration; enumeration-list is a commadelimited list of discreet values, enumerators (or enumeration constants). Each enumerator is assigned a fixed integral value. In the absence of explicit initializers, the first enumerator is set to zero, and each succeeding enumerator is set to one more than its predecessor.
Variables of enum type are declared same as variables of any other type. For example, the following declaration:
enum colors { black, red, green, blue, violet, white } c; establishes a unique integral type, enum colors , a variable c of this type, and a set of enumerators with constant integer values (black = 0, red = 1, ...). page
79
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
In C, a variable of an enumerated type can be assigned any value of type int – no type checking beyond that is enforced. That is: c = red; // OK c = 1; // Also OK, means the same
With explicit integral initializers, you can set one or more enumerators to specific values. The initializer can be any expression yielding a positive or negative integer value (after possible integer promotions). Any subsequent names without initializers will then increase by one. These values are usually unique, but duplicates are legal.
The order of constants can be explicitly re-arranged. For example:
enum colors { black, // value 0 red, // value 1 green, // value 2 blue=6, // value 6 violet, // value 7 white=4 }; // value 4
Initializer expression can include previously declared enumerators. For example, in the following declaration:
enum memory_sizes { bit = 1, nibble = 4 * bit, byte = 2 * nibble, kilobyte = 1024 * byte }; nibble would acquire the value 4, byte the value 8, and kilobyte the value 8192.
Anonymous Enum Type
In our previous declaration, the identifier colors is the optional enumeration tag that can be used in subsequent declarations of enumeration variables of type enum colors :
enum colors bg, border; /* declare variables bg and border */
As with struct and union declarations, you can omit the tag if no further variables of this enum type are required:
/* Anonymous enum type: */
enum { black, red, green, blue, violet, white } color; page
80
RSC-4x mikroC
making it simple...
Enumeration Scope
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Enumeration tags share the same name space as structure and union tags.
Enumerators share the same name space as ordinary variable identifiers:
int blue = 73;
{ // open a block
enum colors { black, red, green, blue, violet, white } c;
/* enumerator blue = 3 now hides outer declaration of int blue */
struct colors { int i, j; }; // ILLEGAL: colors duplicate tag
double red = 2;
// ILLEGAL: redefinition of red
} blue = 37; // back in int blue scope
Void Type
void is a special type indicating the absence of any value. There are no objects of void ; instead, void is used for deriving more complex types.
Void Functions
Use the void keyword as a function return type if the function does not return a value.
void print_temp(char temp) {
Lcd_Out_Cp("Temperature:");
Lcd_Out_Cp(temp);
Lcd_Chr_Cp(223); // degree character
Lcd_Chr_Cp('C');
}
Use void as a function heading if the function does not take any parameters.
Alternatively, you can just write empty parentheses: main(void) { // same as main()
...
}
Generic Pointers
Pointers can be declared as void, meaning that they can point to any type. These pointers are sometimes called generic.
page
81
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Derived Types
The derived types are also known as structured types. These types are used as elements in creating more complex user-defined types. The derived types include:
- arrays
- pointers
- structures
- unions
Arrays
Array is the simplest and most commonly used structured type. Variable of array type is actually an array of objects of the same type. These objects represent elements of an array and are identified by their position in array. An array consists of a contiguous region of storage exactly large enough to hold all of its elements.
Array Declaration
Array declaration is similar to variable declaration, with the brackets added after identifer: type array_name[constant-expression]
This declares an array named as array_name composed of elements of type. The type can be scalar type (except void), user-defined type, pointer, enumeration, or another array. Result of the constant-expression within the brackets determines the number of elements in array. If an expression is given in an array declarator, it must evaluate to a positive constant integer. The value is the number of elements in the array.
Each of the elements of an array is numbered from 0 through the number of elements minus one. If the number is n, elements of array can be approached as variables array_name[0] .. array_name[n-1] of type .
Here are a few examples of array declaration:
#define MAX = 50
int
vector_one[10]; /* declares an array of 10 integers */
float vector_two[MAX]; /* declares an array of 50 floats */
float vector_three[MAX - 20];/* declares an array of 30 floats */ page
82
RSC-4x mikroC
making it simple...
Array Initialization
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Array can be initialized in declaration by assigning it a comma-delimited sequence of values within braces. When initializing an array in declaration, you can omit the number of elements – it will be automatically determined acording to the number of elements assigned. For example:
/* Declare an array which holds number of days in each month: */
int days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
/* This declaration is identical to the previous one */
int days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
If you specify both the length and starting values, the number of starting values must not exceed the specified length. Vice versa is possible, when the trailing
“excess” elements will be assigned some encountered runtime values from memory.
In case of array of char , you can use a shorter string literal notation. For example:
/* The two declarations are identical: */
const char msg1[] = {'T', 'e', 's', 't', '\0'};
const char msg2[] = "Test";
For more information on string literals, refer to String Constants.
Arrays in Expressions
When name of the array comes up in expression evaluation (except with operators
& and sizeof ), it is implicitly converted to the pointer pointing to array’s first element. See Arrays and Pointers for more information.
page
83
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Multi-dimensional Arrays
An array is one-dimensional if it is of scalar type. One-dimensional arrays are sometimes referred to as vectors.
Multidimensional arrays are constructed by declaring arrays of array type. These arrays are stored in memory in such way that the right most subscript changes fastest, i.e. arrays are stored “in rows”. Here is a sample 2-dimensional array:
float m[50][20]; /* 2-dimensional array of size 50x20 */
Variable m is an array of 50 elements, which in turn are arrays of 20 floats each.
Thus, we have a matrix of 50x20 elements: the first element is m[0][0] , the last one is m[49][19 ]. First element of the 5th row would be m[0][5] .
If you are not initializing the array in the declaration, you can omit the first dimension of multi-dimensional array. In that case, array is located elsewhere, e.g. in another file. This is a commonly used technique when passing arrays as function parameters:
int a[3][2][4]; /* 3-dimensional array of size 3x2x4 */
void func(int n[][2][4]) { /* we can omit first dimension */
//...
n[2][1][3]++; /* increment the last element*/
}//~
void main() {
//...
func(a);
}//~!
You can initialize a multi-dimensional array with an appropriate set of values within braces. For example:
int a[3][2] = {{1,2}, {2,6}, {3,7}}; page
84
RSC-4x mikroC
making it simple...
Pointers
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Note: This topic discusses the concept and syntax of pointers according to ANSI C
Standard; for the implemenatation specifics and storage see Pointers Specifics.
Pointers are special objects for holding (or “pointing to”) memory addresses. In C, address of an object in memory can be obtained by means of unary operator & . To reach the pointed object, we use indirection operator (*) on a pointer.
A pointer of type “pointer to object of type ” holds the address of (that is, points to) an object of type. Since pointers are objects, you can have a pointer pointing to a pointer (and so on). Other objects commonly pointed at include arrays, structures, and unions.
A pointer to a function is best thought of as an address, usually in a code segment, where that function’s executable code is stored; that is, the address to which control is transferred when that function is called.
Although pointers contain numbers with most of the characteristics of unsigned integers, they have their own rules and restrictions for declarations, assignments, conversions, and arithmetic. The examples in the next few sections illustrate these rules and restrictions.
Pointer Declarations
Pointers are declared same as any other variable, but with * ahead of identifier.
Type at the beginning of declaration specifies the type of a pointed object. A pointer must be declared as pointing to some particular type, even if that type is void, which really means a pointer to anything. Pointers to void are often called generic
pointers.
If type is any predefined or user-defined type, including void, the declaration type *p; /* Uninitialized pointer */ declares p to be of type “pointer to type ”. All the scoping, duration, and visibility rules apply to the p object just declared. You can view the declaration in this way: if *p is an object of type , then p has to be a pointer to such objects.
Note: You must initialize pointers before using them! Our previously declared pointer *p is not initialized (i.e. assigned a value), so it cannot be used yet.
page
85
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Note: In case of multiple pointer declarations, each identifier requires an indirect operator. For example:
int *pa, *pb, *pc;
/* is same as: */
int *pa;
int *pb;
int *pc;
Once declared, though, a pointer can usually be reassigned so that it points to an object of another type. mikroC lets you reassign pointers without typecasting, but the compiler will warn you unless the pointer was originally declared to be pointing to void . You can assign a void* pointer to a non-void* pointer – refer to void for details.
Null Pointers
A null pointer value is an address that is guaranteed to be different from any valid pointer in use in a program. Assigning the integer constant 0 to a pointer assigns a null pointer value to it. Instead of zero, the mnemonic NULL (defined in the standard library header files, such as stdio.h
) can be used for legibility. All pointers can be successfully tested for equality or inequality to NULL .
For example:
int *pn = 0; /* Here's one null pointer */
int *pn = NULL; /* This is an equivalent declaration */
/* We can test the pointer like this: */
if ( pn == 0 ) { ... }
/* .. or like this: */
if ( pn == NULL ) { ... }
The pointer type “pointer to void” must not be confused with the null pointer. The declaration
void *vp; declares that vp is a generic pointer capable of being assigned to by any “pointer to type” value, including null, without complaint.
page
86
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Assignments without proper casting between a “pointer to type1 ” and a “pointer to type2 ”, where type1 and type2 are different types, can invoke a compiler warning or error. If type1 is a function and type2 isn’t (or vice versa), pointer assignments are illegal. If type1 is a pointer to void , no cast is needed. If type2 is a pointer to void, no cast is needed.
Pointer Arithmetic
Pointer arithmetic in C is limited to:
- assigning one pointer to another,
- comparing two pointers,
- comparing pointer to zero (NULL),
- adding/subtracting pointer and an integer value,
- subtracting two pointers.
The internal arithmetic performed on pointers depends on the memory model in force and the presence of any overriding pointer modifiers. When performing arithmetic with pointers, it is assumed that the pointer points to an array of objects.
Arrays and Pointers
Arrays and pointers are not completely independent types in C. When name of the array comes up in expression evaluation (except with operators & and sizeof ), it is implicitly converted to the pointer pointing to array’s first element. Due to this fact, arrays are not modifiable lvalues.
Brackets [ ] indicate array subscripts. The expression id[exp] is defined as
*((id) + (exp)) where either:
- id is a pointer and exp is an integer, or
- id is an integer and exp is a pointer. page
87
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The following is true:
&a[i] = a + i a[i] = *(a + i)
According to these guidelines, we can write: pa = &a[4]; // pa points to a[4] x = *(pa + 3); // x = a[7]
/* .. but: */ y = *pa + 3; // y = a[4] + 3
Also, you need to be careful with operator precedence:
*pa++; // Equal to *(pa++), increments the pointer
(*pa)++; // Increments the pointed object!
Following examples are also valid, but better avoid this syntax as it can make the code really illegible:
(a + 1)[i] = 3;
// same as: *((a + 1) + i) = 3, i.e. a[i + 1] = 3
(i + 2)[a] = 0;
// same as: *((i + 2) + a) = 0, i.e. a[i + 2] = 0
Assignment and Comparison
You can use a simple assignment operator ( =) to assign value of one pointer to another if they are of the same type. If they are of different types, you must use a typecast operator. Explicit type conversion is not necessary if one of the pointers is generic (of void type).
Assigning the integer constant 0 to a pointer assigns a null pointer value to it. The mnemonic NULL (defined in the standard library header files, such as stdio.h
) can be used for legibility.
page
88
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Two pointers pointing into the same array may be compared by using relational operators ==, !=, <, <=, >, and >= . Results of these operations are same as if they were used on subscript values of array elements in question: int *pa = &a[4], *pb = &a[2]; if (pa == pb) {... /* won't be executed as 4 is not equal 2 */ } if (pa > pb) {... /* will be executed as 4 is greater than 2 */ }
You can also compare pointers to zero value – this tests if pointer actually points to anything. All pointers can be successfully tested for equality or inequality to
NULL : if (pa == NULL) { ... } if (pb != NULL) { ... }
Note: Comparing pointers pointing to different objects/arrays can be performed at programmer’s responsibility — precise overview of data’s physical storage is required.
Pointer Addition
You can use operators +, ++, and += to add an integral value to a pointer. The result of addition is defined only if pointer points to an element of an array and if the result is a pointer pointing into the same array (or one element beyond it).
If a pointer is declared to point to type, adding an integral value to the pointer advances the pointer by that number of objects of type. Informally, you can think of P + n as advancing the pointer P by (n * sizeof(type)) bytes, as long as the pointer remains within the legal range (first element to one beyond the last element). If type has size of 10 bytes, then adding 5 to a pointer to type advances the pointer 50 bytes in memory. In case of void type, size of the step is one byte.
For example: int a[10]; /* array a containing 10 elements of type int */ int *pa = &a[0]; /* pa is pointer to int, pointing to a[0] */
*(pa + 3) = 6;
/* pa+3 is a pointer pointing to a[3], so a[3] now equals 6 */
pa++;
/* pa now points to the next element of array a: a[1] */
page
89
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
There is no such element as “one past the last element”, of course, but a pointer is allowed to assume such a value. C “guarantees” that the result of addition is defined even when pointing to one element past array. If P points to the last array element, P + 1 is legal, but P + 2 is undefined.
This allows you to write loops which access the array elements in a sequence by means of incrementing pointer — in the last iteration you will have a pointer pointing to one element past an array, which is legal. However, applying the indirection operator ( * ) to a “pointer to one past the last element” leads to undefined behavior.
For example:
void f (some_type a[], int n) {
/* function f handles elements of array a; */
/* array a has n elements of type some_type */
int i; some_type *p=&a[0];
}
for ( i = 0; i < n; i++ ) {
/* .. here we do something with *p .. */
p++; /* .. and with the last iteration p exceeds
the last element of array a */
}
/* at this point, *p is undefined! */
Pointer Subtraction
Similar to addition, you can use operators , -, and -= to subtract an integral value from a pointer.
Also, you may subtract two pointers. Difference will equal the distance between the two pointed addresses, in bytes.
For example:
int a[10];
int *pi1 = &a[0];
int *pi2 = &a[4]; i = pi2 - pi1; /* i equals 8 */ pi2 -= (i >> 1); /* pi2 = pi2 - 4: pi2 now points to a[0] */ page
90
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Structures
A structure is a derived type usually representing a user-defined collection of named members (or components). The members can be of any type, either fundamental or derived (with some restrictions to be noted later), in any sequence. In addition, a structure member can be a bit field type not allowed elsewhere.
Unlike arrays, structures are considered to be single objects. The RSC-4x mikroC structure type lets you handle complex data structures almost as easily as single variables.
Note: RSC-4x mikroC does not support anonymous structures (ANSI divergence).
Structure Declaration and Initialization
Structures are declared using the keyword struct:
struct tag {member-declarator-list};
Here, tag is the name of the structure; member-declarator-list is a list of structure members, actually a list of variable declarations. Variables of structured type are declared same as variables of any other type.
The member type cannot be the same as the struct type being currently declared.
However, a member can be a pointer to the structure being declared, as in the following example:
struct mystruct {mystruct s;}; /* illegal! */
struct mystruct {mystruct *ps;}; /* OK */
Also, a structure can contain previously defined structure types when declaring an instance of a declared structure. Here is an example:
/* Structure defining a dot: */
struct Dot {float x, y;};
/* Structure defining a circle: */
struct Circle {
float r;
struct Dot center;
} o1, o2;
/* declare variables o1 and o2 of Circle */
page
91
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Note that you can omit structure tag, but then you cannot declare additional objects of this type elsewhere. For more information, see the “Untagged
Structures” below.
Structure is initialized by assigning it a comma-delimited sequence of values within braces, similar to array. For example:
/* Referring to declarations from the example above: */
/* Declare and initialize dots p and q: */
struct Dot p = {1., 1.}, q = {3.7, -0.5};
/* Declare and initialize circle o1: */
struct Circle o1 = {1., {0., 0.}};
// radius is 1, center is at (0, 0)
Incomplete Declarations
Incomplete declarations are also known as forward declarations. A pointer to a structure type A can legally appear in the declaration of another structure B before
A has been declared: struct A; // incomplete struct B {struct A *pa;}; struct A {struct B *pb;};
The first appearance of A is called incomplete because there is no definition for it at that point. An incomplete declaration is allowed here, because the definition of
B doesn’t need the size of A .
Untagged Structures and Typedefs
If you omit the structure tag, you get an untagged structure. You can use untagged structures to declare the identifiers in the comma-delimited member-declaratorlist to be of the given structure type (or derived from it), but you cannot declare additional objects of this type elsewhere.
page
92
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
It is possible to create a typedef while declaring a structure, with or without a tag:
/* With tag: */
typedef struct mystruct { ... } Mystruct;
Mystruct s, *ps, arrs[10]; /* same as struct mystruct s, etc. */
/* Without tag: */
typedef struct { ... } Mystruct;
Mystruct s, *ps, arrs[10];
Usually, you don’t need both tag and typedef : either can be used in structure type declarations.
Untagged structure and union members are ignored during initialization.
Note: See also Working with structures.
Working with Structures
Structures represent user-defined types. Set of rules governing the application of structures is strictly defined.
Assignment
Variables of same structured type may be assigned one to another by means of simple assignment operator (=). This will copy the entire contents of the variable to destination, regardless of the inner complexitiy of a given structure.
Note that two variables are of same structured type only if they were both defined by the same instruction or were defined using the same type identifier. For example:
/* a and b are of the same type: */
struct {int m1, m2;} a, b;
/* But c and d are _not_ of the same type although their structure descriptions are identical: */
struct {int m1, m2;} c;
struct {int m1, m2;} d; page
93
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Size of Structure
You can get size of the structure in memory by means of operator sizeof . Size of the structure does not necessarily need to be equal to the sum of its members’ sizes. It is often greater due to certain limitations of memory storage.
Structures and Functions
A function can return a structure type or a pointer to a structure type: mystruct func1(void); /* func1() returns a structure */ mystruct *func2(void); /* func2() returns pointer to structure */
A structure can be passed as an argument to a function in the following ways:
void func1(mystruct s;); /* directly */
void func2(mystruct *sptr;); /* via a pointer */
Structure Member Access
Structure and union members are accessed using the following two selection operators:
. (period)
-> (right arrow)
The operator . is called the direct member selector and it is used to directly access one of the structure’s members. Suppose that the object s is of struct type S . Then if m is a member identifier of type M declared in s, the expression s.m // direct access to member m is of type M , and represents the member object m in S .
page
94
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The operator -> is called the indirect (or pointer) member selector. Suppose that the object s is of struct type S, and ps is a pointer to s . Then if m is a member identifier of type M declared in s , the expression ps->m // indirect access to member m;
// identical to (*ps).m
is of type M , and represents the member object m in s . The expression ps->m is a convenient shorthand for (*ps).m
.
For example:
struct mystruct {
int i;
char str[21];
double d;
} s, *sptr = &s;
//...
s.i = 3; // assign to the i member of mystruct s sptr -> d = 1.23; // assign to the d member of mystruct s
The expression s.m
is an lvalue, provided that s is an lvalue and m is not an array type. The expression sptr->m is an lvalue unless m is an array type.
Accessing Nested Structures
If structure B contains a field whose type is structure A , the members of A can be accessed by two applications of the member selectors:
struct A {
int j; double x;
};
struct B {
int i; struct A aa; double d;
} s, *sptr;
//...
s.i = 3; // assign 3 to the i member of B s.aa.j = 2; // assign 2 to the j member of A sptr->d = 1.23; // assign 1.23 to the d member of B sptr->aa.x = 3.14; // assign 3.14 to x member of A page
95
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Structure Uniqueness
Each structure declaration introduces a unique structure type, so that in
struct A {
int i,j; double d;
} aa, aaa;
struct B {
int i,j; double d;
} bb; the objects aa and aaa are both of type struct A, but the objects aa and bb are of different structure types. Structures can be assigned only if the source and destination have the same type: aa = aaa; /* OK: same type, member by member assignment */ aa = bb; /* ILLEGAL: different types */
/* but you can assign member by member: */
aa.i = bb.i; aa.j = bb.j; aa.d = bb.d; page
96
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Unions
Union types are derived types sharing many of the syntactic and functional features of structure types. The key difference is that a union allows only one of its members to be “active” at any given time, the most recently changed member.
Note: RSC-4x mikroC does not support anonymous unions (ANSI divergence).
Union Declaration
Unions are declared same as structures, with the keyword union used instead of struct : union tag { member-declarator-list };
Unlike structures’ members, the value of only one of union’s members can be stored at any time. Let’s have a simple example:
union myunion { // union tag is 'myunion'
int i;
double d;
char ch;
} mu, *pm;
The identifier mu , of type union myunion , can be used to hold a 2-byte int , a 4byte double , or a single-byte char , but only one of these at any given time. The identifier pm is a pointer to union myunion .
Size of Union
The size of a union is the size of its largest member. In our previous example, both sizeof(union myunion) and sizeof(mu) return 4, but 2 bytes are unused
(padded) when mu holds an int object, and 3 bytes are unused when mu holds a char .
page
97
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Union Member Access
Union members can be accessed with the structure member selectors (. and ->), but care is needed:
/* Referring to declarations from the example above: */
pm = μ mu.d = 4.016; tmp = mu.d; // OK: mu.d = 4.016 tmp = mu.i; // peculiar result pm->i = 3; tmp = mu.i; // OK: mu.i = 3
The third line is legal, since mu.i
is an integral type. However, the bit pattern in mu.i
corresponds to parts of the previously assigned double . As such, it won’t likely provide a useful integer interpretation.
When properly converted, a pointer to a union points to each of its members, and vice versa.
Bit Fields
Bit fields are specified numbers of bits that may or may not have an associated identifier. Bit fields offer a way of subdividing structures into named parts of userdefined sizes.
RSC-4x mikroC supports using bitfields in structures. The length of each bitfield cannot exceed 16 bits. Only unsigned bitfields are supported.
Bit Fields Declaration
Bit fields can be declared only in structures. Declare a structure normally, and assign individual fields like this (fields need to be unsigned ):
struct [tag] {
unsigned bitfield-declarator-list;
}
Here, tag is an optional name of the structure; bitfield-declarator-list is a list of bit fields. Each component identifer requires a colon and its width in bits to be explicitly specified.
page
98
RSC-4x mikroC
making it simple...
Function Calls
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The compiler arranges bitfields within 16-bit words. Bitfields are arranged starting from the lower bits in the word. Consequent bitfields are placed in the following higher bits right after the used bits. When there is not enough free bits remaining in the current word to accommodate next bitfield, the compiler places that bitfield in the next following word, thus leaving an unused gap between the words. If you specify an unnamed bitfield, the corresponding bits will also remain unused, simply serving as a gap between the bitfields.
Here’s an example:
struct { /* the structure occupies two words */
unsigned type : 7;/* occupies [0...6] bits of the first word */
unsigned
: 4;/* bits [7...10] of the first word are free*/
unsigned index : 4;/* occupies [10...13] bits of the first word
*/
/* [14...15] bits of the first word are free */
unsigned value : 7;/* occupies [0...6] bits of the second word
*/
unsigned exp : 5; /* occupies [7...11] bits of the second
word */
unsigned flag : 1; /* occupies bit 12 of the second word
*/
/* [13...15] bits of the second word are free */
} S;
Bit Fields Access
Bit fields can be accessed in same way as the structure members. Use direct and indirect member selector ( . and -> ).
Performance
Bitfield operations are much more time-consuming for processor than operations with object of base types ( int, char ). Moreover, bitfield operations result in enlarged code size, therefore and it is not recommended to use bitfields unless
RAM size is not enough to accommodate modifiable objects.
page
99
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Types Conversion
C is strictly typed language, with each operator, statement and function demanding appropriately typed operands/arguments. However, we often have to use objects of
“mismatching” types in expressions. In that case, type conversion is needed.
Conversion of object of one type is changing it to the same object of another type
(i.e. applying another type to a given object). C defines a set of standard conversions for built-in types, provided by compiler when necessary. For more information, refer to Standard Conversions.
Conversion is required in following situations:
- if statement requires an expression of particular type (according to language defi nition), and we use an expression of different type,
- if operator requires an operand of particular type, and we use an operand of dif ferent type,
- if a function requires a formal parameter of particular type, and we pass it an object of different type,
- if an expression following the keyword return does not match the declared func tion return type,
- if intializing an object (in declaration) with an object of different type.
In these situations, compiler will provide an automatic implicit conversion of types, without any user interference. Also, user can demand conversion explicitly by means of typecast operator. For more information, refer to Explicit
Typecasting.
See also Specialized Types Conversions.
Standard Conversions
Standard conversions are built in C. These conversions are performed automatically, whenever required in the program. They can be also explicitly required by means of typecast operator (refer to Explicit Typecasting).
The basic rule of automatic (implicit) conversion is that the operand of simpler type is converted (promoted) to the type of more complex operand. Then, type of the result is that of more complex operand.
page
100
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Arithmetic Conversions
When you use an arithmetic expression, such as a + b , where a and b are of different arithmetic types, RSC-4x mikroC performs implicit type conversions before the expression is evaluated. These standard conversions include promotions of
“lower” types to “higher” types in the interests of accuracy and consistency.
Assigning a signed character object (such as a variable) to an integral object results in automatic sign extension. Objects of type signed char always use sign extension; objects of type unsigned char always set the high byte to zero when converted to int.
Converting a longer integral type to a shorter type truncates the higher order bits and leaves low-order bits unchanged. Converting a shorter integral type to a longer type either sign-extends or zero-fills the extra bits of the new value, depending on whether the shorter type is signed or unsigned, respectively.
When a value of floating type is converted to integral type, the fractional part is discarded, in accordance with the standard. If the value of the integral part cannot be represented by the integral type, the result is the maximum valid value of the required integral type.
When a value of integral type is converted to a floating type, if the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is the nearest lower value, also in accordance with the standard.
In details:
Here are the steps RSC-4x mikroC uses to convert the operands in an arithmetic expression:
First, any small integral types are converted according to the following rules:
1. unsigned char converts to int
2. signed char converts to int , with the same value
3. short converts to int , with the same value, sign-extended
4. unsigned short converts to unsigned int , with the same value, zero-filled
5. enum converts to int , with the same value page
101
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
After this, any two values associated with an operator are either int (including the long and unsigned long double modifiers), or they are in RSC-4x mikroC).
float (equivalent with double and
1. If either operand is float , the other operand is converted to float .
2. Otherwise, if either operand is unsigned long , the other operand is converted to unsigned long .
3. Otherwise, if either operand is long , then the other operand is converted to long .
4. Otherwise, if either operand is unsigned , then the other operand is converted to unsigned .
5. Otherwise, both operands are int .
The result of the expression is the same type as that of the two operands.
Here are several examples of implicit conversion:
2 + 3.1 /* -> 2. + 3.1 -> 5.1 */
5 / 4 * 3. /* -> (5/4)*3. -> 1*3. -> 1.*3. -> 3. */
3. * 5 / 4 /*->(3.*5)/4->(3.*5.)/4->15./4->15./4.->3.75 */
Pointer Conversions
Pointer types can be converted to other pointer types using the typecasting mechanism:
char *str;
int *ip; str = (char *)ip;
More generally, the cast type* will convert a pointer to type “pointer to type”. page
102
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Explicit Types Conversions (Typecasting)
In most situations, compiler will provide an automatic implicit conversion of types where needed, without any user interference. Also, you can explicitly convert an operand to another type using the prefix unary typecast operator:
(type) object
This will convert object to a specified type . Parentheses are mandatory.
For example:
/* Let's have two variables of char type: */
char a, b;
/* Following line will coerce a to unsigned int: */
(unsigned int) a;
/* Following line will coerce a to double, then coerce b to double automatically, resulting in double type value: */
(double) a + b; // equivalent to ((double) a) + b; page
103
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Declarations
Declaration introduces one or several names to a program – it informs the compiler what the name represents, what is its type, what are allowed operations with it, etc. This section reviews concepts related to declarations: declarations, definitions, declaration specifiers, and initialization.
The range of objects that can be declared includes:
- Variables
- Constants
- Functions
- Types
- Structure, union, and enumeration tags
- Structure members
- Union members
- Arrays of other types
- Statement labels
- Preprocessor macros
Declarations and Definitions
Defining declarations, also known as definitions, beside introducing the name of an object, also establish the creation (where and when) of the object; that is, the allocation of physical memory and its possible initialization. Referencing declarations, or just declarations, simply make their identifiers and types known to the compiler.
Here is an overview. Declaration is also a definition, except if:
- it declares a function without specifying its body
- it has an extern specifier, and has no initializator or body (in case of func.)
- it is a typedef declaration
There can be many referencing declarations for the same identifier, especially in a multifile program, but only one defining declaration for that identifier is allowed.
page
104
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
For example:
/* Here is a nondefining declaration of function max; */
/* it merely informs compiler that max is a function */
int max();
/* Here is a definition of function max: */
int max(int x, int y) { return (x >= y) ? x : y;
}
/* Definition of variable i: */
int i;
/* Following line is an error, i is already defined! */
int i;
Declarations and Declarators
A declaration is a list of names. The names are sometimes referred to as declarators or identifiers. The declaration begins with optional storage class specifiers, type specifiers, and other modifiers. The identifiers are separated by commas and the list is terminated by a semicolon.
Declarations of variable identifiers have the following pattern:
storage-class [type-qualifier] type var1 [=init1], var2 [=init2],
... ;
where var1, var2 ,... are any sequence of distinct identifiers with optional initializers. Each of the variables is declared to be of type ; if omitted, type defaults to int . Specifier storage-class can take values extern , static , register , or the default auto . Optional type-qualifier can take values const or volatile . For more details, refer to Storage Classes and Type Qualifiers.
For example:
/* Create 3 integer variables called x, y, and z and initialize x and y to the values 1 and 2, respectively: */
int x = 1, y = 2, z; // z remains uninitialized
/* Create a floating-point variable q with static modifier, and initialize it to 0.25: */
static float q = .25;
These are all defining declarations; storage is allocated and any optional initializers are applied.
page
105
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Linkage
An executable program is usually created by compiling several independent trans-
lation units, then linking the resulting object files with preexisting libraries. The term translation unit refers to a source code file together with any included files, but less any source lines omitted by conditional preprocessor directives. A problem arises when the same identifier is declared in different scopes (for example, in different files), or declared more than once in the same scope.
Linkage is the process that allows each instance of an identifier to be associated correctly with one particular object or function. All identifiers have one of two linkage attributes, closely related to their scope: external linkage or internal linkage. These attributes are determined by the placement and format of your declarations, together with the explicit (or implicit by default) use of the storage class specifier static or extern .
Each instance of a particular identifier with external linkage represents the same object or function throughout the entire set of files and libraries making up the program. Each instance of a particular identifier with internal linkage represents the same object or function within one file only.
Linkage Rules
Local names have internal linkage; same identifier can be used in different files to signify different objects. Global names have external linkage; identifier signifies the same object throughout all program files.
If the same identifier appears with both internal and external linkage within the same file, the identifier will have internal linkage.
Internal Linkage Rules
1. names having file scope, explicitly declared as static , have internal linkage
2. names having file scope, explicitly declared as const and not explicitly declared as extern , have internal linkage
3. typedef names have internal linkage
4. enumeration constants have internal linkage page
106
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
External Linkage Rules
1. names having file scope, that do not comply to any of previously stated internal linkage rules, have external linkage.
The storage class specifiers auto and register cannot appear in an external declaration. For each identifier in a translation unit declared with internal linkage, no more than one external definition can be given. An external definition is an external declaration that also defines an object or function; that is, it also allocates storage. If an identifier declared with external linkage is used in an expression (other than as part of the operand of sizeof ), then exactly one external definition of that identifier must be somewhere in the entire program.
Storage Classes
Associating identifiers with objects requires each identifier to have at least two attributes: storage class and type (sometimes referred to as data type). The RSC-4x mikroC compiler deduces these attributes from implicit or explicit declarations in the source code.
Storage class dictates the location (data segment, register, heap, or stack) of the object and its duration or lifetime (the entire running time of the program, or during execution of some blocks of code). Storage class can be established by the syntax of the declaration, by its placement in the source code, or by both of these factors:
storage-class type identifier
The storage class specifiers in RSC-4x mikroC are:
- auto
- register
- static
- extern
Auto
Use the auto modifer to define a local variable as having a local duration. This is the default for local variables and is rarely used. You cannot use auto with globals.
See also Functions.
page
107
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Register
By default, RSC-4x mikroC stores variables within internal microcontroller memory. Thus, modifier register technically has no special meaning. RSC-4x mikroC compiler simply ignores requests for register allocation.
Static
Global name declared with static specifier has internal linkage, meaning that it is local for a given file. See Linkage for more information.
Local name declared with static specifier has static duration. Use static with a local variable to preserve the last value between successive calls to that function.
See Duration for more information.
Extern
Name declared with extern specifier has external linkage, unless it has been previously declared as having internal linkage. Declaration is not a definition if it has extern specifier and is not initialized. The keyword extern is optional for a function prototype.
Use the extern modifier to indicate that the actual storage and initial value of a variable, or body of a function, is defined in a separate source code module.
Functions declared with extern are visible throughout all source files in a program, unless you redefine the function as static .
See Linkage for more information.
page
108
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Type Qualifiers
Type qualifiers const and volatile are optional in declarations and do not actually affect the type of declared object.
Qualifier const
Qualifier const implies that the declared object will not change its value during runtime. In declarations with const qualifier, you need to initialize all the objects in the declaration.
Effectively, RSC-4x mikroC treats objects declared with const qualifier same as literals or preprocessor constants. Compiler will report an error if trying to change an object declared with const qualifier.
For example:
const double PI = 3.14159;
Qualifier volatile
Qualifier volatile implies that variable may change its value during runtime indepent from the program. Use the volatile modifier to indicate that a variable can be changed by a background routine, an interrupt routine, or an I/O port.
Declaring an object to be volatile warns the compiler not to make assumptions concerning the value of the object while evaluating expressions in which it occurs because the value could change at any moment.
page
109
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Typedef Specifier
Specifier typedef introduces a synonym for a specified type. You can use typedef declarations to construct shorter or more meaningful names for types already defined by the language or for types that you have declared. You cannot use the typedef specifier inside a function definition.
The specifier typedef stands first in the declaration:
typedef <type_definition> synonym;
The typedef keyword assigns the synonym to the < type_definition >. The synonym needs to be a valid identifier.
Declaration starting with the typedef specifier does not introduce an object or function of a given type, but rather a new name for a given type. That is, the typedef declaration is identical to “normal” declaration, but instead of objects, it declares types. It is a common practice to name custom type identifiers with starting capital letter — this is not required by C.
For example:
/* Let's declare a synonym for "unsigned long int" */
typedef unsigned long int Distance;
/* Now, synonym "Distance" can be used as type identifier: */
Distance i; // declare variable i of unsigned long int
In typedef declaration, as in any declaration, you can declare several types at once.
For example:
typedef int
*Pti, Array[10];
Here, Pti is synonym for type “pointer to int ”, and Array is synonym for type
“ array of 10 int elements”.
page
110
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Inline Assembler
According to standard, C should allow embedding assembler in the source code by means of
asm
declaration. In addition, RSC-4x mikroC also supports declarations
_asm
and
__asm
which have the same meaning.
Group assembler instructions by the asm keyword (or
_asm
or
__asm
):
asm { block of assembler instructions
}
Assembler one-line comments starting with semicolon are allowed in the embedded assembly code; C/C++ style comments are also allowed.
Embedding assembler with pragma
For the sake of backward compatibility, RSC-4x mikroC compiler supports another method for embedding assembler in C source code.
Note: Preferred method is using the
asm
declaration as described above.
/* Single-line format: */
#pragma asm <machine_instruction0> [; <machine_instruction1> ] ...
or:
/* Block format: */
#pragma asm
<machine_instruction0> [; <machine_instruction1> ] ...
...
#pragma endasm
In the single-line format, instructions should follow the #pragma asm directive in the same line. You can specify more than one instruction in one directive.
Instructions should be separated by semicolons.
In the block format, the #pragma asm directive indicates the beginning of assembler block, and #pragma endasm directive indicates the end of the block. You can write one or more instructions in each line of the block. Multiple instructions in one line should be separated by semicolons.
You can also use function-like macros in the assembly language blocks and lines.
Inside an assembler block, the preprocessor acts in a regular way and processes the assembler block properly. Therefore, in the built-in assembler you can use Cstyle macros and other preprocessing directives. The # and ## operators may not be used.
page
111
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Initialization
At the time of declaration, you can set the initial value of a declared object, i.e.
initialize it. Part of the declaration which specifies the initialization is called the
initializer.
Initializers for globals and static objects must be constants or constant expressions. The initializer for an automatic object can be any legal expression that evaluates to an assignment-compatible value for the type of the variable involved.
Scalar types are initialized with a single expression, which can optionally be enclosed in braces. The initial value of the object is that of the expression; the same constraints for type and conversions apply as for simple assignments.
For example:
int i = 1;
char *s = "hello";
struct complex c = {0.1, -0.2};
// where 'complex' is a structure (float, float)
For structures or unions with automatic storage duration, the initializer must be one of the following:
- An initializer list.
- A single expression with compatible union or structure type. In this case, the initial value of the object is that of the expression.
For example:
struct dot {int x; int y; } m = {30, 40};
For more information, refer to Structures and Unions.
Also, you can initialize arrays of character type with a literal string, optionally enclosed in braces. Each character in the string, including the null terminator, initializes successive elements in the array. For more information, refer to Arrays.
Automatic Initialization
RSC-4x mikroC does not provide automatic initialization for objects. Uninitialized globals and objects with static duration will take random values from memory.
page
112
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Functions
Note: This topic discusses the syntax and usage of functions. For specialized functions and implemenation details see Functions Specifics.
Functions are central to C programming. Functions are usually defined as subprograms which return a value based on a number of input parameters. Return value of a function can be used in expressions – technically, function call is considered to be an expression like any other.
C allows a function to create results other than its return value, referred to as side
effects. Often, function return value is not used at all, depending on the side effects. These functions are equivalent to procedures of other programming languages, such as Pascal. C does not distinguish between procedure and function – functions play both roles.
Each program must have a single external function named main marking the entry point of the program. Functions are usually declared as prototypes in standard or user-supplied header files, or within program files. Functions have external linkage by default and are normally accessible from any file in the program. This can be restricted by using the static storage class specifier in function declaration (see
Storage Classes and Linkage).
Note: Check the ANSI Compliance section for more info on functions’ limitations on RSC-4x.
Function Declaration
Functions are declared in your source files or made available by linking precompiled libraries. Declaration syntax of a function is:
type function_name(parameter-declarator-list);
The function_name must be a valid identifier. This name is used to call the function; see Function Calls for more information.
The type represents the type of function result, and can be any standard or userdefined type. For functions that do not return value, you should use void type. The type can be omitted in global function declarations, and function will assume int type by default.
page
113
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Function type can also be a pointer. For example, float* means that the function result is a pointer to float. Generic pointer, void* is also allowed.
Function cannot return an array or another function.
Within parentheses, parameter-declarator-list is a list of formal arguments that function takes. These declarators specify the type of each function parameter.
The compiler uses this information to check function calls for validity. If the list is empty, function does not take any arguments. Also, if the list is void , function also does not take any arguments; note that this is the only case when void can be used as an argument’s type.
Unlike with variable declaration, each argument in the list needs its own type specifier and a possible qualifier const or volatile .
Function Prototypes
A given function can be defined only once in a program, but can be declared several times, provided the declarations are compatible. If you write a nondefining declaration of a function, i.e. without the function body, you do not have to specify the formal arguments.
This kind of declaration, commonly known as the function prototype, allows better control over argument number and type checking, and type conversions. Name of the parameter in function prototype has its scope limited to the prototype. This allows different parameter names in different declarations of the same function:
/* Here are two prototypes of the same function: */
int test(const char*) /* declares function test */
int test(const char*p) /* declares the same function test */
Function prototypes greatly aid in documenting code. For example, the function
Cf_Init takes two parameters: Control Port and Data Port. The question is, which is which? The function prototype
void Cf_Init(char *ctrlport, char *dataport); makes it clear. If a header file contains function prototypes, you can that file to get the information you need for writing programs that call those functions. If you include an identifier in a prototype parameter, it is used only for any later error messages involving that parameter; it has no other effect.
page
114
RSC-4x mikroC
making it simple...
Function Definition
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Function definition consists of its declaration and a function body. The f unction body is technically a block – a sequence of local definitions and statements enclosed within braces {}. All variables declared within function body are local to the function, i.e. they have function scope.
The function itself can be defined only within the file scope. This means that function declarations cannot be nested.
To return the function result, use the return statement. Statement return in functions of void type cannot have a parameter – in fact, you can omit the return statement altogether if it is the last statement in the function body.
Here is a sample function definition:
/* function max returns greater one of its 2 arguments: */
int max(int x, int y) {
return (x>=y) ? x : y;
}
Here is a sample function which depends on side effects rather than return value:
/*function converts Descartes coordinates (x,y) to polar (r,fi): */
#include <math.h>
void polar(double x, double y, double *r, double *fi) {
*r = sqrt(x * x + y * y);
*fi = (x == 0 && y == 0) ? 0 : atan2(y, x);
return; /* this line can be omitted */
} page
115
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Function Calls and Argument Conversions
Function Calls
A function is called with actual arguments placed in the same sequence as their matching formal parameters. Use the function-call operator ():
function_name(expression_1, ... , expression_n)
Each expression in the function call is an actual argument. Number and types of actual arguments should match those of formal function parameters. If types disagree, implicit type conversions rules apply. Actual arguments can be of any complexity, but you should not depend on their order of evaluation, because it is not specified.
Upon function call, all formal parameters are created as local objects initialized by values of actual arguments. Upon return from a function, temporary object is created in the place of the call, and it is initialized by the expression of return statement. This means that function call as an operand in complex expression is treated as the function result.
If the function is without result (type void ) or you don’t need the result, you can write the function call as a self-contained expression.
In C, scalar parameters are always passed to function by value. A function can modify the values of its formal parameters, but this has no effect on the actual arguments in the calling routine. You can pass scalar object by the address by declaring a formal parameter to be a pointer. Then, use the indirection operator * to access the pointed object.
// For example, Lcd_Init takes the address of PORT,
// so it can change the value of an actual argument:
Lcd_Init(&PORTB);
// This would be wrong; you would pass the value
// of PORT to the function:
Lcd_Init(PORTB); page
116
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Operators
Operators Precedence and Associativity
There are 15 precedence categories, some of which contain only one operator.
Operators in the same category have equal precedence with each other.
10
3
2
5
4
1
7
6
9
8
Where duplicates of operators appear in the table, the first occurrence is unary, the second binary. Each category has an associativity rule: left-to-right (?), or right-toleft (?). In the absence of parentheses, these rules resolve the grouping of expressions with operators of equal precedence.
Precedence Operands Operators Associativity
15
14
13
2
1
2
() [] . ->
! ~ ++ -- + - * &
(type) sizeof
* / %
->
<-
->
12
+ ->
11
2
2
<< >> ->
2
3
2
2
2
2
2
2
2
2
< <= > >=
== !=
&
^
|
&&
||
?:
= *= /= %= += -= &=
^= |= <<= >>=
,
->
->
->
<-
<-
->
->
->
->
-> page
117
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Arithmetic Operators
Arithmetic operators are used to perform mathematical computations. They have numerical operands and return numerical results. Type char technically represents small integers, so char variables can used as operands in arithmetic operations.
All of arithmetic operators associate from left to right.
Operator
+
-
*
/
%
+
-
++
--
Operation
Binary Operators
addition subtraction multiplication division modulus operator returns the remainder of integer division (cannot be used with floating points)
Unary Operators
unary plus does not affect the operand unary minus changes the sign of operand increment adds one to the value of the operand. Postincrement adds one to the value of the operand after it evaluates; while preincrement adds one before it evaluates decrement subtracts one from the value of the operand. Postdecrement subtracts one from the value of the operand after it evaluates; while predecrement subtracts one before it evaluates
Precedence
12
12
13
13
13
14
14
14
14
Note: Operator * is context sensitive and can also represent the pointer reference operator.
page
118
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Binary Arithmetic Operators
Division of two integers returns an integer, while remainder is simply truncated:
/* for example: */
7 / 4; /* equals 1 */
7 * 3 / 4; /* equals 5 */
/* but: */
7. * 3. / 4.; /* equals 5.25 because we are working with floats */
Remainder operand % works only with integers; sign of result is equal to the sign of first operand:
/* for example: */
9 % 3; /* equals 0 */
7 % 3; /* equals 1 */
-7 % 3; /* equals -1 */
We can use arithmetic operators for manipulating characters:
' A' + 32; /* equals 'a' (ASCII only) */
'G' - 'A' + 'a'; /* equals 'g' (both ASCII and EBCDIC) */
Unary Arithmetic Operators
Unary operators ++ and -- are the only operators in C which can be either prefix
(e.g. ++k , --k ) or postfix (e.g. k++ , k-).
When used as prefix, operators ++ and -(preincrement and predecrement) add or subtract one from the value of operand before the evaluation. When used as suffix, operators ++ and -(postincrement and postdecrement) add or subtract one from the value of operand after the evaluation.
For example:
int j = 5; j = ++k; /* k = k + 1, j = k, which gives us j = 6, k = 6 */ but:
int j = 5; j = k++; /* j = k, k = k + 1, which gives us j = 5, k = 6 */ page
119
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Relational Operators
Use relational operators to test equality or inequality of expressions. If the expression evaluates to be true, it returns 1; otherwise it returns 0.
All relational operators associate from left to right.
Relational Operators Overview
Operator
==
!=
>
<
>=
<=
Operation
equal not equal greater then less than greater than or equal less than or equal
Precedence
9
9
10
10
10
10
Relational Operators in Expressions
Precedence of arithmetic and relational operators was designated in such a way to allow complex expressions without parentheses to have expected meaning: a + 5 >= c - 1.0 / e /* -> (a + 5) >= (c - (1.0 / e)) */
Always bear in mind that relational operators return either 0 or 1. Consider the following examples:
/* ok: */
5 > 7 /* returns 0 */
10 <= 20 /* returns 1 */
/* this can be tricky: */
8 == 13 > 5 /* returns 0, as: 8 == (13 > 5) -> 8 == 1 -> 0 */
14 > 5 < 3 /* returns 1, as: (14 > 5) < 3 -> 1 < 3 -> 1 */ a < b < 5 /* returns 1, as: (a < b) < 5 -> (0 or 1) < 5 -> 1*/ page
120
RSC-4x mikroC
making it simple...
Bitwise Operators
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Use the bitwise operators to modify the individual bits of numerical operands.
Bitwise operators associate from left to right. The only exception is the bitwise complement operator ~ which associates from right to left.
Operator
&
|
^
~
<<
>>
Operation
bitwise AND; compares pairs of bits and returns 1 if both bits are 1, otherwise returns 0 bitwise (inclusive) OR; compares pairs of bits and returns 1 if either or both bits are 1, otherwise returns 0 bitwise exclusive OR (XOR); compares pairs of bits and returns 1 if the bits are complementary, otherwise returns 0 bitwise complement (unary); inverts each bit bitwise shift left; moves the bits to the left, discards the far left bit and assigns 0 to the right most bit.
bitwise shift right; moves the bits to the right, discards the far right bit and if unsigned assigns 0 to the left most bit, otherwise sign extends
Precedence
8
6
7
14
11
11
Logical Operations on Bit Level
&
0
1
0
0
0
1
0
1
0
|
1
0
0
1
1
1
1
^
0
1
0
0
1
1
1
0 page
121
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
~ 0
1
1
0
Bitwise operators & , | , and ^ perform logical operations on appropriate pairs of bits of their operands. Operator ~ complements each bit of its operand.
For example:
0x1234 & 0x5678 /* equals 0x1230 */
/* because ..
0x1234 : 0001 0010 0011 0100
0x5678 : 0101 0110 0111 1000
----------------------------
& : 0001 0010 0011 0000
.. that is, 0x1230 */
/* Similarly: */
0x1234 | 0x5678; /* equals 0x567C */
0x1234 ^ 0x5678; /* equals 0x444C */
~ 0x1234; /* equals 0xEDCB */
Note: Operator & can also be the pointer reference operator. Refer to Pointers for more information.
Bitwise Shift Operators
Binary operators << and >> move the bits of the left operand for a number of positions specified by the right operand, to the left or right, respectively. Right operand has to be positive.
With shift left ( << ), left most bits are discarded, and “new” bytes on the right are assigned zeros. Thus, shifting unsigned operand to the left by n positions is equivalent to multiplying it by 2n if all the discarded bits are zero. This is also true for signed operands if all the discarded bits are equal to sign bit.
page
122
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
000001 << 5; /* equals 000040 */
0x3801 << 4; /* equals 0x8010, overflow! */
With shift right ( >> ), right most bits are discarded, and the “freed” bytes on the left are assigned zeros (in case of unsigned operand) or the value of the sign bit zeros (in case of signed operand). Shifting operand to the right by n positions is equivalent to dividing it by 2n.
0xFF56 >> 4; /* equals 0xFFF5 */
0xFF56u >> 4; /* equals 0x0FF5 */
Bitwise vs. Logical
Be aware of the principle difference between how bitwise and logical operators work. For example:
0222222 & 0555555; /* equals 000000 */
0222222 && 0555555; /* equals 1 */
~ 0x1234; /* equals 0xEDCB */
! 0x1234; /* equals 0 */
Logical Operators
Operands of logical operations are considered true or false, that is non-zero or zero. Logical operators always return 1 or 0. Operands in a logical expression must be of scalar type.
Logical operators && and || associate from left to right. Logical negation operator
!
associates from right to left.
Logical Operators Overview
Operator
&&
||
!
Operation
logical AND logical OR logical negation
Precedence
5
4
14 page
123
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
&& 0 x
| | 0 x
!
0 x
0
0 0
0
0 1
0 1
x
0 1
x
1 1
Precedence of logical, relational, and arithmetic operators was designated in such a way to allow complex expressions without parentheses to have expected meaning: c >= '0' && c <= '9'; /* reads as: (c >= '0') && (c <= '9') */ a + 1 == b || ! f(x); /* reads as: ((a + 1) == b) || (! (f(x))) */
Logical AND && returns 1 only if both expressions evaluate to be nonzero, otherwise returns 0. If the first expression evaluates to false, the second expression is not evaluated. For example: a > b && c < d; /* reads as (a > b) && (c < d) */
/* if (a > b) is false (0), (c < d) will not be evaluated */
Logical OR || returns 1 if either of the expressions evaluate to be nonzero, otherwise returns 0. If the first expression evaluates to true, the second expression is not evaluated. For example: a && b || c && d; /* reads as: (a && b) || (c && d) */
/* if (a && b) is true (1), (c && d) will not be evaluated */
Logical Expressions and Side Effects
General rule with complex logical expressions is that the evaluation of consecutive logical operands stops the very moment the final result is known. For example, if we have an expression a && b && c where a is false (0), then operands b and c will not be evaluated. This is very important if b and c are expressions, as their possible side effects will not take place!
page
124
RSC-4x mikroC
making it simple...
Logical vs. Bitwise
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Be aware of the principle difference between how bitwise and logical operators work. For example:
0222222 & 0555555 /* equals 000000 */
0222222 && 0555555 /* equals 1 */
~ 0x1234 /* equals 0xEDCB */
! 0x1234 /* equals 0 */
Conditional Operator ?
The conditional operator ? : is the only ternary operator in C. Syntax of the conditional operator is:
expression1 ? expression2 : expression3
The expression1 is evaluated first. If its value is true, then expression2 evaluates and expression3 is ignored. If expression1 evaluates to false, then expression3 evaluates and expression2 is ignored. The result will be the value of either expression2 or expression3 depending upon which evaluates. The fact that only one of these two expressions evaluates is very important if you expect them to produce side effects!
Conditional operator associates from right to left.
Here are a couple of practical examples:
/* Find max(a, b): */
max = ( a > b ) ? a : b;
/* Convert small letter to capital: */
/* (no parentheses are actually necessary) */
c = ( c >= 'a' && c <= 'z' ) ? ( c - 32 ) : c; page
125
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Conditional Operator Rules
Expression1 must be a scalar expression; expression2 and expression3 must obey one of the following rules:
1. Both of arithmetic type. expression2 and expression3 are subject to the usual arithmetic conversions, which determines the resulting type.
2. Both of compatible struct or union types. The resulting type is the structure or union type of expression2 and expression3 .
3. Both of void type. The resulting type is void .
4. Both of type pointer to qualified or unqualified versions of compatible types.
The resulting type is a pointer to a type qualified with all the type qualifiers of the types pointed to by both operands.
5. One operand is a pointer, and the other is a null pointer constant. The resulting type is a pointer to a type qualified with all the type qualifiers of the types pointed to by both operands.
6. One operand is a pointer to an object or incomplete type, and the other is a pointer to a qualified or unqualified version of void . The resulting type is that of the non-pointer-to-void operand.
Assignment Operators
Unlike many other programming languages, C treats value assignment as operation (represented by an operator) rather than instruction.
Simple Assignment Operator
For a common value assignment, we use a simple assignment operator (=) : expression1 = expression2
The expression1 is an object (memory location) to which we assign value of expression2 . Operand expression1 has to be a lvalue, and expression2 can be any expression. The assignment expression itself is not an lvalue.
If expression1 and expression2 are of different types, result of the expression2 will be converted to the type of expression1 , if necessary. Refer to Type
Conversions for more information.
page
126
RSC-4x mikroC
making it simple...
Sizeof Operator
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Prefix unary operator sizeof returns an integer constant that gives the size in bytes of how much memory space is used by its operand (determined by its type, with some exceptions).
Operator sizeof can take either a type identifier or an unary expression as an operand. You cannot use sizeof with expressions of function type, incomplete types, parenthesized names of such types, or with an lvalue that designates a bit field object.
Sizeof Applied to Expression
If applied to expression, size of the operand is determined without evaluating the expression (and therefore without side effects). Result of the operation will be the size of the type of the expression’s result.
Sizeof Applied to Type
If applied to a type identifier, sizeof returns the size of the specified type. Unit for type size is the sizeof(char) which is equivalent to one byte. Operation sizeof(char) gives the result 1, whether the char is signed or unsigned .
sizeof(char) sizeof(int) sizeof(unsigned long) sizeof(float)
/* returns 1 */
/* returns 2 */
/* returns 4 */
/* returns 4 */
When the operand is a non-parameter of array type, the result is the total number of bytes in the array (in other words, an array name is not converted to a pointer type):
int i, j, a[10];
//...
j = sizeof(a[1]); /* j = sizeof(int) = 2 */ i = sizeof(a); /* i = 10*sizeof(int) = 20 */
/* To get the number of elements in an array: */
int num_elem = i/j;
If the operand is a parameter declared as array type or function type, sizeof gives the size of the pointer. When applied to structures and unions , sizeof gives the total number of bytes, including any padding. Operator sizeof cannot be applied to a function.
page
127
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Expressions
An expression is a sequence of operators, operands, and punctuators that specifies a computation. Formally, expressions are defined recursively: subexpressions can be nested without formal limit. However, the compiler will report an out-of-memory error if it can’t compile an expression that is too complex.
In ANSI C, the primary expressions are: constant (also referred to as literal), identifier, and ( expression ), defined recursively.
Expressions are evaluated according to certain conversion, grouping, associativity, and precedence rules that depend on the operators used, the presence of parentheses, and the data types of the operands. The precedence and associativity of the operators are summarized in Operator Precedence and Associativity. The way operands and subexpressions are grouped does not necessarily specify the actual order in which they are evaluated by RSC-4x mikroC.
Expressions can produce an lvalue, an rvalue, or no value. Expressions might cause side effects whether they produce a value or not.
Comma Expressions
One of the specifics of C is that it allows you to use comma as a sequence opera-
tor to form the so-called comma expressions or sequences . Comma expression is a comma-delimited list of expressions – it is formally treated as a single expression so it can be used in places where an expression is expected. The following sequence: expression_1, expression_2; results in the left-to-right evaluation of each expression , with the value and type of expression_2 giving the result of the whole expression. Result of expression_1 is discarded.
Binary operator comma (,) has the lowest precedence and associates from left to right, so that a, b, c is same as (a, b), c . This allows us to write sequences with any number of expressions: expression_1, expression_2, ... expression_n; page
128
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers results in the left-to-right evaluation of each expression , with the value and type of expression_2 giving the result of the whole expression. Result of expression_1 is discarded.
Binary operator comma (,) has the lowest precedence and associates from left to right, so that a, b, c is same as (a, b), c . This allows us to write sequences with any number of expressions: expression_1 , expression_2 , ... expression_n; this results in the left-to-right evaluation of each expression , with the value and type of expression_n giving the result of the whole expression. Results of other expressions are discarded, but their (possible) side-effect do occur.
For example: result = ( a = 5, b /= 2, c++ );
/* returns preincremented value of variable c, but also intializes a, divides b by 2, and increments c */
result = ( x = 10, y = x + 3, x--, z -= x * 3 - --y );
/* returns computed value of variable z, and also computes x and y */
Note
Do not confuse comma operator (sequence operator) with the comma punctuator which separates elements in a function argument list and initializator lists. Mixing the two uses of comma is legal, but you must use parentheses to distinguish them.
To avoid ambiguity with the commas in function argument and initializer lists, use parentheses. For example, func(i, (j = 1, j + 4), k); calls function func with three arguments (i, 5, k), not four.
page
129
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Statements
Statements specify the flow of control as a program executes. In the absence of specific jump and selection statements, statements are executed sequentially in the order of appearance in the source code.
Statements can be roughly divided into:
- Labeled Statements
- Expression Statements
- Selection Statements
- Iteration Statements (Loops)
- Jump Statements
- Compound Statements (Blocks)
Labeled Statements
Every statement in program can be labeled. Label is an identifier added before the statement like this: label_identifier: statement;
There is no special declaration of a label – it just “tags” the statement .
Label_identifier has a function scope and label cannot be redefined within the same function.
Labels have their own namespace: label identifier can match any other identifier in the program.
A statement can be labeled for two reasons:
- The label identifier serves as a target for the unconditional goto statement,
- The label identifier serves as a target for the switch statement. For this purpose, only case and default labeled statements are used: case constant-expression : statement default : statement page
130
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Expression Statements
Any expression followed by a semicolon forms an expression statement: expression;
RSC-4x mikroC executes an expression statement by evaluating the expression .
All side effects from this evaluation are completed before the next statement is executed. Most expression statements are assignment statements or function calls.
The null statement is a special case, consisting of a single semicolon (;). The null statement does nothing, and is therefore useful in situations where the C syntax expects a statement but your program does not need one. For example, null statement is commonly used in “empty” loops: for (; *q++ = *p++ ;);
/* body of this loop is a null statement */
Selection Statements
Selection or flow-control statements select from alternative courses of action by testing certain values. There are two types of selection statements:
- if
- switch
If Statement
Use the if statement to implement a conditional statement. Syntax of the if statement is:
if (expression) statement1 [else statement2]
When expression evaluates to true, statement1 executes. If expression is false, statement2 executes. The expression must evaluate to an integral value; otherwise, the condition is ill-formed. Parentheses around the expression are mandatory.
page
131
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The else keyword is optional, but no statements can come between the if and the else.
Nested If statements
Nested if statements require additional attention. General rule is that the nested conditionals are parsed starting from the innermost conditional, with each else bound to the nearest available if on its left:
if (expression1) statement1
else if (expression2)
if (expression3) statement2
else statement3 /* this belongs to: if (expression3) */
else statement4 /* this belongs to: if (expression2) */
Note
The #if and #else preprocessor statements (directives) look similar to the if and else statements, but have very different effects. They control which source file lines are compiled and which are ignored.
Switch Statement
Use the switch statement to pass control to a specific program branch, based on a certain condition. Syntax of switch statement is: switch (expression) { case constant-expression_1 : statement_1;
.
.
.
case constant-expression_n : statement_n;
[default : statement;]
}
First, the expression (condition) is evaluated. The switch statement then compares it to all the available constant-expressions following the keyword case .
If the match is found, switch passes control to that matching case, at which point the statement following the match evaluates. Note that constant-expressions must evaluate to integer. There cannot be two same constant expressions evaluating to same value.
page
132
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Parentheses around expression are mandatory.
Upon finding a match, program flow continues normally: following instructions will be executed in natural order regardless of the possible case label. If no case satisfies the condition, the default case evaluates (if the label default is specified).
For example, if variable i has value between 1 and 3, following switch would always return it as 4:
switch (i) {
case 1: i++;
case 2: i++;
case 3: i++;
}
To avoid evaluating any other cases and relinquish control from the switch , terminate each case with break.
Here is a simple example with switch . Let’s assume we have a variable phase with only 3 different states (0, 1, or 2) and a corresponding function (event) for each of these states. This is how we could switch the code to the appopriate routine:
switch (phase) {
case 0: Lo(); break;
case 1: Mid(); break;
case 2: Hi(); break;
default: Message("Invalid state!");
}
Nested switch
Conditional switch statements can be nested – labels case and default are then assigned to the innermost enclosing switch statement.
page
133
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Iteration Statements
Iteration statements let you loop a set of statements. There are three forms of iteration statements in RSC-4x mikroC:
- while
- do
- for
While Statement
Use the while keyword to conditionally iterate a statement. Syntax of while statement is:
while (expression) statement
The statement executes repeatedly until the value of expression is false. The test takes place before statement executes. Thus, if expression evaluates to false on the first pass, the loop does not execute. Note that parentheses around expression are mandatory.
Here is an example of calculating scalar product of two vectors, using the while statement:
int s = 0, i = 0;
while (i < n) { s += a[i] * b[i]; i++;
}
Note that body of a loop can be a null statement. For example:
while (*q++ = *p++); page
134
RSC-4x mikroC
making it simple...
Do Statement
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The do statement executes until the condition becomes false. Syntax of do statement is:
do statement while (expression);
The statement is executed repeatedly as long as the value of expression remains non-zero. The expression is evaluated after each iteration, so the loop will execute statement at least once.
Parentheses around expression are mandatory.
Note that do is the only control structure in C which explicitly ends with semicolon (;). Other control structures end with statement which means that they implicitly include a semicolon or a closing brace.
Here is an example of calculating scalar product of two vectors, using the do statement: s = 0; i = 0;
do { s += a[i] * b[i]; i++;
} while ( i < n ); page
135
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
For Statement
The for statement implements an iterative loop. Syntax of for statement is:
for ([init-expression]; [condition-expression]; [increment-expression]) statement
Before the first iteration of the loop, init-expression sets the starting variables for the loop. You cannot pass declarations in init-expression .
condition-expression ment is checked before the first entry into the block; stateis executed repeatedly until the value of condition-expression is false. After each iteration of the loop, increment-expression increments a loop counter.
Consequently, i++ is functionally the same as ++i .
All the expressions are optional. If condition-expression is left out, it is assumed to be always true. Thus, “empty” for statement is commonly used to create an endless loop in C:
for ( ; ; ) statement
The only way to break out of this loop is by means of break statement.
Here is an example of calculating scalar product of two vectors, using the for statement:
for ( s = 0, i = 0; i < n; i++ ) s += a[i] * b[i];
You can also do it like this:
for ( s = 0, i = 0; i < n; s += a[i] * b[i], i++ ); /* valid, but
ugly */
but this is considered a bad programming style. Although legal, calculating the sum should not be a part of the incrementing expression, because it is not in the service of loop routine. Note that we used a null statement (;) for a loop body.
page
136
RSC-4x mikroC
making it simple...
Jump Statements
mikroC - C Compiler for Sensory RSC-4x microcontrollers
A jump statement, when executed, transfers control unconditionally. There are four such statements in RSC-4x mikroC:
- break
- continue
- goto
- return
Break and Continue Statements
Break Statement
Sometimes, you might need to stop the loop from within its body. Use the break statement within loops to pass control to the first statement following the innermost switch , for , while , or do block.
Break is commonly used in switch statements to stop its execution upon the first positive match. For example:
switch (state) {
case 0: Lo(); break;
case 1: Mid(); break;
case 2: Hi(); break;
default: Message("Invalid state!");
}
Continue Statement
You can use the continue statement within loops to “skip the cycle”. It passes control to the end of the innermost enclosing end brace belonging to a looping construct. At that point the loop continuation condition is re-evaluated. This means that continue demands the next iteration if loop continuation condition is true.
page
137
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Specifically, continue statement within the loop will jump to the marked position as you can see below: while (..) {
.
.
.
// continue jumps here
.
.
}do {
.
// continue jumps here
while (..); for (..;..;..;) {
.
.
.
// continue jumps here
}
Goto Statement
Use the goto statement to unconditionally jump to a local label — for more information on labels, refer to Labeled Statements. Syntax of goto statement is:
goto label_identifier ;
This will transfer control to the location of a local label specified by
label_identifier
. The
label_identifier
has to be a name of the label within the same function in which the goto statement is. The goto line can come before or after the label.
You can use goto to break out from any level of nested control structures. But, goto cannot be used to jump into block while skipping that block’s initializations
– for example, jumping into loop’s body, etc.
page
138
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Use of goto statement is generally discouraged as practically every algorithm can be realized without it, resulting in legible structured programs. One possible application of goto statement is breaking out from deeply nested control structures:
for (...) {
for (...) {
...
if (disaster) goto Error;
...
}
}
.
.
.
Error: /* error handling code */
Return Statement
Use the return statement to exit from the current function back to the calling routine, optionally returning a value. Syntax is:
return [expression];
This will evaluate the
expression
and return the result. Returned value will be automatically converted to the expected function type, if needed. The
expression
is optional; if omitted, function will return a random value from memory.
Note: Statement return in functions of void type cannot have an
expression
– in fact, you can omit the return statement altogether if it is the last statement in the function body.
page
139
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Compound Statements (Blocks)
A compound statement, or block, is a list (possibly empty) of statements enclosed in matching braces { }. Syntactically, a block can be considered to be a single statement, but it also plays a role in the scoping of identifiers. An identifier declared within a block has a scope starting at the point of declaration and ending at the closing brace. Blocks can be nested to any depth up to the limits of memory.
For example, for loop expects one statement in its body, so we can pass it a compound statement:
for (i = 0; i < n; i++ ) {
int temp = a[i]; a[i] = b[i]; b[i] = temp;
}
Note that, unlike other statements, compound statements do not end with semicolon (;), i.e. there is never a semicolon following the closing brace.
Preprocessor
Preprocessor is an integrated text processor which prepares the source code for compiling. Preprocessor allows:
- inserting text from a specifed file to a certain point in code (see File Inclusion),
- replacing specific lexical symbols with other symbols (see Macros),
- conditional compiling which conditionally includes or omits parts of code (see
Conditional Compilation).
Note that preprocessor analyzes text at token level, not at individual character level. Preprocessor is controled by means of preprocessor directives and preprocessor operators.
page
140
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Preprocessor Directives
Any line in source code with a leading # is taken as a preprocessing directive
(or control line ), unless the # is within a string literal, in a character constant, or embedded in a comment. The initial # can be preceded or followed by whitespace (excluding new lines).
The null directive consists of a line containing the single character # . This line is always ignored.
Preprocessor directives are usually placed at the beginning of the source code, but they can legally appear at any point in a program. The RSC-4x mikroC preprocessor detects preprocessor directives and parses the tokens embedded in them.
Directive is in effect from its declaration to the end of the program file.
Here is one commonly used directive:
#include <math.h>
For more information on including files with #include directive, refer to File
Inclusion.
RSC-4x mikroC supports standard preprocessor directives:
# (null directive) #if
#define #ifdef
#elif #ifndef
#else #include
#endif #line
#error #undef
For the list of pragma directives see Pragma Directives.
Line Continuation with Backslash (\)
If you need to break directive into multiple lines, you can do it by ending the line with a backslash (\):
#define MACRO This directive continues to \ the following line.
page
141
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Macros
Macros provide a mechanism for token replacement, prior to compilation, with or without a set of formal, function-like parameters.
Defining Macros and Macro Expansions
The #define directive defines a macro:
#define macro_identifier <token_sequence>
Each occurrence of macro_identifier in the source code following this control line will be replaced in the original position with the possibly empty token_sequence (there are some exceptions, which are noted later). Such replacements are known as macro expansions. The token_sequence is sometimes called the body of the macro. An empty token sequence results in the removal of each affected macro identifier from the source code.
No semicolon ( ; ) is needed to terminate a preprocessor directive. Any character found in the token sequence, including semicolons, will appear in the macro expansion. The token_sequence terminates at the first non-backslashed new line encountered. Any sequence of whitespace, including comments in the token sequence, is replaced with a single-space character.
After each individual macro expansion, a further scan is made of the newly expanded text. This allows for the possibility of nested macros: The expanded text can contain macro identifiers that are subject to replacement. However, if the macro expands into what looks like a preprocessing directive, such a directive will not be recognized by the preprocessor. Any occurrences of the macro identifier found within literal strings, character constants, or comments in the source code are not expanded.
A macro won’t be expanded during its own expansion (so #define MACRO MACRO won’t expand indefinitely).
page
142
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Let’s have an example:
/* Here are some simple macros: */
#define ERR_MSG "Out of range!"
#define EVERLOOP for( ; ; )
/* which we could use like this: */
main() {
EVERLOOP {
...
if (error) { Lcd_Out_Cp(ERR_MSG); break; }
...
}
}
Attempting to redefine an already defined macro identifier will result in a warning unless the new definition is exactly the same token-by-token definition as the existing one. The preferred strategy where definitions might exist in other header files is as follows:
#ifndef BLOCK_SIZE
#define BLOCK_SIZE 512
#endif
The middle line is bypassed if BLOCK_SIZE is currently defined; if BLOCK_SIZE is not currently defined, the middle line is invoked to define it.
Macros with Parameters
The following syntax is used to define a macro with parameters:
#define macro_identifier(<arg_list>) <token_sequence>
Note there can be no whitespace between the macro_identifier and the “(”. The optional arg_list is a sequence of identifiers separated by commas, not unlike the argument list of a C function. Each comma-delimited identifier plays the role of a formal argument or placeholder.
page
143
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Such macros are called by writing macro_identifier(<actual_arg_list>) in the subsequent source code. The syntax is identical to that of a function call; indeed, many standard library C “functions” are implemented as macros.
However, there are some important semantic differences.
The optional actual_arg_list must contain the same number of comma-delimited token sequences, known as actual arguments, as found in the formal arg_list of the #define line – there must be an actual argument for each formal argument. An error will be reported if the number of arguments in the two lists is different.
A macro call results in two sets of replacements. First, the macro identifier and the parenthesis-enclosed arguments are replaced by the token sequence. Next, any formal arguments occurring in the token sequence are replaced by the corresponding real arguments appearing in the actual_arg_list . As with simple macro definitions, rescanning occurs to detect any embedded macro identifiers eligible for expansion.
Here is a simple example:
/* A simple macro which returns greater of its 2 arguments: */
#define _MAX(A, B) ((A) > (B)) ? (A) : (B)
/* Let's call it: */
x = _MAX(a + b, c + d);
/* Preprocessor will transform the previous line into: x = ((a + b) > (c + d)) ? (a + b) : (c + d) */
It is highly recommended to put parentheses around each of the arguments in macro body – this will avoid possible problems with operator precedence.
page
144
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Undefining Macros
You can undefine a macro using the #undef directive.
#undef macro_identifier
Directive #undef detaches any previous token sequence from the macro_identifier ; the macro definition has been forgotten, and the macro_identifier is undefined. No macro expansion occurs within #undef lines.
The state of being defined or undefined is an important property of an identifier, regardless of the actual definition. The #ifdef and #ifndef conditional directives, used to test whether any identifier is currently defined or not, offer a flexible mechanism for controlling many aspects of a compilation.
After a macro identifier has been undefined, it can be redefined with #define , using the same or a different token sequence.
File Inclusion
The preprocessor directive #include pulls in header files (extension .h) into the source code. Do not rely on preprocessor to include source files (extension .c) — see Add/Remove Files from Project for more information.
The syntax of #include directive has two formats:
#include <header_name>
#include "header_name"
The preprocessor removes the #include line and replaces it with the entire text of the header file at that point in the source code. The placement of the #include can therefore influence the scope and duration of any identifiers in the included file.
The difference between the two formats lies in the searching algorithm employed in trying to locate the include file.
page
145
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
If #include directive was used with the <header_name> version, the search is made successively in each of the following locations, in this particular order:
1. RSC-4x mikroC installation folder › “include” folder
2. your custom include paths
The " header_name " version specifies a user-supplied include file; RSC-4x mikroC will look for the header file in following locations, in this particular order:
1. the project folder (folder which contains the project file .psc
)
2. RSC-4x mikroC installation folder › “include” folder
3. your custom include paths
Explicit Path
If you place an explicit path in the header_name , only that directory will be searched. For example:
#include "C:\headers\my.h"
Note
There is also a third version of #include directive, rarely used, which assumes that neither < nor " appears as the first non-whitespace character following
#include :
#include macro_identifier
It assumes a macro definition exists that will expand the macro identifier into a valid delimited header name with either of the <header_name> or "header_name" formats.
Preprocessor Operators
The # (pound sign) is a preprocessor directive when it occurs as the first nonwhitespace character on a line. Also, # and ## perform operator replacement and merging during the preprocessor scanning phase.
page
146
RSC-4x mikroC
making it simple...
Operator #
mikroC - C Compiler for Sensory RSC-4x microcontrollers
In C preprocessor, character sequence enclosed by quotes is considered a token and its content is not analyzed. This means that macro names within quotes are not expanded.
If you need an actual argument (the exact sequence of characters within quotes) as result of preprocessing, you can use the # operator in macro body. It can be placed in front of a formal macro argument in definition in order to convert the actual argument to a string after replacement.
For example, let’s have macro LCD_PRINT for printing variable name and value on
LCD:
#define LCD_PRINT(val) Lcd_Out_Cp(#val ": "); \
Lcd_Out_Cp(IntToStr(val));
Now, the following code,
LCD_PRINT(temp) will be preprocessed to this:
Lcd_Out_Cp("temp" ": "); Lcd_Out_Cp(IntToStr(temp));
Operator ##
Operator ## is used for token pasting: you can paste (or merge) two tokens together by placing ## in between them (plus optional whitespace on either side). The preprocessor removes the whitespace and the ##, combining the separate tokens into one new token. This is commonly used for constructing identifiers.
For example, we could define macro SPLICE for pasting two tokens into one identifier:
#define SPLICE(x,y) x ## _ ## y
Now, the call SPLICE(cnt, 2) would expand to identifier cnt_2 .
Note
RSC-4x mikroC does not support the older nonportable method of token pasting using (l/**/r) .
page
147
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Conditional Compilation
Conditional compilation directives are typically used to make source programs easy to change and easy to compile in different execution environments. RSC-4x mikroC supports conditional compilation by replacing the appropriate source-code lines with a blank line.
All conditional compilation directives must be completed in the source or include file in which they are begun.
Directives #if, #elif, #else, and #endif
The conditional directives #if, #elif, #else , and #endif work very similar to the common C conditional statements. If the expression you write after the #if has a nonzero value, the line group immediately following the #if directive is retained in the translation unit.
Syntax is:
#if constant_expression_1
<section_1>
[#elif constant_expression_2
<section_2>]
...
[#elif constant_expression_n
<section_n>]
[#else
<final_section>]
#endif
Each #if directive in a source file must be matched by a closing #endif directive.
Any number of #elif directives can appear between the #if and #endif directives, but at most one #else directive is allowed. The #else directive, if present, must be the last directive before #endif .
The sections can be any program text that has meaning to the compiler or the preprocessor. The preprocessor selects a single section by evaluating the constant_expression following each #if or #elif directive until it finds a true
(nonzero) constant expression. The constant expressions are subject to macro expansion.
page
148
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
If all occurrences of constant-expression are false, or if no #elif directives appear, the preprocessor selects the text block after the #else clause. If the #else clause is omitted and all instances of constant_expression in the #if block are false, no section is selected for further processing.
Any processed section can contain further conditional clauses, nested to any depth.
Each nested #else , #elif , or #endif directive belongs to the closest preceding
#if directive.
The net result of the preceding scenario is that only one code section (possibly empty) will be compiled.
Directives #ifdef and #ifndef
You can use the #ifdef and #ifndef directives anywhere #if can be used. The
#ifdef and #ifndef conditional directives let you test whether an identifier is currently defined or not. The line
#ifdef identifier has exactly the same effect as #if 1 if
identifier
is currently defined, and the same effect as #if 0 if
identifier
is currently undefined. The other directive,
#ifndef , tests true for the “not-defined” condition, producing the opposite results.
The syntax thereafter follows that of the #if, #elif, #else, and #endif .
An identifier defined as NULL is considered to be defined.
page
149
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC
making it simple...
page
150
CHAPTER
5
RSC-4x mikroC
Libraries
RSC-4x mikroC provides a number of built-in and library routines which help you develop your application faster and easier. Libraries for Character Handling
Mathematics, Input/Output, General Utilities, String Handling, Compact Flash
Library, LCD Library, Software I2C Library, Software SPI Library and many other are included along with practical, ready-to-use code examples.
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC Libraries
To use any of the following libraries include the appropriate header file in your source code.
C Standard Library
Character Handling (ctype.h)
Mathematics (math.h)
Input/Output (stdio.h)
General Utilities (stdlib.h)
String Handling
Additional Libraries
Compact Flash Library (cf.h)
LCD Library (lcd.h)
Software I2C Library (soft_i2c.h)
Software SPI Library (soft_spi.h)
See also Built-in Routines.
Note: All library functions have been compiled with the option “store const vars in
CDATA area” disabled; i.e., library functions take only pointers to SRAM, which means that you should pay additional attention if enabling this option. (The only exception is the function sprintf.) page
152
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
C Ctype Library
Header file ctype.h contains functions used to classify characters by their types or to convert between upper and lower case in a way that is independent of the used character set.
Library Routines
isalnum isalpha iscntrl isdigit isgraph islower ispunct isspace isupper isxdigit toupper tolower
isalnum
Prototype
Description
unsigned char isalnum(unsigned char character);
Function returns 1 if the character is alphanumeric (A-Z, a-z, 0-9), otherwise returns zero.
page
153
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
isalpha
Prototype
unsigned char isalpha(unsigned char character);
Description
Function returns 1 if the character is alphabetic (A-Z, a-z), otherwise returns zero.
iscntrl
Prototype
Description
unsigned char iscntrl(unsigned char character);
Function returns 1 if the character is a control character or delete (decimal 0-31 and
127), otherwise returns zero.
isdigit
Prototype
Description
unsigned char isdigit(unsigned char character);
Function returns 1 if the character is a digit (0-9), otherwise returns zero.
isgraph
Prototype
Description
unsigned char isgraph(unsigned char character);
Function returns 1 if the character is a printable character, excluding the space (decimal 32), otherwise returns zero.
page
154
RSC-4x mikroC
making it simple...
islower
Prototype
mikroC - C Compiler for Sensory RSC-4x microcontrollers
unsigned char islower(unsigned char character);
Description
Function returns 1 if the character is a lowercase letter (a-z), otherwise returns zero.
isprint
Prototype
Description
unsigned char isprint(unsigned char character);
Function returns 1 if the character is printable (decimal 32-126), otherwise returns zero.
ispunct
Prototype
Description
unsigned char ispunct(unsigned char character);
Function returns 1 if the character is punctuation (decimal 32-47, 58-63, 91-96, 123-
126), otherwise returns zero.
isspace
Prototype
Description
unsigned char isspace(unsigned char character);
Function returns 1 if the character is white space (space, CR, HT, VT, NL, FF), otherwise returns zero.
page
155
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
isupper
Prototype
unsigned char isupper(unsigned char character);
Description
Function returns 1 if the character is an uppercase letter (A-Z), otherwise returns 0.
isxdigit
Prototype
Description
unsigned char isxdigit(unsigned char character);
Function returns 1 if the character is a hex digit (0-9, A-F, a-f), otherwise returns zero.
toupper
Prototype
Description
unsigned char toupper(unsigned char character);
If the character is a lowercase letter (a-z), function returns an uppercase letter.
Otherwise, function returns an unchanged input parameter.
tolower
Prototype
Description
unsigned char tolower(unsigned char character);
If the character is an uppercase letter (A-Z), function returns a lowercase letter.
Otherwise, function returns an unchanged input parameter.
page
156
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
C Math Library
Header file math.h contains declarations of common mathematical functions.
Library Routines
acos asin atan atan2 ceil cos cosh exp fabs floor frexp ldexp log log10 modf pow sin sinh sqrt tan tanh
acos
Prototype
Description
double acos(double x);
Function returns the arc cosine of parameter x
; that is, the value whose cosine is x
.
Input parameter x must be between -1 and 1 (inclusive). The return value is in radians, between 0 and pi (inclusive).
page
157
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
asin
Prototype
double asin(double x);
Description
Function returns the arc sine of parameter x
; that is, the value whose sine is x
. Input parameter x must be between -1 and 1 (inclusive). The return value is in radians, between -pi/2 and pi/2 (inclusive).
atan
Prototype
Description
double atan(double x);
Function computes the arc tangent of parameter x
; that is, the value whose tangent is x
.
The return value is in radians, between -pi/2 and pi/2 (inclusive).
atan2
Prototype
Description
double atan2(double x, double y);
This is the two argument arc tangent function. It is similar to computing the arc tangent of y/x, except that the signs of both arguments are used to determine the quadrant of the result, and x is permitted to be zero. The return value is in radians, between -pi and pi (inclusive).
ceil
Prototype
Description
double ceil(double num);
Function returns value of parameter num rounded up to the next whole number.
page
158
RSC-4x mikroC
making it simple...
cos
Prototype
double cos(double x); mikroC - C Compiler for Sensory RSC-4x microcontrollers
Description
Function returns the cosine of x in radians. The return value is from -1 to 1.
cosh
Prototype
Description
double cosh(double x);
Function returns the hyperbolic cosine of x
, defined mathematically as
(e x
+e
-x
)/2
. If the value of x is too large (if overflow occurs), the function fails.
exp
Prototype
Description
double exp(double x);
Function returns the value of e
— the base of natural logarithms — raised to the power of x
(i.e. e x
).
fabs
Prototype
Description
double fabs(double num);
Function returns the absolute (i.e. positive) value of num
.
page
159
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
floor
Prototype
double floor(double num);
Description
Function returns value of parameter num rounded down to the nearest integer.
frexp
Prototype
Description
double frexp(double num, int *n);
Function splits a floating-point value num into a normalized fraction and an integral power of 2. Return value is the normalized fraction, and the integer exponent is stored in the object pointed to by n
.
ldexp
Prototype
Description
double ldexp(double num, int n);
Function returns the result of multiplying the floating-point number num by 2 raised to the power exp
(i.e. returns x*2 n
).
log
Prototype
Description
double log(double x);
Function returns the natural logarithm of x
(i.e. log e
(x)
).
page
160
RSC-4x mikroC
making it simple...
log10
Prototype
mikroC - C Compiler for Sensory RSC-4x microcontrollers
double log10(double x);
Description
Function returns the base-10 logarithm of x
(i.e. log
10
(x)
).
modf
Prototype
Description
double modf(double num, double *whole);
Function returns the signed fractional component of num
, placing its whole number component into the variable pointed to by whole
.
pow
Prototype
Description
double pow(double x, double y);
Function returns the value of x raised to the power of y (i.e. x y
). If the x is negative, function will automatically cast the y into unsigned long
.
sin
Prototype
Description
double sin(double x);
Function returns the sine of x in radians. The return value is from -1 to 1.
page
161
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
sinh
Prototype
double sinh(double x);
Description
Function returns the hyperbolic sine of x
, defined mathematically as
(e x
-e
-x
)/2
. If the value of x is too large (if overflow occurs), the function fails.
sqrt
Prototype
Description
double sqrt(double num);
Function returns the non negative square root of num
.
tan
Prototype
Description
double tan(double x);
Function returns the tangent of x in radians. The return value spans the allowed range of floating point in mikroC.
tanh
Prototype
Description
double tanh(double x);
Function returns the hyperbolic tangent of x
, defined mathematically as sinh(x)/cosh(x)
.
page
162
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
C stdio.h Library
Header file stdio.h provides basic input and output capabilities of RSC-4x mikroC.
Library Routines
sprintf sscanf
sprintf
Description:
Function formats a series of strings and numeric values and stores the resulting string in buffer.
Note: format string must be in the CDATA area because sprintf parameter is of cdata type.
The fmtstr argument is a format string and may be composed of characters, escape sequences, and format specifications. Ordinary characters and escape sequences are copied to the buffer in the order in which they are interpreted. Format specifications always begin with a percent sign (%) and require additional arguments to be included in the function call.
The format string is read from left to right. The first format specification encountered references the first argument after fmtstr and converts and outputs it using the format specification. The second format specification accesses the second argument after fmtstr, and so on. If there are more arguments than format specifications, the extra arguments are ignored. Results are unpredictable if there are not enough arguments for the format specifications. Format specifications have the following format:
% [flags] [width] [.precision] [{ h | l | L }] conversion_type
Each field in the format specification can be a single character or a number which specifies a particular format option. The conversion_type field is where a single character specifies that the argument is interpreted as a character, a string, a number, or a pointer, as shown in the following table.
page
163
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers p
% c s u o d
Conversion Type
int
Argument Type
unsigned int unsigned int x unsigned int
X double e double
E double g double int char * void * none
Output Format
Signed decimal number
Unsigned decimal number
Unsigned octal number
Unsigned hexadecimal number using
0123456789ABCEDF
Floating-point number using the format [-
]dddd.dddd
Floating-point number using the format [-
]d.dddde[-]dd
Floating-point number using the format [-
]d.ddddE[-]dd
Floating-point number using either e or f format, whichever is more compact for the specified value and precision
The int is converted to an unsigned char, and the resulting character is written
String with a terminating null character
Pointer value, the X format is used
A % is written. No argument is converted. The complete conversion specification shall be
%%.
page
164
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The flags field is where a single character is used to justify the output and to print
+/- signs and blanks, decimal points, and octal and hexadecimal prefixes, as shown in the following table.
Flags
Meaning
-
+
Left justify the output in the specified field width.
Prefix the output value with a + or - sign if the output is a signed type.
space (' ') Prefix the output value with a blank if it is a signed positive value.
Otherwise, no blank is prefixed
# Prefixes a non-zero output value with 0, 0x, or 0X when used with o, x, and X field types, respectively. When used with the e, E, f, g, and G field types, the # flag forces the output value to include a decimal point.
The # flag is ignored in all other cases.
* Ignore format specifier.
The width field is a non-negative number that specifies the minimum number of characters printed. If the number of characters in the output value is less than width, blanks are added on the left or right (when the - flag is specified) to pad to the minimum width. If width is prefixed with a 0, zeros are padded instead of blanks. The width field never truncates a field. If the length of the output value exceeds the specified width, all characters are output.
The precision field is a non-negative number that specifies the number of characters to print, the number of significant digits, or the number of decimal places. The precision field can cause truncation or rounding of the output value in the case of a floating-point number as specified in the following table.
page
165
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Flags
Meaning of precision field
d, u, o, x, X The precision field is where you specify the minimum number of digits that will be included in the output value. Digits are not truncated if the number of digits in the argument exceeds that defined in the precision field. If the number of digits in the argument is less than the precision field, the output value is padded on the left with zeros.
f The precision field is where you specify the number of digits to the right of the decimal point. The last digit is rounded.
e, E The precision field is where you specify the number of digits to the right of the decimal point. The last digit is rounded.
g c, C
The precision field is where you specify the maximum number of significant digits in the output value.
The precision field has no effect on these field types.
s The precision field is where you specify the maximum number of characters in the output value. Excess characters are not output.
The optional characters h and l or L may immediately precede the conversion_type to respectively specify short or long versions of the integer types d, i, u, o, x, and
X.
You must ensure that the argument type matches that of the format specification.
You can use type casts to ensure that the proper type is passed to sprintf.
Prototype:
int sprintf (
char *buffer, /* storage buffer */
const cdata char *fmtstr, /* format string */
... ); /* additional arguments */ page
166
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
sscanf
Description:
Function returns the number of input fields that were successfully converted. An
EOF is returned if an error is encountered before any conversion.
Function reads data from the string buffer . Data input are stored in the locations specified by argument according to the format string fmtstr . Each argument must be a pointer to a variable that corresponds to the type defined in fmtstr which controls the interpretation of the input data.
The fmtstr argument is composed of one or more whitespace characters, nonwhitespace characters, and format specifications as defined below.
Whitespace characters cause sscanf to skip whitespace characters in the buffer .
Whitespace characters are such ones for which the isspace function returns nonzero value. Note that a single whitespace character in the format string matches 0 or more whitespace characters in the buffer .
Non-whitespace characters, with the exception of the percent sign ( % ), cause sscanf to read but not store a matching character from the buffer . The sscanf function terminates if the next character in the buffer does not match the specified non-whitespace character.
Format specifications begin with a percent sign ( % ) and cause sscanf to read and convert characters from the buffer to the specified type values. The converted value is stored to an argument in the parameter list. Characters following a percent sign that are not recognized as a format specification are treated as an ordinary character. For example, %% matches a single percent sign in the buffer .
The format string is read from left to right. Characters that are not part of the format specifications must match characters in the buffer . These characters are read from the buffer but are discarded and not stored. If a character in the buffer conflicts with the format string, sscanf terminates. Any conflicting characters remain in the buffer .
The first format specification encountered in the format string references the first argument after fmtstr and converts input characters and stores the value using the format specification. The second format specification accesses the second argument after fmtstr, and so on. If there are more arguments than format specifications, the extra arguments are ignored. Results are unpredictable if there are not enough arguments for the format specifications.
page
167
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Values in the buffer are called input fields and are delimited by whitespace characters. When converting input fields, sscanf ends a conversion for an argument when a whitespace character is encountered. Additionally, any unrecognized character for the current format specification ends a field conversion. Format specifications have the following format:
% * width { b | h | l } type
Each field in the format specification can be a single character or a number which specifies a particular format option.
The type field is where a single character specifies whether input characters are interpreted as a character, string, or number. This field can be any one of the characters in the following table.
Character
d i u o x, X c s
Argument Type
int *
Input Format
Signed decimal number int * Signed decimal, hexadecimal, or octal integer unsigned int * Unsigned decimal number unsigned int * Unsigned octal number unsigned int * Unsigned hex number char * char *
A single character
A string of characters terminated by whitespace page
168
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
An asterisk (*) as the first character of a format specification causes the input field to be scanned but not stored. The asterisk suppresses assignment of the format specification.
The width field is a non-negative number that specifies the maximum number of characters read from the buffer . No more than width characters will be read from the buffer and converted for the corresponding argument. However, fewer than width characters may be read if a whitespace character or an unrecognized character is encountered first.
The optional characters h and l or L may immediately precede the type character to respectively specify short, or long versions of the integer types d, i, u, o, and x .
page
169
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
C Stdlib Library
Header file stdlib.h
contains functions for performing a variety of operations, including conversion, pseudo-random numbers, memory allocation, process control, and sorting.
Library Routines
abs atof atoi atol div ldiv labs max min rand srand strtod strtol xtoi
abs
Prototype
Description
int abs(int num);
Function returns the absolute (i.e. positive) value of num
.
atof
Prototype
Description
double atof(char *s)
Function converts the input string s into a double precision value, and returns the value.
Input string s should conform to the floating point literal format, with an optional whitespace at the beginning. The string will be processed one character at a time, until the function reaches a character which it doesn’t recognize (this includes a null character).
page
170
RSC-4x mikroC
making it simple...
atoi
Prototype
int atoi(char *s);
Description
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Function converts the input string s into an integer value, and returns the value. Input string s should consist exclusively of decimal digits, with an optional whitespace and a sign at the beginning. The string will be processed one character at a time, until the function reaches a character which it doesn’t recognize (this includes a null character).
atol
Prototype
Description
long atol(char *s)
Function converts the input string s into a long integer value, and returns the value.
Input string s should consist exclusively of decimal digits, with an optional whitespace and a sign at the beginning. The string will be processed one character at a time, until the function reaches a character which it doesn’t recognize (this includes a null character).
div
Prototype
Description
div_t div(int numer, int denom);
Function computes the result of the division of the numerator numer by the denominator denom
; function returns a structure of type div_t comprising quotient ( quot
) and remainder ( rem
).
page
171
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
ldiv
Prototype
ldiv_t ldiv(long numer, long denom);
Description
Function is similar to the div function, except that the arguments and the result structure members all have type long
.
Function computes the result of the division of the numerator numer by the denominator denom
; function returns a structure of type div_t comprising quotient ( quot
) and remainder ( rem
).
labs
Prototype
Description
long labs(long num);
Function returns the absolute (i.e. positive) value of a long integer num
.
max
Prototype
Description
int max(int a, int b);
Function returns greater of the two integers, a and b
.
min
Prototype
Description
int min(int a, int b);
Function returns lower of the two integers, a and b
.
page
172
RSC-4x mikroC
making it simple...
rand
Prototype
int rand(void);
Description
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Function returns a sequence of pseudo-random numbers between 0 and 32767. Function will always produce the same sequence of numbers unless srand() is called to seed the starting point.
srand
Prototype
Description
void srand(unsigned seed);
Function uses the seed as a starting point for a new sequence of pseudo-random numbers to be returned by subsequent calls to rand()
. No values are returned by this function.
strtod
Prototype
Returns
Description
double strtod (
const char * s, /* string to be converted */
char ** sret); /* ptr to final string */
Function returns the converted value, if any. If no conversion performed, zero is returned. If the correct value is outside the range of representable values, plus or minus
HUGE_VAL is returned (according to the sign of value).
Function converts the initial portion of the string pointed to by s to double representation. First, it decomposes the input string into three parts: an initial, possibly empty, sequence of white-space characters, a subject sequence resembling floating point constant; and a final string of one or more unrecognized characters. Then, it attempts to convert the subject sequence to a floating point number, and returns the result. A pointer to the final string is stored in the object pointed to by sret
, provided that sret is not a null pointer.
page
173
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
strtol
Prototype
Returns
Description
long int strtol (
const char * s, /* string to be converted */
char ** sret, /* ptr to the final string */
int base); /* radix base */
Function returns the converted value, if any. If no conversion performed, zero is returned. If the correct value is outside the range of representable values,
LONG_MAX or
LONG_MIN is returned (according to the sign of value).
Function converts the initial portion of the string pointed to by s to
long int
representation. First, it decomposes the input string into three parts: an initial, possibly empty, sequence of white-space characters, a subject sequence resembling an integer represented in some radix determined by the value of base
, and a final string of one or more unrecognized characters. Then, it attempts to convert the subject sequence to an integer, and returns the result. A pointer to the final string is stored in the object pointed to by sret
, provided that sret is not a null pointer.
xtoi
Prototype
Description
int xtoi(char *s);
Function converts the input string s consisting of hexadecimal digits into an integer value. Input parametes s should consist exclusively of hexadecimal digits, with an optional whitespace and a sign at the beginning. The string will be processed one character at a time, until the function reaches a character which it doesn’t recognize (this includes a null character).
page
174
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
C String Library
Header file string.h
contains various functions for string handling.
Library Routines
memchr memcmp memcpy memmove memset strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr strtok
memchr
Prototype
Returns
Description
void *memchr(
const void *s, /* buffer to search */
int c, /* byte to find */ size_t n); /* maximum buffer length */
Function returns a pointer to the located character or a null pointer if the character was not found.
Function compares the first n characters of objects pointed to by s1 and s2
, and returns zero if the objects are equal, or returns a difference between the first differing characters
(in a left-to-right evaluation). Accordingly, the result is greater than zero if the object pointed to by s1 is greater than the object pointed to by s2
, and vice versa.
page
175
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
memcmp
Prototype
Returns
Description
int memcmp (
const void *buf1, /* first buffer */
const void *buf2, /* second buffer */ size_t len);
Function returns a positive, negative, or zero value indicating the relationship of first len bytes of buf1 and buf2
.
The memcmp function compares two objects buf1 and buf2 for len bytes and returns a value indicating their relationship as follows:
Value Meaning
< 0 buf1 less than buf2
= 0 buf1 equal to buf2
> 0 buf1 greater than buf2
In other words, the sign of nonzero value returned by function is determined by the sign of the difference between the values of the first pair of bytes (both interpreted as
unsigned char
) that differ in the objects being compared.
memcpy
Prototype
Returns
Description
void *memcpy (
void *dest, /* destination buffer */
const void *src, /* source buffer */ size_t len); /* bytes to copy */
Function returns dest
.
Function copies len bytes from src to dest
. If these memory buffers overlap, the memcpy function cannot guarantee that bytes in src are copied to dest before being overwritten. If these buffers do overlap, use the memmove function.
page
176
RSC-4x mikroC
making it simple...
memmove
Prototype
Returns
Description
mikroC - C Compiler for Sensory RSC-4x microcontrollers
void *memmove (
void *dest, /* destination buffer */
const void *src, /* source buffer */
int len); /* maximum bytes to move */
Function returns dest
.
Function copies len bytes from src to dest
. If these memory buffers overlap, the memmove function ensures that bytes in src are copied to dest before being overwritten.
memset
Prototype
Returns
Description
void *memset (
void *s, /* buffer to initialize */
int c, /* byte value to set */ size_t len); /* buffer length */
Function returns the value of s.
Function sets the first len bytes in object pointed to by s to c
(converted to an
unsigned char
).
strcat
Prototype
Returns
Description
char *strcat (
char *dest, /* destination string */
const char *src); /* source string */
Function returns dest
.
Function concatenates or appends src to dest and terminates dest with a null character.
page
177
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
strcat
Prototype
Returns
Description
char *strcat (
char *dest, /* destination string */
const char *src); /* source string */
Function returns dest
.
Function concatenates or appends src to dest and terminates dest with a null character.
strchr
Prototype
Returns
Description
char *strchr (
const char *string, /* string to search */
char c);
Function returns a pointer to the character c found in string or a null pointer if no matching character was found.
Function searches string for the first occurrence of c
. The null character terminating string is included in the search.
strcmp
Prototype
Returns
char strcmp (
char *string1, /* first string */
char *string2); /* second string */
Function returns the following values to indicate the relationship of string1 to string2:
Value Meaning
< 0 string1 less than string2
= 0 string1 equal to string2
> 0 string1 greater than string2
Description
Function lexicographically compares the contents of string1 and string2 and returns a value indicating their relationship.
page
178
RSC-4x mikroC
making it simple...
strcpy
Prototype
Returns
Description
mikroC - C Compiler for Sensory RSC-4x microcontrollers
char *strcpy (
char *dest, /* destination string */
const char *src); /* source string */
Function returns dest
.
PFunction copies src to dest and appends a null character to the end of dest
.
strcspn
Prototype
Returns
size_t strcspn (
const char *src, /* source string */
const char *set); /* characters to find */
Function returns the index of the first character located in src that matches any character in set
. If the first character in src matches a character in set
, a value of 0 is returned. If there are no matching characters in src
, the length of the string is returned
(not including the terminating null character).
Function searches the src string for any of the characters in the set string.
Description
strlen
Prototype
Returns
Description
int strlen (
char *src); /* source string */
Function returns the length of src
.
Function calculates the length, in bytes, of src
. This calculation does not include the null terminating character.
page
179
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
strncat
Prototype
Returns
char strncmp (
const char *string1, /* first string */
const char *string2, /* second string */ size_t len); /* maximum characters to compare */
Function returns dest
.
Description
Function appends at most len characters from src to dest and terminates dest with a null character. If src is shorter than len characters, src is copied up to and including the null terminating character.
strncmp
Prototype
Returns
Description
char strncmp (
const char *string1, /* first string */
const char *string2, /* second string */ size_t len); /* maximum characters to compare */
Function returns the following values to indicate the relationship of string1 to string2
:
Value Meaning
< 0 string1 less than string2
= 0 string1 equal to string2
> 0 string1 greater than string2
Function lexicographically compares the first len bytes of string1 and string2 and returns a value indicating their relationship.
strncat
Prototype
Returns
Description
char *strncpy (
char *dest, /* destination string */
const char *src, /* source string */ size_t len); /* maximum characters to copy */
Function returns dest
.
Function copies at most len characters from src to dest
. If src contains fewer characters than len
, dest is padded out with null characters to len characters.
page
180
RSC-4x mikroC
making it simple...
strpbrk
Prototype
mikroC - C Compiler for Sensory RSC-4x microcontrollers
char *strpbrk (
const char *string, /* string to search */
const char *set); /* characters to find */
Returns
Description
Function returns a pointer to the matching character in string
. If string contains no characters from set, a null pointer is returned.
Function searches string for the first occurrence of any character from set. The null terminator is not included in the search.
strrchr
Prototype
Returns
Description
char *strrchr (
const char *string, /* string to search */
int c); /* character to find */
Function returns a pointer to the last character c found in string or a null pointer if no matching character was found.
Function searches string for the last occurrence of c
. The null character terminating string is included in the search.
strspn
Prototype
Returns
Description
size_t strspn (
const char *string, /* string to search */
const char *set); /* characters that not allowed */
Function returns the index of first character located in string that does not match a character in set
. If the first character in string does not match a character in set
, a value of 0 is returned. If all characters in string are found in set
, the length of string is returned (not including the terminating null character).
Function searches string for characters not found in the set string.
page
181
mikroC - C Compiler for Sensory RSC-4x microcontrollers
strstr
Prototype
char * strstr (
const char * s, /* string to search */
const char * find); /* string to be found */
RSC-4x mikroC
making it simple...
Returns
Description
Function returns a pointer to the located string, or a null pointer if the string is not found. If find points to a string with zero length, the function returns s.
Function locates the first occurrence in the string pointed to by s of the sequence of characters (excluding the terminating null character) in the string pointed to by find
.
strstr
Prototype
Returns
Description
char * strtok (
char * s, /* string to be broken into tokens */
const char * delim); /* separator-string */
Function returns a pointer to the first character of token, or a null pointer if there is no token.
A sequence of calls to the strtok function breaks the string pointed to by s into a sequence of tokens, each of which is delimited by a character from the string pointed to by delim
. The first call in the sequence has s as its first argument, and is followed by calls with a null pointer as their first argument. The separator string pointed to by delim may be different from call to call.
The first call in the sequence searches the string pointed to by s for the first character that is not contained in the current separator string pointed to by delim
. If no such character is found, then there are no tokens in the string pointed to by s and the strtok function returns a null pointer.
The strtok function then searches from there for a character that is contained in the current separator string. If no such character is found, the current token extends to the end of the string pointed to by s
, and subsequent searches for a token will return a null pointer. If such a character is found, it is overwritten by a null character, which terminates the current token. The strtok function saves a pointer to the following character, from which the next search for token will start.
Each subsequent call, with a null pointer as the value of the first argument, starts searching from the saved pointer and behaves as described above.
page
182
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Built-in Routines
The RSC-4x mikroC compiler provides a set of useful built-in utility functions.
Built-in functions do not require any header files to be included; you can use them in any part of your project.
Delay_us
Delay_ms
Clock_Khz
Clock_Mhz
_cli_
_sti_
_nop_
_wdc_
Delay_us
Prototype
Description
Example
void Delay_us(const time_in_us);
Creates a software delay in duration of time_in_us microseconds (a constant). Range of applicable constants depends on the oscillator frequency. This is an “inline” routine; code is generated in the place of the call.
Delay_us(10); /* Ten microseconds pause */
Delay_ms
Prototype
Description
Example
void Delay_ms(const time_in_ms);
Creates a software delay in duration of time_in_ms milliseconds (a constant). Range of applicable constants depends on the oscillator frequency. This is an “inline” routine; code is generated in the place of the call.
Delay_ms(1000); /* One second pause */ page
183
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Clock_Khz
Prototype
unsigned Clock_Khz(void);
Returns
Description
Example
Device clock in KHz, rounded to the nearest integer.
Returns device clock in KHz, rounded to the nearest integer.
This is an “in-line” routine; code is generated in the place of the call.
clk = Clock_Khz();
RSC-4x mikroC
making it simple...
Clock_Mhz
Prototype
unsigned Clock_Mhz(void);
Returns
Description
Example
Device clock in MHz, rounded to the nearest integer.
Returns device clock in MHz, rounded to the nearest integer.
This is an “in-line” routine; code is generated in the place of the call.
clk = Clock_Mhz();
_cli_
Prototype
void _cli_ (void);
Returns
Description
Nothing.
Function executes the CLI instruction.
This is an “in-line” routine; code is generated in the place of the call.
page
184
RSC-4x mikroC
making it simple...
_nop_
Prototype
void _nop_ (void); mikroC - C Compiler for Sensory RSC-4x microcontrollers
Returns
Description
Nothing.
Function executes the NOP instruction.
This is an “in-line” routine; code is generated in the place of the call.
_wdc_
Prototype
void _wdc_ (void);
Returns
Description
Nothing.
Function executes the WDC instruction.
This is an “in-line” routine; code is generated in the place of the call.
page
185
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Compact Flash Library
Compact Flash Library provides routines for accessing data on Compact Flash card (abbrev. CF further in text). CF cards are widely used memory elements, commonly found in digital cameras. Great capacity (8MB ~ 2GB, and more) and excellent access time of typically few microseconds make them very attractive for microcontroller applications.
In CF card, data is divided into sectors, one sector usually comprising 512 bytes
(few older models have sectors of 256B). Read and write operations are not performed directly, but successively through 512B buffer. These routines can be used for CF with the FAT16 and the FAT32 file system. Note that routines for file handling can be used only with the FAT16 file system.
To use the CF Library, include the header file cf.h in your source code.
Important! File accessing routines can write file. File names must be exactly 8 characters long and written in uppercase. User must ensure different names for each file, as CF routines will not check for possible match.
Important! Before write operation, make sure you don’t overwrite boot or FAT sector as it could make your card on PC or digital cam unreadable. Drive mapping tools, such as Winhex, can be of a great assistance.
Library Routines
Cf_Init
Cf_Detect
Cf_Read_Init
Cf_Read_Byte
Cf_Write_Init
Cf_Write_Byte page
186
RSC-4x mikroC
making it simple...
Cf_Init
Prototype
mikroC - C Compiler for Sensory RSC-4x microcontrollers
void Cf_Init(char *ctrlport, char *dataport);
Description
Example
Initializes ports appropriately for communication with CF card. Specify two different ports: ctrlport and dataport
. The function uses all 8 pins on dataport and 5 pins on ctrlport
, as given in the CF library header file (Cf_Lib.h).
Cf_Init(&p2out, &p1out);
Cf_Detect
Prototype
Returns
Requires
Description
Example
unsigned short Cf_Detect(void);
Returns 1 if CF is present, otherwise returns 0.
Control port ( ctrlport
) must be initialized. See Cf_Init.
Checks for presence of CF card on ctrlport .
// Wait until CF card is inserted:
do nop; while (Cf_Detect() == 0);
Cf_Read_Init
Prototype
Description
void Cf_Read_Init(unsigned long address, unsigned short sectcnt);
Initializes CF card for reading. Parameter address specifies sector address from where data will be read, and sectcnt is the number of sectors prepared for reading operation.
Requires
Example
Ports must be initialized. See
Cf_Init
.
Cf_Read_Init(590, 1); page
187
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Cf_Read_Byte
Prototype
Returns
Description
Requires
Example
unsigned short Cf_Read_Byte(void);
Returns byte from CF.
Reads one byte from CF.
Ports must be initialized. See Cf_Init.
CF must be initialized for read operation. See Cf_Read_Init.
Read byte and display it on port0: p0out = Cf_Read_Byte();
Cf_Write_Init
Prototype
Description
void Cf_Write_Init(unsigned long address, unsigned short sectcnt);
Initializes CF card for writing. Parameter address specifies sector address where data will be stored, and sectcnt is total number of sectors prepared for write operation.
Requires
Example
Ports must be initialized. See
Cf_Init
.
Cf_Write_Init(590, 1);
Cf_Write_Byte
Prototype
Description
Requires
Example
void Cf_Write_Byte(unsigned short data);
Writes one byte ( data
) to CF. All 512 bytes are transferred to a buffer.
CF must be initialized for write operation. See
Cf_Write_Init
.
CF must be initialized for write operation. See Cf_Write_Init.
int i = 20;
Cf_Write_Byte(100);
Cf_Write_Byte(i); page
188
RSC-4x mikroC
making it simple...
Library Example
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The following example writes 512 bytes at sector no.595, and then reads the data and prints on port0 for a visual check.
#include <rsc4128.h>
#include <cf.h>
void main() {
unsigned i;
//--- init rscxxx - all pins digital I/O
cmpCtl |= 0x07; p0ctla = 255; p0ctlb = 255;
//--- init CF
Cf_Init(&p2out, &p1out);
//--- wait until CF card is inserted
while (!Cf_Detect()) ;
//--- stabilize
Delay_us(500);
//--- init CF for write
Cf_Write_Init(595, 1);
//--- write 512 bytes to sector (595)
for (i = 0; i < 512; i++)
Cf_Write_Byte(i);
//--- init CF for read
Cf_Read_Init(595, 1);
//--- read 512 bytes from sector (595)
for (i = 0; i < 512; i++) { p0out = Cf_Read_Byte();
Delay_ms(500);
}
}//~!
page
189
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
LCD Library (4-bit interface)
RSC-4x mikroC provides a library for communicating with commonly used LCD
(4-bit interface).
Note: Be sure to designate port with LCD as output, before using any of the following library functions.
Library Routines
Lcd_Config
Lcd_Init
Lcd_Out
Lcd_Out_Cp
Lcd_Chr
Lcd_Chr_Cp
Lcd_Cmd
Lcd_Config
Prototype
void Lcd_Config(char * data_port, char db3, char db2, char db1,
char db0, char * ctrl_port, char rs, char rw, char enable);
Description
Example
Initializes LCD with data lines at data_port and control lines at ctrl_port
, with pin settings you specify: parameters rs, enable, rw, db3 .. db0 need to be a combination of values 0–7 (e.g. 3,6,0,7,2,1,4).
Lcd_Config(&p0out,4,5,6, &p1out,4,5,6,7); page
190
RSC-4x mikroC
making it simple...
Lcd_Init
Prototype
Description
mikroC - C Compiler for Sensory RSC-4x microcontrollers
void Lcd_Init(unsigned short * data_port, unsigned short * ctrl_port);
Initializes LCD at port with default pin settings (see the connection scheme at the end of the chapter):
D7 -> PORT.7,
D6 -> PORT.6,
D5 -> PORT.5,
D4 -> PORT.4,
E -> PORT.3,
RS -> PORT.2.
Lcd_Init(&p1out, &p0out);
Example
Lcd_Out
Prototype
Description
Requires
Example
void Lcd_Out(unsigned short row, unsigned short col, char *text);
Prints text on LCD at specified row and column (parameter row and col
). Both string variables and literals can be passed as text
.
Port with LCD must be initialized. See
Lcd_Config or
Lcd_Init
.
Lcd_Out(1, 3, "Hello!"); // Print "Hello!" at line 1, char 3
Lcd_Out_Cp
Prototype
Description
void Lcd_Out_Cp(char *text);
Prints text on LCD at current cursor position. Both string variables and literals can be passed as text
.
Requires
Example
Port with LCD must be initialized. See
Lcd_Config or
Lcd_Init
.
Lcd_Out_Cp("Here!"); // Print "Here!" at current cursor position page
191
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Lcd_Chr
Prototype
Description
void Lcd_Chr(unsigned short row, unsigned short col, char character);
Prints character on LCD at specified row and column (parameters row and col
).
Both variables and literals can be passed as character
.
Requires
Example
Port with LCD must be initialized. See
Lcd_Config or
Lcd_Init
.
Lcd_Out(2, 3, 'i'); // Print 'i' at line 2, char 3
Lcd_Chr_Cp
Prototype
Description
void Lcd_Chr_Cp(char character);
Prints character on LCD at current cursor position. Both variables and literals can be passed as character
.
Requires
Example
Port with LCD must be initialized. See
Lcd_Config or
Lcd_Init
.
Lcd_Out_Cp('e'); // Print 'e' at current cursor position
Lcd_Cmd
Prototype
Description
Requires
Example
void Lcd_Cmd(unsigned short command);
Sends command to LCD. You can pass one of the predefined constants to the function.
The complete list of available commands is shown on the following page.
Port with LCD must be initialized. See
Lcd_Config or
Lcd_Init
.
Lcd_Cmd(Lcd_Clear); // Clear LCD display page
192
RSC-4x mikroC
making it simple...
LCD Commands
mikroC - C Compiler for Sensory RSC-4x microcontrollers
LCD Command
LCD_FIRST_ROW
LCD_SECOND_ROW
LCD_THIRD_ROW
LCD_FOURTH_ROW
LCD_CLEAR
Move cursor to 1st row
Move cursor to 2nd row
Move cursor to 3rd row
Move cursor to 4th row
Clear display
Purpose
LCD_RETURN_HOME
Return cursor to home position, returns a shifted display to original position. Display data RAM is unaffected.
LCD_CURSOR_OFF
LCD_UNDERLINE_ON
Turn off cursor
LCD_BLINK_CURSOR_ON
LCD_MOVE_CURSOR_LEFT
Blink cursor on
LCD_TURN_ON
Move cursor left without changing display data RAM
LCD_MOVE_CURSOR_RIGHT
Move cursor right without changing display data RAM
Turn LCD display on
LCD_TURN_OFF
LCD_SHIFT_LEFT
Underline cursor on
Turn LCD display off
Shift display left without changing display data RAM
LCD_SHIFT_RIGHT
Shift display right without changing display data RAM page
193
RSC-4x mikroC
making it simple...
Library Example
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Here’s a simple test for LCD Library; the example should print a text message on the LCD connected to port1 (data port) and port0 (ctrl port).
#include <rsc4128.h>
#include <lcd.h>
char *text = "mikroElektronika";
void main() {
//--- init rscxxx - all pins digital I/O
cmpCtl |= 0x07; p0ctla = 255; p0ctlb = 255; p1ctla = 255; p1ctlb = 255;
//--- Configure LCD connections
Lcd_Config(&p1out, 7, 6, 5, 4, &p0out, 4, 5, 6);
Lcd_Cmd(LCD_CURSOR_OFF); // Turn off cursor
Lcd_Out(1, 1, text); // Print text at LCD
}//~!
page
195
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Software I2C Library
RSC-4x mikroC provides routines which implement software I²C. These routines are hardware independent and can be used with any MCU. Software I2C enables you to use MCU as Master in I2C communication. Multi-master mode is not supported.
Note: This library implements time-based activities, so interrupts need to be disabled when using Soft I²C.
Library Routines
Soft_I2C_Config
Soft_I2C_Start
Soft_I2C_Read
Soft_I2C_Write
Soft_I2C_Stop
Soft_I2C_Config
Prototype
void Soft_I2C_Config(unsigned short *portOut, char SDI, char SD0,
char SCK);
Description
Example
Configures software I²C. Parameter port specifies port of MCU on which
SDA and
SCL pins are located. Parameters
SCL and
SDA need to be in range 0–7 and cannot point at the same pin.
Soft_I2C_Config needs to be called before using other functions from Soft I2C
Library.
Soft_I2C_Config(&p0Out, 1, 2); page
196
RSC-4x mikroC
making it simple...
Soft_I2C_Start
Prototype
mikroC - C Compiler for Sensory RSC-4x microcontrollers
void Soft_I2C_Start(void);
Description
Requires
Example
Issues START signal. Needs to be called prior to sending and receiving data.
Soft I²C must be configured before using this function. See
Soft_I2C_Config
.
Soft_I2C_Start();
Soft_I2C_Read
Prototype
Returns
Description
Requires
Example
unsigned short Soft_I2C_Read(unsigned short ack);
Returns one byte from the slave.
Reads one byte from the slave, and sends not acknowledge signal if parameter ack is 0, otherwise it sends acknowledge.
START signal needs to be issued in order to use this function. See
Soft_I2C_Start
.
Read data and send not acknowledge signal: short take;
...
take = Soft_I2C_Read(0); page
197
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Soft_I2C_Write
Prototype
unsigned short Soft_I2C_Write(unsigned short data);
RSC-4x mikroC
making it simple...
Returns
Description
Requires
Example
Returns 0 if there were no errors.
Sends data byte (parameter data
) via I²C bus.
START signal needs to be issued in order to use this function. See
Soft_I2C_Start
.
Soft_I2C_Write(0xA3);
Soft_I2C_Stop
Prototype
void Soft_I2C_Stop(void);
Description
Requires
Example
Issues STOP signal.
START signal needs to be issued in order to use this function. See
Soft_I2C_Start
.
Soft_I2C_Stop(); page
198
RSC-4x mikroC
making it simple...
Library Example
mikroC - C Compiler for Sensory RSC-4x microcontrollers
The following example is a simple demonstration how to read date and time from PCF8583 RTC
(real-time clock). Date and time are read from the RTC every second and printed on LCD.
#include <rsc4128.h>
#include <soft_i2c.h>
#include <lcd.h>
void Delay_ms(unsigned int time_ms);
unsigned char sec, mnt, hr, day, mn, year;
char *txt, tnum[4];
char *R_Trim(char *str1){
while (*str1 == ' ') str1++;
return str1;
}//~
void Zero_Fill(char *value) { // fill text repesentation
if (value[1] == 0) { // with leading zero value[1] = value[0]; value[0] = 48; value[2] = 0;
}
}//~
//--------------------- Reads time and date information from RTC (PCF8583)
void Read_Time(char *sec, char *mnt, char *hr, char *day, char *mn, char *year)
{
Soft_I2C_Start();
Soft_I2C_Write(0xA0);
Soft_I2C_Write(2);
Soft_I2C_Start();
Soft_I2C_Write(0xA1);
*sec = Soft_I2C_Read(1);
*mnt = Soft_I2C_Read(1);
*hr = Soft_I2C_Read(1);
*day = Soft_I2C_Read(1);
*mn = Soft_I2C_Read(0);
Soft_I2C_Stop();
}//~
//continues ...
page
199
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
//-------------------- Formats date and time
void Transform_Time(char *sec, char *mnt, char *hr, char *day,
char *mn, char *year) {
*sec = ((*sec & 0xF0) >> 4)*10 + (*sec & 0x0F);
*mnt = ((*mnt & 0xF0) >> 4)*10 + (*mnt & 0x0F);
*hr = ((*hr & 0xF0) >> 4)*10 + (*hr & 0x0F);
*year = (*day & 0xC0) >> 6;
*day = ((*day & 0x30) >> 4)*10 + (*day & 0x0F);
*mn = ((*mn & 0x10) >> 4)*10 + (*mn & 0x0F);
}//~
//-------------- Converts unsigned short number to string
char * ByteToStr(unsigned short inByte, char *outStr) {
char *strCnv;
unsigned short tmpV; strCnv = outStr + 4;
*strCnv-- = 0; //termination tmpV = inByte;
while (tmpV != 0) {
*strCnv-- = (tmpV % 10) + 48; //ASCII value tmpV /= 10;
}
while (strCnv >= outStr)
*strCnv-- = 32; //SPACE
return outStr;
}//~
//continues ...
page
200
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
//-------------------- Output values to LCD
void Display_Time(char sec, char mnt, char hr, char day, char mn,
char year) {
char *tc;
ByteToStr(day, tnum); // day tc = R_Trim(tnum);
Zero_Fill(tc);
Lcd_Out(1,6, tc);
ByteToStr(mn, tnum); // month tc = R_Trim(tnum);
Zero_Fill(tc);
Lcd_Out(1,9, tc);
Lcd_Chr(1,15,52+year); // year
ByteToStr(hr,tnum); // hour tc = R_Trim(tnum);
Zero_Fill(tc);
Lcd_Out(2,6,tc);
ByteToStr(mnt,tnum); // minute tc = R_Trim(tnum);
Zero_Fill(tc);
Lcd_Out(2,9,tc);
ByteToStr(sec,tnum); // second tc = R_Trim(tnum);
Zero_Fill(tc);
Lcd_Out(2,12,tc);
}//~
//------------------ Performs project-wide init
void Init_Main() {
//--- init rscxxx - all pins digital I/O
cmpCtl |= 0x07; p0ctla = 255; p0ctlb = 255;
Lcd_Config(&p1out,7,6,5,4, &p0out,4,5,6);
Soft_I2C_Init(&p0out, 2, 7); // Initialize I2C txt = "Date:"; // Prepare and output static text on LCD
Lcd_Out(1,1,txt);
Lcd_Chr(1,8,':');
Lcd_Chr(1,11,':'); txt = "Time:";
Lcd_Out(2,1,txt);
Lcd_Chr(2,8,':');
Lcd_Chr(2,11,':'); txt = "200";
Lcd_Out(1,12,txt);
Lcd_Cmd(LCD_CURSOR_OFF); // Cursor off
}//~
//continues ...
page
201
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
//----------------- Main function
void main() {
Init_Main(); // Perform initialization
while (1) {
Read_Time(&sec,&mnt,&hr,&day,&mn,&year);
// Read time from RTC(PCF8583)
Transform_Time(&sec,&mnt,&hr,&day,&mn,&year);
// Format date and time
Display_Time(sec, mnt, hr, day, mn, year);
// Prepare and display on LCD
}
}//~!
Delay_ms(1000);
// Wait 1s
page
202
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Software SPI Library
RSC-4x mikroC provides library which implement software SPI. These routines are hardware independent and can be used with any MCU. You can easily communicate with other devices via SPI: A/D converters, D/A converters, MAX7219,
LTC1290, etc.
The library configures SPI to master mode, clock = 50kHz, data sampled at the middle of interval, clock idle state low and data transmitted at low to high edge.
Note: These functions implement time-based activities, so interrupts need to be disabled when using the library.
Library Routines
Soft_Spi_Config
Soft_Spi_Read
Soft_Spi_Write
Soft_Spi_Config
Prototype
Description
void Soft_Spi_Init(unsigned short *portOut, const unsigned short rx, const unsigned short tx, const unsigned short clk);
Configures and initializes software SPI. Parameter portOut specifies port of MCU on which SDI (rx), SDO (tx), and SCK (clk) pins will be located. Parameters
SDI, SDO, and
SCK need to be in range 0–7 and cannot point at the same pin.
Soft_Spi_Init needs to be called before using other functions from Soft SPI Library.
Example
This will set SPI to master mode, clock = 50kHz, data sampled at the middle of interval, clock idle state low and data transmitted at low to high edge. SDI (rx) pin is p0.5, SDO
(tx) pin is p0.6 and SCK (clk) pin is p0.4:
Soft_Spi_Init(&p0Out, 5,6,4); page
203
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Soft_Spi_Read
Prototype
Returns
Description
Requires
Example
unsigned short Soft_Spi_Read(unsigned short buffer);
Returns the received data.
Provides clock by sending buffer and receives data.
Soft SPI must be initialized and communication established before using this function.
See
Soft_Spi_Config
.
short take, buffer;
...
take = Soft_Spi_Read(buffer);
Soft_Spi_Write
Prototype
void Soft_Spi_Write(unsigned short data);
Description
Requires
Immediately transmits data
.
Soft SPI must be initialized and communication established before using this function.
See
Soft_Spi_Config
.
Example
Soft_Spi_Write(1); page
204
RSC-4x mikroC
making it simple...
mikroC - C Compiler for Sensory RSC-4x microcontrollers
Library Example
This code demonstrates using library routines for SPI communication. Also, this example demonstrates working with max7219. Eight 7 segment displays are connected to MAX7219. MAX7219 is connected to port2 and SDO, SDI, SCK pins are connected accordingly.
#define CHIP_SELECT 2
#define N_CHIP_SELECT 253
#include <rsc4128.h>
#include <soft_spi.h>
unsigned char i;
void Max7219_Init() { p2out &= N_CHIP_SELECT; // SELECT MAX
Soft_Spi_Write(0x09); // BCD mode for digit decoding
Soft_Spi_Write(0xFF); p2out |= CHIP_SELECT; // DESELECT MAX p2out &= N_CHIP_SELECT; // SELECT MAX
Soft_Spi_Write(0x0A);
Soft_Spi_Write(0x0F); // Segment luminosity intensity p2out |= CHIP_SELECT; // DESELECT MAX p2out &= N_CHIP_SELECT; // SELECT MAX
Soft_Spi_Write(0x0B);
Soft_Spi_Write(0x07); // Display refresh p2out |= CHIP_SELECT; // DESELECT MAX p2out &= N_CHIP_SELECT; // SELECT MAX
Soft_Spi_Write(0x0C);
Soft_Spi_Write(0x01); // Turn on the display p2out |= CHIP_SELECT; // DESELECT MAX p2out &= N_CHIP_SELECT; // SELECT MAX
Soft_Spi_Write(0x00);
Soft_Spi_Write(0xFF); // No test p2out |= CHIP_SELECT; // DESELECT MAX
}//~
void main() {
//--- init rscxxx - all pins digital I/O
cmpCtl |= 0x07; p2ctla = 255; p2ctlb = 255;
Soft_Spi_Init(&p2out,4,5,3); // Configure SPI
Max7219_Init(); // Initialize max7219
for (i = 1; i <= 8u; i++) { p2out &= N_CHIP_SELECT; // Select max7219
Soft_Spi_Write(i); // Send i to max7219 (digit place)
Soft_Spi_Write(10-i); // Send i to max7219 (digit) p2out |= CHIP_SELECT; // Deselect max7219 }}//~! page
205
mikroC - C Compiler for Sensory RSC-4x microcontrollers
RSC-4x mikroC
making it simple...
Contact us:
If you are experiencing problems with any of our products or you just want additional information, please let us know.
Technical Support for compiler
If you are experiencing any trouble with mikroC, please do not hesitate to contact us - it is in our mutual interest to solve these issues.
Discount for schools and universities
mikroElektronika offers a special discount for educational institutions. If you would like to purchase RSC-4x mikroC for purely educational purposes, please contact us.
Problems with transport or delivery
If you want to report a delay in delivery or any other problem concerning distribution of our products, please use the link given below.
Would you like to become mikroElektronika's distributor?
We in mikroElektronika are looking forward to new partnerships. If you would like to help us by becoming distributor of our products, please let us know.
Other
If you have any other question, comment or a business proposal, please contact us:
mikroElektronika
Admirala Geprata 1B
11000 Belgrade
EUROPE
Phone: + 381 (11) 30 66 377, + 381 (11) 30 66 378
Fax: + 381 (11) 30 66 379
E-mail: [email protected]
Website: www.mikroe.com
page
206
ডাউনলোড
বিজ্ঞাপন