Programming PIC MCUs in Basic PDF
Programming PIC MCUs in Basic PDF
Home
Development Tools
q
Compilers
q
Projects
Special Offer
Home > Books > BASIC
Download
Books
Distributors
About us
Table of Contents
q q q q q q
Preface Chapter 1: The Basics Chapter 2: Elements of BASIC Language Chapter 3: Operators Chapter 4: Control Structures Chapter 5: Built-in and Library Routines
q q q q q
Chapter 6: Examples with PIC Integrated Peripherals Chapter 7: Examples with Displaying Data Chapter 8: Examples with Memory and Storage Media Chapter 9: Communications Examples Appendix A: mikroBasic IDE
Preface
In order to simplify things and crash some prejudices, I will allow myself to give you some advice before reading this book. You should start reading it from the chapter that interests you the most, in any order you find suitable. As the time goes by, read the parts you may need at that exact moment. If something starts functioning without you knowing exactly how, it shouldnt bother you too much. Anyway, it is better that your program works than that it doesnt. Always stick to the practical side of life. Better to finish the application on time, make it reliable and, of course, get paid for it as well as possible. In other words, it doesnt matter if the exact manner in which the electrons move within the PN junctions escapes your knowledge. You are not supposed to know the whole history of electronics in order to assure the income for you or your family. Do not expect that you will find everything you need in a single book, though. The information are dispersed literally everywhere around us, so it is necessary to collect them diligently and sort them out carefully. If you do so, the success is inevitable. With all my hopes of having done something worthy investing your time in. Yours, Nebojsa Matic
mikroElektronika Recommends
EasyPIC 3
Development system for PIC MCUs USB programmer on board! System supports 18, 28 and 40-pin microcontrollers (it is delivered with PIC16F877). With the system also comes the programmer. You can test many different industrial applications on the system: temperature controllers, counters, timers [more]
mikroBasic
Advanced BASIC compiler for PIC A beginner? Worry not. Easy-to-learn BASIC syntax, advanced compiler features, built-in routines, sourcelevel debugger, and many practical examples we have provided allow quick start in programming PIC. Highly intuitive, user-friendly IDE and comprehensive help guarantee success! [more]
PICFlash2
Programmer for PIC16 and PIC18 family PIC Flash is the USB InSystem programmer for Flash family of Microchips MCUs. Beside standard FLASH MCUs, it can also program the latest models of PIC18 family. [more]
PIC Microcontrollers
On-line book, 3rd edition The purpose of the book is not to make a microcontroller expert out of you, but to make you equal to those who had somebody to ask. Many practical examples allow quick start in programming PIC. [more]
To Readers Knowledge
The contents published in the book Programming PIC microcontrollers in BASIC is subject to copyright and it must not be reproduced in any form without an explicit written permission released from the editorial of mikroElektronika. The contact address for the authorization regarding contents of this book: office@mikroe.com. The book was prepared with due care and attention, however the publisher does not accept any responsibility neither for the exactness of the information published therein, nor for any consequences of its application.
Comment:
Send
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip
Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home Books
Compilers
Projects
Special Offer
Download
About us
Introduction 1.1 Why BASIC? 1.2 Choosing the right PIC for the task 1.3 A word about code writing 1.4 Writing and compiling your program 1.5 Loading program to microcontroller 1.6 Running the program 1.7 Troubleshooting
Introduction
Simplicity and ease which higher programming languages bring in, as well as broad application of microcontrollers today, were reasons to incite some companies to adjust and upgrade BASIC programming language to better suit needs of microcontroller programming. What did we thereby get? First of all, developing applications is faster and easier with all the predefined routines which BASIC brings in, whose programming in assembly would take the largest amount of time. This allows programmer to concentrate on solving the important tasks without wasting his time on, say, code for printing on LCD display. To avoid any confusion in the further text, we need to clarify several terms we will be using frequently throughout the book: Programming language is a set of commands and rules according to which we write the program. There are various programming languages such as BASIC, C, Pascal, etc. There is plenty of resources on BASIC programming language out there, so we will focus our attention particularly to programming of microcontrollers. Program consists of a sequence of commands written in programming language that microcontroller executes one after another. Chapter 2 deals with the structure of BASIC program in details. Compiler is a program run on computer and its task is to translate the original BASIC code into language of zeros and ones that can be fed to microcontroller. The process of translation of BASIC program into executive HEX code is shown in the figure below. The program written in BASIC and saved as file program.
pbas is converted by compiler into assembly code (program.asm). The generated assembly code is further translated into executive HEX code which can be written to microcontroller memory. Programmer is a device which we use to transfer our HEX files from computer to microcontroller memory.
Originally devised as an easy-to-use tool, BASIC became widespread on home microcomputers in the 1980s, and remains popular to this day in a handful of heavily evolved dialects. BASICs name, coined in classic, computer science tradition to produce a nice acronym, stands for Beginners All-purpose Symbolic Instruction Code. BASIC is still considered by many PC users to be the easiest programming language to use. Nowadays, this reputation is being shifted to the world of microcontrollers. BASIC allows faster and much easier development of applications for PIC compared to the Microchips assembly language MPASM. When writing the code for MCUs, programmers frequently deal with the same issues, such as serial communication, printing on LCD display, generating PWM signals, etc. For the purpose of facilitating programming, BASIC provides a number of built-in and library routines intended for solving these problems. As far as the execution and program size are in question, MPASM has a small advantage in respect with BASIC. This is why there is an option of combining BASIC and assembly code assembly is commonly used for parts of program in which execution time is critical or same commands are executed great number of times. Modern microcontrollers, such as PIC, execute instructions in a single cycle. If microcontroller clock is 4MHz, then one assembly instruction requires 250ns x 4 = 1us. As each BASIC command is technically a sequence of assembly instructions, the exact time necessary for its execution can be calculated by simply summing up the execution times of constituent assembly instructions.
back to the top
The program examples worked out throughout the book are mostly to be run on the microcontrollers PIC16F84 or PIC6F877, but with minor adjustments, can be run on any other PIC microcontroller.
program LED_Blink main: TRISB = 0 eloop: PORTB = $FF Delay_ms(1000) PORTB = 0 Delay_ms(1000) goto eloop end. ' Configure pins of PORTB as output ' Turn on diodes on PORTB ' Wait 1 second ' Turn off diodes on PORTB ' Wait 1 second ' Stay in loop
When the program is completed and saved as .pbas file, it can be compiled by clicking on Compile Icon (or just hit CTRL+F9) in mikroBasic IDE. The compiling procedure takes place in two consecutive steps:
1. Compiler will convert .pbas file to assembly code and save it as blink.asm file. 2. Then, compiler automatically calls assembly, which converts .asm file into executable HEX code ready for feeding to microcontroller. You cannot actually make the difference between the two steps, as the process is completely automated and indivisible. In case of syntax error in program code, program will not be compiled and HEX file will not be generated. Errors need to be corrected in the original .pbas file and then the source file may be compiled again. The best approach is to write and test small, logical parts of the program to make debugging easier.
back to the top
q q q q
MCL file (mikro compile library) is created for each module you have included in the project. In the process of compiling, .mcl files will be linked together to output asm, lst and hex files. If you want to distribute your module without disclosing the source code, you can send your compiled library (file extension .mcl). User will be able to use your library as if he had the source code. Although the compiler is able to determine which routines are implemented in the library, it is a common practice to provide routine prototypes in a separate text file. HEX file is the one you need to program the microcontroller. Commonly, generated HEX will be standard 8bit Merged Intel HEX format, accepted by the vast majority of the programming software. The programming device (programmer) with accessory software installed on PC is in charge of writing the physical contents of HEX file into the internal memory of a microcontroller. The contents of a file blink.hex is given below:
:100000000428FF3FFF3FFF3F031383168601FF30A5 :10001000831286000630F000FF30F100FF30F2005E :10002000F00B13281A28F10B16281928F20B1628A2 :10003000132810281A30F000FF30F100F00B2128AF :100040002428F10B21281E284230F000F00B26282E :1000500086010630F000FF30F100FF30F200F00BB7 :1000600032283928F10B35283828F20B3528322868 :100070002F281A30F000FF30F100F00B4028432801 :10008000F10B40283D284230F000F00B45280428B1 :100090004828FF3FFF3FFF3FFF3FFF3FFF3FFF3F3E :02400E007A3FF7 :00000001FF
Beside loading a program code into programming memory, programmer also configures the target
microcontroller, including the type of oscillator, protection of memory against reading, watchdog timer, etc. The following figure shows the connection between PC, programming device and the MCU.
Note that the programming software should be used only for the communication with the programming device it is not suitable for code writing.
back to the top
Oscillator can be 4MHz crystal and either two 22pF capacitors or the ceramic resonator of the same frequency (ceramic resonator already contains the mentioned capacitors, but unlike oscillator has three termination instead of only two). The rate at which the microcontroller operates, i.e. the speed at which the program runs, depends heavily on the oscillator frequency. During the application development, the easiest thing to do is to use the internal reset circuit MCLR pin is connected to +5V through a 10K resistor. Below is the scheme of a rectifier with LM7805 circuit which gives the output of stable +5V, and the minimal configuration relevant for the operation of a PIC microcontroller.
After the supply is brought to the circuit previously shown, PIC microcontroller should look animated, and the LED diode should blink once every second. If the signal is completely missing (LED diode does not blink), then check if +5V is present at all the relevant pins of PIC.
back to the top
1.7 Troubleshooting
There are several commonly encountered problems of bringing PIC microcontroller to working conditions. You need to check a few external components and test whether their values correspond to the desired ones, and finally to see whether all the connections are done right. We will present a few notes you may find useful. Check whether the MCLR pin is connected to +5V, over reset circuit, or simply with 10K resistor. If the pin remains disconnected, its level will be floating and it may work sometimes, but it usually wont. Chip has power-on-reset circuit, so the appropriate external pull-up resistor on MCLR pin should be sufficient. Check whether the connection with the resonator is stable. For most PIC microcontrollers to begin with 4MHz resonator is well enough. Check the supply. PIC microcontroller consumes very little energy but the supply needs to be well filtrated. At the rectifier output, the current is direct but pulsating, and as such is not suitable for the supply of microcontroller. To avoid the pulsating, the electrolytic capacitor of high capacitance (e.g. 470 mF) is placed at the rectifier output. If PIC microcontroller supervises devices that pull a lot of energy, they may provoke enough malfunctioning on the supply lines to cause the microcontroller start behaving somewhat strangely. Even seven-segmented LED display may well induce tension drops (the worst scenario is when all the digits are 8, when LED display needs the most power), if the source itself is not capable to procure enough current (e.g. 9V battery). Some PIC microcontrollers feature multi-functional I/O pins, for example PIC16C62x family (PIC16C620, 621 and 622). Controllers of this family are provided with analog comparators on port A. After putting those chips to work, port A is set to analog mode, which brings about the unexpected behavior of the pin functions on the port. Upon reset, any PIC with analog inputs will show itself in analog mode (if the same pins are used as digital lines they need to be set to digital mode). One possible source of troubles is that the fourth pin of port A exhibits singular behavior when it is used as output, because the pin has open collectors output instead of usual bipolar state. This implies that clearing this pin will nevertheless set it to low level, while setting the pin will let it
float somewhere in between, instead of setting it to high level. To make the pin behave as expected, the pull-up resistor was placed between RA4 and 5V. Its magnitude is between 4.7K and 10K, depending on the current necessary for the input. In this way, the pin functions as any other input pin (all pins are output after reset). More problems are to be expected if you plan to be seriously working with PIC. Sometimes the thing seems like it is going to work, but it just wont, regardless of the effort. Just remember that there is always more than one way to solve the problem, and that a different approach may bring solution.
back to the top Previous Chapter | Table of Contents | Next Chapter
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home Books
Compilers
Projects
Special Offer
Download
About us
Introduction 2.1 Identifiers 2.2 Operators 2.3 Expressions 2.4 Instructions 2.5 Data Types 2.6 Constants 2.7 Variables 2.8 Symbols 2.9 Directives 2.10 Comments 2.11 Labels 2.12 Procedures and Functions 2.13 Modules
Introduction
This chapter deals with the elements of BASIC language and the ways to use them efficiently. Learning how to program is not complicated, but it requires skill and experience to write code that is efficient, legible, and easy to handle. First of all, program is supposed to be comprehensible, so that the programmer himself, or somebody else working on the application, could make necessary corrections and improvements. We have provided a code sample written in a clear and manifest way to give you an idea how programs could be written:
This project is designed to work with PIC 16F877A; with minor adjustments, it should work with any other PIC MCU. The code demonstrates blinking of diodes connected to PORTB. Diodes go on and off each second.
'****************************************************************************** program LED_Blinking main: TRISB = 0 PORTB = %11111111 Delay_ms(1000) PORTB = %00000000 Delay_ms(1000) goto main end. ' Beginning of program ' Configure pins of PORTB as output ' Turn ON diodes on PORTB ' Wait for 1 second ' Turn OFF diodes on PORTB ' Wait for 1 second ' Endless loop ' End of program
Through clever use of comments, symbols, labels and other elements supported by BASIC, program can be rendered considerably clearer and more understandable, offering programmer a great deal of help. Also, it is advisable to divide larger programs into separate logical entities (such as routines and modules, see below) which can be addressed when needed. This also increases reusability of code. Names of routines and labels indicating a program segment should make some obvious sense. For example, program segment that swaps values of 2 variables, could be named "Swap", etc.
back to the top
2.1 Identifiers
Identifiers are names used for referencing the stored values, such as variables and constants. Every program, module, procedure, and function must be identified (hence the term) by an identifier. Valid identifier: 1. Must begin with a letter of English alphabet or possibly the underscore (_) 2. Consists of alphanumeric characters and the underscore (_) 3. May not contain special characters: ~ ! @ # $ % ^ & * ( ) + ` - = { } [ ] : " ; ' < > ? , . / | \ 4. Can be written in mixed case as BASIC is case insensitive; e.g. First, FIRST, and fIrST are an equivalent identifier. Elements ignored by the compiler include spaces, new lines, and tabs. All these elements are collectively known as the white space. White space serves only to make the code more legible it does not affect the actual compiling.
Several identifiers are reserved in BASIC, meaning that you cannot use them as your own identifiers (e. g. words function, byte, if, etc). For more information, please refer to the list of reserved words. Also, BASIC has a number of predefined identifiers which are listed in Chapter 4: Instructions.
back to the top
2.2 Operators
BASIC language possesses set of operators which is used to assign values, compare values, and perform other operations. The objects manipulated for that purpose are called operands (which themselves can be variables, constants, or other elements). Operators in BASIC must have at least two operands, with an exception of two unary operators. They serve to create expressions and instructions that in effect compose the program. There are four types of operators in BASIC: 1. 2. 3. 4. Arithmetic Operators Boolean Operators Logical (Bitwise) Operators Relation Operators (Comparison Operators)
2.3 Expressions
Expression is a construction that returns a value. BASIC syntax restricts you to single line expressions, where carriage return character marks the end of the expression. The simplest expressions are variables and constants, while more complex can be constructed from simpler ones using operators, function calls, indexes, and typecasts. Here is one simple expression:
A = B + C
' This expression sums up the values of variables B and C ' and stores the result into variable A.
You need to pay attention that the sum must be within the range of variable A in order to avoid the overflow and therefore the evident computational error. If the result of the expression amounts to 428, and the variable A is of byte type (having range between 0 and 255), the result accordingly obtained will be 172, which is obviously wrong.
back to the top
2.4 Instructions
Each instruction determines an action to be performed. As a rule, instructions are being executed in an exact order in which they are written in the program. However, the order of their execution can be changed by means of jump, routine call, or an interrupt.
if Time = 60 then goto Minute end if ' If variable Time equals 60 jump to label Minute
Instruction if..then contains the conducting expression Time = 60 composed of two operands, variable Time, constant 60 and the comparison operator (=). Generally, instructions may be divided into conditional instructions (decision making), loops (repeating blocks), jumps, and specific builtin instructions (e.g. for accessing the peripherals of microcontroller). Instruction set is explained in detail in Chapter 4: Instructions.
back to the top
Type byte char* word short integer longint 8-bit 8-bit 16-bit 8-bit 16-bit 32-bit
Range of values
Structured types include: Array, which represent an indexed collection of elements of the same type, often called the base type. Base type can be any simple type. String represents a sequence of characters. It is an array that holds characters and the first element
Sign is important attribute of data types, and affects the way variable is treated by the compiler. Unsigned can hold only positive numbers:
byte word
0 .. 255 0 .. 65535
2.6 Constants
Constant is data whose value cannot be changed during the runtime. Every constant is declared under unique name which must be a valid identifier. It is a good practice to write constant names in uppercase. If you frequently use the same fixed value throughout the program, you should declare it a constant (for example, maximum number allowed is 1000). This is a good practice since the value can be changed simply by modifying the declaration, instead of going trough the entire program and adjusting each instance manually. As simple as this:
Constants can be declared in decimal, hex, or binary form. Decimal constants are written without any prefix. Hexadecimal constants begin with a sign $, while binary begin with %.
It is important to understand why constants should be used and how this affects the MCU. Using a constant in a program consumes no RAM memory. This is very important due to the limited RAM space (PIC16F877 has 368 locations/bytes).
back to the top
2.7 Variables
Variable is data whose value can be changed during the runtime. Each variable is declared under unique name which has to be a valid identifier. This name is used for accessing the memory location occupied by the variable. Variable can be seen as a container for data and because it is typed, it instructs the compiler how to interpret the data it holds. In BASIC, variable needs to be declared before it can be used. Specifying a data type for each variable is mandatory. Variable is declared like this:
where identifier is any valid identifier and type can be any given data type. For example:
' Declare variable temperature of byte type ' Declare variable voltage of word type
Individual bits of byte variables (including SFR registers such as PORTA, etc) can be accessed by means of dot, both on left and right side of the expression. For example:
Data_Port.3 = 1
2.8 Symbols
Symbol makes possible to replace a certain expression with a single identifier alias. Use of symbols can increase readability of code. BASIC syntax restricts you to single line expressions, allowing shortcuts for constants, simple statements, function calls, etc. Scope of symbol identifier is a whole source file in which it is declared.
For example:
symbol MaxAllowed = 234 symbol PORT = PORTC symbol DELAY1S = Delay_ms(1000) ... if teA > MaxAllowed then teA = teA - 100
' Symbol as alias for numeric value ' Symbol as alias for Special Function Register ' Symbol as alias for procedure call
Note that using a symbol in a program technically consumes no RAM memory compiler simply replaces each instance of a symbol with the appropriate code from the declaration.
back to the top
2.9 Directives
Directives are words of special significance for BASIC, but unlike other reserved words, appear only in contexts where user-defined identifiers cannot occur. You cannot define an identifier that looks exactly like a directive.
Meaning specify exact location of variable in RAM specify exact location of routine in ROM
Absolute specifies the starting address in RAM for variable (if variable is multi-byte, higher bytes are stored at consecutive locations). Directive absolute is appended to the declaration of variable:
dim rem as byte absolute $22 ' Variable will occupy 1 byte at address $22 dim dot as word absolute $23 ' Variable will occupy 2 bytes at addresses $23 and $24
Org specifies the starting address of routine in ROM. For PIC16 family, routine must fit in one page otherwise, compiler will report an error. Directive org is appended to the declaration of routine:
sub procedure test org $200 ' Procedure will start at address $200 ... end sub
2.10 Comments
Comments are text that is added to the code for purpose of description or clarification, and are completely ignored by the compiler.
' Any text between an apostrophe and the end of the ' line constitutes a comment. May span one line only.
It is a good practice to comment your code, so that you or anybody else can later reuse it. On the other hand, it is often useful to comment out a troublesome part of the code, so it could be repaired or modified later. Comments should give purposeful information on what the program is doing. Comment such as Set Pin0 simply explains the syntax but fails to state the purpose of instruction. Something like Turn Relay on might prove to be much more useful. Specialized editors feature syntax highlighting it is easy to distinguish comments from code due to different color, and comments are usually italicized.
back to the top
2.11 Labels
Labels represent the most direct way of controlling the program flow. When you mark a certain program line with label, you can jump to that line by means of instructions goto and gosub. It is convenient to think of labels as bookmarks of sort. Note that the label main must be declared in every BASIC program because it marks the beginning of the main module. Label name needs to be a valid identifier. You cannot declare two labels with same name within the same routine. The scope of label (label visibility) is tied to the routine where it is declared. This ensures that goto cannot be used for jumping between routines. Goto is an unconditional jump statement. It jumps to the specified label and the program execution
continues normally from that point on. Gosub is a jump statement similar to goto, except it is tied to a matching word return. Upon jumping to a specified label, previous address is saved on the stack. Program will continue executing normally from the label, until it reaches return statement this will exit the subroutine and return to the first program line following the caller gosub instruction. Here is a simple example:
program test main: ' some instructions... ' simple endless loop using a label my_loop: ' some instructions... ' now jump back to label _loop goto my_loop end.
Note: Although it might seem like a good idea to beginners to program by means of jumps and labels, you should try not to depend on it. This way of thinking strays from the procedural programming and can teach you bad programming habits. It is far better to use procedures and functions where applicable, making the code structure more legible and easier to maintain.
back to the top
where procedureName is any valid identifier, statements is a sequence of statements that are executed upon the calling the procedure, and (parameterList), and localDeclarations are optional declaration of variables and/or constants.
sub procedure pr1_procedure(dim par1 as byte, dim par2 as byte, dim byref vp1 as byte, dim byref vp2 as byte) dim locS as byte par1 = locS + par1 + par2 vp1 vp2 end sub = par1 or par2 = locS xor par1
par1 and par2 are passed to the procedure by the value, but variables marked by keyword byref are passed by the address. This means that the procedure call pr1_procedure(tA, tB, tC, tD) passes tA and tB by the value: creates par1 = tA; and par2 = tB; then manipulates par1 and par2 so that tA and tB remain unchanged; passes tC and tD by the address: whatever changes are made upon vp1 and vp2 are also made upon tC and tD.
Function declaration is similar to procedure declaration, except it has a specified return type and a return value. Function declaration has the form:
where functionName is any valid identifier, returnType is any simple type, statements is a sequence of statements to be executed upon calling the function, and (parameterList), and localDeclarations are optional declaration of variables and/or constants. In BASIC, we use the keyword Result to assign return value of a function. For example:
sub function Calc(dim par1 as byte, dim par2 as word) as word dim locS as word locS = par1 * (par2 + 1) Result = locS end sub
As functions return values, function calls are technically expressions. For example, if you have defined a function called Calc, which collects two integer arguments and returns an integer, then the function call Calc(24, 47) is an integer expression. If I and J are integer variables, then I + Calc(J, 8) is also an integer expression.
back to the top
2.13 Modules
Large programs can be divided into modules which allow easier maintenance of code. Each module is an actual file, which can be compiled separately; compiled modules are linked to create an application. Note that each source file must end with keyword end followed by a dot. Modules allow you to: 1. Break large code into segments that can be edited separately, 2. Create libraries that can be used in different programs, 3. Distribute libraries to other developers without disclosing the source code. In mikroBasic IDE, all source code including the main program is stored in .pbas files. Each project consists of a single project file, and one or more module files. To build a project, compiler needs either a source file or a compiled file for each module. Every BASIC application has one main module file and any number of additional module files. All source files have same extension (pbas). Main file is identified by keyword program at the beginning, while other files have keyword module instead. If you want to include a module, add the keyword include followed by a quoted name of the file. For example:
tA = sqrt(tb) end.
Keyword include instructs the compiler which file to compile. The example above includes module math2.pbas in the program file. Obviously, routine sqrt used in the example is declared in module math2.pbas. If you want to distribute your module without disclosing the source code, you can send your compiled library (file extension .mcl). User will be able to use your library as if he had the source code. Although the compiler is able to determine which routines are implemented in the library, it is a common practice to provide routine prototypes in a separate text file. Module files should be organized in the following manner:
module unit_name include ... symbol ... const ... dim ... sub procedure procedure_name ... end sub sub function function_name ... end sub end.
' Module name ' Include other modules if necessary ' Symbols declaration ' Constants declaration ' Variables declaration ' Procedures declaration
Note that there is no body section in the module module files serve to declare functions, procedures, constants and global variables.
back to the top Previous Chapter | Table of Contents | Next Chapter
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong.
mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
q
Compilers
q
Projects
Special Offer
Home > Books > BASIC
Download
Books
Distributors
About us
Chapter 3: Operators
q q q q q
Introduction 3.1 Arithmetic Operators 3.2 Boolean Operators 3.3 Logical (Bitwise) Operators 3.4 Relation Operators (Comparison Operators)
Introduction
In complex expressions, operators with higher precedence are evaluated before the operators with lower precedence; operators of equal precedence are evaluated according to their position in the expression starting from the left.
Operator not *, div, mod, and, <<, >> +, -, or, xor =, <>, <, >, <=, >=
Operator +
Operation addition
Result type byte, short, integer, words, longint byte, short, integer, words, longint integer, words, long byte, short, integer, words byte, short, integer, words
subtraction
* div mod
byte, short, integer, words byte, short, integer, words byte, short, integer, words
A div B is the value of A divided by B rounded down to the nearest integer. The mod operator returns the remainder obtained by dividing its operands. In other words, X mod Y = X - (X div Y) * Y. If 0 (zero) is used explicitly as the second operand (i.e. X div 0), compiler will report an error and will not generate code. But in case of implicit division by zero : X div Y , where Y is 0 (zero), result will be the maximum value for the appropriate type (for example, if X and Y are words, the result will be $FFFF). If number is converted from less complex to more complex data type, upper bytes are filled with zeros. If number is converted from more complex to less complex data type, data is simply truncated (upper bytes are lost). If number is converted from less complex to more complex data type, upper bytes are filled with ones if sign bit equals 1 (number is negative). Upper bytes are filled with zeros if sign bit equals 0 (number is positive). If number is converted from more complex to less complex data type, data is simply truncated (upper bytes are lost). BASIC also has two unary arithmetic operators:
For example:
if (astr > 10) and (astr < 20) then PORTB = 0xFF end if
Operand types byte, word, short, integer, long byte, word, short, integer, long
Result type byte, word, short, integer, long byte, word, short, integer, long
byte, word, short, integer, long byte, word, short, integer, long byte, word, short, integer, long byte, word, short, integer, long
byte, word, short, integer, long byte, word, short, integer, long byte, word, short, integer, long byte, word, short, integer, long
<< : shift left the operand for a number of bit places specified in the right operand (must be positive and less then 255). >> : shift right the operand for a number of bit places specified in the right operand (must be positive and less then 255). For example, if you need to extract the higher byte, you can do it like this:
Operand types All simple types All simple types All simple types All simple types All simple types All simple types
Result type True or False True or False True or False True or False True or False True or False
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
q
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Introduction
q q q q
4.1 Conditional Statements 4.1.1 IF..THEN Statement 4.1.2 SELECT..CASE Statement 4.1.3 GOTO Statement
q q q q
4.2 Loops 4.2.1 FOR Statement 4.2.2 DO..LOOP Statement 4.2.3 WHILE Statement
Introduction
Statements define algorithmic actions within a program. Simple statements - like assignments and procedure calls - can be combined to form loops, conditional statements, and other structured statements. Simple statement does not contain any other statements. Simple statements include assignments, and calls to procedures and functions. Structured statements are constructed from other statements. Use a structured statement when you want to execute other statements sequentially, conditionally, or repeatedly.
Syntax
Description
Instruction selects one of two possible program paths. Instruction IF.. THEN is the fundamental instruction of program branching in PIC BASIC and it can be used in several ways to allow flexibility necessary for realization of decision making logic. Expression returns a True or False value. If expression is True, then statements1 are executed; otherwise statements2 are executed, if the else clause is present. Statements1 and statements2 can be statements of any type.
Example
The simplest form of the instruction is shown in the figure below. Our example tests the button connected to RB0 - when the button is pressed, program jumps to the label "Add" where value of variable "w" is increased. If the button is not pressed, program jumps back to the label "Main".
More complex form of instruction is program branching with the ELSE clause:
dim j as byte Main: if PORTB.0 = 0 then j = j + 1 else j = j - 1 endif goto Main end.
Syntax
select case Selector case Value_1 Statements_1 case Value_2 Statements_2 ... case Value_N Statements_n [ case else Statements_else ] end select
Description
Select Case statement is used for selecting one of several available branches in the program course. It consists of a selector variable as a switch condition, and a list of possible values. These values can be constants, numerals, or expressions. Eventually, there can be an else statement which is executed if none of the labels corresponds to the value of the selector. As soon as the Select Case statement is executed, at most one of the statements statements_1 .. statements_n will be executed. The Value which matches the Selector determines the statements to be executed. If none of the Value items matches the Selector, then the statements_else in the else clause (if there is one) are executed.
Example
select case W case 0 B = 1 PORTB = B case 1 A = 1 PORTA = A case else PORTB = 0 end select ... select case Ident case testA
PORTB = 6 Res = T mod 23 case teB + teC T = 1313 case else T = 0 end select
Syntax
goto Label
Description
Goto statement jumps to the specified label unconditionally, and the program execution continues normally from that point on. Avoid using GOTO too often, because over-labeled programs tend to be less intelligible.
Example
program test main: ' some instructions ... goto myLabel ' some instructions... myLabel: ' some instructions... end.
4.2 Loops
Loop statements allow repeating one or more instructions for a number of times. The conducting expression determines the number of iterations loop will go through.
Syntax
for counter = initialValue to finalValue [step step_value] statement_1 statement_2 ... statement_N next counter
Description
For statement requires you to specify the number of iterations you want the loop to go through. Counter is variable; initialValue and finalValue are expressions compatible with counter; statement is any statement that does not change the value of counter; step_value is value that is added to the counter in each iteration. Step_value is optional, and defaults to 1 if not stated otherwise. Be careful when using large values for step_value, as overflow may occur. Every statement between for and next will be executed once per iteration.
Example
Here is a simple example of a FOR loop used for emitting hex code on PORTB for 7-segment display with common cathode. Nine digits should be printed with one second delay. for i = 1 to 9 portb = i delay_ms(1000) next i
Syntax
Description
Expression returns a True or False value. The do..loop statement executes statement_1; ...; statement_N continually, checking the expression after each iteration. Eventually, when expression returns True, the do..loop statement terminates. The sequence is executed at least once because the check takes place in the end.
Example
I = 0 do I = I + 1 PORTB = I loop until I = 10 ' execute these 2 statements ' until i equals 10 (ten)
Syntax
Description
Expression is tested first. If it returns True, all the following statements enclosed by while and wend will be executed (or only one statement, alternatively). It will keep on executing statements until the expression returns False. Eventually, as expression returns False, while will be terminated without executing statements. While is similar to do..loop, except the check is performed at the
beginning of the loop. If expression returns False upon first test, statements will not be executed.
Example
Syntax
Description
Sometimes it can be useful to write part of the program in assembly. ASM statement can be used to embed PIC assembly instructions into BASIC code. Note that you cannot use numerals as absolute addresses for SFR or GPR variables in assembly instructions. You may use symbolic names instead (listing will display these names as well as addresses). Be careful when embedding assembly code - BASIC will not check if assembly instruction changed memory locations already used by BASIC variables.
Example
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Introduction 5.1 Built-in Routines 5.1.1 SetBit 5.1.2 ClearBit 5.1.3 TestBit 5.1.4 Lo 5.1.5 Hi 5.1.6 Higher 5.1.7 Highest 5.1.8 Delay_us 5.1.9 Delay_ms 5.1.10 Inc 5.1.11 Dec 5.1.12 Length
q q
5.2.6 EEPROM Library 5.2.6.1 EEPROM_Read 5.2.6.2 EEPROM_Write 5.2.7 Flash Memory Library 5.2.7.1 Flash_Read 5.2.7.2 Flash_Write 5.2.8 I2C Library 5.2.8.1 I2C_Init 5.2.8.2 I2C_Start 5.2.8.3 I2C_Repeated_Start 5.2.8.4 I2C_Rd 5.2.8.5 I2C_Wr 5.2.8.6 I2C_Stop 5.2.9 LCD Library 5.2.9.1 LCD_Init 5.2.9.2 LCD_Config
q q q q
5.2.13 PWM Library 5.2.13.1 PWM_Init 5.2.13.2 PWM_Change_Duty 5.2.13.3 PWM_Start 5.2.13.4 PWM_Stop 5.2.14 RS485 Library 5.2.14.1 RS485Master_Init 5.2.14.2 RS485Master_Read 5.2.14.3 RS485Master_Write 5.2.14.4 RS485Slave_Init 5.2.14.5 RS485Slave_Read 5.2.14.6 RS485Slave_Write 5.2.15 SPI Library 5.2.15.1 SPI_Init 5.2.15.2 SPI_Init_Advanced 5.2.15.3 SPI_Read
q q q q q q q q q q q q
q q q
q q
q q q q q q q
q q q q q
q q
q q
q q
q q
q q q q q q q q q
5.2.1 Numeric Formatting 5.2.1.1 ByteToStr 5.2.1.2 WordToStr 5.2.1.3 ShortToStr 5.2.1.4 IntToStr 5.2.1.5 Bcd2Dec 5.2.1.6 Dec2Bcd 5.2.1.7 Bcd2Dec16 5.2.1.8 Dec2Bcd16 5.2.2 ADC Library 5.2.2.1 ADC_read 5.2.3 CAN Library 5.2.3.1 CANSetOperationMode 5.2.3.2 CANGetOperationMode 5.2.3.3 CANInitialize 5.2.3.4 CANSetBaudRate 5.2.3.5 CANSetMask 5.2.3.6 CANSetFilter 5.2.3.7 CANWrite 5.2.3.8 CANRead 5.2.3.9 CAN Library Constants 5.2.4 CANSPI Library 5.2.4.1 CANSPISetOperationMode 5.2.4.2 CANSPIGetOperationMode 5.2.4.3 CANSPIInitialize 5.2.4.4 CANSPISetBaudRate 5.2.4.5 CANSPISetMask 5.2.4.6 CANSPISetFilter
q q q q q
5.2.9.3 LCD_Chr 5.2.9.4 LCD_Chr_CP 5.2.9.5 LCD_Out 5.2.9.6 LCD_Out_CP 5.2.9.7 LCD_Cmd 5.2.10 LCD8 Library 5.2.10.1 LCD8_Init 5.2.10.2 LCD8_Config 5.2.10.3 LCD8_Chr 5.2.10.4 LCD8_Chr_CP 5.2.10.5 LCD8_Out 5.2.10.6 LCD8_Out_CP 5.2.10.7 LCD8_Cmd 5.2.11 Graphic LCD Library 5.2.11.1 GLCD_Config 5.2.11.2 GLCD_Init 5.2.11.3 GLCD_Put_Ins 5.2.11.4 GLCD_Put_Data 5.2.11.5 GLCD_Put_Data2 5.2.11.6 GLCD_Select_Side 5.2.11.7 GLCD_Data_Read 5.2.11.8 GLCD_Clear_Dot 5.2.11.9 GLCD_Set_Dot 5.2.11.10 GLCD_Circle 5.2.11.11 GLCD_Line 5.2.11.12 GLCD_Invert 5.2.11.13 GLCD_Goto_XY 5.2.11.14 GLCD_Put_Char
5.2.15.4 SPI_Write 5.2.16 USART Library 5.2.16.1 USART_Init 5.2.16.2 USART_Data_Ready 5.2.16.3 USART_Read 5.2.16.4 USART_Write 5.2.17 One-wire Library 5.2.17.1 OW_Reset 5.2.17.2 OW_Read 5.2.17.3 OW_Write 5.2.18 Software I2C Library 5.2.18.1 Soft_I2C_Config 5.2.18.2 Soft_I2C_Start 5.2.18.3 Soft_I2C_Write 5.2.18.4 Soft_I2C_Read 5.2.18.5 Soft_I2C_Stop 5.2.19 Software SPI Library 5.2.19.1 Soft_SPI_Config 5.2.19.2 Soft_SPI_Read 5.2.19.3 Soft_SPI_Write 5.2.20 Software UART Library 5.2.20.1 Soft_UART_Init 5.2.20.2 Soft_UART_Read 5.2.20.3 Soft_UART_Write 5.2.21 Sound Library
q q q q q
q q q q
q q q q
q q
q q q q
q q q q q q q q q q
q q q q q q
q q q q q q q q q q q q q q q
q q q q
q q q q q q q
q q q q
q q q
5.2.4.7 CANSPIWrite 5.2.4.8 CANSPIRead 5.2.4.9 CANSPI Library Constants 5.2.5 Compact Flash Library 5.2.5.1 CF_Init_Port 5.2.5.2 CF_Detect 5.2.5.3 CF_Write_Init 5.2.5.4 CF_Write_Byte 5.2.5.5 CF_Write_Word 5.2.5.6 CF_Read_Init 5.2.5.7 CF_Read_Byte 5.2.5.8 CF_Read_Word 5.2.5.9 CF_File_Write_Init 5.2.5.10 CF_File_Write_Byte 5.2.5.11 CF_File_Write_Complete
q q q q
5.2.11.15 GLCD_Clear_Screen 5.2.11.16 GLCD_Put_Text 5.2.11.17 GLCD_Rectangle 5.2.11.18 GLCD_Set_Font 5.2.12 Manchester Code Library 5.2.12.1 Man_Receive_Init 5.2.12.2 Man_Receive_Config 5.2.12.3 Man_Receive 5.2.12.4 Man_Send_Init 5.2.12.5 Man_Send_Config 5.2.12.6 Man_Send
q q
5.2.21.1 Sound_Init 5.2.21.2 Sound_Play 5.2.22 Trigonometry Library 5.2.22.1 SinE3 5.2.22.2 CosE3 5.2.23 Utilities 5.2.23.1 Button
q q
q q q q q q q q q q q q
q q q q q q q
q q
Introduction
BASIC was designed with focus on simplicity of use. Great number of built-in and library routines are included to help you develop your applications quickly and easily.
Prototype Description
sub procedure SetBit(dim byref Reg as byte, dim Bit as byte) Sets <Bit> of register <Reg>. Any SFR (Special Function Register) or variable of byte type can pass as valid variable parameter, but constants should be in range [0..7]. SetBit(PORTB,2) ' set bit RB2
Example
Prototype Description
sub procedure ClearBit(dim byref Reg as byte, dim Bit as byte) Clears <Bit> of register <Reg>. Any SFR (Special Function Register) or variable of byte type can pass as valid variable parameter, but constants should be in range [0..7]. ClearBit(PORTC,7) ' clear bit RC7
Example
Prototype Description
sub function TestBit(dim byref Reg as byte, dim Bit as byte) as byte Tests <Bit> of register <Reg>. If set, returns 1, otherwise 0. Any SFR (Special Function Register) or variable of byte type can pass as valid variable parameter, but constants should be in range [0..7].
Example
Prototype Description
sub function Lo(dim Par as byte..longint) as byte Returns byte 0 of <Par>, assuming that word/integer comprises bytes 1 and 0, and longint comprises bytes 3, 2, 1, and 0. Lo(A) ' returns lower byte of variable A
Example
Prototype Description
sub function Hi(dim arg as word..longint) as byte Returns byte 1 of <Par>, assuming that word/integer comprises bytes 1 and 0, and longint comprises bytes 3, 2, 1, and 0. Hi(Aa) ' returns hi byte of variable Aa
Example
Prototype
Description Example
Returns byte 2 of <Par>, assuming that longint comprises bytes 3, 2, 1, and 0. Higher(Aaaa) ' returns byte next to the highest byte of variable Aaaa
sub function Highest(dim arg as longint) as byte Returns byte 3 of <Par>, assuming that longint comprises bytes 3, 2, 1, and 0. Highest(Aaaa) ' returns the highest byte of variable Aaaa
sub procedure Delay_us(const Count as word) Routine creates a software delay in duration of <Count> microseconds. Delay_us(100) ' creates software delay equal to 1s
Prototype
Description Example
Routine creates a software delay in duration of <Count> milliseconds. Delay_ms(1000) ' creates software delay equal to 1s
sub procedure Inc(byref Par as byte..longint) Routine increases <Par> by one. Inc(Aaaa) ' increments variable Aaaa by 1
sub procedure Dec(byref Par as byte..longint) Routine decreases <Par> by one. Dec(Aaaa) ' decrements variable Aaaa by 1
Prototype
Description Example
Routine returns length of string <Text> as byte. Length(Text) ' returns string length as byte
Prototype Description
sub procedure ByteToStr(dim input as byte, dim byref txt as char[6]) Parameter <input> represents numerical value of byte type that should be converted to string; parameter <txt> is passed by the address and contains the result of conversion. Parameter <txt> has to be of sufficient size to fit the converted string.
Example
ByteToStr(Counter, Message) ' Copies value of byte Counter into string Message
Prototype Description
sub procedure WordToStr(dim input as word, dim byref txt as char[6]) Parameter <input> represents numerical value of word type that should be converted to string; parameter <txt> is passed by the address and contains the result of conversion. Parameter <txt> has to be of sufficient size to fit the converted string.
Example
WordToStr(Counter, Message) ' Copies value of word Counter into string Message
Prototype Description
sub procedure ShortToStr(dim input as short, dim byref txt as char[6]) Parameter <input> represents numerical value of short type that should be converted to string; parameter <txt> is passed by the address and contains the result of conversion. Parameter <txt> has to be of sufficient size to fit the converted string.
Example
ShortToStr(Counter, Message) ' Copies value of short Counter into string Message
Prototype Description
sub procedure IntToStr(dim input as integer, dim byref txt as char[6]) Parameter <input> represents numerical value of integer type that should be converted to string; parameter <txt> is passed by the address and contains the result of conversion. Parameter <txt> has to be of sufficient size to fit the converted string.
Example
IntToStr(Counter, Message) ' Copies value of integer Counter into string Message
Prototype Description
sub procedure Bcd2Dec(dim bcd_num as byte) as byte Function converts 8-bit BCD numeral to its decimal equivalent and returns the result as byte.
Example
dim a as byte dim b as byte ... a = 140 b = Bcd2Dec(a) ' b equals 224 now
Prototype Description
sub procedure Dec2Bcd(dim dec_num as byte) as byte Function converts 8-bit decimal numeral to BCD and returns the result as byte.
Example
dim a as byte dim b as byte ... a = 224 b = Dec2Bcd(a) ' b equals 140 now
Prototype Description
sub procedure Bcd2Dec16(dim bcd_num as word) as word Function converts 16-bit BCD numeral to its decimal equivalent and returns the result as byte.
Example
dim a as word dim b as word ... a = 1234 b = Bcd2Dec16(a) ' b equals 4660 now
Prototype Description
sub procedure Dec2Bcd16(dim dec_num as word) as word Function converts 16-bit decimal numeral to BCD and returns the result as word.
Example
dim a as word dim b as word ... a = 4660 b = Dec2Bcd16(a) ' b equals 1234 now
Prototype Description
sub function ADC_Read(dim Channel as byte) as word Routine initializes ADC module to work with RC clock. Clock determines the time period necessary for performing AD conversion (min 12TAD). RC sources typically have Tad 4uS. Parameter <Channel> determines which channel will be sampled. Refer to the device data sheet for information on device channels.
Example
res = ADC_Read(2) ' reads channel 2 and stores value in variable res
ADC HW connection
back to the top
Prototype Description
sub procedure CANSetOperationMode(dim Mode as byte, dim Wait as byte) The procedure copies <Mode> to CANSTAT and sets CAN to requested mode. Operation <Mode> code can take any of predefined constant values. <Wait> takes values TRUE(255) or FALSE(0) If Wait is true, this is a blocking call. It won't return until requested mode is set. If Wait is false, this is a non-blocking call. It does not verify if CAN module is switched to requested mode or not. Caller must use CANGetOperationMode() to verify correct operation mode before performing mode specific operation.
Example
CANSetOperationMode(CAN_MODE_LISTEN, TRUE)
Prototype Description
sub function CANGetOperationMode as byte The function returns the current operation mode of CAN.
Example
CANGetOperationMode
Prototype
sub procedure CANInitialize(dim SJW as byte, dim BRP as byte, dim PHSEG1 as byte, dim PHSEG2 as byte, dim PROPSEG as byte, dim CAN_CONFIG_FLAGS as byte)
Description
The procedure initializes CAN module. CAN must be in Configuration mode or else these values will be ignored. Parameters: SJW value as defined in 18XXX8 datasheet (must be between 1 thru 4) BRP value as defined in 18XXX8 datasheet (must be between 1 thru 64) PHSEG1 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PHSEG2 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PROPSEG value as defined in 18XXX8 datasheet (must be between 1 thru 8) CAN_CONFIG_FLAGS value is formed from constants (see below) Output: CAN bit rate is set. All masks registers are set to '0' to allow all messages. Filter registers are set according to flag value: If (CAN_CONFIG_FLAGS and CAN_CONFIG_VALID_XTD_MSG) <> 0 Set all filters to XTD_MSG Else if (config and CONFIG_VALID_STD_MSG) <> 0 Set all filters to STD_MSG Else Set half of the filters to STD, and the rest to XTD_MSG Side Effects:
Example
dim aa as byte aa = CAN_CONFIG_SAMPLE_THRICE and CAN_CONFIG_PHSEG2_PRG_ON and CAN_CONFIG_STD_MSG and CAN_CONFIG_DBL_BUFFER_ON and CAN_CONFIG_VALID_XTD_MSG and CAN_CONFIG_LINE_FILTER_OFF CANInitialize(1, 1, 3, 3, 1, aa) ' form value to be used ' with CANInitialize
Prototype
sub procedure CANSetBaudRate(dim SJW as byte, dim BRP as byte, dim PHSEG1 as byte, dim PHSEG2 as byte, dim PROPSEG as byte, dim CAN_CONFIG_FLAGS as byte)
Description
The procedure sets CAN Baud Rate. CAN must be in Configuration mode or else these values will be ignored. Parameters: SJW value as defined in 18XXX8 datasheet (must be between 1 thru 4) BRP value as defined in 18XXX8 datasheet (must be between 1 thru 64) PHSEG1 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PHSEG2 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PROPSEG value as defined in 18XXX8 datasheet (must be between 1 thru 8) CAN_CONFIG_FLAGS - Value formed from constants (see section below) Output:
Given values are bit adjusted to fit in 18XXX8 and BRGCONx registers and copied. CAN bit rate is set as per given values.
Example
CANSetBaudRate(1, 1, 3, 3, 1, aa)
Prototype
Description
The procedure sets the CAN message mask. CAN must be in Configuration mode. If not, all values will be ignored. Parameters: CAN_MASK - One of predefined constant value val - Actual mask register value CAN_CONFIG_FLAGS - Type of message to filter, either CAN_CONFIG_XTD_MSG or CAN_CONFIG_STD_MSG Output: Given value is bit adjusted to appropriate buffer mask registers.
Example
Prototype
sub procedure CANSetFilter(dim CAN_FILTER as byte, dim val as longint, dim CAN_CONFIG_FLAGS as byte)
Description
The procedure sets the CAN message filter. CAN must be in Configuration mode. If not, all values will be ignored. Parameters: CAN_FILTER - One of predefined constant values val - Actual filter register value. CAN_CONFIG_FLAGS - Type of message to filter, either CAN_CONFIG_XTD_MSG or CAN_CONFIG_STD_MSG Output: Given value is bit adjusted to appropriate buffer filter registers
Example
CANSetFilter(CAN_FILTER_B1_F1, 3, CAN_CONFIG_XTD_MSG)
Prototype
sub function CANWrite(dim id as longint, dim byref Data : as byte[8], dim DataLen as byte, dim CAN_TX_MSG_FLAGS as byte) as byte
Description
If at least one empty transmit buffer is found, given message is queued for the transmission. If none found, FALSE value is returned. CAN must be in Normal mode. Parameters: id - CAN message identifier. Only 11 or 29 bits may be used depending on message type (standard or extended) Data - array of bytes up to 8 bytes in length DataLen - Data length from 1 thru 8 CAN_TX_MSG_FLAGS - Value formed from constants (see section below)
Example
aa1 =
Prototype
sub function CANRead(dim byref id as longint, dim byref Data as byte[8], dim byref DataLen as byte, dim byref CAN_RX_MSG_FLAGS as byte) as byte
Description
If at least one full receive buffer is found, the function extracts and returns the message as byte. If none found, FALSE value is returned. CAN must be in mode in which receiving is possible. Parameters: id - CAN message identifier Data - array of bytes up to 8 bytes in length DataLen - Data length from 1 thru 8 CAN_TX_MSG_FLAGS - Value formed from constants (see below)
Example
const CAN_MODE_NORMAL = 0
CAN_TX_MSG_FLAGS These constant values define flags related to transmission of a CAN message. There could be more than one this flag ANDed together to form multiple flags. const CAN_TX_PRIORITY_BITS = $03
const CAN_TX_FRAME_BIT = $08 const CAN_TX_STD_FRAME = $FF const CAN_TX_XTD_FRAME = $F7 const CAN_TX_RTR_BIT = $40 const CAN_TX_NO_RTR_FRAME = $FF const CAN_TX_RTR_FRAME = $BF ' X1XXXXXX ' X0XXXXXX ' XXXXX1XX ' XXXXX0XX
CAN_RX_MSG_FLAGS These constant values define flags related to reception of a CAN message. There could be more than one this flag ANDed together to form multiple flags. If a particular bit is set; corresponding meaning is TRUE or else it will be FALSE. e.g. if (MsgFlag and CAN_RX_OVERFLOW) <> 0 then ' Receiver overflow has occurred. ' We have lost our previous message.
const CAN_RX_FILTER_BITS = $07 const CAN_RX_FILTER_1 = $00 const CAN_RX_FILTER_2 = $01 const CAN_RX_FILTER_3 = $02 const CAN_RX_FILTER_4 = $03 const CAN_RX_FILTER_5 = $04 const CAN_RX_FILTER_6 = $05 const CAN_RX_OVERFLOW = $08 const CAN_RX_INVALID_MSG = $10 const CAN_RX_XTD_FRAME = $20 const CAN_RX_RTR_FRAME = $40 const CAN_RX_DBL_BUFFERED = $80
' Set if Overflowed else cleared ' Set if invalid else cleared ' Set if XTD message else cleared ' Set if RTR message else cleared ' Set if this message was hardware double-buffered
CAN_MASK These constant values define mask codes. Routine CANSetMask()requires this code as one of its arguments. These enumerations must be used by itself i.e. it cannot be ANDed to form multiple values. const CAN_MASK_B1 = 0 const CAN_MASK_B2 = 1
CAN_FILTER These constant values define filter codes. Routine CANSetFilter() requires this code as one of its arguments. These enumerations must be used by itself, i.e. it cannot be ANDed to form multiple values. const CAN_FILTER_B1_F1 = 0 const CAN_FILTER_B1_F2 = 1 const CAN_FILTER_B2_F1 = 2 const CAN_FILTER_B2_F2 = 3 const CAN_FILTER_B2_F3 = 4 const CAN_FILTER_B2_F4 = 5
CAN_CONFIG_FLAGS These constant values define flags related to configuring CAN module. Routines CANInitialize() and CANSetBaudRate() use these codes. One or more these values may be ANDed to form multiple flags const CAN_CONFIG_DEFAULT = $FF const CAN_CONFIG_PHSEG2_PRG_BIT = $01 const CAN_CONFIG_PHSEG2_PRG_ON = $FF const CAN_CONFIG_PHSEG2_PRG_OFF = $FE const CAN_CONFIG_LINE_FILTER_BIT = $02 const CAN_CONFIG_LINE_FILTER_ON = $FF ' XXXXXX1X ' XXXXXXX1 ' XXXXXXX0 ' 11111111
const CAN_CONFIG_LINE_FILTER_OFF = $FD ' XXXXXX0X const CAN_CONFIG_SAMPLE_BIT = $04 const CAN_CONFIG_SAMPLE_ONCE = $FF const CAN_CONFIG_SAMPLE_THRICE = $FB ' XXXXX1XX ' XXXXX0XX
const CAN_CONFIG_MSG_TYPE_BIT = $08 const CAN_CONFIG_STD_MSG = $FF const CAN_CONFIG_XTD_MSG = $F7 const CAN_CONFIG_DBL_BUFFER_BIT = $10 const CAN_CONFIG_DBL_BUFFER_ON = $FF const CAN_CONFIG_DBL_BUFFER_OFF = $EF const CAN_CONFIG_MSG_BITS = $60 const CAN_CONFIG_ALL_MSG = $FF const CAN_CONFIG_VALID_XTD_MSG = $DF const CAN_CONFIG_VALID_STD_MSG = $BF const CAN_CONFIG_ALL_VALID_MSG = $9F ' X11XXXXX ' X10XXXXX ' X01XXXXX ' X00XXXXX ' XXX1XXXX ' XXX0XXXX ' XXXX1XXX ' XXXX0XXX
Prototype Description
sub procedure CANSPISetOperationMode(dim mode as byte, dim Wait as byte) The procedure copies <mode> to CANSTAT and sets CAN to requested mode. Operation <mode> code can take any of predefined constant values. <Wait> takes values TRUE(255) or FALSE(0) If Wait is true, this is a blocking call. It won't return until requested mode is set. If Wait is false, this is a non-blocking call. It does not verify if CAN module is switched to requested mode or not. Caller must use CANGetOperationMode() to verify correct operation mode before performing mode specific operation.
Example
CANSPISetOperationMode(CAN_MODE_LISTEN, TRUE)
Prototype Description
sub function CANSPIGetOperationMode as byte The function returns the current operation mode of CAN.
Example
CANGetOperationMode
Prototype
sub procedure CANSPIInitialize(dim SJW as byte, dim BRP as byte, dim PHSEG1 as byte, dim PHSEG2 as byte, dim PROPSEG as byte, dim CAN_CONFIG_FLAGS as byte)
Description
The procedure initializes CAN module. CAN must be in Configuration mode or else these values will be ignored. Parameters: SJW value as defined in 18XXX8 datasheet (must be between 1 thru 4) BRP value as defined in 18XXX8 datasheet (must be between 1 thru 64) PHSEG1 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PHSEG2 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PROPSEG value as defined in 18XXX8 datasheet (must be between 1 thru 8) CAN_CONFIG_FLAGS value is formed from constants (see below) Output: CAN bit rate is set. All masks registers are set to '0' to allow all messages. Filter registers are set according to flag value: If (CAN_CONFIG_FLAGS and CAN_CONFIG_VALID_XTD_MSG) <> 0 Set all filters to XTD_MSG Else if (config and CONFIG_VALID_STD_MSG) <> 0 Set all filters to STD_MSG
Else Set half of the filters to STD, and the rest to XTD_MSG Side Effects: All pending transmissions are aborted.
Example
dim aa as byte aa = CAN_CONFIG_SAMPLE_THRICE and CAN_CONFIG_PHSEG2_PRG_ON and CAN_CONFIG_STD_MSG and CAN_CONFIG_DBL_BUFFER_ON and CAN_CONFIG_VALID_XTD_MSG and CAN_CONFIG_LINE_FILTER_OFF CANInitialize(1, 1, 3, 3, 1, aa) ' form value to be used ' with CANSPIInitialize
Prototype
sub procedure CANSPISetBaudRate(dim SJW as byte, dim BRP as byte, dim PHSEG1 as byte, dim PHSEG2 as byte, dim PROPSEG as byte, dim CAN_CONFIG_FLAGS as byte)
Description
The procedure sets CAN Baud Rate. CAN must be in Configuration mode or else these values will be ignored. Parameters: SJW value as defined in 18XXX8 datasheet (must be between 1 thru 4) BRP value as defined in 18XXX8 datasheet (must be between 1 thru 64) PHSEG1 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PHSEG2 value as defined in 18XXX8 datasheet (must be between 1 thru 8) PROPSEG value as defined in 18XXX8 datasheet (must be between 1 thru 8) CAN_CONFIG_FLAGS - Value formed from constants (see section below) Output: Given values are bit adjusted to fit in 18XXX8 and BRGCONx registers and copied. CAN bit rate is set as per given values.
Example
CANSPISetBaudRate(1, 1, 3, 3, 1, aa)
Prototype
Description
The procedure sets the CAN message mask. CAN must be in Configuration mode. If not, all values will be ignored. Parameters: CAN_MASK - One of predefined constant value val - Actual mask register value CAN_CONFIG_FLAGS - Type of message to filter, either CAN_CONFIG_XTD_MSG or CAN_CONFIG_STD_MSG Output: Given value is bit adjusted to appropriate buffer mask registers.
Example
Prototype
sub procedure CANSPISetFilter(dim CAN_FILTER as byte, dim val as longint, dim CAN_CONFIG_FLAGS as byte)
Description
The procedure sets the CAN message filter. CAN must be in Configuration mode. If not, all values will be ignored. Parameters: CAN_FILTER - One of predefined constant values val - Actual filter register value. CAN_CONFIG_FLAGS - Type of message to filter, either CAN_CONFIG_XTD_MSG or CAN_CONFIG_STD_MSG Output: Given value is bit adjusted to appropriate buffer filter registers
Example
CANSPISetFilter(CAN_FILTER_B1_F1, 3, CAN_CONFIG_XTD_MSG)
Prototype
sub function CANSPIWrite(dim id as longint, dim byref Data : as byte[8], dim DataLen as byte, dim CAN_TX_MSG_FLAGS as byte) as byte
Description
If at least one empty transmit buffer is found, given message is queued for the transmission. If none found, FALSE value is returned. CAN must be in Normal mode. Parameters: id - CAN message identifier. Only 11 or 29 bits may be used depending on message type (standard or extended) Data - array of as bytes up to 8 as bytes in length DataLen - Data length from 1 thru 8 CAN_TX_MSG_FLAGS - Value formed from constants (see section below)
Example
aa1 =
Prototype
sub function CANSPIRead(dim byref id as longint, dim byref Data as byte[8], dim byref DataLen as byte, dim byref CAN_RX_MSG_FLAGS as byte) as byte
Description
If at least one full receive buffer is found, the function extracts and returns the message as byte. If none found, FALSE value is returned. CAN must be in mode in which receiving is possible. Parameters: id - CAN message identifier Data - array of bytes up to 8 bytes in length DataLen - Data length from 1 thru 8 CAN_TX_MSG_FLAGS - Value formed from constants (see below)
Example
const CAN_MODE_NORMAL = 0
CAN_TX_MSG_FLAGS
These constant values define flags related to transmission of a CAN message. There could be more than one this flag ANDed together to form multiple flags. const CAN_TX_PRIORITY_BITS const CAN_TX_PRIORITY_0 const CAN_TX_PRIORITY_1 const CAN_TX_PRIORITY_2 const CAN_TX_PRIORITY_3 = $03 ' XXXXXX00 ' XXXXXX01 ' XXXXXX10 ' XXXXXX11
const CAN_TX_FRAME_BIT = $08 const CAN_TX_STD_FRAME = $FF const CAN_TX_XTD_FRAME = $F7 const CAN_TX_RTR_BIT = $40 const CAN_TX_NO_RTR_FRAME = $FF const CAN_TX_RTR_FRAME = $BF ' X1XXXXXX ' X0XXXXXX ' XXXXX1XX ' XXXXX0XX
CAN_RX_MSG_FLAGS These constant values define flags related to reception of a CAN message. There could be more than one this flag ANDed together to form multiple flags. If a particular bit is set; corresponding meaning is TRUE or else it will be FALSE. e.g. if (MsgFlag and CAN_RX_OVERFLOW) <> 0 then ' Receiver overflow has occurred. ' We have lost our previous message.
const CAN_RX_FILTER_BITS = $07 const CAN_RX_FILTER_1 = $00 const CAN_RX_FILTER_2 = $01 const CAN_RX_FILTER_3 = $02 const CAN_RX_FILTER_4 = $03 const CAN_RX_FILTER_5 = $04 const CAN_RX_FILTER_6 = $05 const CAN_RX_OVERFLOW = $08 const CAN_RX_INVALID_MSG = $10 const CAN_RX_XTD_FRAME = $20
' Set if Overflowed else cleared ' Set if invalid else cleared ' Set if XTD message else cleared
' Set if RTR message else cleared ' Set if this message was hardware double-buffered
CAN_MASK These constant values define mask codes. Routine CANSetMask()requires this code as one of its arguments. These enumerations must be used by itself i.e. it cannot be ANDed to form multiple values. const CAN_MASK_B1 = 0 const CAN_MASK_B2 = 1
CAN_FILTER These constant values define filter codes. Routine CANSetFilter() requires this code as one of its arguments. These enumerations must be used by itself, i.e. it cannot be ANDed to form multiple values. const CAN_FILTER_B1_F1 = 0 const CAN_FILTER_B1_F2 = 1 const CAN_FILTER_B2_F1 = 2 const CAN_FILTER_B2_F2 = 3 const CAN_FILTER_B2_F3 = 4 const CAN_FILTER_B2_F4 = 5
CAN_CONFIG_FLAGS These constant values define flags related to configuring CAN module. Routines CANInitialize() and CANSetBaudRate() use these codes. One or more these values may be ANDed to form multiple flags const CAN_CONFIG_DEFAULT = $FF const CAN_CONFIG_PHSEG2_PRG_BIT = $01 const CAN_CONFIG_PHSEG2_PRG_ON = $FF const CAN_CONFIG_PHSEG2_PRG_OFF = $FE const CAN_CONFIG_LINE_FILTER_BIT = $02 const CAN_CONFIG_LINE_FILTER_ON = $FF ' XXXXXX1X ' XXXXXXX1 ' XXXXXXX0 ' 11111111
const CAN_CONFIG_SAMPLE_BIT = $04 const CAN_CONFIG_SAMPLE_ONCE = $FF const CAN_CONFIG_SAMPLE_THRICE = $FB const CAN_CONFIG_MSG_TYPE_BIT = $08 const CAN_CONFIG_STD_MSG = $FF const CAN_CONFIG_XTD_MSG = $F7 const CAN_CONFIG_DBL_BUFFER_BIT = $10 const CAN_CONFIG_DBL_BUFFER_ON = $FF const CAN_CONFIG_DBL_BUFFER_OFF = $EF const CAN_CONFIG_MSG_BITS = $60 const CAN_CONFIG_ALL_MSG = $FF const CAN_CONFIG_VALID_XTD_MSG = $DF const CAN_CONFIG_VALID_STD_MSG = $BF const CAN_CONFIG_ALL_VALID_MSG = $9F ' X11XXXXX ' X10XXXXX ' X01XXXXX ' X00XXXXX ' XXX1XXXX ' XXX0XXXX ' XXXX1XXX ' XXXX0XXX ' XXXXX1XX ' XXXXX0XX
Example of interfacing CAN transceiver MCP2551, and MCP2510 with MCU and bus
back to the top
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. Following routines can be used for CF with FAT16 and FAT32 file system. Note: routines for file handling (CF_File_Write_Init, CF_File_Write_Byte, CF_File_Write_Complete) can be used only with FAT16 file system, and only with PIC18 family!
Before write operation, make sure you dont 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.
Prototype Description
sub procedure CF_INIT_PORT(dim byref CtrlPort as byte, dim byref DataPort as byte) The procedure initializes ports appropriately: <CtrlPort> is control port, and <DataPort> is data port to which CF is attached. CF_Init_Port(PORTB, PORTD) ' Control port is PORTB, Data port is PORTD
Example
Prototype Description
sub function CF_DETECT(dim byref CtrlPort as byte) as byte The function checks if Compact Flash card is present. Returns true if present, otherwise returns false. <CtrlPort> must be initialized (call CF_INIT_PORT first).
Example
do nop loop until CF_Detect(PORTB) = true ' wait until CF card is inserted
Prototype
sub procedure CF_WRITE_INIT(dim byref CtrlPort as byte, dim byref DataPort as byte, dim Adr as longint, dim SectCnt as byte)
Description
The procedure initializes CF card for writing. Ports need to be initialized. Parameters: CtrlPort - control port, DataPort - data port, k - specifies sector address from where data will be written, SectCnt - parameter is total number of sectors prepared for write.
Example
' Initialize write at sector address 590 ' of 1 sector (512 bytes)
Prototype
sub procedure CF_WRITE_BYTE(dim byref CtrlPort as byte, dim byref DataPort as byte, dim BData as byte)
Description
The procedure writes 1 byte to Compact Flash. The procedure has effect only if CF card is initialized for writing. Parameters: CtrlPort - control port, DataPort - data port, dat - data byte written to CF
Example
' Initialize write at sector address 590 ' of 1 sector (512 bytes)
Prototype
sub procedure CF_WRITE_WORD(dim byref CtrlPort as byte, dim byref DataPort as byte, dim WData as word)
Description
The procedure writes 1 word to Compact Flash. The procedure has effect only if CF card is initialized for writing. Parameters: CtrlPort - control port, DataPort - data port, Wdata - data word written to CF
Example
Prototype
sub procedure CF_READ_INIT(dim byref CtrlPort as byte, dim byref DataPort as byte, dim Adr as longint, dim SectCnt as byte)
Description
Parameters: CtrlPort - control port, DataPort - data port, Adr - specifies sector address from where data will be read, SectCnt - total number of sectors prepared for read operations.
Example
' Initialize write at sector address 590 ' of 1 sector (512 bytes)
Prototype
sub function CF_READ_BYTE(dim byref CtrlPort as byte, dim byref DataPort as byte) as byte
Description
Function reads 1 byte from Compact Flash. Ports need to be initialized, and CF must be initialized for reading. Parameters: CtrlPort - control port, DataPort - data port
Example
Prototype
sub function CF_READ_WORD(dim byref CtrlPort as byte, dim byref DataPort as byte) as word
Description
Function reads 1 word from Compact Flash. Ports need to be initialized, and CF must be initialized for reading. Parameters: CtrlPort - control port, DataPort - data port
Example
5.2.5.9 CF_File_Write_Init Initializes CF card for file writing operation (FAT16 only, PIC18 only)
Prototype
sub procedure CF_File_Write_Init(dim byref CtrlPort as byte, dim byref DataPort as byte)
Description
This procedure initializes CF card for file writing operation (FAT16 only, PIC18 only). Parameters: CtrlPort - control port, DataPort - data port
Example
CF_File_Write_Init(PORTB, PORTD)
5.2.5.10 CF_File_Write_Byte Adds one byte to file (FAT16 only, PIC18 only)
Prototype
sub procedure CF_File_Write_Byte(dim byref CtrlPort as byte, dim byref DataPort as byte,dim Bdata as byte)
Description
This procedure adds one byte (Bdata) to file (FAT16 only, PIC18 only). Parameters: CtrlPort - control port, DataPort - data port, Bdata - data byte to be written.
Example
while i < 50000 CF_File_Write_Byte(PORTB, PORTD, 48 + index) ' demonstration: writes 50000 bytes to file inc(i) wend
5.2.5.11 CF_File_Write_Complete Closes file and makes it readable (FAT16 only, PIC18 only)
Prototype
sub procedure CF_File_Write_Complete(dim byref CtrlPort as byte, dim byref DataPort as byte,dim byref Filename as char[9])
Description
Upon all data has be written to file, use this procedure to close the file and make it readable by Windows (FAT16 only, PIC18 only). Parameters: CtrlPort - control port, DataPort - data port, Filename (must be in uppercase and must have exactly 8 characters).
Example
Ensure minimum 20ms delay between successive use of routines EEPROM_Write and EEPROM_Read. Although EEPROM will write the correct value, EEPROM_Read might return undefined result.
Prototype Description
sub function EEprom_Read(dim Address as byte) as byte Function reads byte from <Address>. <Address> is of byte type, which means it can address only 256 locations. For PIC18 MCU models with more EEPROM data locations, it is programmer's responsibility to set SFR EEADRH register appropriately. Ensure minimum 20ms delay between successive use of routines EEPROM_Write and EEPROM_Read. Although EEPROM will write the correct value, EEPROM_Read might return undefined result.
Example
TRISB = 0 Delay_ms(30) for i = 0 to 20 PORTB = EEPROM_Read(i) for j = 0 to 200 Delay_us(500) next j next i
Prototype
Description
Function writes byte to <Address>. <Address> is of byte type, which means it can address only 256 locations. For PIC18 MCU models with more EEPROM data locations, it is programmer's responsibility to set SFR EEADRH register appropriately. All interrupts will be disabled during execution of EEPROM_Write routine (GIE bit of INTCON register will be cleared). Routine will set this bit on exit Ensure minimum 20ms delay between successive use of routines EEPROM_Write and EEPROM_Read. Although EEPROM will write the correct value, EEPROM_Read might return undefined result.
Example
Prototype
sub function Flash_Read(dim Address as longint) as byte ' for PIC18 sub function Flash_Read(dim Address as word) as word ' for PIC16
Description
Example
for i = 0 to 63 toRead = Flash_Read($0D00 + i) ' read 64 consecutive locations starting from 0x0D00 next i
Prototype
sub procedure Flash_Write(dim Address as longint, dim byref Data as byte[64]) ' for PIC18 sub procedure Flash_Write(dim Address as word, dim Data as word) ' for PIC16
Description
Procedure writes chunk of data to Flash memory (for PIC18, data needs to exactly 64 bytes in size). Keep in mind that this function erases target memory before writing <Data> to it. This means that if write was unsuccessful, your previous data will be lost.
Example
I2C interface is serial interface used for communicating with peripheral or other microcontroller devices. Routines below are intended for PIC MCUs with MSSP module. By using these, you can configure and use PIC MCU as master in I2C communication.
Prototype Description
sub procedure I2C_Init(const Clock as longint) Initializes I2C module. Parameter <Clock> is a desired I2C clock (refer to device data sheet for correct values in respect with Fosc).
Example
I2C_Init(100000)
sub function I2C_Start as byte Determines if I2C bus is free and issues START condition; if there is no error, function returns 0. I2C_Start
Prototype Description
Example
I2C_Repeated_Start
Prototype Description
sub function I2C_Rd(dim Ack as byte) as byte Receives 1 byte from slave and sends not acknowledge signal if <Ack> is 0; otherwise, it sends acknowledge. Data = I2C_Rd(1) ' read data w/ acknowledge
Example
Prototype Description
sub function I2C_Wr(dim Data as byte) as byte After you have issued a start or repeated start you can send <Data> byte via I2C bus. The function returns 0 if there are no errors.
Example
I2C_Wr($A2)
Prototype
Description
Example
I2C_Stop
Prototype Description
sub procedure LCD_Init(dim byref Port as byte) Initializes LCD at <Port> with default pin settings (see the figure below).
Example
LCD_Init(PORTB) ' Initializes LCD on PORTB (check pin settings in the figure below)
Prototype
sub procedure LCD_Config(dim byref Port as byte, const RS, const EN, const WR, const D7, const D6, const D5, const D4)
Description
Initializes LCD at <Port> with pin settings you specify: parameters <RS>, <EN>, <WR>, <D7> .. <D4> need to be a combination of values 0..7 (e.g. 3,6,0,7,2,1,4).
Example
LCD_Config(PORTD, 1, 2, 0, 3, 5, 4, 6) ' Initializes LCD on PORTD with our custom pin settings
Prototype Description
sub procedure LCD_Chr(dim Row as byte, dim Column as byte, dim Character as byte) Prints <Character> at specified <Row> and <Column> on LCD.
Example
LCD_Chr(1, 2, "e") ' Prints character "e" on LCD (1st row, 2nd column)
Prototype Description
sub procedure LCD_Chr_CP(dim Character as byte) Prints <Character> at current cursor position.
Example
Prototype
sub procedure LCD_Out(dim Row as byte, dim Column as byte, dim byref Text as char [255])
Description
Prints <Text> (string variable) at specified <Row> and <Column> on LCD. Both string variables and string constants can be passed.
Example
LCD_Out(1, 3, Text) ' Prints string variable Text on LCD (1st row, 3rd column)
Prototype Description
sub procedure LCD_Out_CP(dim byref Text as char[255]) Prints <Text> (string variable) at current cursor position. Both string variables and string constants can be passed.
Example
Prototype Description
sub procedure LCD_Cmd(dim Command as byte) Sends <Command> to LCD. List of available commands follows: LCD_First_Row ' Moves cursor to 1st row LCD_Second_Row ' Moves cursor to 2nd row LCD_Third_Row ' Moves cursor to 3rd row LCD_Fourth_Row ' Moves cursor to 4th row
LCD_Clear ' Clears display LCD_Return_Home ' Returns cursor to home position, ' returns a shifted display to original position. ' Display data RAM is unaffected. LCD_Cursor_Off ' Turn off cursor LCD_Underline_On ' Underline cursor on LCD_Blink_Cursor_On ' Blink cursor on LCD_Move_Cursor_Left ' Move cursor left without changing display data RAM LCD_Move_Cursor_Right ' Move cursor right without changing display data RAM LCD_Turn_On ' Turn LCD display on LCD_Turn_Off ' Turn LCD display off LCD_Shift_Left ' Shift display left without changing display data RAM LCD_Shift_Right
Example
LCD_Cmd(LCD_Clear)
LCD HW connection
back to the top
Prototype Description
sub procedure LCD8_Init(dim byref Port_Ctrl as byte, dim byref Port_Data as byte) Initializes LCD at <Port_Ctrl> and <Port_Data> with default pin settings (see the figure below).
Example
LCD8_Init(PORTB, PORTC) ' Initializes LCD on PORTB and PORTC with default pin settings ' (check pin settings in the figure below)
Prototype
sub procedure LCD8_Config(dim byref Port_Ctrl as byte, dim byref Port_Data as byte, const RS, const EN, const WR, const D7, const D6, const D5, const D4, const D3, const D2, const D1, const D0)
Description
Initializes LCD at <Port_Ctrl> and <Port_Data> with pin settings you specify: parameters <RS>, <EN>, <WR> need to be in range 0..7; parameters <D7>..<D0> need to be a combination of values 0..7 (e.g. 3,6,5,0,7,2,1,4).
Example
LCD8_Config(PORTC, PORTD, 0, 1, 2, 6, 5, 4, 3, 7, 1, 2, 0) ' Initializes LCD on PORTC and PORTD with our custom pin settings
Prototype Description
sub procedure LCD8_Chr(dim Row as byte, dim Column as byte, dim Character as byte) Prints <Character> at specified <Row> and <Column> on LCD.
Example
LCD8_Chr(1, 2, "e") ' Prints character "e" on LCD (1st row, 2nd column)
Prototype Description
sub procedure LCD8_Chr_CP(dim Character as byte) Prints <Character> at current cursor position.
Example
Prototype
sub procedure LCD8_Out(dim Row as byte, dim Column as byte, dim byref Text as char [255]) Prints <Text> (string variable) at specified <Row> and <Column> on LCD. Both string variables and string constants can be passed.
Description
Example
LCD8_Out(1, 3, Text) ' Prints string variable Text on LCD (1st row, 3rd column)
Prototype Description
sub procedure LCD8_Out_CP(dim byref Text as char[255]) Prints <Text> (string variable) at current cursor position. Both string variables and string constants can be passed.
Example
Prototype Description
sub procedure LCD8_Cmd(dim Command as byte) Sends <Command > to LCD. List of available commands follows: LCD_First_Row ' Moves cursor to 1st row LCD_Second_Row ' Moves cursor to 2nd row
LCD_Third_Row ' Moves cursor to 3rd row LCD_Fourth_Row ' Moves cursor to 4th row LCD_Clear ' Clears display LCD_Return_Home ' Returns cursor to home position, ' returns a shifted display to original position. ' Display data RAM is unaffected. LCD_Cursor_Off ' Turn off cursor LCD_Underline_On ' Underline cursor on LCD_Blink_Cursor_On ' Blink cursor on LCD_Move_Cursor_Left ' Move cursor left without changing display data RAM LCD_Move_Cursor_Right ' Move cursor right without changing display data RAM LCD_Turn_On ' Turn LCD display on LCD_Turn_Off
' Turn LCD display off LCD_Shift_Left ' Shift display left without changing display data RAM LCD_Shift_Right ' Shift display right without changing display data RAM
Example
LCD8_Cmd(LCD_Clear)
LCD HW connection
back to the top
Prototype
sub procedure GLCD_Config(dim byref Ctrl_Port as byte, dim byref Data_Port as byte, dim Reset as byte, dim Enable as byte,dim RS as byte, dim RW as byte, dim CS1 as byte, dim CS2 as byte)
Description
Example
Prototype Description
sub procedure GLCD_Init(dim Ctrl_Port as byte, dim Data_Port as byte) Initializes LCD at <Ctrl_Port> and <Data_Port>. With default pin settings Reset=7, Enable=1, RS=3, RW=5, CS1=2, CS2=0.
Example
GLCD_LCD_Init(PORTB, PORTC)
Prototype Description
sub procedure GLCD_Put_Ins(dim Ins as byte) Sends instruction <Ins> to GLCD. Available instructions include: X_ADRESS = $B8 Y_ADRESS = $40 START_LINE = $C0 DISPLAY_ON = $3F ' Adress base for Page 0 ' Adress base for Y0 ' Adress base for line 0 ' Turn display on
Example
GLCD_Put_Ins(DISPLAY_ON)
Prototype Description
Example
GLCD_Put_Data(temperature)
Prototype
Description
Sends data to GLCD at specified <side> (<side> can take constant value LEFT or RIGHT) .
Example
GLCD_Put_Data2(temperature, 1)
Prototype Description
sub procedure GLCD_Select_Side(dim LCDSide as byte) Selects the side of the GLCD: ' const RIGHT = 0 ' const LEFT = 1
Example
GLCD_Select_Side(1)
Prototype Description
Example
GLCD_Data_Read
Prototype Description
sub procedure GLCD_Clear_Dot(dim x as byte, dim y as byte) Clears a dot on the GLCD at specified coordinates.
Example
GLCD_Clear_Dot(20, 32)
Prototype Description
sub procedure GLCD_Set_Dot(dim x as byte, dim y as byte) Draws a dot on the GLCD at specified coordinates.
Example
GLCD_Set_Dot(20, 32)
Prototype
sub procedure GLCD_Circle(dim CenterX as integer, dim CenterY as integer, dim Radius as integer)
Description
Example
GLCD_Circle(30, 42, 6)
Prototype
sub procedure GLCD_Line(dim x1 as integer, dim y1 as integer, dim x2 as integer, dim y2 as integer)
Description
Example
Prototype Description
sub procedure GLCD_Invert(dim Xaxis as byte, dim Yaxis as byte) Procedure inverts display (changes dot state on/off) in the specified area, X pixels wide starting from 0 position, 8 pixels high. Parameter Xaxis spans 0..127, parameter Yaxis spans 0..7 (8 text lines).
Example
GLCD_Invert(60, 6)
Prototype
Description
Sets cursor to dot (x,y). Procedure is used in combination with GLCD_Put_Data, GLCD_Put_Data2, and GLCD_Put_Char.
Example
GLCD_Goto_XY(60, 6)
Prototype Description
Example
GLCD_Put_Char(k)
Prototype Description
Example
GLCD_Clear_Screen
Prototype
sub procedure GLCD_Put_Text(dim x_pos as word, dim y_pos as word, dim byref text as char[25], dim invert as byte)
Description
Example
Prototype
sub procedure GLCD_Rectangle(dim X1 as byte, dim Y1 as byte, dim X2 as byte, dim Y2 as byte)
Description
Draws a rectangle on the GLCD. (x1,y1) sets the upper left corner, (x2,y2) sets the lower right corner.
Example
Prototype
Description
Sets font for GLCD. Parameter <font_index> spans from 1 to 4, and determines which font will be used: 1: 5x8 dots 2: 5x7 3: 3x6 4: 8x8
Example
GLCD_Set_Font(2)
Note: Manchester receive routines are blocking calls (Man_Receive_Config, Man_Receive_Init, Man_Receive). This means that PIC will wait until the task is performed (e.g. byte is received, synchronization achieved, etc). Note: Routines for receiving are limited to a baud rate scope from 340 ~ 560 bps.
Prototype Description
sub procedure Man_Receive_Init(dim byref Port as byte) Procedure works same as Man_Receive_Config, but with default pin setting (pin 6).
Example
Man_Receive_Init(PORTD)
Prototype Description
sub procedure Man_Receive_Config(dim byref Port as byte, dim RXpin as byte) This procedure needs to be called in order to receive signal by procedure Man_Receive. You need to specify the <Port> and <RXpin> of input signal. In case of multiple errors on reception, you should call Man_Receive_Init once again to enable synchronization.
Example
Man_Receive_Config(PORTD, 5)
Prototype Description
sub function Man_Receive(dim byref Error as byte) as byte Function extracts one byte from signal. If format does not match the expected, <Error> flag will be set True.
Example
Prototype Description
sub procedure Man_Send_Init(dim byref Port as byte) Procedure works same as Man_Send_Config, but with default pin setting (pin 0).
Example
Man_Send_Init(PORTB)
Prototype Description
sub procedure Man_Send_Config(dim byref Port as byte, dim TXpin as byte) Procedure needs to be called in order to send signals via procedure Man_Send. Procedure specifies <Port> and <TXpin> for outgoing signal (const baud rate).
Example
Man_Send_Config(PORTB, 4)
Prototype Description
sub procedure Man_Send(dim Data as byte) Procedure sends one <Data> byte.
Example
Prototype
Description
Initializes PWM module with (duty ratio) 0%. <PWM_Freq> is a desired PWM frequency (refer to device data sheet for correct values in respect with Fosc).
Example
PWM_Init(5000)
Prototype Description
sub procedure PWM_Change_Duty(dim New_Duty as byte) Routine changes duty ratio. <New_Duty> takes values from 0 to 255, where 0 is 0% duty ratio, 127 is 50% duty ratio, and 255 is 100% duty ratio. Other values for specific duty ratio can be calculated as (Percent*255)/100.
Example
Prototype Description
Example
PWM_Start
Prototype Description
Example
PWM_Stop
PWM demonstration
back to the top
Note: Address 50 is a common address for all Slave devices: packets containing address 50 will be received by all Slaves. The only exceptions are Slaves with addresses 150 and 169, which require their particular address to be specified in the packet.
Prototype Description
sub procedure RS485master_init Initializes MCU as Master in RS485 communication. USART needs to be initialized.
Example
RS485Master_Init
Prototype Description
sub procedure RS485master_read(dim byref data as byte[5]) Master receives any message sent by Slaves. As messages are multi-byte, this procedure must be called for each byte received (see the example at the end of the chapter). Upon receiving a message, buffer is filled with the following values:
q q q q q
data[0..2] is actual data data[3] is number of bytes received, 1..3 data[4] is set to 255 when message is received data[5] is set to 255 if error has occurred data[6] is the address of the Slave which sent the message
Procedure automatically sets data[4] and data[5] upon every received message. These flags need to be cleared repeatedly from the program. Note: MCU must be initialized as Master in 485 communication to assign an address to MCU
Example
RS485Master_Read(dat)
Prototype
sub procedure RS485Master_Write(dim byref data as byte[2], dim datalen as byte, dim address as byte)
Description
Routine sends number of bytes (1 < datalen <= 3) from buffer via 485, to slave specified by <address>. MCU must be initialized as Master in 485 communication. It is programmer's responsibility to ensure (by protocol) that only one device sends data via 485 bus at a time.
Example
RS485Master_Write(dat, 1)
Prototype Description
sub procedure RS485Slave_Init(dim address as byte) Initializes MCU as Slave in RS485 communication. USART needs to be initialized. <address> can take any value between 0 and 255, except 50, which is common address for all slaves.
Example
RS485Slave_Init(160)
Prototype Description
sub procedure RS485Slave_Read(dim byref data as byte[5]) Only messages that appropriately address Slaves will be received. As messages are multi-byte, this procedure must be called for each byte received (see the example at the end of the chapter). Upon receiving a message, buffer is filled with the following values:
q q q q q
data[0..2] is actual data data[3] is number of bytes received, 1..3 data[4] is set to 255 when message is received data[5] is set to 255 if error has occurred rest of the buffer is undefined
Procedure automatically sets data[4] and data[5] upon every received message. These flags need to be cleared repeatedly from the program. MCU must be initialized as Master in 485 communication to assign an address to MCU.
Example
RS485Slave_Read(dat)
Prototype
Description
Sends number of bytes (1 < datalen <= 3) from buffer via 485 to Master. MCU must be initialized as Slave in 485 communication. It is programmer's responsibility to ensure (by protocol) that only one device sends data via 485 bus at a time.
Example
RS485Slave_Write(dat, 1)
Prototype Description
Master mode, clock Fosc/4, clock idle state low, data transmitted on low to high edge, input data sampled at the middle of interval.
Example
SPI_Init
Prototype
sub procedure SPI_Init_Advanced(dim Master as byte, dim Data_Sample as byte, dim Clock_Idle as byte, dim Low_To_High as byte)
Description
For advanced settings, configure and initialize SPI using the procedure SPI_Init_Advanced. Allowed values of parameters: <Master> determines the work mode for SPI:
q q q q q q
Master_OSC_div4 : Master clock=Fosc/4 Master_OSC_div16 : Master clock=Fosc/16 Master_OSC_div64 : Master clock=Fosc/64 Master_TMR2 : Master clock source TMR2 Slave_SS_ENABLE : Master Slave select enabled Slave_SS_DIS : Master Slave select disabled
Data_SAMPLE_MIDDLE : input data sampled in middle of interval Data_SAMPLE_END : input data sampled at the end of interval
LOW_2_HIGH : data transmit on low to high edge HIGH_2_LOW : data transmit on high to low edge
Example
SPI_Init_Advanced(Master_OSC_div4, Data_SAMPLE_MIDDLE, CLK_Idle_LOW,LOW_2_HIGH) ' This will set SPI to: ' master mode, ' clock = Fosc/4, ' data sampled at the middle of interval, ' clock idle state low, ' data transmitted at low to high edge.
Prototype Description
sub function SPI_Read(dim Buffer as byte) as byte Routine provides clock by sending <Buffer> and reads the received data at the end of the period.
Example
Prototype Description
sub procedure SPI_Write(dim Data as byte) Routine writes <Data> to SSPBUF and immediately starts the transmission.
Example
SPI_Write(7)
Prototype Description
sub procedure USART_Init(const Baud_Rate) Initializes PIC MCU USART hardware and establishes communication at specified <Baud_Rate>. Refer to the device data sheet for baud rates allowed for specific Fosc. If you specify the unsupported baud rate, compiler will report an error.
Example
USART_Init(2400)
Prototype Description
sub function USART_Data_Ready as byte Function checks if data is ready. Returns 1 if so, returns 0 otherwise.
Example
USART_Data_Ready
Prototype Description
sub function USART_Read as byte Receives a byte; if byte is not received returns 0.
Example
USART_Read
Prototype Description
Example
USART_Write(dat)
RS232 HW connection
back to the top
Prototype
sub function OW_Reset(dim byref PORT as byte, dim Pin as byte) as byte
Description
Issues 1-wire reset signal for DS1820. Parameters <PORT> and <Pin> specify the location of DS1820; return value of the function is 0 if DS1820 is present, and 1 otherwise.
Example
OW_Reset(PORTA, 5)
Prototype Description
sub function OW_Read(dim byref PORT as byte, Pin as byte) as byte Reads one byte via 1-wire bus.
Example
temp = OW_Read(PORTA, 5)
Prototype Description
sub procedure OW_Write(dim byref PORT as byte, dim Pin as byte, dim par as byte) Writes one byte (<par>) via 1-wire bus
Example
OW_Write(PORTA, 5, $44)
Prototype Description
sub procedure Soft_I2C_Config(dim byref Port as byte, const SDA,const SCL) Configure the I2C master mode. Parameter <Port> specifies port of MCU on which SDA and SCL pins will be located; parameters <SCL> and <SDA> need to be in range 0..7 and cannot point at the same pin;
Example
Soft_I2C_Config(PORTD, 3, 4)
Prototype Description
Example
Soft_I2C_Start
Prototype Description
sub function Soft_I2C_Write(dim Data as byte) as byte After you have issued a start signal you can send <Data> byte via I2C bus. The function returns 0 if there are no errors.
Example
Soft_I2C_Write($A3)
Prototype Description
sub function Soft_I2C_Read(dim Ack as byte) as byte Receives 1 byte from slave and sends not acknowledge signal if <Ack> is 0; otherwise, it sends acknowledge.
Example
EE_data = Soft_I2C_Read(0)
Prototype Description
Example
Soft_I2C_Stop
Prototype
sub procedure Soft_SPI_Config(dim byref Port as byte, const SDI, const SD0, const SCK)
Description
Routine configures and initializes software SPI with the following defaults:
q q q q q
Set MCU to master mode, Clock = 50kHz, Data sampled at the middle of interval, Clock idle state low Data transmitted at low to high edge.
SDI pin, SDO pin, and SCK pin are specified by the appropriate parameters.
Example
Soft_SPI_Config(PORTB, 1, 2, 3) ' SDI pin is RB1, SDO pin is RB2, and SCK pin is RB3.
Prototype Description
sub function Soft_SPI_read(dim Buffer as byte) as byte Routine provides clock by sending <Buffer> and reads the received data at the end of the period.
Example
Soft_SPI_Read(dat)
Prototype Description
sub procedure Soft_SPI_Write(dim Data as byte) Routine writes <Data> to SSPBUF and immediately starts the transmission.
Example
Soft_SPI_Write(dat)
Prototype
sub procedure Soft_UART_Init(dim byref Port as byte, const RX, const TX, const Baud_Rate)
Description
Initializes PIC MCU UART at specified pins establishes communication at <Baud_Rate>. If you specify the unsupported baud rate, compiler will report an error.
Example
Soft_UART_Init(PORTB, 1, 2, 9600)
Prototype Description
sub function Soft_UART_Read(dim byref Msg_received as byte) as byte Function returns a received byte. Parameter <Msg_received> will take true if transfer was succesful. Soft_UART_Read is a non-blocking function call, so you should test <Msg_received> manually (check the example below).
Example
Received_byte = Soft_UART_Read(Rec_ok)
Prototype Description
Example
Soft_UART_Write(Received_byte)
Prototype Description
sub procedure Sound_Init(dim byref Port, dim Pin as byte) Procedure Sound_Init initializes sound engine and prepares it for output at specified <Port> and <Pin>. Parameter <Pin> needs to be within range 0..7.
Example
PORTB TRISB
= 0 = 0
' Clear PORTB ' PORTB is output ' Initialize sound on PORTB.RB2
Sound_Init(PORTB, 2)
Prototype
Description
Procedure Sound_Play plays the sound at the specified port pin. <Period_div_10> is a sound period given in MCU cycles divided by ten, and generated sound lasts for a specified number of periods (<Num_of_Periods>). For example, if you want to play sound of 1KHz: T = 1/f = 1ms = 1000 cycles @ 4MHz<.code>. This gives us our first parameter: 1000/10 = 100. Then, we could play 150 periods like this: Sound_Play(100, 150).
Example
... Sound_Init(PORTB,2) while true adcValue = ADC_Read(2) Sound_Play(adcValue, 200) wend ' Get lower byte from ADC ' Play the sound ' Initialize sound on PORTB.RB2
Prototype
Description
Function takes a word-type number which represents angle in degrees and returns the sine of <Angle> as integer, multiplied by 1000 (1E3) and rounded up to nearest integer: result = round_up(sin(Angle)*1000). Thus, the range of the return values for these functions is from 1000 to 1000. Note that parameter <Angle> cannot be negative. Function is implemented as lookup table, and the maximum error obtained is 1.
Example
dim angle
as word
result = sinE3(angle)
Prototype Description
sub function cosE3(dim Angle as word) as integer Function takes a word-type number which represents angle in degrees and returns the cosine of <Angle> as integer, multiplied by 1000 (1E3) and rounded up to nearest integer: result = round_up(cos(Angle)*1000). Thus, the range of the return values for these functions is from 1000 to 1000. Note that parameter <Angle> cannot be negative. Function is implemented as lookup table, and the maximum error obtained is 1.
Example
dim angle
as word
result = cosE3(angle)
5.2.23 Utilities
BASIC provides a utility set of procedures and functions for faster development of your applications.
Prototype
sub function Button(dim byref PORT as byte, dim Pin as byte, dim Time as byte, dim Astate as byte) as byte
Description
Function eliminates the influence of contact flickering due to the pressing of a button (debouncing). Parameters <PORT> and <Pin> specify the location of the button; parameter <Time> represents the minimum time interval that pin must be in active state in order to return one; parameter <Astate> can be only zero or one, and it specifies if button is active on logical zero or logical one.
Example
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Introduction 6.1 Interrupt Mechanism 6.2 Internal AD Converter 6.3 TMR0 Timer 6.4 TMR1 Timer 6.5 PWM Module 6.6 Hardware UART module (RS-232 Communication)
Introduction
It is commonly said that microcontroller is an entire computer on a single chip, which implies that it has more to offer than a single CPU (microprocessor). This additional functionality is actually located in microcontrollers subsystems, also called the integrated peripherals. These (sub)devices basically have two major roles: they expand the possibilities of the MCU making it more versatile, and they take off the burden for some repetitive and dumber tasks (mainly communication) from the CPU. Every microcontroller is supplied with at least a couple of integrated peripherals commonly, these include timers, interrupt mechanisms and AD converters. More powerful microcontrollers can command a larger number of more diverse peripherals. In this chapter, we will cover some common systems and the ways to utilize them from BASIC programming language.
Here is a simple example: In the main loop, program keeps LED_run diode on and LED_int diode off. Pressing the button T causes the interrupt microcontroller stops
program testinterrupt symbol LED_run = PORTB.7 symbol LED_int = PORTB.6 ' LED_run is connected to PORTB pin 7 ' LED_int is connected to PORTB pin 6
sub procedure interrupt if INTCON.RBIF = 1 then INTCON.RBIF = 0 else if INTCON.INTF = 1 then LED_run = 0 LED_int = 1 Delay_ms(500) INTCON.INTF = 0 else if INTCON.T0IF = 1 then INTCON.T0IF = 0 else if INTCON.EEIF = 1 then INTCON.EEIF = 0 end if end if end if end if end sub
main: TRISB = %00111111 OPTION_REG = %10000000 ' Pins RB6 and RB7 are output ' Turn off pull-up resistors
' ' INTCON = %10010000 PORTB = 0 eloop: LED_run = 1 LED_int = 0 goto eloop end.
' Enable external interrupts ' Initial value on PORTB ' While there is no interrupt, program runs in endless loop: ' ' LED_run is on LED_int is off
Now, what happens when we push the button? Our interrupt routine first analyzes the interrupt by checking flag bits with couple of if.. then instructions, because there are several possible interrupt causes. In our case, an external interrupt took place (pin RB0/INT state changes) and therefore bit INTF in INTCON register is set. Microcontroller will change LED states, and provide a half second delay for us to actually see the change. Then it will clear INTF bit in order to enable interrupts again, and return to executing the main program. In situations where microcontroller must respond to events unrelated to the main program, it is very useful to have an interrupt service routine. Perhaps, one of the best examples is multiplexing the seven-segment display if multiplexing code is tied to timer interrupt, main program will be much less burdened because display refreshes in the background.
back to the top
Potentiometer gives 0V in one terminal position and 5V in the other since we use 8-bit conversion, our digitalized voltage can have 256 steps. The following program reads voltage on RA0 pin and displays it on port B diodes. If not one diode is on, result is zero and if all of
program ADC_8 main: TRISA = %111111 PORTD = 0 TRISD = %00000000 ADCON1 = %1000010 ' Port A is in analog mode, ' ' ' ADCON0 = %11010001 0 and 5V are referent voltage values, and the result is aligned right (higher 6 bits of ADRESH are zero). ' Port A is input
' ADC clock is generated by internal RC ' ' circuit; voltage is measured on RA2 and allows the use of AD converter
' wait for ADC to finish Delay_ms(5) if ADCON0.2 = 1 then goto wait end if PORTD = ADRESH Delay_ms(500) goto eloop end. ' Set lower 8 bits on port D ' 500 ms pause ' Repeat all ' End of program.
First, we need to properly initialize registers ADCON1 and ADCON0. After that, we set ADCON0.2 bit which initializes the conversion and then check ADCON0.2 to determine if conversion is over. If over, the result is stored into ADRESH and ADRESL where from it can be copied. Former example could also be carried out via ADC_Read instruction. Our following example uses 10-bit resolution:
main: TRISA TRISD = %11111111 = %00000000 ' PORTA is input ' PORTD is output ' PORTA is in analog mode, ' ' eloop: AD_Res = ADC_read(2) ' Execute conversion and store result ' PORTD = Lo(AD_Res) Delay_ms(500) goto eloop end. in variable AD_Res. 0 and 5V are referent voltage values, and the result is aligned right
ADCON1 = %1000010
' Display lower byte of result on PORTD ' 500 ms pause ' Repeat all ' End of program
As one port is insufficient, we can use LCD for displaying all 10 bits of result. Connection scheme is below and the appropriate program follows. For more information on LCD routines, check Chapter 5.2: Library Routines.
program ADC_on_LCD dim AD_Res as word dim dummyCh as char[6] main: TRISA TRISB = %1111111 = 0 ' PORTA is input ' PORTB is output (for LCD)
ADCON1 = %10000010
' PORTA is in analog mode, ' ' 0 and 5V are referent voltage values, and the result is aligned right.
' Initialize LCD ' Clear LCD ' and turn the cursor off
LCD_Out(1, 1, "
")
WordToStr(AD_Res, dummyCh) ' Convert the result in text, LCD_Out(1, 1, dummyCh) Delay_ms(500) goto eloop end. ' and print it in line 1, char 1
sub procedure interrupt cnt = cnt + 1 TMR0 = 96 INTCON = $20 end sub main: a = 0 b = 1 OPTION_REG = $84 TRISB PORTB cnt = TMR0 = 0 ' Assign prescaler to TMR0 ' PORTB as output ' Initialize PORTB ' Initialize cnt 96 ' Enable TMRO interrupt ' Increment value of cnt on every interrupt ' Set T0IE, clear T0IF
= $FF 0 =
INTCON = $A0
' If cnt is 200, then toggle PORTB LEDs and reset cnt do if cnt = 200 then PORTB = not(PORTB) cnt = 0 end if loop until 0 = 1 end.
Prescaler is set to 32, so that internal clock is divided by 32 and TMR0 increments every 31 microseconds. If TMR0 is initialized at 96, overflow occurs in (256-96)*31 us = 5 ms. We increase cnt every time interrupt takes place, effectively measuring time according to the
value of this variable. When cnt reaches 200, time will total 200*5 ms = 1 second.
back to the top
program Timer1_10sec dim cnt as byte sub procedure interrupt cnt = cnt + 1 pir1.0 = 0 end sub main: TRISB = 0 T1CON = 1 PIR1.TMR1IF = 0 PIE1 = 1 PORTB = $F0 cnt = 0 ' Clear TMR1IF ' Enable interrupts ' Initialize cnt ' Clear TMR1IF
INTCON = $C0 ' If cnt is 152, then toggle PORTB LEDs and reset cnt do if cnt = 152 then PORTB = not(PORTB) cnt = 0 end if loop until 0 = 1 end.
Prescaler is set to 00 so there is no dividing the internal clock and overflow occurs every 65.536 ms. We increase cnt every time interrupt takes place, effectively measuring time according to the value of this variable. When cnt reaches 152, time will total 152*65.536 ms = 9.96 seconds.
back to the top
TRISB = 0 PORTB = 0 j = 0 TRISC = 0 PORTC = $FF PWM_Init(5000) PWM_Start while true Delay_ms(10) j = j + 1 PWM_Change_Duty(j) PORTB = wend end. CCPR1L
' PORTB is output ' Set PORTB to 0 ' PORTC is output ' Set PORTC to $FF ' Initialize PWM module ' Start PWM ' Endless loop ' Wait 10ms ' Increment j ' Set new duty ratio ' Send value of CCPR1L to PORTB
Our following program example illustrates use of hardware serial communication. Data received from PC is stored into variable dat and sent back to PC as confirmation of successful transfer. Thus, it is easy to check if communication works properly. Transfer format is 8N1 and transfer rate is 2400 baud.
main: USART_Init(2400) while true if USART_Data_Ready = 1 then dat = USART_Read USART_Write(dat) end if wend end. ' If data is received ' Read the received data ' Send data via USART ' Initialize USART module
In order to establish the communication, PC must have a communication software installed. One such communication terminal is part of mikroBasic IDE. It can be accessed by clicking Tools > Terminal from the drop-down menu. Terminal allows you to monitor transfer and to set all the necessary transfer settings. First of all, we need to set the transfer rate to 2400 to match the microcontroller's rate. Then, select the appropriate communication port by clicking one of the 4 available (check where you plugged the serial cable). After making these adjustments, clicking Connect starts the communication. Type your message and click Send Message message will be sent to the microcontroller and back, where it will be displayed on the screen. Note that serial communication can also be software based on any of 2 microcontroller pins for more information, check the Chapter 9: Communications.
back to the top Previous Chapter | Table of Contents | Next Chapter
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Introduction 7.1 LED Diode 7.2 Seven-Segment Display 7.3 LCD Display, 4-bit and 8-bit Interface 7.4 Graphical LCD 7.5 Sound Signalization
Introduction
Microcontrollers deal very well with 0s and 1s, but humans do not. We need indicator lights, numbers, letters, charts, beepers In order to comprehend the information presented quicker and better, we need that information to be displayed to us in many different ways. In practice, human - machine communication can require substantial (machine) resources, so it is sometimes better to dedicate an entire microcontroller to that task. This device is then called the Human - Machine Interface or simply HMI. The second microcontroller is then required to get the human wishes from HMI, do the job and put the results back to HMI, so that operator can see it. Clearly, the most important form of communication between the microcontroller system and a man is the visual communication. In this chapter we will discuss various ways of displaying data, from the simplest to more elaborate ones. Youll see how to use LED diodes, Seven-Segment Displays, character- and graphic LCDs. We will also consider using BASIC for sound signalization necessary in certain
applications. Just remember: the more profound communication you wish to be, the more MCU resources itll take.
The positive pole is connected to anode, while ground is connected to cathode. For matter of differentiating the two, cathode is marked by mark on casing and shorter pin. Diode will emit light only if current flows from anode to cathode; in the other case there will be no current. Resistor is added serial to LED diode, limiting the maximal current through diode and protecting it from damage. Resistor value can be calculated from the equation on the picture above, where Ur represents voltage on resistor. For +5V power supply and 10 mA current resistor used should have value of 330. LED diode can be connected to microcontroller in two ways. One way is to have microcontroller "turning on" LED diode with logical one and the other way is with logical zero. The first way is not so frequent (which doesn't mean it doesn't have applications) because it requires the
microcontroller to be diode current source. The second way works with higher current LED diodes.
program LED_Blinking main: TRISB = 0 PORTB = %11111111 Delay_ms(1000) PORTB = %00000000 Delay_ms(1000) goto main ' PORTB is output ' Turn ON diodes on PORTB ' Wait for 1 second ' Turn OFF diodes on PORTB ' Wait for 1 second ' Endless loop
end.
As seven-segment digits have better temperature tolerance and visibility than LCD displays, they are very common in industrial applications. Their use satisfies all criteria including the financial one. They are commonly used for displaying value read from sensors, etc. One of the ways to connect seven-segment display to the microcontroller is given in the figure below. System is connected to use sevensegment digits with common cathode. This means that segments emit light when logical one is brought to them, and that output of all segments must be a transistor connected to common cathode, as shown on the picture. If transistor is in conducting mode any segment with logical one will emit light, and if not no segment will emit light, regardless of its pin state.
Bases of transistors T1 and T2 are connected to pin0 and pin1 of PORTA. Setting those pins turns on the transistor, allowing every segment from "a" to "h", with logical one on it, to emit light. If zero is on transistor base, none of the segments will emit light, regardless of the pin state. Using the previous scheme, we could display a sequence of nine digits like this:
program seven_seg_onedigit
dim i as byte ' Function mask returns mask of parameter 'num' ' for common cathode 7-seg. display sub function mask(dim num as byte) as byte select case num case 0 case 1 case 2 case 3 case 4 case 5 case 6 case 7 case 8 case 9 end select end sub main: INTCON TRISA TRISB PORTB PORTA do for i = 0 to 9 PORTB = mask(i) Delay_ms(1000) next i ' Endless loop loop until false end. = = = = = 0 0 0 0 2 ' Disable PEIE, INTE, RBIE, T0IE result = $3F result = $06 result = $5B result = $4F result = $66 result = $6D result = $7D result = $07 result = $7F result = $6F
Purpose of the program is to display numbers 0 to 9 on the ones digit, with 1 second delay. In order to display a number, its mask must be sent to PORTB. For example, if we need to display "1", segments b and c must be set to 1 and the rest must be zero. If (according to the scheme above) segments b and c are connected to the first and the second pin of PORTB, values 0000 and 0110 should be set to PORTB. Thus, mask for number "1" is value 0000 0110 or 06 hexadecimal. The following table contains corresponding mask values for numbers 0-9:
Digit 0 1 2 3 4 5 6 7 8 9
Seg. h 0 0 0 0 0 0 0 0 0 0
Seg. g 0 0 1 1 1 1 1 0 1 1
Seg. f 1 0 0 0 1 1 1 0 1 1
Seg. e 1 0 1 0 0 0 1 0 1 0
Seg. d 1 0 1 1 0 1 1 0 1 1
Seg. c 1 1 0 1 1 1 1 1 1 1
Seg. b 1 1 1 1 1 0 0 1 1 1
Seg. a 1 0 1 1 0 1 1 1 1 1
HEX $3F $06 $5B $4F $66 $6D $7D $07 $7F $6F
You are not, however, limited to displaying digits. You can use 7seg Display Decoder, a built-in tool of mikroBasic, to get hex code of any other viable combination of segments you would like to display. But what do we do when we need to display more than one digit on two or more displays? We have to put a mask on one digit quickly enough and activate its transistor, then put the second mask and activate the second transistor (of course, if one of the transistors is in conducting mode, the other should not work because both digits will display the same value). The process is known as multiplexing: digits are displayed in a way that human eye gets impression of simultaneous display of both digits actually only one display emits at any given moment.
Now, lets say we need to display number 38. First, the number should be separated into tens and ones (in this case, digits 3 and 8) and their masks sent to PORTB. The rest of the program is very similar to the last example, except for having one transition caused by displaying one digit after another:
sub procedure interrupt begin if v = 0 then PORTB = por2 PORTA = 1 v = 1 else PORTB = por1 PORTA = 2 v = 0 end if TMR0 = 0 INTCON = $20 end sub main: OPTION_REG = $80 TRISA TRISB PORTB PORTA TMR0 por1 por2 = = = = = 0 0 0 0 0 ' Pull-up resistors ' PORTA is output ' PORTB is output ' Clear PORTB (make sure LEDs are off) ' Clear PORTA (make sure both displays are off) ' Clear TMRO ' Mask for '8' (check the table above) ' Mask for '3' (check the table above) ' Clear TMRO ' Clear TMR0IF and set TMR0IE ' Send mask of ones to PORTB ' Turn on 2nd 7seg, turn off 1st ' Send mask of tens to PORTB ' Turn on 1st 7seg, turn off 2nd
= $7F = $4F
= $A0
The multiplexing problem is solved for now, but your program probably doesnt have a sole purpose of printing constant values on 7seg display. It is usually just a subroutine for displaying certain information. However, this approach to printing data on display has proven sto be very convenient for more complicated programs. You can also move part of the program for refreshing the digits (handling the masks) to the interrupt routine. The following example increases variable i from 0 to 99 and prints it on displays. After reaching 99, counter begins anew.
program seven_seg_counting dim dim dim dim dim i j v as byte as byte as byte
' This function returns masks ' for common cathode 7-seg display sub function mask(dim num as byte) as byte select case num case 0 case 1 case 2 case 3 case 4 result = $3F result = $06 result = $5B result = $4F result = $66
result = $6D result = $7D result = $07 result = $7F result = $6F
end select end sub sub procedure interrupt if v = 0 then PORTB = por2 PORTA = 1 v = 1 else PORTB = por1 PORTA = 2 v = 0 end if TMR0 = 0 INTCON = $20 end sub main: OPTION_REG por2 j TMR0 INTCON TRISA TRISB PORTB PORTA do for i = 0 to 99 ' Count from 0 to 99 = $80 = $3F = 0 = 0 = $A0 = 0 = 0 = = 0 0 ' Disable PEIE, INTE, RBIE, T0IE ' Prepare mask for digit ' Turn on 2nd, turn off 1st 7seg ' Prepare mask for digit ' Turn on 1st, turn off 2nd 7seg
' Prepare ones digit j = i mod 10 por1 = mask(j) ' Prepare tens digit j = (i div 10) mod 10 por2 = mask(j) Delay_ms(1000) next i loop until false end.
In the course of the main program, programmer doesnt need to worry of refreshing the display. Just call the subroutine mask every time display needs to change.
back to the top
LCD connects to microcontroller via 4-bit or 8-bit bus (4 or 8 lines). R/W signal is on the ground, because communication is one-way (toward LCD). Some displays have built-in backlight that can be turned on with RD1 pin via PNP transistor BC557. Our following example prints text on LCD via 4-bit interface. Assumed pin configuration is default.
' PORTB is output ' Initialize LCD at PORTB ' Turn off cursor ' Print text at LCD
Our second example prints text on LCD via 8-bit interface, with custom pin configuration.
program LCD8_test dim Text as char[20] main: TRISB = 0 TRISD = 0 ' PORTB is output ' PORTD is output
' Initialize LCD at PORTB and PORTD with custom pin settings LCD8_Config(PORTB,PORTD,2,3,0,7,6,5,4,3,2,1,0) LCD8_Cmd(LCD_CURSOR_OFF) Text = "mikroElektronika" LCD8_Out(1, 1, Text) end. ' Turn off cursor ' Print text at LCD
The following figure shows GLCD HW connection by default initialization (using GLCD_LCD_Init routine); if you need different pin settings, refer to GLCD_LCD_Config.
BASIC offers a comprehensive library for GLCD refer to Chapter 5: Built-in and Library Routines for more information. Our following example demonstrates the possibilities of GLCD and the mentioned library. Note that the library works with PIC18 only.
main: PORTC PORTB PORTD TRISC TRISD TRISB = = = = = = 0 0 0 0 0 0 ' default settings
' Draw Circles GLCD_Clear_Screen text = "Circle" GLCD_Put_Text(0, 7, text, NONINVERTED_TEXT) GLCD_Circle(63,31,10) Delay_Ms(4000) ' Draw Rectangles GLCD_Clear_Screen text = "Rectangle" GLCD_Put_Text(0, 7, text, NONINVERTED_TEXT)
GLCD_Clear_Screen ' Draw Lines GLCD_Clear_Screen text = "Line" GLCD_Put_Text(55, 7, text, NONINVERTED_TEXT) GLCD_Line(0, 0, 127, 50) GLCD_Line(0,63, 50, 0) Delay_Ms(5000) ' Fonts Demo GLCD_Clear_Screen text = "Fonts DEMO" GLCD_Set_Font(FONT_TINY) GLCD_Put_Text(0, 4, text, GLCD_Put_Text(0, 5, text, GLCD_Set_Font(FONT_BIG) GLCD_Put_Text(0, 6, text, GLCD_Put_Text(0, 7, text, Delay_ms(5000) wend end.
program Sound ' The following three tones are calculated for 4MHz crystal sub procedure Tone1 Sound_Play(200, 200) end sub sub procedure Tone2 Sound_Play(180, 200) end sub sub procedure Tone3 Sound_Play(160, 200) end sub sub procedure Melody Tone1 Tone2 Tone3 Tone3 Tone1 Tone2 Tone3 Tone3 Tone1 Tone2 Tone3 Tone1 Tone2 Tone3 Tone3 ' Plays the melody "Yellow house" ' Period = 1.6ms <=> 625Hz ' Period = 1.8ms <=> 555Hz ' Period = 2ms <=> 500Hz, Duration = 200 periods
Tone1 Tone2 Tone3 Tone3 Tone3 Tone2 Tone1 end sub main: TRISB = $F0 Sound_Init(PORTB, 2) Sound_Play(50, 100) while true if Button(PORTB,7,1,1) then Tone1 end if while TestBit(PORTB,7) = 1 nop wend if Button(PORTB,6,1,1) then Tone2 end if while TestBit(PORTB,6) = 1 nop wend if Button(PORTB,5,1,1) then Tone3 end if while TestBit(PORTB,5) = 1 nop wend ' Wait for button to be released ' RB5 plays Tone3 ' Wait for button to be released ' RB6 plays Tone2 ' Wait for button to be released ' RB7 plays Tone1 ' Connect speaker on pins RB2 and GND
if Button(PORTB,4,1,1) then Melody end if while TestBit(PORTB,4) = 1 nop wend wend end.
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
q
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Introduction 8.1 EEPROM Memory 8.2 Flash Memory 8.3 Compact Flash
Introduction
There is no program on this world that doesnt interact with memory in some way. First, during its execution, it retains the operational data from, uses or alters it, and puts it back into the program memory. Second, it is often necessary to store and handle large amount of data that can be obtained from various sources, whether it is the car engine temperature acquisition data or some bitmap image to be displayed on the GLCD. In this chapter we will focus on the latter problem, i.e. well go through the techniques of manipulating data on the so-called memory storage devices and systems.
In our following example, we will write a sequence of numbers to successive locations in EEPROM. Afterwards, well read these and output to PORTB to verify the process.
program EEPROM_test dim i as byte dim j as byte main: TRISB = 0 for i = 0 to 20 EEPROM_Write(i, i + 6) next i Delay_ms(30) for i = 0 to 20 PORTB = EEPROM_Read(i) for j = 0 to 200 Delay_us(500) next j next i end.
Serial EEPROM connects to microcontroller via SCL and SDA lines. SCL line is a clock for synchronizing the transfer via SDA line, with frequency going up to 1MHz.
I2C communication allows connecting multiple devices on a single line. Therefore, bits A1 and A0 have an option of assigning addresses to certain I2C devices by connecting the pins A1 and A0 to the ground and +5V (one I2C line could be EEPROM on address $A2 and, say, real time clock PCF8583 on address $A0). R/W bit of address byte selects the operation of reading or writing data to memory. More detailed data on I2C communication can be found in the technical documentation of any I2C device. Our following program sends data to EEPROM at address 2. To verify transfer, well read data via I2C from EEPROM and send its value to PORTD. For more information on I2C Library consult Chapter 5: Built-in and Library Routines.
program EEPROM_test dim EE_adr as byte dim EE_data as byte dim jj as word main: I2C_init(100000) TRISD = 0 PORTD = $ff I2C_Start I2C_Wr($a2) EE_adr = 2 ' Initialize full master mode ' PORTD is output ' Initialize PORTD ' Issue I2C start signal ' Send byte via I2C(command to 24cO2)
I2C_Wr(EE_adr) EE_data = $aa I2C_Wr(EE_data) I2C_Stop for jj = 0 to 65500 nop next jj I2C_Start I2C_Wr($a2) EE_adr = 2 I2C_Wr(EE_adr) I2C_Repeated_Start I2C_Wr($a3) EE_data = I2C_Rd(1) I2C_Stop PORTD = EE_data noend: goto noend end.
' Send byte(address of EEPROM) ' Send data(data that will be written) ' Issue I2C stop signal ' Pause while EEPROM writes data
' Issue I2C start signal ' Send byte via I2C ' Send byte(address for EEPROM) ' Issue I2C repeated start signal ' Send byte(request data from EEPROM) ' Read the data ' Issue I2C_Stop signal ' Print data on PORTD ' Endless loop
' for PIC18 program flash_pic18_test const FLASH_ERROR const FLASH_OK dim toRead as byte dim i as byte dim toWrite as byte[64] = $FF = $AA
main: TRISB = 0 for i = 0 to 63 toWrite[i] = i next i Flash_Write($0D00, toWrite) ' verify write PORTB = 0 ' turn off PORTB ' initialize error state ' write contents of the array to the address 0x0D00 ' PORTB is output ' initialize array
toRead = FLASH_ERROR for i = 0 to 63 toRead = Flash_Read($0D00+i) if toRead <> toWrite[i] then PORTB = FLASH_ERROR Delay_ms(500) else PORTB = FLASH_OK end if next i end.
' read 64 consecutive locations starting from 0x0D00 ' stop on first error ' indicate error
' for PIC16 program flash_pic16_test const FLASH_ERROR = $FF const FLASH_OK dim toRead as word dim i as word main: TRISB = 0 for i = 0 to 63 Flash_Write(i+$0A00, i) next i ' verify write PORTB = 0 ' turn off PORTB ' initialize error state ' Read 64 consecutive locations starting from 0x0A00 ' Stop on first error ' i contains the address of the erroneous location ' indicate error ' write the value of i starting from the address 0x0A00 ' PORTB is output = $AA
toRead = FLASH_ERROR for i = 0 to 63 toRead = Flash_Read($0A00+i) if toRead <> i then i = i + $0A00 PORTB = FLASH_ERROR Delay_ms(500) else PORTB = FLASH_OK end if next i end.
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. 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.
Heres an example for using Compact Flash card from BASIC. A set of files is written on CF card. This can be checked later by plugging the CF card on a PC or a digital camera. Observe the way the file is being written: First, write-to-file is initialized, telling to PIC that all consecutive CF_File_Write_Byte instructions will write to a new file;
q q
Then, actual write of data is performed (with CF_File_Write_Byte); Finally, finish of write-to-file cycle is signallized with call to CF_File_Write_Complete routine. At that moment, the newly created file is given its name.
program CompactFlash_File ' for PIC18 dim i1 as word dim index as byte dim fname as char[9] dim ext as char[4] sub procedure Init TRISC = 0 ' PORTC is output. We'll use it only to signal ' CF_Init_Port(PORTB, PORTD) do nop loop until CF_DETECT(PORTB) = true Delay_ms(50) end sub ' Wait until CF card is inserted ' Wait for a while until the card is stabilized ' ' main: i.e. its power supply is stable and CF card controller is on end of our program.
ext = "txt" index = 0 while index < 5 PORTC = 0 Init PORTC = index CF_File_Write_Init(PORTB, PORTD) i1 = 0 while i1 < 50000
' Must be 8 character long in upper case ' Ensure that files have different name ' Close the file
If you do not wish to use your CF card in PCs and digicams but ruther as a simple storage device for your PIC MCU only, you can then ignore the entire FAT system and store data directly to CF memory sectors:
main: TRISC = 0 CF_Init_Port(PORTB,PORTD) do nop loop until CF_Detect(PORTB) = true ' Wait until CF card is inserted ' PORTC is output ' Initialize ports
Delay_ms(500) CF_Write_Init(PORTB, PORTD, 590, 1) ' Initialize write at sector address 590 ' for i = 0 to 511 CF_Write_Byte(PORTB, PORTD, i + 11) next i PORTC = $FF Delay_ms(1000) CF_Read_Init(PORTB, PORTD, 590, 1) ' Initialize write at sector address 590 ' for i = 0 to 511 PORTC = CF_Read_Byte(PORTB, PORTD) Delay_ms(1000) next i end. of 1 sector (512 bytes) of 1 sector (512 bytes)
' Read 512 bytes from sector (590) ' and display it on PORTC
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
q
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Chapter 9: Communications
q q q q q q q q
Introduction 9.1 USART and Software UART 9.2 SPI and Software SPI 9.3 I2C and Software I2C 9.4 Manchester Code 9.5 RS485 9.6 OneWire 9.7 CAN & CANSPI
Introduction
When you start writing real-life programs for PIC, you may soon find yourself having a lack of space feeling, that you need just a few more pins and a couple of dozens of bytes to do the job. You might want to solve this problem by transferring to bigger PIC, and the problem will be solved for a little while. Or, you just happened to have found a beautiful, brand-new humidity sensor that does all the job by itself, leaving you just to connect it to PIC and pick up the data That is, if you know how to do that. If youve come up with these or similar problems, it really is time for you to teach your PIC and yourself some communication lessons. There are many ways for two machines to communicate these days, and PICs are generally well equipped for the task. Depending on the job to be done, data exchange what communication basically is can be done in a fairly simple manner, such as the SPI communication, but can extend to an entire network of various devices MCUs, PCs, cameras, intelligent sensors, etc. With increased demands, rules of device behaviour must encompass a wider set of possible scenarios and therefore protocols dramatically grow in complexity (CAN, for instance). Consider your needs carefully before jumping to CAN-driven solutions. There are different communication methods, offering lot of possibilities at varying levels of complexity. The rule of sacred simplicity remains here as well: do not use more complex communication tools than you really need to! In this chapter, youll get yourself acquainted with various means of communication that are being used by the PIC MCUs, and the ways to access and extend them from the BASIC programming language. You may have already noticed that some of the communication devices also have their software counterparts, meaning you can have the same communication functionality that is achieved through a set of software routines that can be used through the BASIC programming language. You should be using software communication when you have utilized all the real (hardware) communication resouces but still need an extra communication line.
q q
The USART itself can be set to communicate in many ways. The most frequent one is, of course, the one that helps your PIC talk to the PC. This old standard, known as the RS232, is understood by the 99.9% of PCs, although is lately being superseded by the USB standard. You can see from the image below how to connect your PIC to PC. You have to add an extra IC in between (MAX232) that simply adjusts the USART voltage levels to those required by the RS232 standard.
As you can see, you need two wires for this communication: one to receive data (named Rx), and the other one
to send (transmit) it (Tx). Here follows a simple BASIC program that gets (receives) data from the PC and sends it back to it:
program RS232com dim main: USART_Init(2400) while true if USART_Data_Ready = 1 then received_byte = USART_Read USART_Write(Received_byte) end if wend end. ' If data is received ' ' read received data, send it back via USART ' Initialize USART module received_byte as byte
When you compile this program and write it into the PIC, you can open some communication terminal program on your PC, such as Windows Terminal, set up the connection parameters, open connection, and send some characters to PIC. If everything is OK, it will send you that same data back.
program soft_uart_test dim received_byte as byte dim rec_ok as byte main: Soft_UART_Init(PORTB, 1, 2, 2400) ' initialize software UART ' you have to tell PIC which pins ' while true do received_byte = Soft_UART_Read(Rec_ok) loop until rec_ok Soft_UART_write(received_byte) wend end. ' send data via UART ' read received data to use as Rx and Tx
program SPI include "m7219.pbas" dim i as byte main: SPI_Init TRISC = TRISC and $FD max7219_init PORTC.1 = 0 SPI_Write(1) SPI_Write(7) PORTC.1 = 0 end. ' Initialize max7219 ' Select max7219 ' Send address (1) to max7219 ' Send data (7) to max7219 ' Deselect max7219s ' Standard configuration
module m7219 sub procedure max7219_init PORTC = PORTC and $FD SPI_Write($09) SPI_Write($FF) PORTC = PORTC or 2 PORTC = PORTC and $FD SPI_Write($0A) SPI_Write($0F) PORTC = PORTC or 2 PORTC = PORTC and $FD SPI_Write($0B) SPI_Write($07) ' SELECT MAX ' BCD mode for digit decoding ' DESELECT MAX ' SELECT MAX ' Segment luminosity intensity ' DESELECT MAX ' SELECT MAX ' Display refresh
PORTC = PORTC or 2 PORTC = PORTC and $FD SPI_Write($0C) SPI_Write($01) PORTC = PORTC or 2 PORTC = PORTC and $FD SPI_Write($00) SPI_Write($FF) PORTC = PORTC or 2 end sub end.
' DESELECT MAX ' SELECT MAX ' Turn on the display ' DESELECT MAX ' SELECT MAX ' No test ' DESELECT MAX
Using software SPI is similar to any software communication the software contained in BASIC routines simulates the real device. Having that in mind, you must be careful with initialization routines. Heres an example that uses software SPI to talk to another chip (the LTC1290 multiple channel 12-bit A/D converter), this time over the RD1 pin.
'******************************************************************************* ' microcontroller : P18F452 ' ' Project: LTC1290 ' ' This code demonstrates using software routines for SPI communication. ' Also, this example demonstrates working with ADC LTC1290. ' CS pin LTC1290 should be connnected to RD1 ' and SDO, SDI, SCKL pins should be appropriately connected. ' Result of AD conversion is printed on LCD display. ' Tested on 16F877A and 18F452 '******************************************************************************* program ltc1290 dim low_res as byte dim high_res as byte dim t as char[17] ' Formats and prints result on LCD sub procedure Display_ADval dim tmp as word dim value as longint tmp = word((high_res << 4)) + word(low_res value = (5000*tmp) 12 tmp = word(value) t[1]= 48 + word(tmp div 1000) t[3]= 48 + word((tmp div 100) mod 10) t[4]= 48 + word((tmp div 10) mod 10) t[5]= 48 + word(tmp mod 10) t[2]= 46 t[0]= 5 'length of the string is in the zero element 4)
LCD_out(2, 1, t) end sub main: PIE1 = 0 ' disable interrupts ' designate portb as output ' initialize LCD on PORTB ' LCD cursor off INTCON = 0 TRISB = 0
LCD_Init(PORTB) LCD_Cmd(LCD_CURSOR_OFF) low_res = 110 high_res = 1 Display_ADval Soft_SPI_Config(PORTD,7,6,5) SetBit(PORTD,1) ClearBit(TRISD,1) t = "mikroElektronika" LCD_Out(1, 1, t) while true ClearBit(PORTD,1)
' pin RD1 is output ' print "mikroElektronika" on LCD ' select LTC1290
high_res = Soft_SPI_Read(255) ' get upper byte of AD conversion low_res = Soft_SPI_Read(0) SetBit(PORTD,1) Display_ADval Delay_ms(1) wend end. ' get 4 least significant bits of AD conversion ' deselect LTC1290 ' format and print value on LCD ' wait 1 ms before next conversion
q q q
We will demonstrate this by connecting a 24c02 EEPROM to our PIC. Here is how to connect them:
' Example of communication with 24c02 EEPROM program i2c_test dim dim dim main: I2C_init(100000) TRISD = 0 PORTD = $FF I2C_Start I2C_Wr($A2) EE_adr = 2 I2C_Wr(EE_adr) EE_data = $AA I2C_Wr(EE_data) I2C_Stop ' initialize full master mode ' PORTD is output ' initialize PORTD ' issue I2C start signal ' send byte via I2C(command to 24cO2) ' send byte(address for EEPROM) ' send data(data that will be written) ' issue I2C stop signal EE_adr as byte EE_data as byte jj as word
for jj = 0 to 65500 ' pause while EEPROM writes data nop next jj I2C_Start I2C_Wr($A2) EE_adr = 2 I2C_Wr(EE_adr) I2C_Repeated_Start I2C_Wr($A3) ' issue I2C start signal ' send byte via I2C ' send byte (address for EEPROM) ' issue I2C signal repeated start ' send byte (request data from EEPROM)
' issue I2C stop signal ' show data on PORTD ' endless loop
You can find more details on I2C routines syntax in Chapter 5: Built-in and Library Routines. You shouldnt bother yourself too much about the meaning of the I2C_Start and I2C_Repeated_Start routines thats the way your PIC performs the initialization of its I2C device.
'****************************************************************************** ' microcontroller P16F877A ' ' Project: soft_i2c_test ' This project is designed to work with PIC 16F877A ' with minor adjustments, it should work with any other PIC MCU ' that has MSSP module. ' ' This code demonstrates comunication with 24c02 EEPROM ' connected to appropriate pins on PORTD. ' After the byte is read, it is displayed on PORTC. '****************************************************************************** program soft_i2c_test dim dim dim Addr as byte EE_ByteOut as byte EE_ByteIn as byte
main: TRISD = $FF TRISC = 0 PORTC = $FF Addr = 2 EE_ByteOut = $9F Soft_I2C_Config(PORTD,4,3) Soft_I2C_Start Soft_I2C_Write($A2) Soft_I2C_Write(2) Soft_I2C_Write(EE_ByteOut) Soft_I2C_Stop PORTC = $B0 Delay_ms(2000) ' initialize I2C, 100 kHz clk, full master mode ' issue I2C start signal ' send byte via I2C (command to 24cO2)
' send byte (address of EEPROM location) ' send data (data to be written) ' issue I2C stop sinal
Soft_I2C_Start Soft_I2C_Write($A2) Soft_I2C_Write(2) Soft_I2C_Start Soft_I2C_Write($A3) EE_ByteIn = Soft_I2C_Read(0) Soft_I2C_Stop PORTC end. = EE_ByteIn
' issue I2C start signal ' send byte via I2C (command to 24cO2 read cycle)
' send byte (address of EEPROM location) ' issue I2C signal repeated start ' send byte (request data from EEPROM) ' Read the data ' display data on PORTC
If you would try to send this data straightforward through the RF channel, you would encounter a number of problems. The biggest one is the existance of the DC component in the signal, meaning that if you integrate the voltage over time for, say, those 8 bits sent in previous example, you would get a non-zero (positive or
negative) value. This means that if you want to send this data through the radio, you need a lot of power, even for short distances. Furthermore, when this kind of data reaches the receiver, it cannot, due to the principles on which it is been built, interpret it properly. Again, its that DC component in the signal that represents the obstruction. Manchester encoding solves this problem by treating the data (i.e. 1s and 0s) not as signal (voltage, current) levels, but rather as a transition pattern between the levels. This means that 1 is coded as transition from high to low signal level, while the 0 is coded in the opposite way as transition from low to high signal level. So, the data from the previous example, in Manchester encoding, looks like this (showing only the data portion of message):
You can see that the voltage summary now remains zero no matter how much and what kind of data we are sending. If you wish to find out more on Manchester encoding, theres plenty of material about it on the Internet
'******************************************************************************* ' microcontroller P18F452 ' ' Project RTX ' This project is designed to work with PIC 18F452 ' with minor adjustments, it should work with any other PIC MCU ' ' This code demonstrates how to send data using Manchester encoding '******************************************************************************* program RF_TX dim i as byte
dim s1 as string[20] main: PORTB TRISB = 0 = %00001110 ' Disable interrupts ' Initialize manchester sender ' Send start marker ' Wait for a while ' Initialize port
ClearBit(INTCON, GIE) Man_Send_Init(PORTB) while TRUE Man_Send($0B) Delay_ms(100) s1 = "mikroElektronika" for i = 1 to Length(s1) Man_Send(s1[i]) Delay_ms(90) next i Man_Send($0E) Delay_ms(1000) wend end.
As you can see, the transmit side is pretty straightforward. The receive side needs to have a little extra coding to provide the re-synchronization during data receive, if necessary. In BASIC, Manchester receive routines (Man_Receive_Config, Man_Receive_Init, Man_Receive) are blocking calls. This means that PIC will wait until the task is performed (e.g. byte is received, synchronization achieved, etc.). Routines for receiving are limited to a baud rate scope from 340 ~ 560 bps.
'******************************************************************************* ' microcontroller: P16F877A ' ' Project: RRX ' This project is designed to work with PIC 16F877A ' with minor adjustments, it should work with any other PIC MCU ' ' This code shows how to use manchester library for receiving data. ' The example works in conjuction with transmitter which sends ' the word "mikroElektronika" using Manchester encoding. '******************************************************************************* program RRX dim ErrorFlag as byte dim ErrorCount as byte dim IdleCount as byte dim temp as byte dim LetterCount as byte main: errorCount = 0 trisc portc = 0 = 0 ' ErrorFlag indicator ' Initialize receiver and try to synchronize it ' Initialize LCD on PORTB
Man_Receive_Config(PORTD,6) LCD_Init(PORTB)
while true do IdleCount = 0 temp = Man_Receive(ErrorFlag) if ErrorFlag then inc(errorCount) else portc = 0 end if if errorCount > 20 then ' If there are too many errors ' errorCount = 0 portc = $AA Man_Receive_Init(PORTD) end if inc(IdleCount) if IdleCount > 18 then IdleCount = 0 Man_Receive_Init(PORTD) end if loop until temp = $0B ' Get the message if errorFlag = false then LCD_Cmd(LCD_CLEAR) LetterCount = 0 while LetterCount < 17 inc(LetterCount) temp = Man_Receive(ErrorFlag) if errorFlag = false then LCD_Chr_CP(temp) else inc(errorCount) end if wend temp = Man_Receive(ErrorFlag) if temp <> $0E then inc(errorCount) end if end if wend end. ' The message is 16 chars in size. ' If no errorFlag then write the message ' End of message marker ' If nothing is received after some time ' try to synchronize again ' Indicate error state ' Synchronize receiver try to syncronize the receiver again ' Clear error indicator ' Loop endlessly ' Reset idle counter ' Attempt byte receive
9.5 RS485
RS232 is a well documented, simple, reliable, good-old standard that is still used a lot and will be so in the near future. You should certainly use it wherever and whenever possible. But what happens when it cannot do the job? This is primarily addressed to the cable length, i.e. distances it cannot cover. The answer is (or should be)
RS485. Together with the RS422, it is one of the most widely used communication standards today, especially in the industrial production facilities and remote stations, although in the past decade it has been constantly losing the battle against the newer and more advanced standard the Ethernet. So, what are the basic differences between RS232 and RS485 and when should you use the latter? The way the signals are represented: At RS232, signals are represented by voltage levels with respect to ground. There is a wire for each signal, together with the ground signal (reference for voltage levels), so if you want to use the communcation without the hardware handshake, youll need 3 wires for this: Rx (receive), Tx (transmit) and GND (ground) as common reference point. This also means that the difference in GND voltage levels between the devices in communication must be very small (if any). On the other hand, at RS485, signals are represented by voltage difference, which allows for much longer
q
cable distances (with much more electrical noise) to be covered. Number of endpoints in communication: RS232 is a single-point protocol, meaning you can connect only one peripheral to your PC or PIC through one RS232 link. RS485 is multipoint protocol, which allows multiple devices to be connected to a single signal cable. Type of communication: RS232 is a full-duplex communication, meaning that both sides can send and receive data simultaneously. RS485 is a half-duplex communication only one device can send messages at a time, while others on the net are listening.
You should use RS485: When you need your device to communicate to more than one of its colleagues, i.e. when you need to have a network of devices. Up to 32 devices (in standard configuration) can be connected; When you need to cover larger distances than those you normally can do with RS232. For RS 485 the cable can be up to 1200 meters long, compared to max. 30 60 meters for RS232;
To implement all this, RS485 uses the Master/Slave architecture. This means that one device (the master) controls the line, allowing other devices (slaves) to send messages only when spoken to. Master and slave devices interchange packets of information, each of these packets containing synchronization bytes, CRC byte, address byte, and the data. In Master/Slave architecture, slave can never initiate communication. Each slave has its unique address and receives only the packets containing that particular address. It is programmers responsibility to ensure that only one device transmits data via 485 bus at a time. BASIC provides a set of library routines to allow you comfortable working with RS485 system. RS485 routines require USART module on PORTC. Pins of USART need to be attached to RS485 interface transceiver, such as LTC485 or similar. Pins of transceiver (Receiver Output Enable and Driver Outputs Enable) should be connected to PORTC, pin 2 (see the figure at end of the chapter). Note that address 50 is a common address for all Slave devices: packets containing address 50 will be received by all Slaves. The only exceptions are slaves with addresses 50 and 169, which require their particular address to be specified in the packet. The following example demonstrates use of Slave nod in RS485 Master/Slave architecture.
program pr485 dim dat as byte[8] dim i as byte dim j as byte sub procedure interrupt if TestBit(RCSTA, OERR) = 1 then PORTD = $81 end if RS485Slave_Read(dat) end sub ' Every byte is received by ' RS485Slave_Read(dat); ' Buffer for receiving/sending messages
' Upon receiving a message w/o errors main: TRISB = 0 TRISD = 0 USART_Init(9600) RS485Slave_Init(160) SetBit(PIE1, RCIE) SetBit(INTCON, PEIE) ClearBit(PIE2, TXIE) SetBit(INTCON, GIE) PORTB = 0 PORTD = 0 dat[4] = 0 dat[5] = 0 while true if dat[5] then PORTD = $AA end if if dat[4] then dat[4] = 0 j = dat[3] for i = 1 to j PORTB = dat[i - 1] next i dat[0] = dat[0] + 1 RS485Slave_Write(dat,1) end if wend end. ' ' Increment received dat[0] Send it back to Master ' Output received data bytes ' If message received: ' ' Clear message received flag Number of data bytes received ' If there is error, set PORTD to $aa ' Ensure that message received flag is 0 ' Ensure that error flag is 0 ' Initialize usart module ' Initialize MCU as Slave with address 160 ' Enable interrupt ' ' on byte received via USART (RS485) ' data[4] is set to 255
9.6 OneWire
This is another Master/Slave protocol, and all the cabling you need is a single wire. Because of the hardware configuration it uses (single pullup and open collector drivers), it allows for the slaves even to get their power supply from that line. Some basic characteristics of this protocol are: single master system, low cost, low transfer rates (up to 16 kbps), fairly long distances (up to 300 meters), small data transfer packages.
q q q q q
Each 1-Wire device also has a unique 64-bit registration number (8-bit device type, 48-bit serial number and 8bit CRC), so multiple slaves can co-exist on the same bus. In low-level part of this protocol, each bit is transferred by the master by pulling the line low. Whether the bit is zero or one depends on how long the line is kept low, longer time for the 0 and shorter for the 1. When the
master is reading a bit from a slave it pulls the line low for a minimum amount of time. The slave pulls the line low as well and after the master releases the line the slave keeps it low for the time required for the bit type (same as for the master). The higher level protocol, also known as 1-wire Bus System, allows the master to enumerate devices on the bus. The master sends a command for all slaves to respond with their registration number. As each bit is being read, the master sends the value of the bit it is interested in. The slaves that match continue while the slaves that dont match stop outputting. By the time the entire configuration code is read, one unique code has been read identifying one device. The command is repeated until no new devices respond and all devices on the bus have been identified. This code demonstrates use of low-level 1-wire library procedures and functions in BASIC. The example reads the temperature using DS1820 connected to PORTA, pin 5. Be sure to set the Fosc (oscillator frequency) appropriately in your project.
dim por1 as byte dim por2 as byte dim text as char[20] main: text PORTB PORTA TRISB = "Temperature:" = 0 = 255 = 0 ' initialize PORTB to 0 ' initialize PORTA to 255 ' PORTB is output ' PORTA is input
TRISA = 255 LCD_Init(PORTB) LCD_Cmd(LCD_CURSOR_OFF) LCD_Out(1, 1, text) do OW_Reset(PORTA, 5) OW_Write(PORTA, 5, $CC) OW_Write(PORTA, 5, $44) Delay_ms(120) i = OW_Reset(PORTA, 5) OW_Write(PORTA, 5, $CC) OW_Write(PORTA, 5, $BE) Delay_ms(1000) j1 = OW_Read(PORTA, 5) j2 = OW_Read(PORTA, 5) j1 = j1 >> 1 ByteToStr(j1, text) LCD_Out(2, 8, text) LCD_Chr(2, 10, 223) LCD_Chr(2, 11, "C") Delay_ms(500) loop until false end.
' 1-wire reset signal ' issue command to DS1820 ' issue command to DS1820
' issue command to DS1820 ' issue command to DS1820 ' get result ' get result ' assuming the temp. >= 0C ' convert j1 to text ' print text ' degree character ()
doesnt pay off using it for distances less than 30-40 meters unless you need some (very) high data throughput. Remember, each of the communication standards, protocols and devices described in this chapter has its own scope of applications! CAN was originally created by the BOSCH company in the early 80s for automotive electronics, to allow for various car/truck/bus electronic systems (such as ABS, Electronic Power Control, AquaStop, GPS/navigation, data display system, etc) to exchange data over (single) serial bus, i.e. to form a network of devices within the vehicle. It soon proved its value, expanding itself into other areas, such as HVAC, elevators and Building Automation systems. Its price and transfer rate characteristics put the CAN in between the RS485 (older, slower, and by far cheaper) and the Ehternet (newer, faster, and more complex/expensive), and thats also where its scope of applications stands. CAN is a very robust protocol that has error detection and signalling, selfchecking and fault confinement. Faulty CAN data and remote frames are re-transmitted automatically, just like at Ethernet. Data transfer rates vary from up to 1 Mbit/s at network lengths below 40 m to 250 kbit/s at 250 m cables, and can go even lower at greater network distances, downto 200 kbit/s, which is the minimum bitrate defined by the standard. Cables used are shielded twisted pairs, and maximum cable length is 1000 m. CAN supports two message formats: Standard format, with 11 identifier bits, and Extended format, with 29 identifier bits
q q
The protocol itself is standardized in ISO 11898-1 (2003). Every CAN solution must implement the standard format and may accept the extended format. Here, all devices are connected to a single shared bus and they are all allowed to start a transmission (whenever they want to), unlike at RS485. Therefore, if two or more devices start transmitting simultaneously, there must be some arbitration scheme involved to decide which one will be granted permission to continue transmitting. This mechanism is called the Carrier Sense Multiple Access / Collision Avoidance (CSMA/CA) scheme. The example that follows is a simple demonstration of working with the CAN system through BASIC programming language. The CAN device is first initialized, then the data is intermittently read, incremented and written back. The PIC that is used for this example must have the CAN module built-in, e.g. you could use the P18F448 or any other PIC MCU from P18Fxx8 family. Furthermore, you need to have a chip that performs signal conditionning for CAN bus (or CAN transceiver) to boost up voltage levels and make level transition cleaner and less noisy, and for that purpose we used the MCP2551 IC.
dim aa1 as byte dim lenn as byte dim aa2 as byte dim data as byte[8] dim id as longint dim zr as byte dim cont as byte dim oldstate as byte sub function TestTaster as byte result = true if Button(PORTB, 0, 1, 0) then
oldstate = 255 end if if oldstate and Button(PORTB, 0, 1, 1) then result = false oldstate = 0 end if end sub main: TRISB.0 = 1 PORTC = 0 TRISC = 0 PORTD = 0 TRISD = 0 aa aa1 aa2 aa1 = = 0 = 0 = 0 CAN_TX_PRIORITY_0 and CAN_TX_XTD_FRAME and CAN_TX_NO_RTR_FRAME aa = CAN_CONFIG_SAMPLE_THRICE and CAN_CONFIG_PHSEG2_PRG_ON and CAN_CONFIG_STD_MSG and CAN_CONFIG_DBL_BUFFER_ON and CAN_CONFIG_VALID_XTD_MSG and CAN_CONFIG_LINE_FILTER_OFF ' Form value to be used ' with CANSendMessage ' Pin RB0 is input
' Upon signal change on RB0 pin ' ' from logical 0 to 1 proceed with program execution
'
' Initialize CAN ' Set CONFIGURATION mode ' Set all mask1 bits to ones ' Set all mask2 bits to ones
CANSetFilter(CAN_FILTER_B1_F1,3,CAN_CONFIG_XTD_MSG) ' Set id of filter B1_F1 to 3 CANSetOperationMode(CAN_MODE_NORMAL,TRUE) PORTD = $FF id = 12111 CANWrite(id, data, 1, aa1) while true oldstate = 0 zr = CANRead(id, Data, lenn, aa2) if (id = 3) and zr then PORTD = $AA PORTC = data[0] data[0] = data[0]+1 ' Output data at PORTC ' Set NORMAL mode
id = 12111 CANWrite(id, data, 1, aa1) if lenn = 2 then PORTD = data[1] end if end if wend end. ' Send incremented data back ' If message contains two data as bytes ' output second as byte at PORTD
9.7.2 CANSPI
Working with CAN is nice, but what about those PICs that do not have the CAN module? The BASIC solution for them is the CANSPI, actual CAN-over-SPI module library. Each routine of CAN library has its CANSPI counterpart with identical syntax. This library provides us with a fictive external CAN module that can be communicated with through the SPI. In example that follows we used the MCP2510 CAN controller. For more information consult the previous entry and example. Please note that the effective communication speed now depends on the SPI, and is certainly slower than the real CAN.
program CANSPI dim dim dim dim dim aa as byte aa1 as byte lenn as byte aa2 as byte data as byte[8]
dim dim
id as longint zr as byte
main: TRISB = 0 SPI_init TRISC.2 = 0 PORTC.2 = 0 PORTC.0 = 1 TRISC.0 = 0 PORTD = 0 TRISD = 0 aa = 0 aa1 = 0 aa2 = 0 aa = CAN_CONFIG_SAMPLE_THRICE and CAN_CONFIG_PHSEG2_PRG_ON and CAN_CONFIG_STD_MSG and CAN_CONFIG_DBL_BUFFER_ON and CAN_CONFIG_VALID_XTD_MSG PORTC.2 = 1 aa1 = CAN_TX_PRIORITY_BITS and CAN_TX_FRAME_BIT and CAN_TX_RTR_BIT CANSPIInitialize( 1,2,3,3,1,aa) ' Prepare flags for CANSPIwrite function ' Initialize MCP2510 ' Set configuration mode ' Prepare flags for CANSPIinitialize procedure ' Activate MCP2510 chip ' Must be performed before any other activity ' This pin is connected to Reset pin of MCP2510 ' Keep MCP2510 in reset state ' Make sure that MCP2510 is not selected ' Make RC0 output ' PORTD is output
CANSPISetOperationMode(CAN_MODE_CONFIG,true) ID = -1 CANSPISetMask(CAN_MASK_B1,id,CAN_CONFIG_XTD_MSG) ' bring all mask1 bits to ones CANSPISetMask(CAN_MASK_B2,0,CAN_CONFIG_XTD_MSG) ' bring all mask2 bits to ones
CANSPISetFilter(CAN_FILTER_B1_F1,12111,CAN_CONFIG_XTD_MSG) ' set filter_b1_f1 id to 12111 CANSPISetOperationMode(CAN_MODE_NORMAL,true) ' get back to Normal mode while true zr = CANSPIRead(id, Data, lenn, aa2) if (id = 12111) and zr then PORTD = $AA PORTB = data[0] data[0] = data[0] + 1 id = 3 Delay_ms(10) CANSPIWrite(id, data, 1, aa1) if lenn = 2 then PORTD = data[1] end if end if wend
end.
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.
Home
Development Tools
q
Compilers
Projects
Special Offer
Download
Books
Distributors
About us
Home > Books > Programming PIC MCUs in BASIC Previous Chapter | Table of Contents | Next Chapter
Introduction A.1 Installation of mikroBasic A.2 First Contact with mikroBasic A.3 Creating First Project
Introduction
As already stated, any text editor that can save program file as pure ASCII text (without special symbols for formatting) can be used for writing your BASIC code. Still, there is no need to do it by hand there are specialized environments, such as mikroBasic, that take care of the code syntax, free the memory and provide all the necessary tools for writing a program. mikroBasic is a Windows-based Integrated Development Environment, and is much more than just BASIC compiler for PIC MCUs. With mikroBasic, you can: Create BASIC source code using the built-in Code Editor, Compile and link your source code, Inspect program flow and debug executable logic with Debugger, Monitor variables in Watch Window, Get error reports, Get detailed statistics how compiled code utilizes PIC MCU memory, hex map, charts, and more
q q q q q q
mikroBasic IDE includes highly adaptable Code Editor, fashioned to satisfy needs of both novice users and experienced programmers. Syntax Highlighting, Code Templates, Code & Parameter Assistant, Auto Correct for common typos, and other features provide comfortable environment for writing a program. In combination with comprehensive help, integrated tools, extensive libraries, and Code Explorer which allows you to easily monitor program items, all the necessary tools are at hand.
Step 1
First you will be welcomed by the following screen. Click on next to continue.
Step 2
You will be asked to review the License Agreement before installing mikroBasic. If you understand and accept the terms in the agreement, select I accept the terms and click Next to proceed with the installation.
Step 3
Select the components you would like to install. Examples included with mikroBasic are optional, but we higly recommend installing them. Without taking much space on hard disk, the included set of pracical examples can be highly useful when developing applications. Also, beginners might find it very hepful.
Step 4
Step 5
Step 6
As with any modern environment, you may customize layout of mikroBasic to best suit your needs toolbars are fully dockable and your arrangement of windows is saved upon exit. By default, the largest part of the screen is taken by Code Editor which contains the program code. This is the advanced text editor where you will be writing your programs. It features Syntax Highlighting to help you differentiate code elements. Try typing one of BASICs keywords and watch it go bold, or type an aposhtophe to see the comments go italic and change color. Code Editor features many other advanced features such as Code & Parameter Assistants, Auto Correct for common typos, Code Templates, etc.
If you had no previous experience with advanced IDEs, you may wonder what Code and Parameter Assistants do. These are utilities which facilitate the code writing. For example, if you type first few letter of a word in Code Editor and then press CTRL+SPACE, all valid identifiers matching the letters you typed will be prompted to you in a floating panel. Now you can keep typing to narrow the choice, or you can select one from the list using keyboard arrows and Enter. You dont have to memorize the exact order or type of the routine parameters. Type CTRL+SHIFT+SPACE to activate the Parameter Assistant which will guide you in filling the appropriate parameters. This feature is automatically invoked upon opening a parenthesis. To the left of the Code Editor, you will see a treeview of declared program elements. This is the Code Explorer which allows you to monitor variables, constants, routines, etc. Double click the element to jump to its declaration in code. You can click tabs over Code Explorer to change view to Keyboard shortcut browser for a list of all IDE shortcuts or to Quick Help browser with complete list of available built-in and library routines. For setting other IDE features, click Tools > Options. In the Options window you can customize the look and feel of mikroBasic, enter your own list of recognized typos, write your own templates, etc. If you get stuck at any point, consult the included help files. You can get help on F1, by right-clicking a specific word in code, or from Quick Help tab in Code Explorer. Help files are syntax and context sensitive.
Step 1
From a drop-down menu, select: Project > New Project, or click New Project icon
Step 2
Fill the New Project Wizard dialog with correct values to set up your new project. Select a device for your project from the drop-down menu Set configuration bits (Device Flags) by clicking Default push-button. Select Device Clock by entering appropriate value in edit box. Enter a name for your new project Enter project description edit box for closer information about your project Enter project path
q q q q q q
After you have set up your project, click OK. mikroBasic will create project for you and automatically open the program file in Code Editor. Now we can write the source code.
Step 3
Upon creating a new project, Code Editor will display an empty program file, named same as your project. This is shown in the following figure.
Now we are about to write the code for this simple example. We want to make LED diode blink once per second. Assuming the configuration given in the following figure, LED diodes are connected to PIC16F877 PORTB pins (it can be any other PIC that has PORTB).
In this configuration, LED will emit light when voltage on pin is high (5V), and will be off when voltage on pin is low (0V). We have to designate PORTD as output, and change its value every second. Listing of the program is given below. Once you are comfortable with each line, feel free to experiment with it and improve the code.
program My_LED main: TRISB = 0 eloop: PORTB = $FF Delay_ms(1000) PORTB = 0 Delay_ms(1000) goto eloop end. ' PORTB is output ' Turn on diodes on PORTB ' Wait 1 second ' Turn of diodes on PORTB ' Wait 1 second ' Stay in loop
Step 4
Before compiling, it is recommended to save your project (menu choice File > Save All). Now you can compile your code by clicking CTRL+F9, or by selecting menu Run > Compile, or by clicking the Compile icon
mikroBasic will generate list and assembly file, and a hex file which can be used to program PIC MCU. But before trying out our program on PIC, let's test it with the Debugger.
Step 5
After successful compiling, we can use mikroBasic Debugger to check our program behavior before we feed it to the device (PIC16F877 or other). For a simple program such as this, simulation is not really necessary, but it is a requirement for more complex projects. To start the Debugger, select Run > Debug, or click the Debug icon , or simply hit F9.
Upon starting the Debugger, Watch Window appears, and the active line in Code Editor marks the instruction to be executed next. We will set the breakpoint at line 9 by positioning the cursor to that line and toggling the breakpoint (Run > Toggle Breakpoint or F5). See the image below:
We will use the Step Over option (Run > Step Over or F8) to execute the current program line. Now, you can see the changes in variables, SFR registers, etc, in the Watch Window items that have changed are marked red, as shown in the image below.
We could have used Run/Pause (F6) option to execute all the instructions between the active line and the breakpoint (Run > Run/Pause Debugger).
Step 6
Now we can use our hex file and feed it to the device (PIC16F877 or other). In order to do so, hex file must be loaded in programmer (PIC Flash by mikroElektronika or other).
PIC, PIC, PICmicro, and MPLAB are registered and protected trademarks of the Microchip Technology Inc. USA. Microchip logo and name are the registered tokens of the Microchip Technology. mikroBasic is a registered trade mark of mikroElektronika. All other tokens mentioned in the book are the property of the companies to which they belong. mikroElektronika 1998 - 2006. All rights reserved. If you have any questions, please contact our office.