Copyright: Les. Johnson


PROTON+ Compiler
PROTON+ BASIC Compiler Version 2.1.5

Getting Started

PICmicro Devices

Supported PICmicro devices

Device Specific issues

Line Labels

Variables

Relational Operators

Floating Point Math

Creating and using ARRAYS

Arrays as Strings

Aliases

Constants

Symbols

Numeric Representations

Creating and using VIRTUAL STRINGS with CDATA

Creating and using VIRTUAL STRINGS with EDATA

Ports and Hardware Registers

General Format

MATH and TRIGONOMETRY Operators and Functions

Inline Commands within Expressions

Boolean Logic Operators

Compiler Commands and Directives

Using a Graphic LCD

Software Interrupts in BASIC

Using the built in Bootloader software

Running an External Program from the Editor and Capturing its Output

Using PROTON+ within MPLAB IDE

DECLARE list

Protected Compiler Words

Supported PICmicro devices

Contact Details


Getting Started

Writing your first Program

The Editor

Locating the EPIC programmer on the hard drive.

Choosing an external Programmer.


Writing your first program

Locate the program PBP_EDITOR.EXE, either from the START menu, the desktop, or directly from the folder that the compiler was installed into. You will be greeted with a blank editor. See below.

Type in the following program, or copy and paste into the editor.

' Flash all the LEDs sequentially connected to PORTD

DEVICE = 16F877	' We'll use a PIC16F877 PICmicro

XTAL = 4	' With a 4MHz crystal

DIM SCAN AS BYTE    	' Declare SCAN variable

SYMBOL LED = PORTD   	' Alias PORTD to LEDS

LOW LED	' Make PORTD output LOW

LOOP:

LED = 1        	' First LED on

DELAYMS 300       	' Delay for .3 seconds

FOR SCAN = 1 TO 7  	' Go through For..Next loop 7 times

LED = LED << 1    	' Shift on LED, one to left

DELAYMS 300       	' Delay for .3 seconds

NEXT	' Close the SCAN loop

GOTO LOOP       	' Go back to loop and blink LED forever

If you're using a PROTON development board, then no extra circuitry will be required, however if not, then you will need to build a compatible circuit with 8 LEDs connected to PORTD of the 16F877 PICmicro. A suitable circuit is shown below. (Note that this is also a standard template for most 16F877 circuits).

Now click on the COMPILE button located on the top toolbar [image]. Because you have not given a name for the program, you will now be prompted for one.

Choose OK, and give the program the name FLASH.BAS. Not forgetting to locate the BASIC program in a suitable place on the hard drive.

One this is done, the program will compile then assemble automatically, as long as no errors where included in the typing.

You now need to place the HEX file created actually into the PICmicro. A PICmicro will sit there doing nothing at all until a program is entered into it. This is the job of a PICmicro programmer.

The PROTON+ editor gives the ability to use virtually any programmer that can accept a command line. Such as the popular EPIC programmer. See Choosing an external Programmer, or Locating the EPIC programmer on the hard drive for more details concerning programmers.

If you're using the PROTON development board for design work, then there is an extremely easy method of placing the HEX file into the PICmicro, using the serial bootloader method. See Using the serial bootloader for more details.

If you've chosen a standard PICmicro programmer, then click on the PROGRAM icon [image] (located on the top toolbar). You should be presented with the programmers software. If not, then check the command line entered.

If you're using the serial bootloader option, then click the DOWNLOAD icon [image]  (also located on the top toolbar).

Once the HEX file has been placed into the PICmicro, you should see each LED connected to PORTD flash in sequence. That's your first program written and operational. Welcome to the fascinating world of PICmicro microcontrollers!

It didn't work !

DON'T PANIC. There is a logical sequence of checks to make when a simple project such as flashing the LEDs hasn't worked.

First. Check your circuit for any obvious mistakes. Such as: -

Wrong component values.

1). Power supply correct, and correct polarity.

2). Is the PICmicro becoming hot to the touch. If so then check the polarity and voltage of the power supply. You may have killed the PICmicro!. Remember PICmicros do not like voltages over 6 volts. Unless they are the special voltage types.

3). Is the Crystal frequency correct, and crystal itself working (check either by replacement, or use an oscilloscope on CLK OUT pin).

4). Check that the capacitors used for the crystal are the correct values, and are not leaking.

5). If using a resonator with or without internal capacitors checking is important, as these devices are notorious for breaking down.

6). Ensure that the MCLR pin of the PICmicro is pulled up to 5 Volts with a suitable value resistor, or is connected directly to 5 Volts.

7). If using a breadboard for development, then ensure that it's integrity has not degraded. Breadboards become worn and loose over time, causing bad connections, or even shorts.

If you're sure that the circuit is correct, then it must be down to a software error. Just because a program compiles without any errors does not mean that it will perform the required task. There is a rather down to earth saying in the software industry "GARBAGE IN GARBAGE OUT", which means that a program written incorrectly will operate incorrectly.

Sometimes there may be clues as to what's gone wrong in the program, such as erratic behaviour. But sometimes no such clues are forthcoming, and the circuit sits there doing nothing (well, nothing that can be seen anyway!).

Check your software for any obvious errors. Such as: -

1). Port not set to output, or input.

2). PORTA, or PORTE not set to digital mode using the ALL_DIGITAL directive.

3). Wrong port used.

4). Wrong type of PICmicro chosen.

5). Wrong Crystal frequency chosen.

There are many more anomalies that could be added to the list above (countless thousands depending on the program). See Device Specific issues.

When programming the device, ensure that the FUSES are set correctly. If using a 4MHz crystal, then ensure the XTAL fuse is set for XT, or HS. If a crystal frequency of more than 4MHz is used, then ensure that the fuse is set for HS. The compiler automatically assigns the appropriate fuse setting, but not all programmers do as their told! Make sure that the WATCHDOG timer is set according to the program. The compiler defaults to the watchdog timer OFF, so ensure the programmer is disabling the watchdog timer. See CONFIG.

If all else fails, then you may need a helping start with a development board such as the PROTON. This eases the burden of designing a circuit, and lets you get on with software development.


The Editor

As from Version 1.20, there has been a separation of the editor and the compiler's executable. This allows the seamless integration into programs such as MPLAB, or PROTEUS VSM, etc. The Editor is activated by clicking on PBP_EDITOR.EXE.

The editor itself has undergone a complete re-write, and now allows multiple BASIC code listings to be opened in the same IDE, using a tabbed notebook approach: -

The above screenshot shows four BASIC programs loaded into the IDE.

Compiling, Programming, Downloading, and Viewing.

The four large graphic buttons at the top of the editor are for Compiling the program, Programming the PICmicro, Serially downloading the program into the PICmicro, using the serial bootloader, and finally, viewing the ASM source produced. These four iconic buttons are shown below.

Automatic File Backup.

The Editor automatically backs up the BASIC source code whenever a SAVE is undertaken, or COMPILE is selected. The backup file has the same Filename, but has an extension or .BAK. The .BACK file is placed at the same location as the BASIC source code being worked with.

CONFIRMATION Information.

Confirmation of a successful compile is indicated in the STATUS bar, located at the bottom of the editor: -

This shows the DEVICE used, as well as the CODE space taken up, and the amount of RAM used.

This information is also available in the REPORT window which is displayed by pressing the F1 key. The REPORT window also shows any errors produced while compiling, and is automatically opened in the event of errors.

The illustration below shows the REPORT window indicating two errors occurred while compiling: -

Separate Compiler.

The actual compiler is now a separate executable, called from the editor. Apart from the obvious advantages this has over a combined Compiler/Editor, such as being able to use a third party editor (Ultraedit being the best of it's kind). It also allows Simulator, and Emulator software to incorporate the compiler more closely into their IDEs. MPLAB being the obvious choice for a simulator, and Emulators such as Proteus, or Virtual Breadboard.

There are four possible outcomes from a compile. The first and most sought, is a successful compile. This is indicated by the successful execution of MPASM after the compiler has scanned the code for errors. Shown below: -

Another possible outcome is a WARNING. This is indicated by the compilation gauge turning YELLOW, and the text "THERE ARE WARNINGS", appearing. This is shown below.

To view the warnings, press the F1 key to bring up the REPORT window. All warnings should be taken seriously, as they may effect the outcome of the BASIC program, either subtly, or catastrophically.

A third outcome of a compilation is an ERROR. This is indicated by the compilation gauge turning RED with the text "THERE ARE ERRORS", appearing. This indicates that there are COMPILER errors. Any errors will be automatically displayed in the REPORT window. This is shown below: -

The report window will not be able to close until the errors have been removed, and a successful compilation has occurred. If multiple BASIC listings are open in the IDE, then the REPORT window will indicate any errors on an individual basis.

A fourth error report is an ASSEMBLER error. This, again causes the compilation gauge to turn RED. However, the text now states "ASSEMBLER ERRORS". The errors causing this message to appear are generally caused by any INLINE assembler instructions within the BASIC listing. But BASIC commands can also be the cause of some assembler errors. Especially if MACRO's are inherent in the code: -


Commands and Directives

ADIN	Read the on-board analogue to digital converter.

ASM-ENDASM    	Insert assembly language code section.

BOX	Draw a square on a graphic LCD.

BRANCH	Computed GOTO (equiv. to ON..GOTO).

BRANCHL	BRANCH out of page (long BRANCH).

BREAK	Exit a FOR-NEXT, REPEAT-UNTIL, or WHILE-WEND loop prematurely.

BSTART	Send a START condition to the I2C bus.

BSTOP	Send a STOP condition to the I2C bus.

BRESTART	Send a RESTART condition to the I2C bus.

BUSACK	Send an ACKNOWLEDGE condition to the I2C bus.

BUSIN	Read bytes from an I2C device.

BUSOUT	Write bytes to an I2C device.

BUTTON	Detect and debounce a key press.

CALL	Call an assembly language subroutine.

CDATA	Define initial contents in memory.

CIRCLE	Draw a circle on a graphic LCD.

CLEAR	Place a variable or bit in a low state, or clear all RAM area.

CLEARBIT	Clear a bit of a port or variable, using a variable index.

CLS	Clear the LCD.

CONFIG	Set or Reset programming fuse configurations.

COUNTER	Count the number of pulses occuring on a pin.

CREAD	Read data from code memory.

CURSOR	Position the cursor on the LCD.

CWRITE	Write data to code memory.

DATA	Define initial contents in memory.

DEC	Decrement a variable.

DECLARE	Adjust library routine parameters.

DELAYMS	Delay (1mSec resolution).

DELAYUS	Delay (1uSec resolution).

DEVICE	Choose the type of PICmicro to compile with.

DIG	Return the value of a decimal digit.

DIM	Create a variable.

DISABLE	DISABLE software interrupts that were previously ENABLED.

DTMFOUT	Produce a DTMF Touch Tone note.

EDATA     	Define initial contents of on-board EEPROM.

ENABLE	ENABLE software interrupts that were previously DISABLED.

END     	Stop execution of the BASIC program.

EREAD    	Read a value from on-board EEPROM.

EWRITE    	Write a value to on-board EEPROM.

FOR…TO…NEXT…STEP	Repeatedly execute statements.

FREQOUT	Generate one or two tones, of differing or the same frequencies.

GETBIT	Examine a bit of a port or variable, using a variable index.

GOSUB   	Call a BASIC subroutine at a specified label.

GOTO    	Continue execution at a specified label.

HBSTART	Send a START condition to the I2C bus using the MSSP module.

HBSTOP	Send a STOP condition to the I2C bus using the MSSP module.

HBRESTART	Send a RESTART condition to the I2C bus using the MSSP module.

HBUSACK	Send an ACKNOWLEDGE condition to the I2C bus using the MSSP module.

HBUSIN	Read from an I2C device using the MSSP module.

HBUSOUT	Write to an I2C device using the MSSP module.

HIGH   	Make a pin or port high.

HPWM	Generate a PWM signal using the CCP module.

HRSIN	Receive data from the serial port on devices that contain a USART.

HRSOUT	Transmit data from the serial port on devices that contain a USART.

HSERIN	Receive data from the serial port on devices that contain a USART.

HSEROUT	Transmit data from the serial port on devices that contain a USART.

HRSIN2	Same as HRSIN but using a 2nd USART if available.

HRSOUT2	Same as HRSOUT but using a 2nd USART if available.

HSERIN2	Same as HSERIN but using a 2nd USART if available.

HSEROUT2	Same as HSEROUT but using a 2nd USART if available.

IF..THEN..ELSEIF..ELSE..ENDIF  Conditionally execute statements.

INC	Increment a variable.

INCLUDE    	Load a BASIC file into the source code.

INKEY	Scan a keypad.

INPUT	 	Make pin an input.

 	[LET]    	Assign the result of an expression to a variable. Optional command and rarely used.

LCDREAD	Read a single byte from a Graphic LCD.

LCDWRITE	Write bytes to a Graphic LCD.

LDATA	Place information into code memory. For access by LREAD.

LINE	Draw a line in any direction on a graphic LCD.

LINETO	Draw a straight line in any direction on a graphic LCD, starting from the previous LINE command's end position.

LOADBIT	Set or Clear a bit of a port or variable, using a variable index.

LOOKDOWN	Search a constant lookdown table for a value.

LOOKDOWNL	Search constant or variable lookdown table for a value.

LOOKUP	Fetch a constant value from a lookup table.

LOOKUPL	Fetch a constant or variable value from lookup table.

LOW   	Make a pin or port low.

LREAD	Read a value from an LDATA table.

ON INTERRUPT   	Execute a BASIC or ASSEMBLER subroutine using a SOFTWARE interrupt.

ON_INTERRUPT   	Execute an ASSEMBLER subroutine on a HARWARE interrupt.

ON_LOW_INTERRUPT	Execute an ASSEMBLER subroutine when a LOW PRIORITY HARDWARE interrupt occurs on a 16-bit core device.

ON GOSUB	Call a Subroutine based on an Index value. For 16-bit core devices only.

ON GOTO	Jump to an address in code memory based on an Index value. (Primarily for smaller PICmicros)

ON GOTOL	Jump to an address in code memory based on an Index value. (Primarily for larger PICmicros)

OUTPUT	Make a pin an output.

OREAD	Receive data from a device using the Dallas 1-wire protocol.

OWRITE	Send data to a device using the Dallas 1-wire protocol.

ORG	Set Program Origin.

PEEK	Read a byte from a register or variable. Rarely used, now obsolete, command.

PIXEL	Read a single pixel from a Graphic LCD.

PLOT	Set a single pixel on a Graphic LCD.

POKE	Write a byte to register or variable. Rarely used, now obsolete, command.

POT	Read a potentiometer on specified pin.

PRINT	Display characters on an LCD.

PULSIN	Measure the pulse width on a pin.

PULSOUT	Generate a pulse to a pin.

PWM	Output a pulse width modulated pulse train to pin.

RANDOM	Generate a pseudo-random number.

RCIN	Measure a pulse width on a pin.

READ	Read a value from memory.

REM	Add a remark to the source code.

REPEAT...UNTIL	Execute a block of instructions until a condition is true.

RESTORE	 	Adjust the position of data to READ.

RESUME	Re-enable software interrupts and return.

RETURN	Continue at the statement following the last GOSUB.

RSIN     	Asynchronous serial input from a fixed pin and baud rate.

RSOUT   	Asynchronous serial output to a fixed pin and baud rate.

SEED	Seed the random number generator, in order to obtain a more random result.

SELECT..CASE..ENDSELECT	Conditionally run blocks of code.

SERIN	Receive asynchronous serial data (i.e. RS232 data).

SEROUT	Transmit asynchronous serial data (i.e. RS232 data).

SERVO    	Control a servo motor.

SET	Place a variable or bit in a high state.

SET_OSCCAL    	Calibrate the internal oscillator found on some PICmicro devices.

SETBIT	Set a bit of a port or variable, using a variable index.

SHIN    	Synchronous serial input.

SHOUT    	Synchronous serial output.

SLEEP     	Power down the processor for a period of time.

SNOOZE   	Power down the processor for short period of time.

SOUND     	Generate a tone or white-noise on a specified pin.

SOUND2    	Generate 2 tones from 2 separate pins.

STOP     	Stop program execution.

STR	Load a Byte array with values.

STRN	Create a NULL terminated Byte array.

STR$    	Convert the contents of a variable to a NULL terminated String.

SWAP    	Exchange the values of two variables.

SYMBOL    	Create an alias to a constant, port, pin, or register.

TOGGLE	Reverse the state of a port's bit.

UNPLOT   	Clear a single pixel on a Graphic LCD.

USBINIT	Initialise the USB interrupt on devices that contain a USB module.

USBIN	Receive data via a USB endpoint on devices that contain a USB module.

USBOUT	Transmit data via a USB endpoint on devices that contain a USB module.

VAL	Convert a NULL terminated String to an integer value.

VARPTR	Locate the address of a variable.

WHILE…WEND   	Execute statements while condition is true.

XIN	Receive data using the X10 protocol.

XOUT	Transmit data using the X10 protocol.


PICmicro Devices

The compiler supports most of the PICmicro range of devices, and takes full advantage of their various features e.g. The A/D converter in the 16F87x series, the data memory eeprom area in the16F84, the hardware multiply present on the 16-bit core devices etc.

This manual is not intended to give you details about PICmicro devices, therefore, for further information visit the Microchip website at www.microchip.com, and download the multitude of datasheets and application notes available.

Limited 12-bit Device Compatibility.

The 12-bit core PICmicro microcontrollers have been available for a long time, and are at the heart of many excellent, and complex projects. However, with their limited architecture, they were never intended to be used for high level languages such as BASIC. Some of these limits include only a two-level hardware stack and small amounts of general purpose RAM memory. The code page size is also small at 512 bytes. There is also a limitation that calls and computed jumps can only be made to the first half (256 words) of any code page. Therefore, these limitations have made it necessary to eliminate some compiler commands and modify the operation of others.

While many useful programs can be written for the 12-bit core PICmicros using the PROTON+ Compiler, there will be some applications that are not suited to these devices. Choosing a 14-bit core device with more resources will, in most instances, be the best solution.

Commands that are not supported for the 12-bit core PICmicros are illustrated in the table below: -

Command	Reason for omission
DWORDs	Memory limitations
FLOATS	Memory limitations
ADIN	No internal ADCs
CDATA	No write modify feature
CLS	Limited stack size
CREAD	No write modify feature
CURSOR	Limited stack size
CWRITE	No write modify feature
DATA	Page size limitations
DTMFOUT	Limited stack size
EDATA	No on-board EEPROM
EREAD	No on-board EEPROM
EWRITE	No on-board EEPROM
FREQOUT	Limited stack size
LCDREAD	No graphic LCD support
LCDWRITE	No graphic LCD support
LDATA	Page size limitations
LREAD	Page size limitations
HPWM	No 12-bit MSSP modules
HRSIN	No hardware serial port
HRSOUT	No hardware serial port
HSERIN	No hardware serial port
HSEROUT	No hardware serial port
INTERRUPTS	No Interrupts
PIXEL	No graphic LCD support
PLOT	No graphic LCD support
READ	Page size limitations
RESTORE	Limited memory
SEROUT	Limited memory
SERIN	Limited memory
UNPLOT	No graphic LCD support
USBIN	No 12-bit USB devices
USBOUT	No 12-bit USB devices
XIN	Limited stack size
XOUT	Limited stack size

Trying to use any of the above commands with 12-bit core devices will result in the compiler producing numerous SYNTAX errors. If any of these commands are a necessity, then choose a comparable 14-bit core device.

The available commands that have had their operation modified are: -

PRINT, RSOUT, BUSIN, BUSOUT

Most of the modifiers are not supported for these commands because of memory and stack size limitations, this includes the AT , and the STR modifier. However, the @, DEC and DEC3 modifiers are still available.

Programming Considerations for 12-bit Devices.

Because of the limited architecture of the 12-bit core PICmicro microcontrollers, programs compiled for them by PROTON+ will be larger and slower than programs compiled for the 14-bit core devices.

The two main programming limitations that will most likely occur are running out of RAM memory for variables, and running past the first 256 word limit for the library routines.

Even though the compiler arranges its internal SYSTEM variables more intuitively than previous versions, it still needs to create temporary variables for complex expressions etc. It also needs to allocate extra RAM for use as a SOFTWARE-STACK so that the BASIC program is still able to nest GOSUBs up to 4 levels deep.

Some PICmicro devices only have 25 bytes of RAM so there is very little space for user variables on those devices. Therefore, use variables sparingly, and always use the appropriately sized variable for a specific task. i.e. BYTE variable if 0-255 is required, WORD variable if 0-65535 required, BIT  variables if a true or false situation is required. Try to alias any commonly used variables, such as loops or temporary stores etc.

As was mentioned earlier, 12-bit core PICmicro microcontrollers can call only into the first half (256 words) of a code page. Since the compiler's library routines are all accessed by calls, they must reside entirely in the first 256 words of the PICmicro code space. Many library routines, such as BUSIN, are quite large. It may only take a few routines to outgrow the first 256 words of code space. There is no work around for this, and if it is necessary to use more library routines that will fit into the first half of the first code page, it will be necessary to move to a 14-bit core PICmicro instead of the 12-bit core device.

No 32-bit variable support for 12-bit devices.

Because of the profound lack of RAM space available on most 12-bit core devices, the compiler does not allow 32-bit DWORD type variables to be used. For 32-bit support, use on of the many 14, or 16-bit core equivalent devices.

Floating point variables are also not supported with 12-bit core devices.

Compatible 12-bit Devices.

12C508

12C509

12CE508

12CE509

RF509AF

RF509AG

16C54

16C55

16C57

16C58

All the above devices have derivatives such as the 16C54B etc. These are also catered for by the compiler.

Supported devices

12-bit core OTP (One Time Programmable)

12C508, 12C509, 12C508A, 12C509A, 12CE518, 12CE519, 16C54, 16C54A, 16C54B

16C55, 16C55A, 16C56, 16C56A, 16CR56, 16C57, 16C57C, 16CR57A, 16CR57B

16C58,16C58A, 16CR58A, 16CR58B, 16CR58C, RF509AF,RF509AG

12-bit core FLASH (Re-Writable)

10F200, 10F202, 10F204, 10F206, 12F508, 12F509

14-bit core OTP (One Time Programmable)

12C671, 12C672, 12CE673, 12CE674, 16C61, 16C62, 16C62A, 16C62B

16C63, 16C63A, 16C64, 16C64A, 16C65, 16C65A, 16C65B, 16C66, 16C67

16C71, 16C71A, 16C72, 16C72A, 16C73, 16C73A, 16C73B, 16C73C, 16C74

16C74A, 16C76, 16C77, 16C554, 16C554A, 16C558, 16C558A, 16C641

16C642, 16C661, 16C662, 16C710, 16C711, 16C712, 16C715, 16C716

16C745, 16C765, 16C770, 16C771

14-bit core FLASH (Re-Writable)

12F675, 12F629, 16F630, 16C84, 16CR84, 16F72, 16F73, 16F74, 16F76, 16F77

16F83, 16F84, 16F84A, 16F87, 16F88, 16F627, 16F628, 16F627A, 16F628A, 16F648A

16F676, 16F684, 16F688, 16F737, 16F747, 16F767, 16F777, 16F818, 16F819, 16F870

16F871, 16F872, 16F873, 16F873A, 16F874, 16F874A, 16F876, 16F876A, 16F877, 16F877A

16-bit core OTP (One Time Programmable)

18C242, 18C252, 18C442, 18C452, 18C658, 18C858

16-bit FLASH (Re-Writable)

18F1220, 18F1320, 18F2220, 18F2320, 18F2439, 18F2539, 18F242, 18F248, 18F252, 18F258

18F442, 18F448, 18F452, 18F458, 18F4220, 18F4320, 18F4439, 18F4539, 18F4525, 18F6620

18F6720, 18F8620, 18F8720

See also : DEVICE .


Contact Details

For your convenience we have set up a web site www.picbasic.org, where there is a section for users of PROTON BASIC to discuss the compiler, and provide self help with programs written for PROTON BASIC, or download sample programs. The web site is well worth a visit now and then either to learn a bit about how other peoples code works or to request help should you encounter any problems with programs that you have written.

Should you need to get in touch with us for any reason our details are as follows: -

Postal

Crownhill Associates Limited

Old Station Yard

Station Road

Wilburton

Cambridgeshire

CB6 3PZ

Telephone

UK: 01353 749990

Int: +44 1353 749990

Fax: UK: 01353 749991

Int: +44 1353 749991

Email

sales@crownhill.co.uk

Web Sites

http://www.crownhill.co.uk

http://www.picbasic.org


Device Specific issues

Before venturing into your latest project, always read the datasheet for the specific device being used. Because some devices have features that may interfere with expected pin operations. The PIC16C62x and the 16F62x devices are examples of this. These PICmicros have analogue comparators on PORTA. When these chips first power up, PORTA is set to analogue mode. This makes the pin functions on PORTA work in a strange manner. To change the pins to digital, simply add the following line near the front of your BASIC program, or before any of the pins are accessed: -

CMCON = 7

Any PICmicro with analogue inputs, such as the PIC16C7xx, PIC16F87x and PIC12C67x series devices, will power up in analogue mode. If you intend to use them as digital types you must set the pins to digital by using the following line of code: -

ADCON1 = 7

For 18Fxx20 PICmicro devices, or any device that contains more than 8 ADC channels, the ADCON1 register will need to be set to 15: -

ADCON1 = 15

Alternatively, you can use a special command that sets all the pins to digital mode: -

 	ALL_DIGITAL = TRUE

This will set analogue pins to digital on most compatible device. However, Microchip insist on moving registers around and re-arranging how registers work, so the ALL_DIGITAL command may not work on some devices, and the datasheet should be referenced in order to set up the ports.

Another example of potential problems is that bit-4 of PORTA (PORTA.4) exhibits unusual behaviour when used as an output. This is because the pin has an open drain output rather than the usual bipolar stage as in the rest of the output pins. This means it can pull to ground when set to 0 (low), but it will simply float when set to a 1 (high), instead of going high.

To make this pin act as expected, add a pull-up resistor between the pin and 5 Volts. A typical value resistor may be between 1K and 33K, depending on the device it is driving. If the pin is used as an input, it behaves the same as any other pin.

Some PICmicros, such as the PIC16F87x range, allow low-voltage programming. This function takes over one of the PORTB (PORTB.3) pins and can cause the device to act erratically if this pin is not pulled low. In normal use, It's best to make sure that low-voltage programming is disabled at the time the PICmicro is programmed. By default, the low voltage programming fuse is disabled, however, if the CONFIG directive is used, then it may inadvertently be omitted.

All of the PICmicro pins are set to inputs on power-up. If you need a pin to be an output, set it to an output before you use it, or use a BASIC command that does it for you. Once again, always read the PICmicro data sheets to become familiar with the particular part.

The name of the port pins on the 8 pin devices such as the PIC12C50X, PIC12C67x ,12CE67x and 12F675 is GPIO. The name for the TRIS register is TRISIO: -

GPIO.0 = 1	' Set GPIO.0 high

TRISIO = %101010	' Manipulate ins and outs

However, these are also mapped as PORTB, therefore any reference to PORTB on these devices will point to the relevant pin.

Some devices have internal pullup resistors on PORTB, or GPIO. These may be enabled or disabled by issuing the PORTB_PULLUPS command: -

PORTB_PULLUPS = ON	' Enable PORTB pullup resistors

 or

PORTB_PULLUPS = OFF	' Disable PORTB pullup resistors


Identifiers

An identifier is a technical term for a name. Identifiers are used in PROTON+ for line labels, variable names, and constant aliases. An identifier is any sequence of letters, digits, and underscores, although it must not start with a digit. Identifiers are not case sensitive, therefore label, LABEL, and Label are all treated as equivalent. And while labels might be any number of characters in length, only the first 32 are recognised.


Line Labels

In order to mark statements that the program may wish to reference with the GOTO, CALL, or GOSUB commands, PROTON+ uses line labels. Unlike many older BASICs, PROTON+ doesn't allow or require line numbers and doesn't require that each line be labelled. Instead, any line may start with a line label, which is simply an identifier followed by a colon ':'.

LAB:

PRINT "Hello World"

GOTO LAB

Label names can be up to 32 characters in length and may contain any alphanumeric character, but they must not begin with a numeric value. For example: -

LABEL1:

is perfectly valid, however: -

1LABEL:

will produce a syntax error because the labels starts with the value 1.

A label that contains more than 32 characters will produce a syntax error pointing out the offending label.

Underscores are also permitted as part of the label's characters. This helps create more meaningful label names. For example: -

THISISALABEL:

does not have the same clarity of meaning as: -

THIS_IS_A_LABEL:

Bank Resets on Every Label

A PICmicro's RAM memory consists of many banks instead of a single addressable area, and this is a compiler writers nightmare, as well as an assembler writers. However, the compiler has an intuitive bank handling algorithm that will automatically locate the bank for the variable of interest. But, as is the way with all software, it is not infalible, and can sometimes (very rarely) get it wrong. Therefore, if you have the suspicion that something is afoot with the bank handling within your program, you can force a bank reset on every BASIC label. This has the effect of forcing the compiler's bank handling algorithm to re-calculate, but at the cost of code memory increases, as mnemonics will be placed just after each Label. The amount of code memory used, depends on the PICmicro's architecture and it's size. 12-bit and 14-bit PICmicros that contain more RAM will require more bank configuring mnemonics placed. However, the 16-bit core devices have a special mnemonic for setting a bank so the code overhead for one of these devices is minimised.

To force a bank reset on each BASIC label, you must use a DECLARE: -

DECLARE LABEL_BANK_RESETS = ON or OFF, or TRUE or FALSE, or 1, 0

 If nothing else, this declare will reasure you that bank handling is not the cause of the problem, and you can get on with finding the cause of the programming problem. However, if it does cure a problem then please let me know and I will make sure the anomaly is fixed as quickly as possible.

Using this DECLARE will increase the size of the code produced, as it will place BCF mnemonics in the case of a 12 or 14-bit core device, and a MOVLB mnemonic in the case of a 16-bit core device.

The LABEL_BANK_RESETS DECLARE can be issued multiple times within the BASIC code, enabling and disabling the bank resets at key points in the code as and when required.

Line Labels as Address's

Line labels are not simply used as references for GOTO, CALL, or GOSUB, they can also be used to ascertain the place in code memory where data is held using either LDATA or CDATA. This could cause a problem if bank resets are forced by using the LABEL_BANK_RESETS DECLARE because assembler mnemonics will be placed preceding the data label that will alter the actual address of the information.

The compiler will automatically disable any bank reset if an LDATA or CDATA table is place on the same line as the label, however, it cannot auto disable a bank reset if the data table is placed on lines following the label's name. To combat this potential problem, issue the LABEL_BANK_RESETS DECLARE in order to disable bank resets prior to placing either CDATA or LDATA tables. Alternatively, place a minus sign after the label's name in order to disable ANY bank resets for that label.

LABEL_NAME:-	' Disable ANY bank resets

See also :	Identifiers, RESET_BANK.


Variables

Variables are where temporary data is stored in a BASIC program. They are created using the DIM keyword. Because RAM space on PICmicros is somewhat limited in size, choosing the right size variable for a specific task is important. Variables may be BITS, BYTES, WORDS, DWORDS, or FLOATS.

Space for each variable is automatically allocated in the microcontroller's RAM area. The format for creating a variable is as follows: -

DIM Label AS Size

Label is any identifier, (excluding keywords). Size is BIT, BYTE , WORD , DWORD or FLOAT. Some examples of creating variables are: -

DIM Dog AS BYTE	' Create an 8-bit unsigned variable (0 to 255)

DIM Cat AS BIT	' Create a single bit variable (0 or 1)

DIM Rat AS WORD	' Create a 16-bit unsigned variable (0 to 65535)

 	DIM Large_Rat as DWORD	' Create a 32-bit signed variable (-2147483648 to +2147483647)

DIM Pointy_Rat as FLOAT	' Create a 32-bit floating point variable

The number of variables available depends on the amount of RAM on a particular device and the size of the variables within the BASIC program. PROTON+ may reserve approximately 26 RAM locations for its own use. It may also create additional temporary (SYSTEM) variables for use when calculating complex equations, or more complex command structures. Especially if floating point calculations are carried out.

Intuitive Variable Handling.

The compiler handles it's SYSTEM variables intuitively, in that it only creates those that it requires. Each of the compiler's built in library subroutines i.e. PRINT, RSOUT etc, require a certain amount of SYSTEM RAM as internal variables. Previous versions of the compiler defaulted to 26 RAM spaces being created before a program had been compiled. However, with the 12-bit core device compatibility, 26 RAM slots is more than some devices possess.

Try the following program, and look at the RAM usage message on the bottom STATUS bar.

DIM WRD1 AS WORD	' Create a WORD variable i.e. 16-bits

Loop:

HIGH PORTB.0	' Set bit 0 of PORTB high

FOR WRD1= 1 TO 20000 : NEXT	' Create a delay without using a library call

LOW PORTB.0	' Set bit 0 of PORTB high

FOR WRD1= 1 TO 20000 : NEXT	' Create a delay without using a library call

GOTO Loop	' Do it forever

Only two bytes of RAM were used, and those were the ones declared in the program as variable WRD1.

The compiler will increase it's SYSTEM RAM requirements as programs get larger, or more complex structures are used, such as complex expressions, inline commands used in conditions, Boolean logic used etc. However, with the limited RAM space available on some PICmicro devices, every byte counts.

There are certain reserved words that cannot be used as variable names, these are the system variables used by the compiler.

The following reserved words should not be used as variable names, as the compiler will create these names when required: -

PP0, PP0H, PP1, PP1H, PP2, PP2H, PP3, PP3H, PP4, PP4H, PP5, PP5H, PP6, PP6H, PP7, PP7H, PP8, PP9H,GEN, GENH, GEN2, GEN2H, GEN3, GEN3H, GEN4, GEN4H, GPR, BPF, BPFH.

RAM space required.

Each type of variable requires differing amounts of RAM memory for its allocation. The list below illustrates this.

FLOAT 	Requires 4 bytes of RAM.

DWORD 	Requires 4 bytes of RAM.

WORD	Requires 2 bytes of RAM.

BYTE	Requires 1 byte of RAM.

BIT	Requires 1 byte of RAM for every 8 BIT variables used.

Each type of variable may hold a different minimum and maximum value.

FLOAT type variables may theoretically hold a value from -1e37 to +1e38, as well as fractional values, making this the most accurate of the variable family types. However, more so than DWORD types, this comes at a price as FLOAT calculations and comparisons will use more code space within the PICmicro. Use this type of variable sparingly, and only when strictly necessary. Smaller floating point values offer more accuracy.

DWORD type variables may hold a value from -2147483648 to +2147483647. This comes at a price however, as DWORD calculations and comparisons will use more code space within the PICmicro. Use this type of variable sparingly, and only when necessary.

WORD type variables may hold a value from 0 to 65535, which is usually large enough for most applications. It still uses more memory, but not nearly as much as a DWORD type.

BYTE type variables may hold a value for 0 to 255, and are the usual work horses of most programs. Code produced for BYTE sized variables is very low compared to WORD, FLOAT, or DWORD types, and should be chosen if the program requires faster, or more efficient operation.

BIT type variables may hold a 0 or a 1. These are created 8 at a time, therefore declaring a single BIT type variable in a program will not save RAM space, but it will save code space, as BIT type variables produce the most efficient use of code for comparisons etc.

See also :	ALIASES, CONSTANTS, Creating and using ARRAYS, DIM, SYMBOL, Floating Point Math.


Relational Operators

Relational operators are used to compare two values as shown in the list below. The result can be used to make a decision regarding program flow.

Operator 	Relation 	Expression Type

  = 	Equality 	X = Y

  <> 	Inequality 	X <> Y

  < 	Less than 	X < Y

  > 	Greater than 	X > Y

  <= 	Less than or Equal to 	X <= Y

  >= 	Greater than or Equal to 	X >= Y

See also :	IF-THEN-ELSE-ELSEIF-ENDIF, REPEAT-UNTIL, SELECT-CASE, WHILE-WEND.


Floating Point Math

The PROTON+ compiler can perform 32 x 32 bit IEEE 754 'Compliant' Floating Point calculations.

Declaring a variable as FLOAT will enable floating point calculations on that variable.

DIM FLT AS FLOAT

To create a floating point constant, add a decimal point. Especially if the value is a whole number.

SYMBOL PI = 3.14	' Create an obvious floating point constant

SYMBOL FL_NUM = 5.0	' Create a floating point format value of a whole number

Please note. Floating point arithmetic is not the utmost in accuracy, it is merely a means of compressing a complex or large value into a small space (4 bytes in the compiler's case). Perfectly adequate results can usually be obtained from correct scaling of integer variables, with an increase in speed and a saving of RAM and code space. 32 bit floating point math is extremely microcontroller intensive since the PICmicro is only an 8 bit processor. It also consumes large amounts of RAM, and code space for its operation, therefore always use floating point sparingly, and only when strictly necessary. Floating point is not available on 12-bit core PICmicros because of memory restrictions, and is most efficient when used with 16-bit core devices because of the more linear code and RAM specifications.

Floating Point Format

The PROTON+ compiler uses the Microchip variation of IEEE 754 floating point format. The differences to standard IEEE 745 are minor, and well documented in Microchip application note AN575 (downloadable from www.microchip.com).

Floating point numbers are represented in a modified IEEE-754 format. This format allows the floating-point routines to take advantage of the PICmicro's architecture and reduce the amount of overhead required in the calculations. The representation is shown below compared to the IEEE-754 format: where s is the sign bit, y is the LSb of the exponent and x is a placeholder for the mantissa and exponent bits.

The two formats may be easily converted from one to the other by manipulation of the Exponent and Mantissa 0 bytes. The following assembly code shows an example of this operation.

Format 	Exponent 	Mantissa 0 	Mantissa 1 	Mantissa 2

IEEE-754 	sxxx xxxx 	yxxx xxxx 	xxxx xxxx 	xxxx xxxx

Microchip 	xxxx xxxy 	sxxx xxxx 	xxxx xxxx 	xxxx xxxx

IEEE-754 TO MICROCHIP

RLF MANTISSA0

RLF EXPONENT

RRF MANTISSA0

MICROCHIP TO IEEE-754

RLF MANTISSA0

RRF EXPONENT

RRF MANTISSA0

Variables Used by the Floating Point Libraries.

Several 8-bit RAM registers are used by the math routines to hold the operands for and results of floating point operations. Since there may be two operands required for a floating point operation (such as multiplication or division), there are two sets of exponent and mantissa registers reserved (A and B). For argument A, PBP_AARGHHH holds the exponent and PBP_AARGHH, PBP_AARGH and PBP_AARG hold the mantissa. For argument B, PBP_BARGHHH holds the exponent and PBP_BARGHH, PBP_BARGH and PBP_BARG hold the mantissa.

Floating Point Example Programs

' Multiply two floating point values

DEVICE = 18F452

XTAL = 4

DIM FLT AS FLOAT

SYMBOL FL_NUM = 1.234	' Create a floating point constant value

CLS

FLT = FL_NUM *10

PRINT DEC FLT

STOP

' Add two floating point variables

DEVICE = 18F452

XTAL = 4

DIM FLT AS FLOAT

DIM FLT1 AS FLOAT

DIM FLT2 AS FLOAT

CLS

FLT1 = 1.23

FLT2 = 1000.1

FLT = FLT1 + FLT2

PRINT DEC FLT

STOP

' A digital voltmeter, using the on-board ADC

DEVICE = 16F877

XTAL = 4

ADIN_RES = 10 	' 10-bit result required

ADIN_TAD = FRC 	' RC OSC chosen

ADIN_DELAY = 50 	' Allow 50us sample time

DIM RAW AS WORD

DIM VOLTS AS FLOAT

SYMBOL QUANTA = 5.0 / 1024	' Calculate the quantising value

CLS

TRISA = %00000001 	' Configure AN0 (PORTA.0) as an input

ADCON1 = %10000000 	' Set analogue input on PORTA.0

AGAIN:

RAW = ADIN 0

VOLTS = RAW * QUANTA

PRINT AT 1,1,DEC2 VOLTS,"V    "

GOTO AGAIN

Notes

Floating point expressions containing more than 3 operands are not allowed, due to the extra RAM space required for a software stack.

Any expression that contains a floating point variable or value will be calculated as a floating point. Even if the expression also contains a BYTE, WORD, or DWORD  value or variable.

If the assignment variable is a BYTE, WORD, or DWORD  variable, but the expression is of a floating point nature. Then the floating point result will be converted into an integer.

DEVICE = 16F877

DIM DWD AS DWORD

DIM FLT AS FLOAT

SYMBOL PI = 3.14

FLT = 10

DWD = FLT + PI	' Float calculation will result in 13.14, but will be reduced to integer 13

PRINT DEC DWD	' Display the integer result 13

STOP

For a more in-depth explanation of floating point, download the Microchip application notes AN575, and AN660. These can be found at www.microchip.com.

Code space requirements.

As mentioned above, floating point accuracy comes at a price of speed, and code space. Both these issues are not a problem if a 16-bit core device is used, however 14-bit core devices can pose a problem. The compiler attempts to load the floating point libraries into low memory, along with all the other library subroutines, but if it does not fit within the first 2048 bytes of code space, and the PICmicro has more than 2048 bytes of code available, the floating point libraries will be loaded into the top 1000 bytes of code memory. This is invisible to the user, however, the compiler will warn that this is occurring in case that part of memory is being used by your BASIC program.

More Accurate Display or Conversion of Floating Point values.

By default, the compiler uses a relatively small routine for converting floating point values to decimal, ready for RSOUT, PRINT STR$ etc. However, because of its size, it does not perform any rounding of the value first, and is only capable of converting relatively small values. i.e. approx 6 digits of accuracy. In order to produce a more accurate result, the compiler needs to use a larger routine. This is implemented by using a DECLARE: -

FLOAT_DISPLAY_TYPE = LARGE or STANDARD

Using the LARGE model for the above declare will trigger the compiler into using the more accurate floating point to decimal routine. Note that even though the routine is larger than the standard converter, it actually operates much faster.

The compiler defaults to STANDARD if the DECLARE is not issued in the BASIC program.

See also : DIM, SYMBOL, ALIASES, ARRAYS, CONSTANTS.


Aliases

The SYMBOL directive is the primary method of creating an alias, however DIM can also be used to create an alias to a variable. This is extremely useful for accessing the separate parts of a variable.

DIM Fido as Dog	' Fido is another name for Dog

DIM Mouse as Rat.LOWBYTE	' Mouse is the first byte (low byte) of word Rat

DIM Tail as Rat.HIGHBYTE	' Tail is the second byte (high byte) of word Rat

DIM Flea as Dog.0	' Flea is bit-0 of Dog

There are modifiers that may also be used with variables. These are HIGHBYTE, LOWBYTE, BYTE0, BYTE1, BYTE2, BYTE3, WORD0, and WORD1.

WORD0, WORD1, BYTE2, and BYTE3 may only be used in conjunction with a 32-bit DWORD , or FLOAT type variable.

HIGHBYTE and BYTE1 are one and the same thing, when used with a WORD type variable, they refer to the High byte of a WORD type variable: -

DIM WRD as WORD	' Declare a WORD sized variable

DIM WRD_HI as WRD.HIGHBYTE	' WRD_HI now represents the HIGHBYTE of variable WRD

Variable WRD_HI is now accessed as a BYTE sized type, but any reference to it actually alters the high byte of WRD.

However, if BYTE1 is used in conjunction with a DWORD type variable, it will extract the second byte. HIGHBYTE will still extract the high byte of the variable, as will BYTE3.

The same is true of LOWBYTE and BYTE0, but they refer to the Low Byte of a WORD type variable: -

DIM WRD as WORD	' Declare a WORD sized variable

DIM WRD_LO as WRD.LOWBYTE	' WRD_LO now represents the LOWBYTE of variable WRD

Variable WRD_LO is now accessed as a BYTE sized type, but any reference to it actually alters the low byte of WRD.

The modifier BYTE2 will extract the 3rd byte from a 32-bit DWORD type variable, as an alias. Likewise BYTE3 will extract the high byte of a 32-bit variable.

DIM DWD as DWORD	' Declare a 32-bit variable named DWD

DIM PART1 as DWD.BYTE0	' Alias PART1 to the low byte of DWD

DIM PART2 as DWD.BYTE1	' Alias PART2 to the 2nd byte of DWD

DIM PART3 as DWD.BYTE2	' Alias PART3 to the 3rd byte of DWD

DIM PART4 as DWD.BYTE3	' Alias PART3 to the high (4th) byte of DWD

The WORD0 and WORD1 modifiers extract the low word and high word of a DWORD type variable, and is used the same as the BYTEn modifiers.

DIM DWD as DWORD	' Declare a 32-bit variable named DWD

DIM PART1 as DWD.WORD0	' Alias PART1 to the low word of DWD

DIM PART2 as DWD.WORD1	' Alias PART2 to the high word of DWD

RAM space for variables is allocated within the PICmicro in the order that they are placed in the BASIC code. For example: -

DIM VAR1 as BYTE

DIM VAR2 as BYTE

Places VAR1 first, then VAR2: -

VAR1 EQU n

VAR2 EQU n

This means that on a PICmicro with more than one BANK, the first n variables will always be in BANK0 (the value of n depends on the specific PICmicro used).

Finer points for variable handling.

The position of the variable within BANKs is usually of little importance if BASIC code is used, however, if assembler routines are being implemented, always assign any variables used within them first.

Problems may also arise if a WORD, DWORD, or FLOAT variable crosses a BANK boundary. If this happens, a warning message will be displayed in the error window. Most of the time, this will not cause any problems, however, to err on the side of caution, try and ensure that WORD, DWORD, or FLOAT type variables are fully inside a BANK. This is easily accomplished by placing a dummy BYTE variable before the offending variable, or relocating the offending variable within the list of DIM statements.

WORD type variables have a low byte and a high byte. The high byte may be accessed by simply adding the letter H to the end of the variable's name. For example: -

DIM WRD as WORD

Will produce the assembler code: -

WRD EQU n

WRDH EQU n

To access the high byte of variable WRD, use: -

WRDH = 1

This is especially useful when assembler routines are being implemented, such as: -

MOVLW 1

MOVWF WRDH 	; Load the high byte of WRD with 1

DWORD and FLOAT type variables have a low, mid1, mid2, and hi byte. The high byte may be accessed by adding three letter H's to the variable's name. For example: -

DIM DWD as DWORD

Will produce the assembler code: -

DWD EQU n

DWDH EQU n

DWDHH EQU n

DWDHHH EQU n

To access the high byte of variable WRD, use: -

DWDHHH = 1

or

DWD.HIGHBYTE = 1

The low, and mid bytes may be similarly accessed by adding or removing the "H" after the variable's name.

See also :	DIM, CONSTANTS, Identifiers, SYMBOL.


Constants

Named constants may be created in the same manner as variables. It can be more informative to use a constant name instead of a constant number. Once a constant is declared, it cannot be changed later, hence the name 'constant'.

DIM Label as Constant expression

DIM MOUSE as 1

DIM MICE as MOUSE * 400

DIM MOUSE_PI as MOUSE + 3.14

Although DIM can be uses to create constants, SYMBOL is more often used.

See also :	DIM, Identifiers, SYMBOL.


Symbols

SYMBOL provides yet another method for aliasing variables and constants. SYMBOL cannot be used to create a variable. Constants declared using SYMBOL do not use any RAM within the PICmicro.

SYMBOL CAT = 123

SYMBOL TIGER = CAT	' TIGER now holds the value of CAT

SYMBOL MOUSE = 1	' Same as DIM Mouse AS 1

SYMBOL TIGOUSE = TIGER + MOUSE ' Add Tiger to Mouse to make Tigouse

Floating point constants may also be created using SYMBOL by simply adding a decimal point to a value.

SYMBOL PI = 3.14	' Create a floating point constant named PI

SYMBOL FL_NUM = 5.0	' Create a floating point constant holding the value 5

Floating point constant can also be created using expressions.

SYMBOL QUANTA = 5.0 / 1024	' Create a floating point constant holding the result of the expression

If a variable or register's name is used in a constant expression then the variable's or register's address will be substituted, not the value held in the variable or register: -

SYMBOL CONST = (PORTA + 1)	' CONST will hold the value 6 (5+1)

SYMBOL is also useful for aliasing Ports and Registers: -

SYMBOL LED = PORTA.1	' LED now references bit-1 of PORTA

SYMBOL T0IF = INTCON.2	' T0IF now references bit-2 of INTCON register

The equal sign between the Constant's name and the alias value is optional: -

SYMBOL LED PORTA.1	' Same as SYMBOL LED=PORTA.1

See also :	ALIASES, ARRAYS, CONSTANTS, DIM, SYMBOL, Floating Point Math, Identifiers.


Numeric Representations

PROTON+ recognises four different number representations: -

Binary is prefixed by %. i.e. %0101

Hexadecimal is prefixed by $. i.e. $0A

Character byte is surrounded by quotes. i.e. "a" represents a value of 97

Decimal values need no prefix.

Floating point is created by using a decimal point. i.e. 3.14


Ports and other Registers
Ports and Hardware Registers

All of the PICmicro registers, including the ports, can be accessed just like any other byte-sized variable. This means that they can be read from, written to or used in equations directly:

PORTA = %01010101	' Write value to PORTA

VAR1 = WRD * PORTA	' Multiply variable WRD with the contents of PORTA

The compiler can also combine16-bit registers such as TMR1 into a WORD type variable. Which makes loading and reading these registers simple: -

DIM TIMER1 AS TMR1L.WORD	' Combine TMR1L, and TMR1H into WORD variable TIMER1

TIMER1 = 12345	' Load TMR1 with value 12345

or

WRD1 = TIMER1	' Load WRD1 with contents of TMR1

The .WORD extension links registers TMR1L, and TMR1H, (which are assigned in the .LBP file associated with relevant PICmicro used).

Any hardware register that can hold a 16-bit result can be assigned as a WORD type variable: -

DIM TIMER3 AS TMR3L.WORD	' Combine TMR3L, and TMR3H into WORD variable TIMER3

DIM AD_RESULT AS ADRES.WORD	' Combine ADRESL, and ADRESH into WORD variable AD_RESULT

DIM MUL_PROD AS PRODL.WORD	' Combine PRODL, and PRODH into WORD variable MUL_PROD


General Format

The compiler is not case sensitive, except when processing string constants such as "hello".

Multiple instructions and labels can be combined on the same line by separating them with colons ':'.

The examples below show the same program as separate lines and as a single-line...

Multiple-line version: -

TRISB = %00000000 	' Make all pins on PORTB outputs

FOR VAR1 = 0 TO 100 	' Count from 0 to 100

PORTB = VAR1 	' Make PORTB = count (VAR1)

NEXT 	' Continue counting until 100 is reached

Single-line version: -

TRISB = %00000000 : FOR VAR1 = 0 TO 100 : PORTB = VAR1 : NEXT

Line Continuation Character '_'

Lines that are too long to display, may be split using the continuation character '_'. This will direct the continuation of a command to the next line. It's use is only permitted after a comma delimiter: -

VAR1 = LOOKUP VAR2,[1,2,3,_

4,5,6,7,8]

or

PRINT AT 1,1,_

"HELLO WORLD",_

DEC VAR1,_

HEX VAR2


Inline Commands within Expressions

A very useful addition to the compiler is the ability to mix INLINE commands into expressions. For example, to convert a serial value into it's ASCII counterpart, 48 must be added to it. The previous method of accomplishing this was by: -

VAR1 = RSIN

VAR1 = VAR1 + 48

Now, the RSIN command may become part of the expression: -

VAR1 = RSIN + 48

Another example is using the INKEY command, again to convert the numeric result produced into ASCII: -

VAR1 = INKEY + "0"

These may then be integrated into a condition: -

IF (INKEY + 48) = "1" THEN do something

or

WHILE (INKEY + 48) = "2"

do some code

WEND

Yet another example integrates eeprom data into an expression: -

EDATA 20	' Place the value 20 into eeprom

VAR1 = (EREAD 0) + 40	' Add 40 to the value held at eeprom address 0

Yet another useful feature is again to the in-line commands: -

ADIN, BUSIN, COUNTER, DIG, EREAD, HBUSIN, INKEY, LCDREAD, LOOKDOWN, LOOKDOWNL, LOOKUP, LOOKUPL, PIXEL, POT, PULSIN, RANDOM, SHIN, RCIN, RSIN etc.

All these commands may be used in an IF-THEN, WHILE-WEND, or REPEAT-UNTIL structure. For example, with the previous versions of the compiler, to read a key using the INKEY command required a two stage process: -

VAR1 = INKEY

IF VAR1 = 12 THEN { do something }

Now, the structure: -

IF INKEY = 12 THEN { do something }

is perfectly valid. And so is: -

IF ADIN 0 = 1020 THEN { do something }	' Test the ADC from channel 0

The new structure of the in-line commands does not always save code space, however, it does make the program easier to write, and a lot easier to understand, or debug if things go wrong.

The LOOKUP, LOOKUPL, LOOKDOWN, and LOOKDOWNL commands may also use another in-line command instead of a variable. For example, to read and re-arrange a keypress from a keypad: -

KEY = LOOKUP INKEY, [1,2,3,15,4,5,6,14,7,8,9,13,10,0,11,12,255]

In-line command differences do not stop there. They may now also be used for display purposes in the RSOUT, SEROUT, HRSOUT, and PRINT commands: -

LABEL: RSOUT LOOKUP INKEY, [1,2,3,15,4,5,6,14,7,8,9,13,10,0,11,12,255] : GOTO LABEL

How's that for a simple serial keypad program. Or: -

WHILE 1 = 1 : PRINT RSIN : WEND

Believe it or not, the above single line of code is a simple serial LCD controller. Accepting serial data through the RSIN command, and displaying the data with the PRINT command.

See also :	IF-THEN.


Creating and using Arrays

The PROTON+ compiler supports multi part BYTE, and WORD variables named arrays. An array is a group of variables of the same size (8-bits wide, or 16-bits wide), sharing a single name, but split into numbered cells, called elements.

An array is defined using the following syntax: -

DIM Name[ length ] AS BYTE

DIM Name[ length ] AS WORD

where Name is the variable's given name, and the new argument, [ length ], informs the compiler how many elements you want the array to contain. For example: -

DIM MYARRAY[10] AS BYTE 	' Create a 10 element byte array.

DIM MYARRAY[10] AS WORD 	' Create a 10 element word array.

A unique feature of the compiler is the ability to allow up to 256 elements within a BYTE array, and 128 elements in a WORD array. However, because of the rather complex way that some PICmicro's RAM cells are organised (i.e. BANKS), there are a few rules that need to be observed when creating arrays.

PICmicro Memory Map Complexities.

Larger PICmicros have more RAM available for variable storage, however, accessing the RAM on the 14-bit core devices is not as straightforward as one might expect. The RAM is organised in BANKS, where each BANK is 128 bytes in length. Crossing these BANKs requires bits 5 and 6 of the STATUS register to be manipulated. The larger PICmicros such as the 16F877 device have 512 RAM locations, but only 368 of these are available for variable storage, the rest are known as SYSTEM REGISTERS and are used to control certain aspects of the PICmicro i.e. TRIS, IO ports, UART etc. The compiler attempts to make this complex system of BANK switching as transparent to the user as possible, and succeeds where standard BIT, BYTE, WORD , and DWORD variables are concerned. However, ARRAY variables will inevitably need to cross the BANKS in order to create arrays larger than 96 bytes, which is the largest section of RAM within BANK0. Coincidently, this is also the largest array size permissible by most (if not all) other compilers at the time of writing this section.

Large arrays (normally over 96 elements) require that their STARTING address be located within the first 255 bytes of RAM (i.e. within BANK0 and BANK2), the array itself may cross this boundary. This is easily accomplished by declaring them at, or near the top of the list of variables. The Compiler does not manipulate the variable declarations. If a variable is placed first in the list, it will be placed in the first available RAM slot within the PICmicro. This way, you, the programmer maintains finite control of the variable usage. For example, commonly used variables should be placed near the top of the list of declared variables. An example of declaring an array is illustrated below: -

DEVICE 16F877	' Choose a PICmicro with extra RAM

DIM SMALL_ARRAY[20] AS BYTE	' Create a small array of 20 elements

DIM VAR1 AS BYTE	' Create a standard BYTE variable

DIM LARGE_ARRAY[256] AS BYTE	' Create a BYTE array of 256 elements

or

DIM ARRAY1[120] AS BYTE	' Create an array of 120 elements

DIM ARRAY2[100] AS BYTE	' Create another smaller array of 100 elements

If an array cannot be resolved, then a warning will be issued informing you of the offending line:

WARNING Array 'array name' is declared at address 'array address'. Which is over the 255 RAM address limit, and crosses BANK3 boundary!

Ignoring this warning will spell certain failure of your program.

The following array declaration will produce a warning when compiled for a 16F877 device: -

DEVICE 16F877	' Choose a PICmicro with extra RAM

DIM ARRAY1[200] AS BYTE	' Create an array of 200 elements

DIM ARRAY2[100] AS BYTE	' Create another smaller array of 100 elements

Examining the assembler code produced, will reveal that ARRAY1 starts at address 32 and finishes at address 295. This is acceptable and the compiler will not complain. Now look at ARRAY2, its start address is at 296 which is over the 255 address limit, thus producing a warning message.

The above warning is easily remedied by re-arranging the variable declaration list: -

DIM ARRAY2[100] AS BYTE	' Create a small array of 100 elements

DIM ARRAY1[200] AS BYTE	' Create an array of 200 elements

Again, examining the asm code produced, now reveals that ARRAY2 starts at address 32 and finishes at address 163. everything OK there then. And ARRAY1 starts at address 164 and finishes at address 427, again, its starting address was within the 255 limit so everything's OK there as well, even though the array itself crossed several BANKs. A simple re-arrangement of code meant the difference between a working and not working program.

Of course, the smaller PICmicro devices do not have this limitation as they do not have 255 RAM cells anyway. Therefore, arrays may be located anywhere in the variable declaration list. The same goes for the 16-bit core devices, as these can address any area of their RAM.

16-bit core simplicity.

The 16-bit core devices i.e. PIC18XXX, have no such complexities in their memory map as the 14-bit core devices do. The memory is still banked, but each bank is 256 bytes in length, and runs linearly from one to the other. Add to that, the ability to access all RAM areas using indirect addressing, makes arrays extremely easy to use. If many large arrays are required in a program, then the 16-bit core devices (especially the Flash types) are highly recommended.

Once an array is created, its elements may be accessed numerically. Numbering starts at 0 and ends at n-1. For example: -

MYARRAY [3] = 57

PRINT "MYARRAY[3] = " , DEC MYARRAY[3]

The above example will access the fourth element in the BYTE array and display "MYARRAY[3] = 57" on the LCD. The true flexibility of arrays is that the index value itself may be a variable. For example: -

DEVICE 16F84	' We'll use a smaller device this time

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

DIM INDEX AS BYTE 	' Create a normal BYTE variable.

FOR INDEX = 0 TO 9 	' Repeat with INDEX= 0,1,2...9

MYARRAY[INDEX] = INDEX * 10 	' Write INDEX*10 to each element of the array.

NEXT

FOR INDEX = 0 TO 9 	' Repeat with INDEX= 0,1,2...9

PRINT AT 1 , 1 , DEC MYARRAY [INDEX] 	' Show the contents of each element.

DELAYMS 500	' Wait long enough to view the values

NEXT

STOP

If the above program is run, 10 values will be displayed, counting from 0 to 90 i.e. INDEX * 10.

A word of caution regarding arrays: If you're familiar with other BASICs and have used their arrays, you may have run into the "subscript out of range" error. Subscript is simply another term for the index value. It is considered 'out-of range' when it exceeds the maximum value for the size of the array.

For example, in the example above, MYARRAY is a 10-element array. Allowable index values are 0 through 9. If your program exceeds this range, the compiler will not respond with an error message. Instead, it will access the next RAM location past the end of the array.

If you are not careful about this, it can cause all sorts of subtle anomalies, as previously loaded variables are overwritten. It's up to the programmer (you!) to help prevent this from happening.

Even more flexibility is allowed with arrays because the index value may also be an expression:

DEVICE 16F84	' We'll use a smaller device

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

DIM INDEX AS BYTE 	' Create a normal BYTE variable.

FOR INDEX = 0 TO 8 	' Repeat with INDEX= 0,1,2...8

MYARRAY[INDEX + 1] = INDEX * 10 	' Write INDEX*10 to each element of the array.

NEXT

FOR INDEX = 0 TO 8 	' Repeat with INDEX= 0,1,2...8

PRINT AT 1 , 1 , DEC MYARRAY [INDEX + 1] 	' Show the contents of each element.

DELAYMS 500	' Wait long enough to view the values

NEXT

STOP

The expression within the square braces should be kept simple, and arrays are not allowed as part of the expression.

Using Arrays in Expressions.

Of course, arrays are allowed within expressions themselves. For example: -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

DIM INDEX AS BYTE 	' Create a normal BYTE variable.

DIM VAR1 AS BYTE	' Create another BYTE variable

DIM Result AS BYTE	' Create a variable to hold the result of the expression

INDEX = 5	' And INDEX now holds the value 5

VAR1 = 10	' Variable VAR1 now holds the value 10

MYARRAY[INDEX] = 20	' Load the 6th element of MYARRAY with value 20

Result = ( VAR1 * MYARRAY[INDEX] ) / 20	' Do a simple expression

PRINT AT 1 , 1 , DEC Result , " "	' Display the result of the expression

STOP

The above example will display 10 on the LCD, because the expression reads as: -

(10 * 20) / 20

VAR1 holds a value of 10, MYARRAY[INDEX] holds a value of 20, these two variables are multiplied together which will yield 200, then they're divided by the constant 20 to produce a result of 10.


Arrays as Strings

Arrays may also be used as simple strings in certain commands, because after all, a string is simply a byte array used to store text.

For this, the STR modifier is used.

The commands that support the STR modifier are: -

BUSOUT - BUSIN

HBUSOUT - HBUSIN

HRSOUT - HRSIN

OWRITE - OREAD

RSOUT - RSIN

SEROUT - SERIN

SHOUT - SHIN

PRINT

The STR modifier works in two ways, it outputs data from a pre-declared array in commands that send data i.e. RSOUT, PRINT etc, and loads data into an array, in commands that input information i.e. RSIN, SERIN etc. The following examples illustrate the STR modifier in each compatible command.

Using STR with the BUSIN and BUSOUT commands.

Refer to the sections explaining the BUSIN and BUSOUT commands.

Using STR with the HBUSIN and HBUSOUT commands.

Refer to the sections explaining the HBUSIN and HBUSOUT commands.

Using STR with the RSIN command.

DIM ARRAY1[10] AS BYTE 	' Create a 10-byte array named ARRAY1

RSIN STR ARRAY1	' Load 10 bytes of data directly into ARRAY1

Using STR with the RSOUT command.

DIM ARRAY1[10] AS BYTE 	' Create a 10-byte array named ARRAY1

RSOUT STR ARRAY1	' Send 10 bytes of data directly from ARRAY1

Using STR with the HRSIN and HRSOUT commands.

Refer to the sections explaining the HRSOUT and HRSIN commands.

Using STR with the SHOUT command.

SYMBOL DTA = PORTA.0	' Define the two lines for the SHOUT command

SYMBOL CLK = PORTA.1

DIM ARRAY1[10] AS BYTE 	' Create a 10-byte array named ARRAY1

SHOUT DTA, CLK, MSBFIRST, [ STR ARRAY1 ]	' Send 10 bytes of data from ARRAY1

Using STR with the SHIN command.

SYMBOL DTA = PORTA.0	' Define the two lines for the SHIN command

SYMBOL CLK = PORTA.1

DIM ARRAY1[10] AS BYTE 	' Create a 10-byte array named ARRAY1

SHIN DTA, CLK, MSBPRE , [ STR ARRAY1 ]	' Load 10 bytes of data directly into ARRAY1

Using STR with the PRINT command.

DIM ARRAY1[10] AS BYTE 	' Create a 10-byte array named ARRAY1

PRINT STR ARRAY1	' Send 10 bytes of data directly from ARRAY1

Using STR with the SEROUT and SERIN commands.

Refer to the sections explaining the SERIN and SEROUT commands.

Using STR with the OREAD and OWRITE commands.

Refer to the sections explaining the OREAD and OWRITE commands.

The STR modifier has two forms for variable-width and fixed-width data, shown below: -

STR byte array ASCII string from byte array until byte = 0 (NULL terminated).

Or array length is reached.

STR byte array\n ASCII string consisting of n bytes from byte array.

NULL terminated means that a zero (NULL) is placed at the end of the string of ASCII characters to signal that the string has finished.

The example below is the variable-width form of the STR modifier: -

DIM MYARRAY[5] AS BYTE	' Create a 5 element array

MYARRAY[0] = "A"	' Fill the array with ASCII

MYARRAY[1] = "B"

MYARRAY[2] = "C"

MYARRAY[3] = "D"

MYARRAY[4] = 0	' Add the NULL Terminator

PRINT STR MYARRAY	' Display the string

The code above displays "ABCD" on the LCD. In this form, the STR formatter displays each character contained in the byte array until it finds a character that is equal to 0 (value 0, not ASCII "0"). NOTE: If the byte array does not end with 0 (NULL), the compiler will read and output all RAM register contents until it cycles through all RAM locations for the declared length of the byte array.

For example, the same code as before without a NULL terminator is: -

DIM MYARRAY[4] AS BYTE	' Create a 4 element array

MYARRAY[0] = "A"	' Fill the array with ASCII

MYARRAY[1] = "B"

MYARRAY[2] = "C"

MYARRAY[3] = "D"

PRINT STR MYARRAY	' Display the string

The code above will display the whole of the array, because the array was declared with only four elements, and each element was filled with an ASCII character i.e. "ABCD".

To specify a fixed-width format for the STR modifier, use the form STR MYARRAY\n; where MYARRAY is the byte array and n is the number of characters to display, or transmit. Changing the PRINT line in the examples above to: -

PRINT STR MYARRAY \ 2

would display "AB" on the LCD.

STR is not only used as a modifier, it is also a command, and is used for initially filling an array with data. The above examples may be re-written as: -

DIM MYARRAY[5] AS BYTE	' Create a 5 element array

STR MYARRAY = "ABCD" , 0	' Fill the array with ASCII, and NULL terminate it

PRINT STR MYARRAY	' Display the string

Strings may also be copied into other strings: -

DIM String1[5] AS BYTE	' Create a 5 element array

DIM String2[5] AS BYTE	' Create another 5 element array

STR String1 = "ABCD" , 0	' Fill the array with ASCII, and NULL terminate it

STR String2 = "EFGH" , 0	' Fill the other array with ASCII, and NULL terminate it

STR String1 = STR String2	' Copy String2 into String1

PRINT STR String1	' Display the string

The above example will display "EFGH", because String1 has been overwritten by String2.

Using the STR command with BUSOUT, HBUSOUT, SHOUT, and OWRITE differs from using it with commands SEROUT, PRINT, HRSOUT, and RSOUT in that, the latter commands are used more for dealing with text, or ASCII data, therefore these are NULL terminated.

The HBUSOUT, BUSOUT, SHOUT, and OWRITE commands are not commonly used for sending ASCII data, and are more inclined to send standard 8-bit bytes. Thus, a NULL terminator would cut short a string of byte data, if one of the values happened to be a 0. So these commands will output data until the length of the array is reached, or a fixed length terminator is used i.e. MYARRAY\n.

See also :	STRN, STR$, VAL.


BOOLEAN LOGIC OPERATORS

The IF-THEN-ELSE-ENDIF, WHILE-WEND, and REPEAT-UNTIL conditions now support the logical operators NOT, AND, OR, and XOR. The NOT operator inverts the outcome of a condition, changing false to true, and true to false. The following two IF-THEN conditions are equivalent: -

IF VAR1 <> 100 THEN NotEqual 	' Goto notEqual if VAR1 is not 100.

IF NOT VAR1 = 100 THEN NotEqual	' Goto notEqual if VAR1 is not 100.

The operators AND, OR, and XOR join the results of two conditions to produce a single true/false result. AND and OR work the same as they do in everyday speech. Run the example below once with AND (as shown) and again, substituting OR for AND: -

DIM VAR1 AS BYTE

DIM VAR2 AS BYTE

CLS

VAR1 = 5

VAR2 = 9

IF VAR1 = 5 AND VAR2 = 10 THEN Res_True

STOP

Res_True:

PRINT "RESULT IS TRUE."

STOP

The condition "VAR1 = 5 AND VAR2 = 10" is not true. Although VAR1 is 5, VAR2 is not 10. AND works just as it does in plain English, both conditions must be true for the statement to be true. OR also works in a familiar way; if one or the other or both conditions are true, then the statement is true. XOR (short for exclusive-OR) may not be familiar, but it does have an English counterpart: If one condition or the other (but not both) is true, then the statement is true.

Parenthesis (or rather the lack of it!).

Every compiler has it's quirky rules, and the PROTON+ compiler is no exception. One of its quirks means that parenthesis is

not supported in a Boolean condition, or indeed with any of the IF-THEN-ELSE-ENDIF, WHILE-WEND, and REPEAT-UNTIL conditions. Parenthesis in an expression within a condition is allowed however. So, for example, the expression: -

IF (VAR1 + 3) = 10 THEN do something. 	Is allowed.

But: -

IF( (VAR1 + 3) = 10) THEN do something. 	Is NOT allowed.

The Boolean operands do have a precedence in a condition. The AND operand has the highest priority, then the OR, then the XOR.

This means that a condition such as: -

IF VAR1 = 2 AND VAR2 = 3 OR VAR3 = 4 THEN do something

Will compare VAR1 and VAR2 to see if the AND condition is true. It will then see if the OR condition is true, based on the result of the AND condition.

THEN operand always required.

The PROTON+ compiler relies heavily on the THEN part. Therefore, if the THEN part of a condition is left out of the code listing, a SYNTAX ERROR will be produced.


Creating and using VIRTUAL STRINGS with CDATA

Some PICmicros such as the 16F87x range and all the 18FXXX range, have the ability to read and write to their own flash memory. And although writing to this memory too many times is unhealthy for the PICmicro, reading this memory is both fast, and harmless. Which offers a unique form of data storage and retrieval, the CDATA command proves this, as it uses the mechanism of reading and storing in the PICmicro's flash memory.

Combining the unique features of the 'self modifying PICmicros ' with a string format, the compiler is capable of reducing the overhead of printing, or transmitting large amounts of text data. The CSTR modifier may be used in commands that deal with text processing i.e. PRINT, SEROUT, HRSOUT, and RSOUT.

The CSTR modifier is used in conjunction with the CDATA command. The CDATA command is used for initially creating the string of characters: -

STRING1: CDATA "HELLO WORLD" , 0

The above line of code will create, in flash memory, the values that make up the ASCII text "HELLO WORLD", at address STRING1. Note the NULL terminator after the ASCII text.

NULL terminated means that a zero (NULL) is placed at the end of the string of ASCII characters to signal that the string has finished.

To display, or transmit this string of characters, the following command structure could be used:

PRINT CSTR STRING1

The label that declared the address where the list of CDATA values resided, now becomes the string's name. In a large program with lots of text formatting, this type of structure can save quite literally hundreds of bytes of valuable code space.

Try both these small programs, and you'll see that using CSTR saves a few bytes of code: -

First the standard way of displaying text: -

DEVICE 16F877

CLS

PRINT "HELLO WORLD"

PRINT "HOW ARE YOU?"

PRINT "I AM FINE!"

STOP

Now using the CSTR modifier: -

CLS

PRINT CSTR TEXT1

PRINT CSTR TEXT2

PRINT CSTR TEXT3

STOP

TEXT1: CDATA "HELLO WORLD" , 0

TEXT2: CDATA "HOW ARE YOU?" , 0

TEXT3: CDATA "I AM FINE!" , 0

Again, note the NULL terminators after the ASCII text in the CDATA commands. Without these, the PICmicro will continue to transmit data in an endless loop.

The term 'virtual string' relates to the fact that a string formed from the CDATA command cannot (rather should not) be written too, but only read from.

Not only label names can be used with the CSTR modifier, constants, variables and expressions can also be used that will hold the address of the CDATA's label (a pointer). For example, the program below uses a WORD size variable to hold 2 pointers (address of a label, variable or array) to 2 individual NULL terminated text strings formed by CDATA.

INCLUDE "PROTON_4.INC"	' Use the PROTON development board for the example

DIM ADDRESS AS WORD	' Pointer variable

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

ADDRESS = STRING1	' Point address to string 1

PRINT CSTR ADDRESS	' Display string 1

ADDRESS = STRING2	' Point ADDRESS to string 2

PRINT CSTR ADDRESS	' Display string 2

STOP

' Create the text to display

STRING1:

CDATA "HELLO ", 0

STRING2:

CDATA "WORLD", 0


Creating and using VIRTUAL Strings with EDATA

Some 14-bit core and all 16-bit core PICmicros have on-board eeprom memory, and although writing to this memory too many times is unhealthy for the PICmicro, reading this memory is both fast and harmless. Which offers a great place for text storage and retrieval.

Combining the eeprom memory of PICmicros with a string format, the compiler is capable of reducing the overhead of printing, or transmitting large amounts of text data using a memory resource that is very often left unused and ignored. The ESTR modifier may be used in commands that deal with text processing i.e. PRINT, SEROUT, HRSOUT, and RSOUT etc.

The ESTR modifier is used in conjunction with the EDATA command, which is used to initially create the string of characters: -

STRING1 EDATA "HELLO WORLD" , 0

The above line of code will create, in eeprom memory, the values that make up the ASCII text "HELLO WORLD", at address STRING1 in DATA memory. Note the NULL terminator after the ASCII text.

To display, or transmit this string of characters, the following command structure could be used:

PRINT ESTR STRING1

The identifier that declared the address where the list of EDATA values resided, now becomes the string's name. In a large program with lots of text formatting, this type of structure can save many bytes of valuable code space.

Try both these small programs, and you'll see that using ESTR saves code space: -

First the standard way of displaying text: -

DEVICE 16F877

CLS

PRINT "HELLO WORLD"

PRINT "HOW ARE YOU?"

PRINT "I AM FINE!"

STOP

Now using the ESTR modifier: -

TEXT1 EDATA "HELLO WORLD" , 0

TEXT2 EDATA "HOW ARE YOU?" , 0

TEXT3 EDATA "I AM FINE!" , 0

CLS

PRINT ESTR TEXT1

PRINT ESTR TEXT2

PRINT ESTR TEXT3

STOP

Again, note the NULL terminators after the ASCII text in the EDATA commands. Without these, the PICmicro will continue to transmit data in an endless loop.

The term 'virtual string' relates to the fact that a string formed from the EDATA command cannot (rather should not) be written to often, but can be read as many times as wished without causing harm to the device.

Not only identifiers can be used with the ESTR modifier, constants, variables and expressions can also be used that will hold the address of the EDATA's identifier (a pointer). For example, the program below uses a BYTE size variable to hold 2 pointers (address of a variable or array) to 2 individual NULL terminated text strings formed by EDATA.

INCLUDE "PROTON_4.INC"	' Use the PROTON development board for the example

DIM ADDRESS AS WORD	' Pointer variable

' Create the text to display in eeprom memory

STRING1 EDATA "HELLO ", 0

STRING2 CDATA "WORLD", 0

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

ADDRESS = STRING1	' Point address to string 1

PRINT ESTR ADDRESS	' Display string 1

ADDRESS = STRING2	' Point ADDRESS to string 2

PRINT ESTR ADDRESS	' Display string 2

STOP

Notes

Note that the identifying text MUST be located on the same line as the EDATA directive or a syntax error will be produced. It must also NOT contain a postfix colon as does a line label or it will be treat as a line label. Think of it as an alias name to a constant.

Any EDATA directives MUST be placed at the head of the BASIC program as is done with SYMBOLS, so that the name is recognised by the rest of the program as it is parsed. There is no need to jump over EDATA directives as you have to with LDATA or CDATA, because they do not occupy code memory, but reside in high DATA memory.


SOFTWARE INTERRUPTS in BASIC

Although the most efficient method of using an interrupt is in assembler, hardware interrupts and BASIC are poor bedfellows. By far the easiest way to write an interrupt handler is to write it in BASIC, in combination with the ON INTERRUPT statement. This is not the same as the compiler's original ON_INTERRUPT statement, which initiates a HARDWARE interrupt. ON INTERRUPT (two separate words.. ON INTERRUPT) informs the compiler to activate its internal interrupt handling and to jump to the BASIC interrupt handler as soon as it's capable, after receiving an interrupt. However, there's no such thing as a free lunch, and there are some penalties to pay for the ease of use that this method brings.

Note: The compiler will highlight the hardware interrupt directive (ON_INTERRUPT) as BOLD RED. While the software interrupt directive (ON INTERRUPT) will highlight BOLD BLACK. This makes for easy debugging should the underscore be forgotten.

When ON INTERRUPT is used, the compiler simply flags that the interrupt has happened and immediately goes back to what it was doing before it was rudely interrupted. Unlike a hardware interrupt, the code does not immediately jump to the interrupt handler. And since the compiler's commands are non re-entrant, there could be a considerable delay before the interrupt is actually handled.

For example, if the program has just started to execute a DELAYMS 2000 command when an interrupt occurs, the compiler will flag the interrupt and continue with the delay. It could be as much as 2 seconds later before the interrupt handler is executed. Any time critical routines dependant on the interrupt occurring regularly will be ruined. For example, multiplexing seven segment display.

To minimise the above problem, use only statements that don't take long to execute. For example, instead of DELAYMS 2000, use DELAYMS 1 in a FOR..NEXT , or REPEAT..UNTIL loop. This will allow the compiler to complete each command more quickly and handle any awaiting interrupts: -

FOR VAR1 = 0 TO 199 : DELAYMS 1 : NEXT	' Delay for 200ms

If interrupt processing needs to occur more regularly, then there is no choice but to use a hardware interrupt, with all it's quirks.

Exactly what happens when ON INTERRUPT is used is this: A short interrupt handler is placed at location 4 in the PICmicro. This interrupt handler is simply a RETURN. What this does is send the program back to what it was doing before the interrupt occurred. It does not require any processor context saving. What it doesn't do is re-enable Global Interrupts as happens when using a RETFIE instruction.

A Call to a short subroutine is placed before each command in the BASIC program once an ON INTERRUPT statement is encountered. This short subroutine checks the state of the Global Interrupt Enable bit (GIE). If it's off, an interrupt is awaiting so it vectors to the users interrupt handler. Which is essentially a BASIC subroutine.

If it is still set, the program continues with the next BASIC statement, after which, the GIE  bit is checked again, and so forth.

RESUME.

When the RESUME statement is encountered at the end of the BASIC interrupt handler, it sets the GIE  bit to re-enable interrupts and returns to where the program was before the interrupt occurred. DISABLE stops the compiler from inserting the Call to the interrupt checker before each command. This allows sections of code to execute without the possibility of being interrupted. ENABLE allows the insertion to continue.

A DISABLE should be placed before the interrupt handler so that it will not be restarted every time the GIE  bit is checked. If it is desired to turn off interrupts for some reason after ON INTERRUPT is encountered, you must not turn off the GIE  bit. Turning off this bit informs the compiler an interrupt has happened and it will execute the interrupt handler forever.

Instead use: -

INTCON = $80

This disables all the individual interrupts but leaves the Global Interrupt Enable bit set.

A final note about interrupts in BASIC is if the program uses the command structure: -

Fin: 	GOTO Fin

You must remember the interrupt flag is checked before each instruction. It immediately jumps to label Fin with no interrupt check. Other commands must be placed in the loop for the interrupt check to happen: -

Fin: DELAYMS 1

GOTO Fin

DISABLE, ENABLE.

ENABLE interrupt processing that was previously DISABLEd following this instruction.

DISABLE and ENABLE are not actually commands in the truest sense of the word, but flags that the compiler uses internally. They do not produce any code.

DEVICE 16F877

OPTION_REG = %00000111

INTCON = %00100000

SYMBOL LED = PORTD.0

ON INTERRUPT GOTO My_Int	' Enable software interrupts, and point to interrupt handler

Fin:

DELAYMS 1

GOTO Fin

DISABLE	' Disable interrupts in the handler

My_Int:

TOGGLE LED	' Toggle an LED when interrupted

RESUME	' Return to main program

ENABLE	' Enable interrupts after the handler


DISABLE

DISABLE interrupt processing that was previously ENABLED following this instruction.

Availability

14-bit and 16-bit core devices.

DISABLE and ENABLE, and RESUME are not actually commands in the truest sense of the word, but flags that the compiler uses internally. They do not produce any code.

DEVICE 16F877

OPTION_REG = %00000111

INTCON = %00100000

SYMBOL LED = PORTD.0

ON INTERRUPT GOTO My_Int	' Enable software interrupts, and point to interrupt handler

Fin:

DELAYMS 1

GOTO Fin

DISABLE	' Disable interrupts in the handler

My_Int:

TOGGLE LED	' Toggle an LED when interrupted

RESUME	' Return to main program

ENABLE	' Enable interrupts after the handler

See also :	SOFTWARE INTERRUPTS in BASIC, ENABLE, RESUME


ENABLE

ENABLE interrupt processing that was previously DISABLED following this instruction.

Availability

14-bit and 16-bit core devices.

DISABLE and ENABLE, and RESUME are not actually commands in the truest sense of the word, but flags that the compiler uses internally. They do not produce any code.

DEVICE 16F877

OPTION_REG = %00000111

INTCON = %00100000

SYMBOL LED = PORTD.0

ON INTERRUPT GOTO My_Int	' Enable software interrupts, and point to interrupt handler

Fin:

DELAYMS 1

GOTO Fin

DISABLE	' Disable interrupts in the handler

My_Int:

TOGGLE LED	' Toggle an LED when interrupted

RESUME	' Return to main program

ENABLE	' Enable interrupts after the handler

See also :	SOFTWARE INTERRUPTS in BASIC, DISABLE, RESUME


RESUME

When the RESUME statement is encountered at the end of the BASIC interrupt handler, it sets the GIE  bit to re-enable interrupts and returns to where the program was before the interrupt occurred. DISABLE stops the compiler from inserting the Call to the interrupt checker before each command. This allows sections of code to execute without the possibility of being interrupted. ENABLE allows the insertion to continue.

A DISABLE should be placed before the interrupt handler so that it will not be restarted every time the GIE  bit is checked. If it is desired to turn off interrupts for some reason after ON INTERRUPT is encountered, you must not turn off the GIE  bit. Turning off this bit informs the compiler an interrupt has happened and it will execute the interrupt handler forever.

Instead use: -

INTCON = $80

This disables all the individual interrupts but leaves the Global Interrupt Enable bit set.

A final note about interrupts in BASIC is if the program uses the command structure: -

Fin: 	GOTO Fin

You must remember the interrupt flag is checked before each instruction. It immediately jumps to label Fin with no interrupt check. Other commands must be placed in the loop for the interrupt check to happen: -

Fin: 	DELAYMS 1

GOTO Fin

Availability

14-bit and 16-bit core devices.

See also :	SOFTWARE INTERRUPTS in BASIC, DISABLE, ENABLE


ADIN

Syntax

Variable = ADIN channel number

Availability

14-bit and 16-bit core devices.

Overview

Read the value from the on-board Analogue to Digital Converter.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Channel number can be a constant, variable, or expression.

Example

 	'Read the value from channel 0 of the ADC and place in variable VAR1.

DECLARE ADIN_RES 10 	' 10-bit result required

DECLARE ADIN_TAD FRC 	' RC OSC chosen

DECLARE ADIN_STIME 50 	' Allow 50us sample time

DIM VAR1 as WORD

TRISA = %00000001 	' Configure AN0 (PORTA.0) as an input

ADCON1 = %10000000 	' Set analogue input on PORTA.0

VAR1 = ADIN 0 	' Place the conversion into variable VAR1

Declares

There are three DECLARE directives for use with ADIN. These are: -

DECLARE ADIN_RES 8 , 10 , or 12.

Sets the number of bits in the result.

If this DECLARE is not used, then the default is the resolution of the PICmicro type used. For example, the 16F87X range will result in a resolution of 10-bits, along with the 16-bit core devices, while the standard PICmicro types will produce an 8-bit result. Using the above DECLARE allows an 8-bit result to be obtained from the 10-bit PICmicro types, but NOT 10-bits from the 8-bit types.

DECLARE ADIN_TAD 2_FOSC , 8_FOSC , 32_FOSC , or FRC.

Sets the ADC's clock source.

All compatible PICmicros have four options for the clock source used by the ADC. 2_FOSC, 8_FOSC, and 32_FOSC, are ratios of the external oscillator, while FRC is the PICmicro's internal RC oscillator. Instead of using the predefined names for the clock source, values from 0 to 3 may be used. These reflect the settings of bits 0-1 in register ADCON0.

Care must be used when issuing this DECLARE, as the wrong type of clock source may result in poor resolution, or no conversion at all. If in doubt use FRC which will produce a slight reduction in resolution and conversion speed, but is guaranteed to work first time, every time. FRC is the default setting if the DECLARE is not issued in the BASIC listing.

DECLARE ADIN_STIME 0 to 65535 microseconds (us).

Allows the internal capacitors to fully charge before a sample is taken. This may be a value from 0 to 65535 microseconds (us).

A value too small may result in a reduction of resolution. While too large a value will result in poor conversion speeds without any extra resolution being attained.

A typical value for ADIN_STIME is 50 to 100. This allows adequate charge time without loosing too much conversion speed. But experimentation will produce the right value for your particular requirement. The default value if the DECLARE is not used in the BASIC listing is 50.

Notes

Before the ADIN command may be used, the appropriate TRIS register must be manipulated to set the desired pin to an input. Also, the ADCON1 register must be set according to which pin is required as an analogue input, and in some cases, to configure the format of the conversion's result. See the numerous Microchip datasheets for more information on these registers and how to set them up correctly for the specific device used.

If multiple conversions are being implemented, then a small delay should be used after the ADIN command. This allows the ADC's internal capacitors to discharge fully: -

Again: VAR1 = ADIN 3	' Place the conversion into variable VAR1

DELAYUS 1	' Wait for 1us

GOTO Again	' Read the ADC forever

See also : RCIN, POT.


VAL

Syntax

Variable = VAL (Variable , Modifier)

Availability

14-bit and 16-bit core devices.

Overview

Convert a Byte Array containing DECIMAL, HEX, or BINARY numeric text into it's integer equivalent.

Operators

Variable is a Byte Array containing the alphanumeric digits to convert and terminated by a NULL.

Modifier can be HEX, DEC, or BIN. To convert a HEX string, use the HEX modifier, for BINARY, use the BIN modifier, for DECIMAL use the DEC modifier.

Variable is a variable that will contain the converted value. Floating point characters and variables cannot be converted, and will be rounded down to the nearest integer value.

Example 1

' Convert a string of HEXADECIMAL characters to an integer

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[10] AS BYTE	' Create a byte array to use as a STRING

DIM WRD1 AS WORD	' Create a variable to hold result

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

STR STRING1 = "12AF",0	' Load the Array with HEX digits

WRD1 = VAL(STRING1,HEX)	' Convert the Array into an integer

PRINT HEX WRD1	' Display the integer as HEX

STOP

Example 2

' Convert a string of DECIMAL characters to an integer

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[10] AS BYTE	' Create a byte array to use as a STRING

DIM WRD1 AS WORD	' Create a variable to hold result

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

STR STRING1 = "1234",0	' Load the Array with DECIMAL digits

WRD1 = VAL(STRING1,DEC)	' Convert the Array into an integer

PRINT DEC WRD1	' Display the integer as DECIMAL

STOP

Example 3

' Convert a string of BINARY characters to an integer

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[17] AS BYTE	' Create a byte array to use as a STRING

DIM WRD1 AS WORD	' Create a variable to hold result

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

STR STRING1 = "1010101010000000",0	' Load the Array with BINARY digits

WRD1 = VAL(STRING1,BIN)	' Convert the Array into an integer

PRINT BIN WRD1	' Display the integer as BINARY

STOP

Notes

There are limitations with the VAL command when used on a 14-bit core device, in that the array must fit into a single RAM bank. But this is not really a problem, just a little thought when placing the variables will suffice. The compiler will inform you if the array is not fully located inside a BANK, and therefore not suitable for use with the VAL command.

This is not a problem with 16-bit core devices, as they are able to access all their memory very easily.

The VAL command is not recommended inside an expression, as the results are not predictable. However, the VAL command can be used within an IF-THEN, WHILE-WEND, or REPEAT-UNTIL construct, but the code produced is not as efficient as using it outside a construct, because the compiler must assume a worst case scenario, and use DWORD comparisons.

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[10] AS BYTE	' Create a byte array as a STRING

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

STR STRING1 = "123",0	' Load the Array with DEC digits

IF VAL(STRING1,HEX) = 123 THEN 	' Compare the result

PRINT AT 1,1,DEC VAL (STRING1,HEX)

ELSE

PRINT AT 1,1,"NOT EQUAL"

ENDIF

STOP

See also: STR, STR$.


STR$

Syntax

Assignment Variable = STR$ (Modifier  Variable)

Availability

14-bit and 16-bit core devices.

Overview

Convert a DECIMAL, HEX, BINARY, or FLOATING POINT value or variable into a NULL terminated string held in either a Byte Array. With 14-bit core devices, STR$ is only for use with the STR and STRN commands.

Operators

Assignment Variable must be a BYTE ARRAY, large enough to accommodate all the characters that make up the value converted.

Modifier is one of the standard modifiers used with PRINT, RSOUT, HSEROUT etc. See list below.

Variable is a variable that holds the value to convert. This may be a BIT, BYTE, WORD, DWORD, or FLOAT.

Notice that there is no comma separating the Modifier from the Variable. This is because the compiler borrows the format and subroutines used in PRINT. Which is why the modifiers are the same: -

BIN{1..32} 	Convert to binary digits

DEC{1..10} 	Convert to decimal digits

HEX{1..8} 	Convert to hexadecimal digits

SBIN{1..32} 	Convert to signed binary digits

SDEC{1..10} 	Convert to signed decimal digits

SHEX{1..8} 	Convert to signed hexadecimal digits

IBIN{1..32} 	Convert to binary digits with a preceding '%' identifier

IDEC{1..10} 	Convert to decimal digits with a preceding '#' identifier

IHEX{1..8} 	Convert to hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Convert to signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Convert to signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Convert to signed hexadecimal digits with a preceding '$' identifier

STRN examples using BYTE ARRAYS as simple STRING variables

STRN Example 1

'Convert a WORD variable to a NULL terminated string of characters in a BYTE array.

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[11] AS BYTE	' Create a byte array long enough to hold converted value, and NULL terminator

DIM WRD1 AS WORD

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

WRD1 = 1234	' Load the variable with a value

STRN STRING1 = STR$(DEC WRD1)	' Convert the Integer to a STRING

PRINT STR STRING1	' Display the string

STOP

STRN Example 2

'Convert a DWORD variable to a NULL terminated string of characters in a BYTE array.

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[11] AS BYTE	' Create a byte array long enough to hold converted value, and NULL terminator

DIM DWD1 AS DWORD

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

DWD1 = 1234	' Load the variable with a value

STRN STRING1 = STR$(DEC DWD1)	' Convert the Integer to a STRING

PRINT STR STRING1	' Display the string

STOP

STRN Example 3

'Convert a FLOAT variable to a NULL terminated string of characters in a BYTE array.

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[11] AS BYTE	' Create a byte array long enough to hold converted value, and NULL terminator

DIM FLT1 AS FLOAT

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

FLT1 = 3.14	' Load the variable with a value

STRN STRING1 = STR$(DEC FLT1 )	' Convert the Float to a STRING

PRINT STR STRING1	' Display the string

STOP

STRN Example 4

'Convert a WORD variable to a NULL terminated BINARY string of characters in a BYTE array.

INCLUDE "PROTON_4.INC"	' Use the PROTON board for the demo

DIM STRING1[34] AS BYTE	' Create a byte array long enough to hold converted value, and NULL terminator

DIM WRD1 AS WORD

DELAYMS 500	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

WRD1 = 1234	' Load the variable with a value

STRN STRING1 = STR$(BIN WRD1 )	' Convert the Integer to a STRING

PRINT STR STRING1	' Display the string

STOP

If we examine the resulting Byte Array converted with example 2, it will contain: -

character "1", character "2", character "3", character "4" , 0

The zero is not character zero, but value zero. This is a NULL terminated string.

Notes

The Byte Array created to hold the resulting conversion, must be large enough to accommodate all the resulting digits, including a possible minus sign and preceding identifying character. %, $, or # if the I version modifiers are used. The compiler will try and warn you if it thinks the array may not be large enough, but this is a rough guide, and you as the programmer must decide whether it is correct or not. If the size is not correct, any adjacent variables will be overwritten, with potentially catastrophic results.

See also: Creating and using Byte Arrays, STR, STRN, VAL.


CALL

Syntax

CALL Label

Availability

All devices.

Overview

Execute the assembly language subroutine named label.

Operators

Label must be a valid label name.

Example

' Call an assembler routine

 	CALL Asm_Sub

 	ASM

 	Asm_Sub

 	{mnemonics}

 	Return

 	ENDASM

Notes

The GOSUB command is usually used to execute a BASIC subroutine. However, if your subroutine happens to be written in assembler, the CALL command should be used. The main difference between GOSUB and CALL is that when CALL is used, the label's existence is not checked until assembly time. Using CALL, a label in an assembly language section can be accessed that would otherwise be inaccessible to GOSUB. This also means that any errors produced will be assembler types.

The CALL command adds PAGE and BANK switching instructions prior to actually calling the subroutine, however, if CALL is used in an all assembler environment, the extra mnemonics preceding the command can interfere with carefully sculptured code such as bit tests etc. By wrapping the subroutine's name in parenthesis, the BANK and PAGE instructions are suppressed, and the CALL command becomes the CALL mnemonic.

CALL (SUBROUTINE_NAME)

Only use the mnemonic variation of CALL, if you know that your destination is within the same PAGE as the section of code calling it. This is not an issue if using 16-bit core devices, as they have a more linear memory organisation with out PAGE boundaries.

See also : GOSUB, GOTO


ASM-ENDASM

Syntax

ASM

assembler mnemonics

ENDASM

or

@ assembler mnemonic

Availability

All devices.

Overview

Incorporate in-line assembler in the BASIC code. The mnemonics are passed directly to the assembler without the compiler interfering in any way. This allows a great deal of flexibility that cannot always be achieved using BASIC commands alone.


BRANCH

Syntax

BRANCH Index, [Label1 {,...Labeln }]

Availability

All devices.

Overview

Cause the program to jump to different locations based on a variable index. On a PICmicro device with only one page of memory.

Operators

Index is a constant, variable, or expression, that specifies the address to branch to.

Label1,...Labeln are valid labels that specify where to branch to. A maximum of 255 labels may be placed between the square brackets, 256 if using a 16-bit core device.

Example

DEVICE 16F84

DIM INDEX as BYTE

INDEX = 2 	' Assign INDEX a value of 2

Start:

BRANCH INDEX,[Lab_0, Lab_1, Lab_2]	' Jump to label 2 (Lab_2) because INDEX = 2

Lab_0: 	INDEX = 2 	' INDEX now equals 2

GOTO Start

Lab_1: 	INDEX = 0 	' INDEX now equals 0

GOTO Start

Lab_2: 	INDEX = 1 	' INDEX now equals 1

GOTO Start

The above example we first assign the index variable a value of 2, then we define our labels. Since the first position is considered 0 and the variable index equals 2 the BRANCH command will cause the program to jump to the third label in the brackets [Lab_2].

Notes

BRANCH has the same function as the ON x GOTO command. It's useful when you want to organise a structure such as: -

IF VAR1 = 0 THEN GOTO Lab_0 	' VAR1 =0: go to label "Lab_0"

IF VAR1 = 1 THEN GOTO Lab_1 	' VAR1 =1: go to label "Lab_1"

IF VAR1 = 2 THEN GOTO Lab_2 	' VAR1 =2: go to label "Lab_2"

You can use BRANCH to organise this into a single statement: -

BRANCH VAR1, [Lab_0 , Lab_1, Lab_2]

This works exactly the same as the above IF...THEN example. If the value is not in range (in this case if VAR1 is greater than 2), BRANCH does nothing. The program continues with the next instruction..

The BRANCH command is primarily for use with PICmicro devices that have one page of memory (0-2047). If larger PICmicros are used and you suspect that the branch label will be over a page boundary, use the BRANCHL command instead.

See also : BRANCHL, ON GOTO, ON GOTOL, ON GOSUB.


BRANCHL

Syntax

BRANCHL Index, [Label1 {,...Labeln }]

Availability

All devices.

Overview

Cause the program to jump to different locations based on a variable index. On a PICmicro device with more than one page of memory.

Operators

Index is a constant, variable, or expression, that specifies the address to branch to.

Label1,...Labeln are valid labels that specify where to branch to. A maximum of 127 labels may be placed between the square brackets, 256 if using a 16-bit core device.

Example

DEVICE 16F877	' Use a larger PICmicro

DIM INDEX as BYTE

INDEX = 2 	' Assign INDEX a value of 2

Start:

BRANCHL INDEX,[Lab_0, Lab_1, Lab_2]	' Jump to label 2 (Lab_2) because INDEX = 2

Lab_0: 	INDEX = 2 	' INDEX now equals 2

GOTO Start

Lab_1: 	INDEX = 0 	' INDEX now equals 0

GOTO Start

Lab_2: 	INDEX = 1 	' INDEX now equals 1

GOTO Start

The above example we first assign the index variable a value of 2, then we define our labels. Since the first position is considered 0 and the variable index equals 2 the BRANCHL command will cause the program to jump to the third label in the brackets [Lab_2].

Notes

The BRANCHL command is mainly for use with PICmicro devices that have more than one page of memory (greater than 2048). It may also be used on any PICmicro device, but does produce code that is larger than BRANCH.

See also : BRANCH, ON GOTO, ON GOTOL, ON GOSUB.


BREAK

Syntax

BREAK

Availability

All devices.

Overview

Exit a FOR...NEXT, WHILE...WEND, or REPEAT...UNTIL loop prematurely.

Example 1

' Break out of a FOR NEXT loop when the count reaches 10

INCLUDE "PROTON_4.INC"	' Demo using PROTON Dev board

DIM VAR1 as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

FOR VAR1 = 0 TO 39	' Create a loop of 40 revolutions

PRINT AT 1,1,DEC VAR1	' Print the revolutions on the first line of the LCD

IF VAR1 = 10 THEN BREAK	' Break out of the loop when VAR1 = 10

DELAYMS 200	' Delay so we can see what's happening

NEXT	' Close the FOR-NEXT loop

PRINT AT 2,1,"EXITED AT " , DEC VAR1	' Display the value when the loop was broken

STOP

Example 2

' Break out of a REPEAT-UNTIL loop when the count reaches 10

INCLUDE "PROTON_4.INC"	' Demo using PROTON Dev board

DIM VAR1 as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

VAR1 = 0

REPEAT	' Create a loop

    	PRINT AT 1,1,DEC VAR1	' Print the revolutions on the first line of the LCD

IF VAR1 = 10 THEN BREAK	' Break out of the loop when VAR1 = 10

DELAYMS 200	' Delay so we can see what's happening

INC VAR1

    	UNTIL VAR1 > 39	' Close the loop after 40 revolutions

PRINT AT 2,1,"EXITED AT " , DEC VAR1	' Display the value when the loop was broken

STOP

Example 3

' Break out of a WHILE-WEND loop when the count reaches 10

INCLUDE "PROTON_4.INC"	' Demo using PROTON Dev board

DIM VAR1 as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

VAR1 = 0

WHILE VAR1 < 40	' Create a loop of 40 revolutions

    	PRINT AT 1,1,DEC VAR1	' Print the revolutions on the first line of the LCD

IF VAR1 = 10 THEN BREAK	' Break out of the loop when VAR1 = 10

DELAYMS 200	' Delay so we can see what's happening

INC VAR1

    	WEND	' Close the loop

PRINT AT 2,1,"EXITED AT " , DEC VAR1	' Display the value when the loop was broken

STOP

Notes

The BREAK command is similar to a GOTO, but operates internally. When the BREAK command is encountered, the compiler will force a jump to the loop's internal exit label.

If the BREAK command is used outside of a FOR-NEXT, REPEAT-UNTIL, or WHILE-WEND loop, an error will be produced. Unless it is inside a SELECT..CASE construct, in which case it will simply cause a jump to the line of code following the ENDSELECT directive, even if it is inside a FOR-NEXT, REPEAT-UNTIL, or WHILE-WEND loop.

See also :	FOR...NEXT, WHILE...WEND, REPEAT...UNTIL.


BSTART

Syntax

BSTART

Availability

All devices.

Overview

Send a START condition to the I2C bus.

Notes

Because of the subtleties involved in interfacing to some I2C devices, the compiler's standard BUSIN, and BUSOUT 	commands were found lacking somewhat. Therefore, individual pieces of the I2C protocol may be used in association with the new structure of BUSIN, and BUSOUT. See relevant sections for more information.

Example

 ' Interface to a 24LC32 serial eeprom

DEVICE = 16F877

DIM Loop AS BYTE

DIM Array[10] AS BYTE

' Transmit bytes to the I2C bus

BSTART 	' Send a START condition

BUSOUT %10100000 	' Target an eeprom, and send a WRITE command

BUSOUT 0 	' Send the HIGHBYTE of the address

BUSOUT 0 	' Send the LOWBYTE of the address

FOR LOOP = 48 TO 57 	' Create a loop containing ASCII 0 to 9

BUSOUT LOOP	' Send the value of LOOP to the eeprom

NEXT 	' Close the loop

BSTOP 	' Send a STOP condition

DELAYMS 10 	' Wait for the data to be entered into eeprom matrix

' Receive bytes from the I2C bus

BSTART 	' Send a START condition

BUSOUT %10100000 	' Target an eeprom, and send a WRITE command

BUSOUT 0 	' Send the HIGHBYTE of the address

BUSOUT 0 	' Send the LOWBYTE of the address

BRESTART 	' Send a RESTART condition

BUSOUT %10100001 	' Target an eeprom, and send a READ command

FOR Loop = 0 TO 9 	' Create a loop

Array[Loop] = BUSIN 	' Load an array with bytes received

IF Loop = 9 THEN BSTOP : ELSE BUSACK 	' ACK or STOP ?

NEXT 	' Close the loop

PRINT AT 1,1, STR Array 	' Display the Array as a STRING

STOP

See also:	BSTOP, BRESTART, BUSACK, BUSIN, BUSOUT, HBSTART, HBRESTART, HBUSACK, HBUSIN, HBUSOUT.


BSTOP

Syntax

BSTOP

Availability

All devices.

Overview

Send a STOP condition to the I2C bus.

See also:	BSTART, BRESTART, BUSACK, BUSIN, BUSOUT, HBSTART, HBRESTART, HBUSACK, HBUSIN, HBUSOUT.


BRESTART

Syntax

BRESTART

Availability

All devices.

Overview

Send a RESTART condition to the I2C bus.

See also:	BSTOP, BSTART, BUSACK, BUSIN, BUSOUT, HBSTART, HBRESTART, HBUSACK, HBUSIN, HBUSOUT.


BUSACK

Syntax

BUSACK

Availability

All devices.

Overview

Send an ACKNOWLEDGE condition to the I2C bus.

See also:	BSTOP, BSTART, BRESTART, BUSIN, BUSOUT, HBSTART, HBRESTART, HBUSACK, HBUSIN, HBUSOUT.


BUSIN

Syntax

Variable = BUSIN Control , { Address }

or

Variable = BUSIN

or

BUSIN Control , { Address }, [ Variable {, Variable…} ]

or

BUSIN Variable

Availability

All devices.

Overview

Receives a value from the I2C bus, and places it into variable/s. If structures TWO or FOUR (see above) are used, then NO ACKNOWLEDGE, or STOP is sent after the data. Structures ONE and THREE first send the control and optional address out of the clock pin (SCL), and data pin (SDA).

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Control may be a constant value or a BYTE sized variable expression.

Address may be a constant value or a variable expression.

The four variations of the BUSIN command may be used in the same BASIC program. The SECOND and FOURTH types are useful for simply receiving a single byte from the bus, and must be used in conjunction with one of the low level commands. i.e. BSTART, BRESTART, BUSACK, or BSTOP. The FIRST, and THIRD types may be used to receive several values and designate each to a separate variable, or variable type.

The BUSIN command operates as an I2C master, and may be used to interface with any device that complies with the 2-wire I2C protocol.

The most significant 7-bits of control byte contain the control code and the slave address of the device being interfaced with. Bit-0 is the flag that indicates whether a read or write command is being implemented.

For example, if we were interfacing to an external eeprom such as the 24C32, the control code would be %10100001 or $A1. The most significant 4-bits (1010) are the eeprom's unique slave address. Bits 1 to 3 reflect the three address pins of the eeprom. And bit-0 is set to signify that we wish to read from the eeprom. Note that this bit is automatically set by the BUSIN command, regardless of its initial setting.

Example

' Receive a byte from the I2C bus and place it into variable VAR1.

DIM VAR1 as BYTE	' We'll only read 8-bits

DIM Address as WORD	' 16-bit address required

SYMBOL Control %10100001	' Target an eeprom

Address = 20	' Read the value at address 20

VAR1 = BUSIN Control , Address	' Read the byte from the eeprom

or

BUSIN Control , Address, [ VAR1 ]	' Read the byte from the eeprom

Address, is an optional parameter that may be an 8-bit or 16-bit value. If a variable is used in this position, the size of address is dictated by the size of the variable used (BYTE or WORD). In the case of the previous eeprom interfacing, the 24C32 eeprom requires a 16-bit address. While the smaller types require an 8-bit address. Make sure you assign the right size address for the device interfaced with, or you may not achieve the results you intended.

The value received from the bus depends on the size of the variables used, except for variation three, which only receives a BYTE (8-bits). For example: -

DIM WRD as WORD	' Declare a WORD size variable

WRD = BUSIN Control , Address

Will receive a 16-bit value from the bus. While: -

DIM VAR1 as BYTE	' Declare a BYTE size variable

VAR1 = BUSIN Control , Address

Will receive an 8-bit value from the bus.

Using the THIRD variation of the BUSIN command allows differing variable assignments. For example: -

DIM VAR1 as BYTE

DIM WRD as WORD

BUSIN Control , Address , [ VAR1 , WRD ]

Will receive two values from the bus, the first being an 8-bit value dictated by the size of variable VAR1 which has been declared as a byte. And a 16-bit value, this time dictated by the size of the variable WRD which has been declared as a word. Of course, BIT type variables may also be used, but in most cases these are not of any practical use as they still take up a byte within the eeprom.

The SECOND and FOURTH variations allow all the subtleties of the I2C protocol to be exploited, as each operation may be broken down into its constituent parts. It is advisable to refer to the datasheet of the device being interfaced to fully understand its requirements. See section on BSTART, BRESTART, BUSACK, or BSTOP, for example code.

Declares

See BUSOUT for declare explanations.

Notes

When the BUSOUT command is used, the appropriate SDA and SCL Port and Pin are automatically setup as inputs, and outputs.

Because the I2C protocol calls for an open-collector interface, pull-up resistors are required on both the SDA and SCL lines. Values of 4.7KΩ to 10KΩ will suffice.

You may imagine that it's limiting having a fixed set of pins for the I2C interface, but you must remember that several different devices may be attached to a single bus, each having a unique slave address. Which means there is usually no need to use up more than two pins on the PICmicro, in order to interface to many devices.

STR modifier with BUSIN

Using the STR modifier allows variations THREE and FOUR of the BUSIN command to transfer the bytes received from the I2C bus directly into a byte array. If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. An example of each is shown below: -

DIM Array[10] AS BYTE	' Define an array of 10 bytes

DIM Address AS BYTE	' Create a word sized variable

BUSIN %10100000 , Address , [ STR Array]	' Load data into all the array

BUSIN %10100000 , Address , [ STR Array\5]	' Load data into only the first 5 elements of the array

BSTART	' Send a START condition

BUSOUT %10100000	' Target an eeprom, and send a WRITE command

BUSOUT 0	' Send the HIGHBYTE of the address

BUSOUT 0	' Send the LOWBYTE of the address

BRESTART	' Send a RESTART condition

BUSOUT %10100001	' Target an eeprom, and send a READ command

BUSIN STR Array	' Load all the array with bytes received

BSTOP	' Send a STOP condition

An alternative ending to the above example is: -

BUSIN STR Array\5	' Load data into only the first 5 elements of the array

BSTOP	' Send a STOP condition

See also : BUSACK, BSTART, BRESTART, BSTOP, BUSOUT, HBSTART, HBRESTART, HBUSACK, HBUSIN, HBUSOUT.


BUSOUT

Syntax

BUSOUT Control , { Address } , [ OutputData ]

or

BUSOUT Variable

Availability

All devices.

Overview

Transmit a value to the I2C bus, by first sending the control and optional address out of the clock pin (SCL), and data pin (SDA). Or alternatively, if only one operator is included after the BUSOUT command, a single value will be transmitted, along with an ACK reception.

Operators

Control may be a constant value or a BYTE sized variable expression.

Address may be a constant, variable, or expression.

OutputData is list of variables, constants, expressions and modifiers that informs BUSOUT how to format outgoing data. BUSOUT can transmit individual or repeating bytes, convert values into decimal, hex or binary text representations, or transmit strings of bytes from variable arrays. These actions can be combined in any order in the OutputData list.

BUSOUT has most of the modifiers that HRSOUT, RSOUT, SEROUT and PRINT has. These are listed below: -

Modifier 	Operation

BIN{1..32} 	Send binary digits

DEC{1..10} 	Send decimal digits

HEX{1..8} 	Send hexadecimal digits

SBIN{1..32} 	Send signed binary digits

SDEC{1..10} 	Send signed decimal digits

SHEX{1..8} 	Send signed hexadecimal digits

IBIN{1..32} 	Send binary digits with a preceding '%' identifier

IDEC{1..10} 	Send decimal digits with a preceding '#' identifier

IHEX{1..8} 	Send hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Send signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Send signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Send signed hexadecimal digits with a preceding '$' identifier

The BUSOUT command operates as an I2C master and may be used to interface with any device that complies with the 2-wire I2C protocol.

The most significant 7-bits of control byte contain the control code and the slave address of the device being interfaced with. Bit-0 is the flag that indicates whether a read or write command is being implemented.

For example, if we were interfacing to an external eeprom such as the 24C32, the control code would be %10100000 or $A0. The most significant 4-bits (1010) are the eeprom's unique slave address. Bits 1 to 3 reflect the three address pins of the eeprom. And Bit-0 is clear to signify that we wish to write to the eeprom. Note that this bit is automatically cleared by the BUSOUT command, regardless of its initial value.

Example

' Send a byte to the I2C bus.

DIM VAR1 as BYTE	' We'll only read 8-bits

DIM Address as WORD	' 16-bit address required

SYMBOL Control = %10100000	' Target an eeprom

Address = 20	' Write to address 20

VAR1 = 200	' The value place into address 20

BUSOUT Control , Address , [ VAR1 ]	' Send the byte to the eeprom

DELAYMS 10	' Allow time for allocation of byte

Address, is an optional parameter that may be an 8-bit or 16-bit value. If a variable is used in this position, the size of address is dictated by the size of the variable used (BYTE or WORD). In the case of the above eeprom interfacing, the 24C32 eeprom requires a 16-bit address. While the smaller types require an 8-bit address. Make sure you assign the right size address for the device interfaced with, or you may not achieve the results you intended.

The value sent to the bus depends on the size of the variables used. For example: -

DIM WRD as WORD	' Declare a WORD size variable

BUSOUT Control , Address , [ WRD ]

Will send a 16-bit value to the bus. While: -

DIM VAR1 as BYTE	' Declare a BYTE size variable

BUSOUT Control , Address , [ VAR1 ]

Will send an 8-bit value to the bus.

Using more than one variable within the brackets allows differing variable sizes to be sent. For example: -

DIM VAR1 as BYTE

DIM WRD as WORD

BUSOUT Control , Address , [ VAR1 , WRD ]

Will send two values to the bus, the first being an 8-bit value dictated by the size of variable VAR1 which has been declared as a byte. And a 16-bit value, this time dictated by the size of the variable WRD which has been declared as a word. Of course, BIT type variables may also be used, but in most cases these are not of any practical use as they still take up a byte within the eeprom.

A string of characters can also be transmitted, by enclosing them in quotes: -

BUSOUT Control , Address , [ "Hello World" , VAR1 , WRD ]

Using the second variation of the BUSOUT command, necessitates using the low level commands i.e. BSTART, BRESTART, BUSACK, or BSTOP.

Using the BUSOUT command with only one value after it, sends a byte of data to the I2C bus, and returns holding the ACKNOWLEDGE reception. This acknowledge indicates whether the data has been received by the slave device.

The ACK reception is returned in the PICmicro's CARRY flag, which is STATUS.0, and also SYSTEM variable PP4.0. A value of zero indicates that the data was received correctly, while a one indicates that the data was not received, or that the slave device has sent a NACK return. You must read and understand the datasheet for the device being interfacing to, before the ACK return can be used successfully. An code snippet is shown below: -

' Transmit a byte to a 24LC32 serial eeprom

BSTART	' Send a START condition

BUSOUT %10100000	' Target an eeprom, and send a WRITE command

BUSOUT 0	' Send the HIGHBYTE of the address

BUSOUT 0	' Send the LOWBYTE of the address

BUSOUT "A"	' Send the value 65 to the bus

IF PP4.0 = 1 THEN GOTO Not_Received	' Has ACK been received OK ?

BSTOP	' Send a STOP condition

DELAYMS 10	' Wait for the data to be entered into eeprom matrix

STR modifier with BUSOUT.

The STR modifier is used for transmitting a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that sends four bytes from an array: -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = "A"	' Load the first 4 bytes of the array

MYARRAY [1] = "B"	' With the data to send

MYARRAY [2] = "C"

MYARRAY [3] = "D"

BUSOUT %10100000 , Address , [ STR MYARRAY \4 ] ' Send 4-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the program would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 4 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE	' Create a 10-byte array.

STR MYARRAY = "ABCD"	' Load the first 4 bytes of the array

BSTART	' Send a START condition

BUSOUT %10100000	' Target an eeprom, and send a WRITE command

BUSOUT 0	' Send the HIGHBYTE of the address

BUSOUT 0	' Send the LOWBYTE of the address

BUSOUT STR MYARRAY \4	' Send 4-byte string.

BSTOP	' Send a STOP condition

The above example, has exactly the same function as the previous one. The only differences are that the string is now constructed using the STR as a command instead of a modifier, and the low-level HBUS commands have been used.

Declares

There are three DECLARE directives for use with BUSOUT.

These are: -

DECLARE SDA_PIN PORT . PIN

Declares the port and pin used for the data line (SDA). This may be any valid port on the PICmicro. If this declare is not issued in the BASIC program, then the default Port and Pin is PORTA.0

DECLARE SCL_PIN PORT . PIN

Declares the port and pin used for the clock line (SCL). This may be any valid port on the PICmicro. If this declare is not issued in the BASIC program, then the default Port and Pin is PORTA.1

These declares, as is the case with all the DECLARES, may only be issued once in any single program, as they setup the I2C library code at design time.

DECLARE SLOW_BUS ON - OFF or 1 - 0

Slows the bus speed when using an oscillator higher than 4MHz.

The standard speed for the I2C bus is 100KHz. Some devices use a higher bus speed of 400KHz. If you use an 8MHz or higher oscillator, the bus speed may exceed the devices specs, which will result in intermittent transactions, or in some cases, no transactions at all. Therefore, use this DECLARE if you are not sure of the device's spec. The datasheet for the device used will inform you of its bus speed.

DECLARE BUS_SCL ON - OFF,  1 - 0 or TRUE - FALSE

Eliminates the necessity for a pullup resistor on the SCL line.

The I2C protocol dictates that a pullup resistor is required on both the SCL and SDA lines, however, this is not always possible due to circuit restrictions etc, so once the BUS_SCL ON DECLARE is issued at the top of the program, the resistor on the SCL line can be omitted from the circuit. The default for the compiler if the BUS_SCL DECLARE is not issued, is that a pullup resistor is required.

Notes

When the BUSOUT command is used, the appropriate SDA and SCL Port and Pin are automatically setup as inputs, and outputs.

Because the I2C protocol calls for an open-collector interface, pull-up resistors are required on both the SDA and SCL lines. Values of 4.7KΩ to 10KΩ will suffice.

You may imagine that it's limiting having a fixed set of pins for the I2C interface, but you must remember that several different devices may be attached to a single bus, each having a unique slave address. Which means there is usually no need to use up more than two pins on the PICmicro, in order to interface to many devices.

A typical use for the I2C commands is for interfacing with serial eeproms. The manual shows the connections to the I2C bus of a 24C32 serial eeprom.

See also : BUSACK, BSTART, BRESTART, BSTOP, BUSIN, HBSTART, HBRESTART, HBUSACK, HBUSIN, HBUSOUT.


BUTTON

Syntax

BUTTON Pin , DownState , Delay , Rate , Workspace , TargetState , Label

Availability

All devices.

Overview

Debounce button input, perform auto-repeat, and branch to address if button is in target state. Button circuits may be active-low or active-high.

Operators

Pin is a PORT.BIT, constant, or variable (0 - 15), that specifies the I/O pin to use. This pin will automatically be set to input.

DownState is a variable, constant, or expression (0 or 1) that specifies which logical state occurs when the button is pressed.

Delay is a variable, constant, or expression (0 - 255) that specifies how long the button must be pressed before auto-repeat starts. The delay is measured in cycles of the BUTTON routine. Delay has two special settings: 0 and 255. If Delay is 0, BUTTON performs no debounce or auto-repeat. If Delay is 255, BUTTON performs debounce, but no auto-repeat.

Rate is a variable, constant, or expression (0 - 255) that specifies the number of cycles between auto-repeats. The rate is expressed in cycles of the BUTTON routine.

Workspace is a byte variable used by BUTTON for workspace. It must be cleared to 0 before being used by BUTTON for the first time and should not be adjusted outside of the BUTTON command.

TargetState is a variable, constant, or expression (0 or 1) that specifies which state the button should be in for a branch to occur. (0 = not pressed, 1 = pressed).

Label is a label that specifies where to branch if the button is in the target state.

Example

DIM BTNVAR AS BYTE 	' Workspace for BUTTON instruction.

Loop: 	' Go to NoPress unless BTNVAR = 0.

BUTTON 0 , 0 , 255 , 250 , BTNVAR, 0 , NoPress

PRINT "* "

NoPress:

GOTO Loop

Notes

When a button is pressed, the contacts make or break a connection. A short (1 to 20ms) burst of noise occurs as the contacts scrape and bounce against each other. BUTTON's debounce feature prevents this noise from being interpreted as more than one switch action.

BUTTON also reacts to a button press the way a computer keyboard does to a key press. When a key is pressed, a character immediately appears on the screen. If the key is held down, there's a delay, then a rapid stream of characters appears on the screen. BUTTON's auto-repeat function can be set up to work much the same way.

BUTTON is designed for use inside a program loop. Each time through the loop, BUTTON checks the state of the specified pin. When it first matches DownState, the switch is debounced. Then, as dictated by TargetState, it either branches to address (TargetState = 1) or doesn't (TargetState = 0).

If the switch stays in DownState, BUTTON counts the number of program loops that execute. When this count equals Delay, BUTTON once again triggers the action specified by TargetState and address. Thereafter, if the switch remains in DownState, BUTTON waits Rate number of cycles between actions. The Workspace variable is used by BUTTON to keep track of how many cycles have occurred since the pin switched to TargetState or since the last auto-repeat.

BUTTON does not stop program execution. In order for its delay and auto repeat functions to work properly, BUTTON must be executed from within a program loop.


BOX

Syntax

BOX Set_Clear , Xpos Start , Ypos Start , Size

Availability

14-bit and 16-bit core devices.

Overview

Draw a square on a graphic LCD.

Operators

Set_Clear may be a constant or variable that determines if the square will set or clear the pixels. A value of 1 will set the pixels and draw a square , while a value of 0 will clear any pixels and erase a square .

Xpos Start may be a constant or variable that holds the X position for the centre of the square. Can be a value from 0 to 127.

Ypos Start may be a constant or variable that holds the Y position for the  centre of the square. Can be a value from 0 to 63.

Size may be a constant or variable that holds the Size of the square (in pixels). Can be a value from 0 to 255.

Example

' Draw a square at position 63,32 with a size of 20 pixels

INCLUDE "PROTON_G4.INT"

DIM XPOS as BYTE

DIM YPOS as BYTE

DIM SIZE as BYTE

DIM SET_CLR as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

XPOS = 63

YPOS = 32

SIZE = 20

SET_CLR = 1

BOX SET_CLR , XPOS , YPOS , SIZE

STOP

Notes

Because of the aspect ratio of the pixels on the graphic LCD (approx 1.5 times higher than wide) the square will appear elongated.

See Also :	CIRCLE, LINE, LINETO.


CDATA

Syntax

CDATA { alphanumeric data }

Availability

14-bit and 16-bit core devices.

Overview

Place information directly into memory for access by CREAD and CWRITE.

Operators

alphanumeric data can be any value, alphabetic character, or string enclosed in quotes (") or numeric data without quotes.

Example

DEVICE 16F877	' Use a 16F877 PICmicro

DIM VAR1 as BYTE

 	VAR1 = CREAD 2000	' Read the data from address 2000

ORG 2000	' Set the address of the CDATA command

CDATA 120	' Place 120 at address 2000

In the above example, the data is located at address 2000 within the PICmicro, then it's read using the CREAD command.

Notes

CDATA is only available on the newer PICmicro types that have self-modifying features, such as the 16F87x range, and offer an excellent, and efficient use of precious code space.

The CREAD and CWRITE  commands can also use a label address as a location variable. For example: -

DEVICE 16F877	' A device with code modifying features

DIM DByte AS BYTE

DIM Loop AS BYTE

FOR Loop = 0 TO 9	' Create a loop of 10

DByte = CREAD Address + Loop	' Read memory location ADDRESS + LOOP

PRINT Dbyte	' Display the value read

NEXT

STOP

ADDRESS: CDATA "HELLO WORLD"	' Create a string of text in FLASH memory

The program above reads and displays 10 values from the address located by the LABEL accompanying the CDATA command. Resulting in "HELLO WORL" being displayed.

Using the new in-line commands structure, the CREAD  and PRINT parts of the above program may be written as: -

PRINT CREAD Address + Loop	' Read and display memory location ADDRESS + LOOP

The CWRITE command uses the same technique for writing to memory: -

DEVICE 16F877	' A device with code modifying features

DIM DByte AS BYTE

DIM Loop AS BYTE

CWRITE Address , [ "HELLO WORLD" ]	' Write a string to FLASH memory at location ADDRESS

FOR Loop = 0 TO 9	' Create a loop of 10

PRINT CREAD Address + Loop	' Read and display memory location ADDRESS + LOOP

NEXT

STOP

' Reserve 10 spaces in FLASH memory

ADDRESS: CDATA 32 , 32 , 32 , 32 , 32 , 32 , 32 , 32 , 32 , 32

Notice the string text now allowed in the CWRITE command. This allows the whole PICmicro to be used for data storage and retrieval if desired.

The configuration fuse setting WRTE must be enabled before CDATA, CREAD and CWRITE  may be used. This enables the self-modifying feature (and is the default fuse setting of the compiler). If the CONFIG directive is used, then the WRTE_ON fuse setting must be included in the list: - CONFIG HS_OSC, WDT_ON, PWRTE_ON, BODEN_OFF, LVP_OFF, WRTE_ON, CP_OFF, DEBUG_OFF

Important Note

Take care not to overwrite existing code when using the CWRITE command, and also remember that the all PICmicro devices have a finite amount of write cycles (approx 1000). A single program can easily exceed this limit, making that particular memory cell or cells inaccessible.

The configuration fuse setting WRTE must be enabled before CDATA, CREAD and CWRITE  may be used. This enables the self-modifying feature. If the CONFIG directive is used, then the WRTE_ON fuse setting must be included in the list: -

CONFIG WDT_ON , XT_OSC , WRTE_ON

Because the 14-bit core devices are only capable of holding 14 bits to a WORD, values greater than 16383 ($3FFF) cannot be stored.

The compiler has a 64K limit to its CDATA tables, therefore ensure that the BASIC program does not exceed the first 64k bytes of code memory.

Formatting a CDATA table with a 16-bit core device.

Sometimes it is nessecary to create a data table with a known format for its values. For example all values will occupy 4 bytes of data space even though the value itself would only occupy 1 or 2 bytes. Formatters are not supported with 14-bit core devices, because they can only hold a maximum value of $3FFF (16383). i.e. 14-bits.

CDATA 100000 , 10000 , 1000 , 100 , 10 , 1

The above line of code would produce an uneven code space usage, as each value requires a different amount of code space to hold the values. 100000 would require 4 bytes of code space, 10000 and 1000  would require 2 bytes, but 100, 10, and 1 would only require 1 byte.

Reading these values using CREAD would cause problems because there is no way of knowing the amount of bytes to read in order to increment to the next valid value.

The answer is to use formatters to ensure that a value occupies a predetermined amount of bytes. These are: -

BYTE

WORD

DWORD

FLOAT

Placing one of these formatters before the value in question will force a given length.

CDATA DWORD 100000 , DWORD 10000 , DWORD  1000 , DWORD  100 , DWORD 10 , DWORD 1

BYTE will force the value to occupy one byte of code space, regardless of it's value. Any values above 255 will be truncated to the least significant byte.

WORD will force the value to occupy 2 bytes of code space, regardless of its value. Any values above 65535 will be truncated to the two least significant bytes. Any value below 255 will be padded to bring the memory count to 2 bytes.

DWORD will force the value to occupy 4 bytes of code space, regardless of its value. Any value below 65535 will be padded to bring the memory count to 4 bytes. The line of code shown above uses the DWORD formatter to ensure all the values in the CDATA table occupy 4 bytes of code space.

FLOAT will force a value to its floating point equivalent, which always takes up 4 bytes of code space.

If all the values in an CDATA table are required to occupy the same amount of bytes, then a single formatter will ensure that this happens.

CDATA AS DWORD 100000 , 10000 , 1000 , 100 , 10 , 1

The above line has the same effect as the formatter previous example using seperate DWORD formatters, in that all values will occupy 4 bytes, regardless of their value. All four formatters can be used with the AS keyword.

The example below illustrates the formatters in use.

' Convert a DWORD value into a string array

' Using only BASIC commands

' Similar principle to the STR$ command

Include "PROTON18_4.INC"	' Use a 16-bit core device

Dim P10 as Dword	' Power of 10 variable

Dim CNT as Byte

Dim J as Byte

Dim VALUE as Dword	' Value to convert

Dim STRING1[11] as Byte	' Holds the converted value

Dim PTR as Byte	' Pointer within the Byte array

Delayms 500	' Wait for PICmicro to stabilise

Cls	' Clear the LCD

Clear	' Clear all RAM before we start

VALUE = 1234576	' Value to convert

Gosub DWORD_TO_STR	' Convert VALUE to string

Print STR STRING1	' Display the result

Stop

'-------------------------------------------------------------

' Convert a DWORD value into a string array

' Value to convert is placed in 'VALUE'

' Byte array 'STRING1' is built up with the ASCII equivalent

DWORD_TO_STR:

PTR = 0

J = 0

Repeat

P10 = CREAD DWORD_TBL + (J * 4)

CNT = 0

While VALUE >= P10

VALUE = VALUE - P10

Inc CNT

Wend

If CNT <> 0 Then

STRING1[PTR] = CNT + "0"

Inc PTR

Endif

Inc J

Until J > 8

STRING1[PTR] = VALUE + "0"

Inc PTR

STRING1[PTR] = 0	' Add the NULL to terminate the string

Return

' CDATA table is formatted for all 32 bit values.

' Which means each value will require 4 bytes of code space

DWORD_TBL:

CDATA  AS DWORD 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10

Label names as pointers.

If a label's name is used in the list of values in a CDATA table, the labels address will be used. This is useful for accessing other tables of data using their address from a lookup table. See example below.

' Display text from two CDATA tables

' Based on their address located in a separate table

       	 Include "PROTON18_4.INC"	' Use a 16-bit core device

       	 Dim ADDRESS as Word

       	 Dim LOOP as Word

       	 Dim DATA_BYTE as Byte

       	Delayms 200	' Wait for PICmicro to stabilise

        	Cls	' Clear the LCD

        	ADDRESS = CREAD ADDR_TABLE	' Locate the address of the first string

       	While 1 = 1	' Create an infinite loop

        	DATA_BYTE = CREAD ADDRESS	' Read each character from the CDATA string

            If DATA_BYTE = 0 Then EXIT_LOOP	' Exit if NULL found

        	Print DATA_BYTE	' Display the character

            Inc ADDRESS	' Next character

        	Wend	' Close the loop

EXIT_LOOP:

        	Cursor 2,1	' Point to line 2 of the LCD

ADDRESS = CREAD ADDR_TABLE + 2	' Locate the address of the second string

       	While 1 = 1	' Create an infinite loop

        	DATA_BYTE = CREAD ADDRESS	' Read each character from the CDATA string

            If DATA_BYTE = 0 Then EXIT_LOOP2 	' Exit if NULL found

        	Print DATA_BYTE	' Display the character

            Inc ADDRESS	' Next character

        	Wend	' Close the loop

EXIT_LOOP2:

        	Stop

ADDR_TABLE:	' Table of address's

CDATA AS WORD STRING1, STRING2

STRING1:

CDATA "HELLO",0

STRING2:

CDATA "WORLD",0

See also : CONFIG, CREAD, CWRITE, EDATA, LDATA, Creating and using VIRTUAL STRINGS with CDATA, Creating and using VIRTUAL STRINGS with EDATA.


CIRCLE

Syntax

CIRCLE Set_Clear , Xpos , Ypos , Radius

Availability

14-bit and 16-bit core devices.

Overview

Draw a circle on a graphic LCD.

Operators

Set_Clear may be a constant or variable that determines if the circle will set or clear the pixels. A value of 1 will set the pixels and draw a circle, while a value of 0 will clear any pixels and erase a circle.

Xpos may be a constant or variable that holds the X position for the centre of the circle. Can be a value from 0 to 127.

Ypos may be a constant or variable that holds the Y position for the  centre of the circle. Can be a value from 0 to 63.

Radius may be a constant or variable that holds the Radius of the circle. Can be a value from 0 to 255.

Example

' Draw a circle at position 63,32 with a radius of 20 pixels

INCLUDE "PROTON_G4.INT"

DIM XPOS as BYTE

DIM YPOS as BYTE

DIM RADIUS as BYTE

DIM SET_CLR as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

XPOS = 63

YPOS = 32

RADIUS = 20

SET_CLR = 1

CIRCLE SET_CLR , XPOS , YPOS , RADIUS

STOP

Notes

Because of the aspect ratio of the pixels on the graphic LCD (approx 1.5 times higher than wide) the circle will appear elongated.

See Also :	BOX, LINE, LINETO.


CLEAR

Syntax

CLEAR Variable or Variable.Bit

or

CLEAR

Availability

All devices.

Overview

Place a variable or bit in a low state. For a variable, this means filling it with 0's. For a bit this means setting it to 0.

CLEAR has another purpose. If no variable is present after the command, all RAM area on the PICmicro used is cleared.

Operators

Variable can be any variable or register.

Variable.Bit can be any variable and bit combination.

Example

CLEAR	' Clear ALL RAM area

CLEAR VAR1.3	' Clear bit 3 of VAR1

CLEAR VAR1	' Load VAR1 with the value of 0

CLEAR STATUS.0	' Clear the carry flag high

Notes

There IS a difference between the CLEAR and LOW command. CLEAR does not alter the TRIS register if a PORT is targeted.

See Also :	SET, LOW, HIGH


CLEARBIT

Syntax

CLEARBIT Variable , Index

Availability

All devices.

Overview

Clear a bit of a variable or register using a variable index to the bit of interest.

Operators

Variable is a user defined variable, of type BYTE, WORD, or DWORD.

Index is a constant, variable, or expression that points to the bit within Variable that requires clearing.

Example

 	' Clear then Set each bit of variable EX_VAR

DEVICE = 16F877

XTAL = 4

DIM EX_VAR AS BYTE

DIM INDEX AS BYTE

CLS

EX_VAR = %11111111

AGAIN:

FOR INDEX = 0 TO 7	' Create a loop for 8 bits

CLEARBIT EX_VAR,INDEX 	' Clear each bit of EX_VAR

PRINT AT 1,1,BIN8 EX_VAR	' Display the binary result

DELAYMS 100	' Slow things down to see what's happening

NEXT	' Close the loop

FOR INDEX = 7 TO 0 STEP -1	' Create a loop for 8 bits

SETBIT EX_VAR,INDEX 	' Set each bit of EX_VAR

PRINT AT 1,1,BIN8 EX_VAR	' Display the binary result

DELAYMS 100	' Slow things down to see what's happening

NEXT	' Close the loop

GOTO AGAIN	' Do it forever

Notes

There are many ways to clear a bit within a variable, however, each method requires a certain amount of manipulation, either with rotates, or alternatively, the use of indirect addressing using the FSR, and INDF registers. Each method has its merits, but requires a certain amount of knowledge to accomplish the task correctly. The CLEARBIT command makes this task extremely simple using a register rotate method, however, this is not necessarily the quickest method, or the smallest, but it is the easiest. For speed and size optimisation, there is no shortcut to experience.

To CLEAR a known constant bit of a variable or register, then access the bit directly using PORT.n.

PORTA.1 = 0

or

VAR1.4 = 0

If a PORT is targeted by CLEARBIT, the TRIS register is NOT affected.

See also : GETBIT, LOADBIT, SETBIT


SETBIT

Syntax

SETBIT Variable , Index

Availability

All devices.

Overview

Set a bit of a variable or register using a variable index to the bit of interest.

Operators

Variable is a user defined variable, of type BYTE, WORD, or DWORD.

Index is a constant, variable, or expression that points to the bit within Variable that requires setting.

Example

 	' Clear then Set each bit of variable EX_VAR

DEVICE = 16F877

XTAL = 4

DIM EX_VAR AS BYTE

DIM INDEX AS BYTE

CLS

EX_VAR = %11111111

AGAIN:

FOR INDEX = 0 TO 7	' Create a loop for 8 bits

CLEARBIT EX_VAR,INDEX 	' Clear each bit of EX_VAR

PRINT AT 1,1,BIN8 EX_VAR	' Display the binary result

DELAYMS 100	' Slow things down to see what's happening

NEXT	' Close the loop

FOR INDEX = 7 TO 0 STEP -1	' Create a loop for 8 bits

SETBIT EX_VAR,INDEX 	' Set each bit of EX_VAR

PRINT AT 1,1,BIN8 EX_VAR	' Display the binary result

DELAYMS 100	' Slow things down to see what's happening

NEXT	' Close the loop

GOTO AGAIN	' Do it forever

Notes

There are many ways to set a bit within a variable, however, each method requires a certain amount of manipulation, either with rotates, or alternatively, the use of indirect addressing using the FSR, and INDF registers. Each method has its merits, but requires a certain amount of knowledge to accomplish the task correctly. The SETBIT command makes this task extremely simple using a register rotate method, however, this is not necessarily the quickest method, or the smallest, but it is the easiest. For speed and size optimisation, there is no shortcut to experience.

To SET a known constant bit of a variable or register, then access the bit directly using PORT.n.

PORTA.1 = 1

or

VAR1.4 = 1

If a PORT is targeted by SETBIT, the TRIS register is NOT affected.

See also : CLEARBIT, GETBIT, LOADBIT


CLS

Syntax

CLS

Availability

All devices.

Overview

Clears the alphanumeric or graphic LCD and places the cursor at the home position i.e. line 1, position 1

Example

CLS	' Clear the LCD

PRINT "HELLO"	' Display the word "HELLO" on the LCD

CURSOR 2 , 1	' Move the cursor to line 2, position 1

PRINT "WORLD"	' Display the word "WORLD" on the LCD

In the above example, the LCD is cleared using the CLS command, which also places the cursor at the home position i.e. line 1, position 1. Next, the word HELLO is displayed in the top left corner. The cursor is then moved to line 2 position 1, and the word WORLD is displayed.

See also : CURSOR, PRINT


CONFIG

Syntax

CONFIG { configuration fuse settings }

Availability

12-bit and 14-bit core devices.

Overview

Enable or Disable particular fuse settings for the PICmicro type used.

Operators

configuration fuse settings vary from PICmicro to PICmicro, however, certain settings are standard to most PICmicro types. These are: -

 	WDT_ON Enable the internal Watchdog timer.

 	WDT_OFF Disable the internal Watchdog timer.

 	HS_OSC Use a High-speed crystal (Xtals over 4MHz) .

 	XT_OSC Use a standard crystal (4MHz or under).

 	LP_OSC Use a low frequency crystal (KHz range).

 	PWRTE_ON Enable power up timer.

 	PWRTE_OFF Disable power up timer.

Example

' Disable the Watchdog timer and specify an HS_OSC etc, on a PIC16F877 device

CONFIG HS_OSC , WDT_OFF , PWRTE_ON , BODEN_OFF , LVP_OFF , WRTE_ON , CP_OFF , DEBUG_OFF

Important.

Because of the complexity that the16-bit core devices require for adjusting their fuse settings, the CONFIG directive is not compatible with these devices directly. If the fuse settings requires altering, then dropping into assembler will be required, either by using the ASM - END_ASM directives, or the @ character. Alternatively, the fuse settings may be altered at programming time.

The example below will set the fuses for a 18F452 device: -

@CONFIG_REQ

@__CONFIG CONFIG1H, OSCS_OFF_1 & HS_OSC_1

@__CONFIG CONFIG2L, BOR_ON_2 & BORV_20_2 & PWRT_ON_2

@__CONFIG CONFIG2H, WDT_OFF_2 & WDTPS_128_2

@__CONFIG CONFIG3H, CCP2MX_ON_3

@__CONFIG CONFIG4L, STVR_ON_4 & LVP_OFF_4 & DEBUG_OFF_4

The fuse names may be found at the end of the PICmicro's .LPB file, situated within the INC folder of the compiler's directory.

Notes

If the CONFIG directive is not used within the BASIC program then default values are used. These may be found in the .LPB files in the INC folder.

When using the CONFIG directive, always use all the fuse settings for the particular PICmicro used.

Any fuse names that are omitted from the CONFIG list will normally assume an OFF or DISABLED state. However, this is not always the case, and unpredictable results may occur, or the PICmicro may refuse to start up altogether..

Before programming the PICmicro, always check the fuse settings at programming time to ensure that the settings are correct.

Always read the datasheet for the particular PICmicro of interest, before using this directive.


COUNTER

Syntax

Variable = COUNTER Pin , Period

Availability

All devices.

Overview

Count the number of pulses that appear on pin during period, and store the result in variable.

Operators

Variable is a user-defined variable.

Pin is a Port.Pin constant declaration i.e. PORTA.0.

Period may be a constant, variable, or expression.

Example

' Count the pulses that occur on PORTA.0 within a 100ms period and displays the results.

DIM WRD as WORD	' Declare a word size variable

SYMBOL Pin = PORTA.0	' Assign the input pin to PORTA.0

CLS

Loop:

WRD = COUNTER Pin , 100	' Variable WRD now contains the Count

CURSOR 1 , 1

PRINT DEC WRD , " "	' Display the decimal result on the LCD

GOTO Loop	' Do it indefinitely

Notes

The resolution of period is in milliseconds (ms). It obtains its scaling from the oscillator declaration, DECLARE XTAL.

COUNTER checks the state of the pin in a concise loop, and counts the rising edge of a transition (low to high).

With a 4MHz oscillator, the pin is checked every 20us, and every 4us with a 20MHz oscillator. From this we can determine that the highest frequency of pulses that may be counted is: -

25KHz using a 4MHz oscillator.

125KHz using a 20MHz oscillator.

See also : DECLARE, RCIN


CREAD

Syntax

Variable = CREAD Address

Availability

14-bit and 16-bit core devices.

Overview

Read data from anywhere in memory.

Operators

Variable is a user defined variable, of type BYTE, WORD, or DWORD.

Address is a constant, variable, label, or expression that represents any valid address within the PICmicro.

Example

' Read memory locations within the PICmicro

DEVICE 16F877	' Needs to be a 16F87x type PICmicro

DIM VAR1 as BYTE

DIM WRD as WORD

DIM Address as WORD

Address = 1000	' Address now holds the base address

VAR1 = CREAD 1000	' Read 8-bit data at address 1000 into VAR1

WRD = CREAD Address+10	' Read 14-bit data at address 1000+10

Notes

The CREAD command takes advantage of the new self-modifying feature that is available in the newer 16F87x, and 18 series devices.

If a WORD size variable is used as the assignment, then a 14-bit WORD will be read. If a BYTE sized variable is used as the assignment, then 8-bits will be read.

Because the 14-bit core devices are only capable of holding 14 bits to a WORD , values greater than 16383 ($3FFF) cannot be read. However, the 16-bit core devices may hold values up to 65535 ($FFFF).

See CDATA for an alternative method for locating the address of a CDATA table.

The configuration fuse setting WRTE must be enabled before CDATA, CREAD, and CWRITE may be used, this is the default setting. This enables the self-modifying feature. If the CONFIG directive is used, then the WRTE_ON fuse setting must be included in the list: -

 CONFIG WDT_ON , XT_OSC , WRTE_ON

See also : CDATA, CONFIG, CWRITE, ORG


CURSOR

Syntax

CURSOR Line , Position

Availability

All devices.

Overview

Move the cursor position on the LCD to a specified line and position.

Operators

Line is a constant, variable, or expression that corresponds to the line number from 1 to maximum lines.

Position is a constant, variable, or expression that moves the position within the line chosen, from 1 to maximum position.

Example 1

DIM Line as BYTE

DIM Xpos as BYTE

Line = 2

Xpos = 1

CLS	' Clear the LCD

PRINT "HELLO"	' Display the word "HELLO" on the LCD

CURSOR Line , Xpos	' Move the cursor to line 2, position 1

PRINT "WORLD"	' Display the word "WORLD" on the LCD

In the above example, the LCD is cleared using the CLS command, which also places the cursor at the home position i.e. line 1, position 1. Next, the word HELLO is displayed in the top left corner. The cursor is then moved to line 2 position 1, and the word WORLD is displayed.

Example 2

DIM Xpos as BYTE

DIM Ypos as BYTE

Again:

Ypos = 1	' Start on line 1

FOR Xpos = 1 TO 16	' Create a loop of 16

CLS	' Clear the LCD

CURSOR Ypos , Xpos	' Move the cursor to position Ypos,Xpos

PRINT "*"	' Display the character

DELAYMS 100

NEXT

Ypos = 2	' Move to line 2

FOR Xpos = 16 TO 1 STEP -1	' Create another loop, this time reverse

CLS	' Clear the LCD

CUSROS Ypos , Xpos	' Move the cursor to position Ypos,Xpos

PRINT "*"	' Display the character

DELAYMS 100

NEXT

GOTO Again	' Repeat forever

 Example 2 displays an asterisk character moving around the perimeter of a 2-line by 16 character LCD.

See also : CLS, PRINT


CWRITE

Syntax

CWRITE Address , [ Variable { , Variable…} ]

Availability

14-bit and 16-bit core devices.

Overview

Write data to anywhere in memory.

Operators

Variable can be a constant, variable, or expression.

Address is a constant, variable, label, or expression that represents any valid address within the PICmicro.

Example

' Write to memory location 2000+ within the PICmicro

DEVICE 16F877	' Needs to be a 16F87x type PICmicro

DIM VAR1 as BYTE

DIM WRD as WORD

DIM Address as WORD

 	Address = 2000	' Address now holds the base address

 	VAR1 = 234

 WRD = 1043

 	CWRITE Address, [10, VAR1, WRD ]	' Write to address 2000 +

 	ORG 2000

Notes

The CWRITE command takes advantage of the new self-modifying feature that is available in the newer 16F87x, and 18 series devices.

If a WORD size variable is used as the assignment, then a 14-bit WORD will be written. If a BYTE sized variable is used as the assignment, then 8-bits will be written.

Because the 14-bit core devices are only capable of holding 14 bits to a WORD, values greater than 16383 ($3FFF) cannot be written. However, the 16-bit core devices may hold values up to 65535 ($FFFF).

See CDATA for an alternative method for locating the address of a CDATA table.

The configuration fuse setting WRTE must be enabled before CDATA, CREAD, and CWRITE may be used, this is the default setting. This enables the self-modifying feature. If the CONFIG directive is used, then the WRTE_ON fuse setting must be included in the list: -

 CONFIG WDT_ON , XT_OSC , WRTE_ON

Warning

The 16-bit core devices, and some of the newer A series 14-bit core devices such as the 16F877A, can only have their code memory written in blocks of 8 bytes, or 4 words. And then only after an erase, which can only be accomplished in blocks of 64 bytes, or 32 words. Therefore, this command should only be used after reading and understanding the particular PICmicro's datasheet.

See also : CDATA, CONFIG, CREAD, ORG


DATA

Syntax

DATA { alphanumeric data }

Availability

14-bit and 16-bit core devices.

Overview

Place information into code memory using the RETLW  instruction when used with 14-bit core devices, and FLASH memory when using a 16-bit core device. For access by READ.

Operators

alphanumeric data can be a 8,16, 32 bit value, or floating point values, or any alphabetic character or string enclosed in quotes.

Example

DIM VAR1 AS BYTE

DATA 5 , 8 , "fred" , 12

RESTORE

READ VAR1	' Variable VAR1 will now contain the value 5

READ VAR1	' Variable VAR1 will now contain the value 8

' Pointer now placed at location 4 in our data table i.e. "r"

RESTORE 3

' VAR1 will now contain the value 114 i.e. the 'r' character in decimal

READ VAR1

The data table is defined with the values 5,8,102,114,101,100,12 as "fred" equates to f:102, r:114, e:101, d:100 in decimal. The table pointer is immediately restored to the beginning of the table. This is not always required but as a general rule, it is a good idea to prevent table reading from overflowing.

The first READ VAR1, takes the first item of data from the table and increments the table pointer. The next READ VAR1 therefore takes the second item of data. RESTORE 3 moves the table pointer to the fourth location (first location is pointer position 0) in the table - in this case where the letter 'r' is. READ VAR1 now retrieves the decimal equivalent of 'r' which is 114.

Notes

DATA tables should be placed near the beginning of your program. Attempts to read past the end of the table will result in errors and unpredictable results.

Only one instance of DATA is allowed per program, however, they be of any length. If the alphanumeric contents of the DATA statement will not fit on one line then the extra information must be placed directly below using another DATA statement: -

DATA "HELLO "

DATA "WORLD"

 is the same as: -

DATA "HELLO WORLD"

See also: READ , RESTORE


DECLARE

Syntax

{DECLARE} code modifying directive = modifying value

Availability

All devices.

Overview

Adjust certain aspects of the produced code, i.e. Crystal frequency, LCD port and pins, serial baud rate etc.

Operators

code modifying directive is a set of pre-defined words. See list below.

modifying value is the value that corresponds to the command. See list below.

The DECLARE directive is an indispensable part of the compiler. It moulds the library subroutines, and passes essential user information to them. However, the DECLARE part of a declare directive is optional.

For example, instead of using: -

DECLARE XTAL 4

The text: -

XTAL = 4

May be used.

Notice that there is an optional equals character separating the declare command and the value to pass. The structure will still be referred to as a DECLARE in the manual, help file, and any future projects.

MISC Declares.

DECLARE WATCHDOG = ON or OFF, or TRUE or FALSE, or 1, 0

The WATCHDOG DECLARE directive enables or disables the watchdog timer. It also sets the PICmicro's CONFIG fuses for no watchdog. In addition, it removes any CLRWDT mnemonics from the assembled code, thus producing slightly smaller programs. The default for the compiler is WATCHDOG OFF, therefore, if the watchdog timer is required, then this DECLARE will need to be invoked.

The WATCHDOG DECLARE can be issued multiple times within the BASIC code, enabling and disabling the watchdog timer as and when required.

DECLARE BOOTLOADER = ON or OFF, or TRUE or FALSE, or 1, 0

The BOOTLOADER DECLARE directive enables or disables the special settings that a serial bootloader requires at the start of code space. This directive is ignored if a PICmicro without bootloading capabilities is targeted.

Disabling the bootloader will free a few bytes from the code produced. This doesn't seem a great deal, however, these few bytes may be the difference between a working or non-working program. The default for the compiler is BOOTLOADER ON

DECLARE SHOW_SYSTEM_VARIABLES = ON or OFF, or TRUE or FALSE, or 1, 0

When using the PROTEUS VSM to simulate BASIC code, it is sometimes beneficial to observe the behaviour of the compiler's SYSTEM variables that are used for its library routines. The SHOW_SYSTEM_VARIABLES DECLARE enables or disables this option.

DECLARE FSR_CONTEXT_SAVE = ON or OFF, or TRUE or FALSE, or 1, 0

When using HARDWARE interrupts, it is not always necessary to save the FSR register. So in order to save code space and time spent within the interrupt handler, the FSR_CONTEXT_SAVE DECLARE can enable or disable the auto CONTEXT saving and restoring of the FSR register.

For 16-bit core devices, this will enable/disable FSR0 context handling. And FSR2L/H registers will be saved/restored if a stack is implemented.

DECLARE PLL_REQ = ON or OFF, or TRUE or FALSE, or 1, 0

Most 16-bit core devices have a built in PLL (Phase Locked Loop) that can multiply the oscillator by a factor of 4. This is set by the fuses at programming time, and the PLL_REQ DECLARE enables or disables the PLL fuse. Using the PLL fuse allows a 1:1 ratio of instructions to clock cycles instead of the normal 4:1 ratio. It can be used with XTAL settings from 4 to 10MHz. Note that the compiler will automatically set it's frequency to a multiple of 4 if the PLL_REQ DECLARE is used to enable the PLL fuse. For example, if a 4MHz XTAL setting is declared, and the PLL_REQ DECLARE is used in the BASIC program, the compiler will automatically set itself up as using a 16MHz XTAL. i.e. 4 * 4. Thus keeping the timings for library functions correct.

DECLARE WARNINGS = ON or OFF, or TRUE or FALSE, or 1, 0

The WARNINGS DECLARE directive enables or disables the compiler's warning messages. This can have disastrous results if a warning is missed or ignored, so use this directive sparingly, and at your own peril.

The WARNINGS DECLARE can be issued multiple times within the BASIC code, enabling and disabling the warning messages at key points in the code as and when required.

DECLARE REMINDERS = ON or OFF, or TRUE or FALSE, or 1, 0

The REMINDERS DECLARE directive enables or disables the compiler's reminder messages. The compiler issues a reminder for a reason, so use this directive sparingly, and at your own peril.

The REMINDERS DECLARE can be issued multiple times within the BASIC code, enabling and disabling the warning messages at key points in the code as and when required.

DECLARE LABEL_BANK_RESETS = ON or OFF, or TRUE or FALSE, or 1, 0

The compiler has very intuitive RAM bank handling, however, if you think that an anomaly is occurring due to misplaced or mishandled RAM bank settings, you can issue this DECLARE and it will reset the RAM bank on every BASIC label, which will force the compiler to re-calculate its bank settings. If nothing else, it will reassure you that bank handling is not the cause of the problem, and you can get on with finding the cause of the programming problem. However, if it does cure a problem then please let me know and I will make sure the anomaly is fixed as quickly as possible.

Using this DECLARE will increase the size of the code produced, as it will place BCF mnemonics in the case of a 12 or 14-bit core device, and a MOVLB mnemonic in the case of a 16-bit core device.

The LABEL_BANK_RESETS DECLARE can be issued multiple times within the BASIC code, enabling and disabling the bank resets at key points in the code as and when required. See LINE LABELS for more information.

DECLARE FLOAT_DISPLAY_TYPE = LARGE or STANDARD

By default, the compiler uses a relatively small routine for converting floating point values to decimal, ready for RSOUT, PRINT, STR$ etc. However, because of its size, it does not perform any rounding of the value first, and is only capable of converting relatively small values. i.e. approx 6 digits of accuracy. In order to produce a more accurate result, the compiler needs to use a larger routine. This is implemented by using the above DECLARE.

Using the LARGE model for the above DECLARE will trigger the compiler into using the more accurate floating point to decimal routine. Note that even though the routine is larger than the standard converter, it actually operates much faster.

The compiler defaults to STANDARD if the DECLARE is not issued in the BASIC program.

DECLARE ICD_REQ =  ON or OFF, or TRUE or FALSE, or 1, 0

When the ICD_REQ DECLARE is set to ON, the compiler configures itself so that the Microchip ICD2 In-Circuit-Debugger can be used. The ICD2 is very invasive to the program, in so much that it requires certain RAM areas for itself. This can be up to 26 bytes on some PICmicros. It also requires 2 call-stack levels, so be careful when using a 14-bit core device or you may overflow the call-stack with disastrous results.

With a 14-bit core device, the top of BANK0 RAM is reserved for the ICD, for 16-bit core devices, the RAM usage is not so noticeable because of its linear nature, but it still requires 12 bytes reserved at the end of RAM.

The list below highlights the requirements for the ICD2 with the most recent PICmicros that support it.

Device	RAM Usage

P12F675	$54 - $5F

P12F629	$54 - $5F

P16F627A	$70 - $7F

P16F628A	$70 - $7F

P16F648A	$70 - $7F

P16F630	$54 - $5F

P16F676	$54 - $5F

P16F87	$70 - $7F

P16F88	$70 - $7F

P16F818	$65 - $7F

P16F819	$65 - $7F

P16F870	$70 - $7F, $B5 - $BF

P16F871	$70 - $7F, $B5 - $BF

P16F872	$70 - $7F, $B5 - $BF

P16F873/873A	$74 - $7F

P16F874/874A	$74 - $7F

P16F876/876A	$70 - $7F

P16F877/877A	$70 - $7F

P18F242/442	$02F4 - $02FF

P18F252/452	$05F4 - $05FF

P18F248/448	$02F4 - $02FF

P18F258/458	$05F4 - $05FF

P18F1220	$F4 - $FF

P18F1320	$F4 - $FF

P18F2220/4220	$01F4 - $01FF

P18F2320/4320	$01F4 - $01FF

P18F2331/4331	$02F4 - $02FF

P18F2431/4431	$02F4 - $02FF

P18F2680/4680	$0CF4 - $0CFF

P18F6520/8520	$0EF4 - $0EFF

P18F6620/8620	$0EF4 - $0EFF

P18F6720/8720	$0EF4 - $0EFF

Whenever ICD2 compatibility is enabled, the compiler will automatically deduct the reserved RAM from the available RAM within the PICmicro, therefore you must take this into account when declaring variables. Remember, there aren't as many variables available with the ICD enabled.

If the ICD is enabled along with hardware interrupts, the compiler will also reserve the RAM required for context saving and restoring. This also will be reflected in the amount of RAM available within the PICmicro.

TRIGONOMETRY Declares.

When using a 16-bit core device, the compiler defaults to using floating point trigonometry functions SIN and COS, as well as SQR. However, if only the BASIC Stamp compatible integer functions are required, they can be enabled by the following three declares. Note that by enabling the integer type function, the floating point function will be disabled permanently within the BASIC code. As with most of the declares, only one of any type is recognised per program.

DECLARE STAMP_COMPATIBLE_COS = ON or OFF, or TRUE or FALSE, or 1, 0

Enable/Disable floating point COS function in favour of the BASIC Stamp compatible integer COS function.

DECLARE STAMP_COMPATIBLE_SIN = ON or OFF, or TRUE or FALSE, or 1, 0

Enable/Disable floating point SIN function in favour of the BASIC Stamp compatible integer SIN function.

DECLARE STAMP_COMPATIBLE_SQR = ON or OFF, or TRUE or FALSE, or 1, 0

Enable/Disable floating point SQR (square root) function in favour of the BASIC Stamp compatible integer SQR function.

ADIN Declares.

DECLARE ADIN_RES 8 , 10 , or 12.

Sets the number of bits in the result.

If this DECLARE is not used, then the default is the resolution of the PICmicro type used. For example, the new 16F87X range will result in a resolution of 10-bits, while the standard PICmicro types will produce an 8-bit result. Using the above DECLARE allows an 8-bit result to be obtained from the 10-bit PICmicro types, but NOT 10-bits from the 8-bit types.

DECLARE ADIN_TAD 2_FOSC , 8_FOSC , 32_FOSC , or FRC.

Sets the ADC's clock source.

All compatible PICmicros have four options for the clock source used by the ADC; 2_FOSC, 8_FOSC, and 32_FOSC, are ratios of the external oscillator, while FRC is the PICmicro's internal RC oscillator. Instead of using the predefined names for the clock source, values from 0 to 3 may be used. These reflect the settings of bits 0-1 in register ADCON0.

Care must be used when issuing this DECLARE, as the wrong type of clock source may result in poor resolution, or no conversion at all. If in doubt use FRC which will produce a slight reduction in resolution and conversion speed, but is guaranteed to work first time, every time. FRC is the default setting if the DECLARE is not issued in the BASIC listing.

DECLARE ADIN_STIME 0 to 65535 microseconds (us).

Allows the internal capacitors to fully charge before a sample is taken. This may be a value from 0 to 65535 microseconds (us).

A value too small may result in a reduction of resolution. While too large a value will result in poor conversion speeds without any extra resolution being attained.

A typical value for ADIN_STIME is 50 to 100. This allows adequate charge time without loosing too much conversion speed.

But experimentation will produce the right value for your particular requirement. The default value if the DECLARE is not used in the BASIC listing is 50.

BUSIN - BUSOUT Declares.

DECLARE SDA_PIN PORT . PIN

Declares the port and pin used for the data line (SDA). This may be any valid port on the PICmicro. If this declare is not issued in the BASIC program, then the default Port and Pin is PORTA.0

DECLARE SCL_PIN PORT . PIN

Declares the port and pin used for the clock line (SCL). This may be any valid port on the PICmicro. If this declare is not issued in the BASIC program, then the default Port and Pin is PORTA.1

DECLARE SLOW_BUS ON - OFF or 1 - 0

Slows the bus speed when using an oscillator higher than 4MHz.

The standard speed for the I2C bus is 100KHz. Some devices use a higher bus speed of 400KHz. If you use an 8MHz or higher oscillator, the bus speed may exceed the devices specs, which will result in intermittent writes or reads, or in some cases, none at all. Therefore, use this DECLARE if you are not sure of the device's spec. The datasheet for the device used will inform you of its bus speed.

DECLARE BUS_SCL ON - OFF,  1 - 0 or TRUE - FALSE

Eliminates the necessity for a pullup resistor on the SCL line.

The I2C protocol dictates that a pullup resistor is required on both the SCL and SDA lines, however, this is not always possible due to circuit restrictions etc, so once the BUS_SCL ON DECLARE is issued at the top of the program, the resistor on the SCL line can be omitted from the circuit. The default for the compiler if the BUS_SCL DECLARE is not issued, is that a pullup resistor is required.

HBUSIN - HBUSOUT Declare.

DECLARE HBUS_BITRATE Constant 100, 400, 1000 etc.

The standard speed for the I2C bus is 100KHz. Some devices use a higher bus speed of 400KHz. The above DECLARE allows the I2C bus speed to be increased or decreased. Use this DECLARE with caution, as too high a bit rate may exceed the device's specs, which will result in intermittent transactions, or in some cases, no transactions at all. The datasheet for the device used will inform you of its bus speed. The default bit rate is the standard 100KHz.

HSERIN, HSEROUT, HRSIN and HRSOUT Declares.

DECLARE HSERIAL_BAUD Constant value

Sets the BAUD rate that will be used to receive a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL_RCSTA Constant value (0 to 255)

HSERIAL_RCSTA, sets the respective PICmicro hardware register RCSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register.

DECLARE HSERIAL_TXSTA Constant value (0 to 255)

HSERIAL_TXSTA, sets the respective PICmicro hardware register, TXSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate correctly.

DECLARE HSERIAL_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For HRSIN , HRSOUT , HSERIN and HSEROUT. The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL_PARITY = ODD 	' Use if odd parity desired

DECLARE HSERIAL_CLEAR ON or OFF

Clear the overflow error bit before commencing a read.

Because the hardware serial port only has a 2-byte input buffer, it can easily overflow is characters are not read from it often enough. When this occurs, the USART stops accepting any new characters, and requires resetting. This overflow error can be reset by strobing the CREN bit within the RCSTA register. Example: -

RCSTA.4 = 0

RCSTA.4 = 1

or

CLEAR RCSTA.4

SET RCSTA.4

Alternatively, the HSERIAL_CLEAR declare can be used to automatically clear this error, even if no error occurred. However, the program will not know if an error occurred while reading, therefore some characters may be lost.

DECLARE HSERIAL_CLEAR = ON

Second USART Declares for use with HRSIN2, HSERIN2, HRSOUT2 and HSEROUT2.

DECLARE HSERIAL2_BAUD Constant value

Sets the BAUD rate that will be used to transmit a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL2_RCSTA Constant value (0 to 255)

HSERIAL2_RCSTA, sets the respective PICmicro hardware register RCSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. Refer to the upgrade manual pages for a description of the RCSTA2 register.

DECLARE HSERIAL2_TXSTA Constant value (0 to 255)

HSERIAL2_TXSTA, sets the respective PICmicro hardware register, TXSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH2 bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate properly.

DECLARE HSERIAL2_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For  HRSOUT2, HRSIN2 , HSEROUT2 and HSERIN2. The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL2_PARITY declare.

DECLARE HSERIAL2_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL2_PARITY = ODD 	' Use if odd parity desired

DECLARE HSERIAL2_CLEAR ON or OFF

Clear the overflow error bit before commencing a read.

Because the hardware serial port only has a 2-byte input buffer, it can easily overflow is characters are not read from it often enough. When this occurs, the USART stops accepting any new characters, and requires resetting. This overflow error can be reset by strobing the CREN bit within the RCSTA2 register. Example: -

RCSTA2.4 = 0

RCSTA2.4 = 1

or

CLEAR RCSTA2.4

SET RCSTA2.4

Alternatively, the HSERIAL2_CLEAR declare can be used to automatically clear this error, even if no error occurred. However, the program will not know if an error occurred while reading, therefore some characters may be lost.

DECLARE HSERIAL2_CLEAR = ON

HPWM Declares.

Not all PICmicros use the same pins for their CCP modules, some devices, such as the PIC16F62x, and PIC18F4xx, have alternate pins that may be used for HPWM. The following DECLARES allow the use of different pins: -

DECLARE CCP1_PIN PORT . PIN  	' Select HPWM port and bit for CCP1 module. i.e. channel 1

DECLARE CCP2_PIN PORT . PIN  	' Select HPWM port and bit for CCP2 module. i.e. channel 2

If the DECLARES are not issued in the BASIC program, then the default values are CCP1_PIN as PORTB.2, and CCP2_PIN as PORTC.1.

LCD PRINT Declares.

DECLARE LCD_DTPIN PORT . PIN

Assigns the Port and Pins that the LCD's DT lines will attach to.

The LCD may be connected to the PICmicro using either a 4-bit bus or an 8-bit bus. If an 8-bit bus is used, all 8 bits must be on one port. If a 4-bit bus is used, it must be connected to either the bottom 4 or top 4 bits of one port. For example: -

DECLARE LCD_DTPIN PORTB.4	' Used for 4-line interface.

DECLARE LCD_DTPIN PORTB.0	' Used for 8-line interface.

In the above examples, PORTB is only a personal preference. The LCD's DT lines can be attached to any valid port on the PICmicro. If the DECLARE is not used in the program, then the default Port and Pin is PORTB.4, which assumes a 4-line interface.

DECLARE LCD_ENPIN PORT . PIN

Assigns the Port and Pin that the LCD's EN line will attach to. This also assigns the graphic LCD's EN pin, however, the default value remains the same as for the alphanumeric type, so this will require changing.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.2.

DECLARE LCD_RSPIN PORT . PIN

Assigns the Port and Pins that the LCD's RS line will attach to. This also assigns the graphic LCD's RS pin, however, the default value remains the same as for the alphanumeric type, so this will require changing.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.3.

DECLARE LCD_INTERFACE 4 or 8

Inform the compiler as to whether a 4-line or 8-line interface is required by the LCD.

If the DECLARE is not used in the program, then the default interface is a 4-line type.

DECLARE LCD_LINES 1 , 2 , or 4

Inform the compiler as to how many lines the LCD has.

LCD's come in a range of sizes, the most popular being the 2 line by 16 character types. However, there are 4-line types as well. Simply place the number of lines that the particular LCD has into the declare.

If the DECLARE is not used in the program, then the default number of lines is 2.

GRAPHIC LCD Declares.

DECLARE LCD_TYPE 1 or 0 , GRAPHIC or ALPHA

Inform the compiler as to the type of LCD that the PRINT command will output to. If GRAPHIC or 1 is chosen then any output by the PRINT command will be directed to a graphic LCD based on the Samsung S6B0108 chipset. A value of 0 or ALPHA, or if the DECLARE is not issued will target the standard alphanumeric LCD type

Targeting the graphic LCD will also enable commands such as PLOT, UNPLOT, LCDREAD, and LCDWRITE.

DECLARE LCD_DTPORT PORT

Assign the port that will output the 8-bit data to the graphic LCD.

If the DECLARE is not used, then the default port is PORTB.

DECLARE LCD_RWPIN PORT . PIN

Assigns the Port and Pin that the graphic LCD's RW line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTC.0.

DECLARE LCD_CS1PIN PORT . PIN

Assigns the Port and Pin that the graphic LCD's CS1 line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTC.0.

DECLARE LCD_CS2PIN PORT . PIN

Assigns the Port and Pin that the graphic LCD's CS2 line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTC.0.

DECLARE INTERNAL_FONT ON - OFF, 1 or 0

The graphic LCD's that are compatible with PROTON+ are non-intelligent types, therefore, a separate character set is required. This may be in one of two places, either externally, in an I2C eeprom, or internally in a CDATA table.

If an external font is chosen, the I2C eeprom must be connected to the specified SDA and SCL pins (as dictated by DECLARE SDA and DECLARE SCL).

If an internal font is chosen, it must be on a PICmicro device that has self modifying code features, such as the 16F87X, or 18XXXX  range.

The CDATA table that contains the font must have a label, named FONT: preceding it. For example: -

FONT: CDATA $7E , $11 , $11 , $11 , $7E , $0	' Chr "A"

CDATA $7F , $49 , $49 , $49 , $36 , $0	' Chr "B"

 	{ rest of font table }

The font table may be anywhere in memory, however, it is best placed after the main program code.

If the DECLARE is omitted from the program, then an external font is the default setting.

DECLARE FONT_ADDR 0 to 7

Set the slave address for the I2C eeprom that contains the font.

When an external source for the font is chosen, it may be on any one of 8 eeproms attached to the I2C bus. So as not to interfere with any other eeproms attached, the slave address of the eeprom carrying the font code may be chosen.

If the DECLARE is omitted from the program, then address 0 is the default slave address of the font eeprom.

DECLARE GLCD_CS_INVERT ON - OFF, 1 or 0

Some graphic LCD types have inverters on their CS lines. Which means that the LCD displays left hand data on the right side, and vice-versa. The GLCD_CS_INVERT DECLARE, adjusts the library LCD handling library subroutines to take this into account.

DECLARE GLCD_STROBE_DELAY 0 to 65535 us (microseconds).

Create a delay of n microseconds between strobing the EN line of the graphic LCD. This can help noisy, or badly decoupled circuits overcome random bits appearing on the LCD. The default if the DECLARE is not used in the BASIC program is a delay of 0.

KEYPAD Declare.

DECLARE KEYPAD_PORT PORT

Assigns the Port that the keypad is attached to.

The keypad routine requires pull-up resistors, therefore, the best Port for this device is PORTB which comes equipped with internal pull-ups. If the DECLARE is not used in the program, then PORTB is the default Port.

RSIN - RSOUT Declares.

DECLARE RSOUT_PIN PORT . PIN

Assigns the Port and Pin that will be used to output serial data from the RSOUT command. This may be any valid port on the PICmicro.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.0.

DECLARE RSIN_PIN PORT . PIN

Assigns the Port and Pin that will be used to input serial data by the RSIN command. This may be any valid port on the PICmicro.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.1.

DECLARE RSOUT_MODE INVERTED , TRUE or 1 , 0

Sets the serial mode for the data transmitted by RSOUT. This may be inverted or true. Alternatively, a value of 1 may be substituted to represent inverted, and 0 for true.

If the DECLARE is not used in the program, then the default mode is INVERTED.

DECLARE RSIN_MODE INVERTED , TRUE or 1 , 0

Sets the serial mode for the data received by RSIN. This may be inverted or true. Alternatively, a value of 1 may be substituted to represent inverted, and 0 for true.

If the DECLARE is not used in the program, then the default mode is INVERTED.

DECLARE SERIAL_BAUD 0 to 65535 bps (baud)

Informs the RSIN and RSOUT routines as to what baud rate to receive and transmit data.

Virtually any baud rate may be transmitted and received, but there are standard bauds, namely: -

300, 600, 1200, 2400, 4800, 9600, and 19200.

When using a 4MHz crystal, the highest baud rate that is reliably achievable is 9600. However, an increase in the oscillator speed allows higher baud rates to be achieved, including 38400 baud.

If the DECLARE is not used in the program, then the default baud is 9600.

DECLARE RSOUT_PACE 0 to 65535 microseconds (us)

Implements a delay between characters transmitted by the RSOUT command.

On occasion, the characters transmitted serially are in a stream that is too fast for the receiver to catch, this results in missed characters. To alleviate this, a delay may be implemented between each individual character transmitted by RSOUT.

If the DECLARE is not used in the program, then the default is no delay between characters.

DECLARE RSIN_TIMEOUT 0 to 65535 milliseconds (ms)

Sets the time, in ms, that RSIN will wait for a start bit to occur.

RSIN waits in a tight loop for the presence of a start bit. If no timeout parameter is issued, then it will wait forever.

The RSIN command has the option of jumping out of the loop if no start bit is detected within the time allocated by timeout.

If the DECLARE is not used in the program, then the default timeout value is 10000ms which is 10 seconds.

SERIN - SEROUT Declares.

If communications are with existing software or hardware, its speed and mode will determine the choice of baud rate and mode. In general, 7-bit/even-parity (7E) mode is used for text, and 8-bit/no-parity (8N) for byte-oriented data. Note: the most common mode is 8-bit/no-parity, even when the data transmitted is just text. Most devices that use a 7-bit data mode do so in order to take advantage of the parity feature. Parity can detect some communication errors, but to use it you lose one data bit. This means that incoming data bytes transferred in 7E (even-parity) mode can only represent values from 0 to 127, rather than the 0 to 255 of 8N (no-parity) mode.

The compiler's serial commands SERIN and SEROUT, have the option of still using a parity bit with 4 to 8 data bits. This is through the use of a DECLARE: -

With parity disabled (the default setting): -

DECLARE SERIAL_DATA 4 ' Set SERIN and SEROUT data bits to 4

DECLARE SERIAL_DATA 5 ' Set SERIN and SEROUT data bits to 5

DECLARE SERIAL_DATA 6 ' Set SERIN and SEROUT data bits to 6

DECLARE SERIAL_DATA 7 ' Set SERIN and SEROUT data bits to 7

DECLARE SERIAL_DATA 8 ' Set SERIN and SEROUT data bits to 8 (default)

With parity enabled: -

DECLARE SERIAL_DATA 5 ' Set SERIN and SEROUT data bits to 4

DECLARE SERIAL_DATA 6 ' Set SERIN and SEROUT data bits to 5

DECLARE SERIAL_DATA 7 ' Set SERIN and SEROUT data bits to 6

DECLARE SERIAL_DATA 8 ' Set SERIN and SEROUT data bits to 7 (default)

DECLARE SERIAL_DATA 9 ' Set SERIN and SEROUT data bits to 8

SERIAL_DATA data bits may range from 4 bits to 8 (the default if no DECLARE is issued). Enabling parity uses one of the number of bits specified.

Declaring SERIAL_DATA as 9 allows 8 bits to be read and written along with a 9th parity bit.

Parity is a simple error-checking feature. When a serial sender is set for even parity it counts the number of 1s in an outgoing byte and uses the parity bit to make that number even. For example, if it is sending the 7-bit value: %0011010, it sets the parity bit to 1 in order to make an even number of 1s (four).

The receiver also counts the data bits to calculate what the parity bit should be. If it matches the parity bit received, the serial receiver assumes that the data was received correctly. Of course, this is not necessarily true, since two incorrectly received bits could make parity seem correct when the data was wrong, or the parity bit itself could be bad when the rest of the data was correct.

Many systems that work exclusively with text use 7-bit/ even-parity mode. For example, to receive one data byte through bit-0 of PORTA at 9600 baud, 7E, inverted.

DECLARE SERIAL_PARITY ODD or EVEN

Sets the parity type for SERIN, and SEROUT. When parity is enabled, this declare chooses whether it is ODD or EVEN. If parity is enabled but the SERIAL_PARITY DECLARE is not issued in the program, the default setting is EVEN parity.

DECLARE SERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE SERIAL_PARITY = ODD 	' Use if odd parity desired

SHIN - SHOUT Declare.

DECLARE SHIFT_DELAYUS 0 - 65535 microseconds (us)

Extend the active state of the shift clock.

The clock used by SHIN and SHOUT runs at approximately 45KHz dependent on the oscillator. The active state is held for a minimum of 2 microseconds. By placing this declare in the program, the active state of the clock is extended by an additional number of microseconds up to 65535 (65.535 milliseconds) to slow down the clock rate.

If the DECLARE is not used in the program, then the default is no clock delay.

CRYSTAL Frequency Declare.

DECLARE XTAL 4 , 8 , 10 , 12 , 16 , 20, or 24. For 12-bit core devices.

DECLARE XTAL 3 , 4 , 8 , 10 , 12 , 14 , 16 , 20, or 24. For 14-bit core devices.

DECLARE XTAL 3 , 4 , 8 , 10 , 12 , 14 , 16 , 20 , 24 , 25 ,32 , 33 , or 40. For 16-bit core devices.

Inform the compiler as to what frequency crystal is being used.

Some commands are very dependant on the oscillator frequency, RSIN, RSOUT, DELAYMS, and DELAYUS being just a few. In order for the compiler to adjust the correct timing for these commands, it must know what frequency crystal is being used.

If an XTAL frequency of 3 or 14 is chosen, then the resulting code is produced for 3.58MHz and 14.32MHz respectively.

If the DECLARE is not used in the program, then the default frequency is 4MHz.

Notes

The DECLARE directive alters the corresponding library subroutine at runtime. This means that once the DECLARE is added to the BASIC program, it cannot be UNDECLARED later, or changed in any way, unless specifically stated in the manual or helpfile.

The DECLARE directive is also capable of passing information to an assembly routine. For example: -

DECLARE USE_THIS_PIN PORTA , 1

Notice the use of a comma, instead of a point for separating the register and bit number. This is because it is being passed directly to the assembler as a #DEFINE directive.


DELAYMS

Syntax

DELAYMS Length

Availability

All devices.

Overview

Delay execution for length x milliseconds (ms). Delays may be up to 65535ms (65.535 seconds) long.

Operators

Length can be a constant, variable, or expression.

Example

XTAL  = 4

DIM VAR1 as BYTE

DIM WRD1 as WORD

VAR1 = 50

WRD1= 1000

DELAYMS 100	' Delay for 100ms

DELAYMS VAR1	' Delay for 50ms

DELAYMS WRD1	' Delay for 1000ms

DELAYMS WRD1+ 10	' Delay for 1010ms

Notes

DELAYMS is oscillator independent, as long as you inform the compiler of the crystal frequency to use, using the DECLARE directive.

See also : DELAYUS, SLEEP, SNOOZE.


DELAYUS

Syntax

DELAYUS Length

Availability

All devices.

Overview

Delay execution for length x microseconds (us). Delays may be up to 65535us (65.535 milliseconds) long.

Operators

Length can be a constant, variable, or expression.

Example

DECLARE XTAL 20

DIM VAR1 as BYTE

DIM WRD1 as WORD

VAR1 = 50

WRD1= 1000

DELAYUS 1	' Delay for 1us

DELAYUS 100	' Delay for 100us

DELAYUS VAR1	' Delay for 50us

DELAYUS WRD1	' Delay for 1000us

DELAYUS WRD1+ 10	' Delay for 1010us

Notes

 DELAYUS is oscillator independent, as long as you inform the compiler of the crystal frequency to use, using the DECLARE directive.

 If a constant is used as length, then delays down to 1us can be achieved, however, if a variable is used as length, then there's a minimum delay time depending on the frequency of the crystal used: -

 CRYSTAL FREQ MINIMUM DELAY

4MHz 24us

8MHz 12us

10MHz 8us

16MHz 5us

20MHz 2us

24MHz 2us

25MHz 2us

32MHz 2us

33MHz 2us

40MHz 2us

See also : DECLARE, DELAYMS, SLEEP, SNOOZE


DEVICE

Syntax

DEVICE Device number

Availability

All devices.

Overview

Inform the compiler which PICmicro device is being used.

Operators

Device number can be  a 12-bit, 14-bit, or 16-bit core device.

Example

DEVICE 16F877	' Produce code for a 16F877 PICmicro device

 or

DEVICE 16F84	' Produce code for a 16F84 PICmicro device

or

DEVICE 12C508	' Produce code for a 12-bit core 12C508 PICmicro device

or

DEVICE 18F452	' Produce code for a 18F452 PICmicro device

Supported devices

12-bit core OTP (One Time Programmable)

12C508, 12C509, 12C508A, 12C509A, 12CE518, 12CE519, 16C54, 16C54A, 16C54B

16C55, 16C55A, 16C56, 16C56A, 16CR56, 16C57, 16C57C, 16CR57A, 16CR57B

16C58,16C58A, 16CR58A, 16CR58B, 16CR58C, RF509AF,RF509AG

12-bit core FLASH (Re-Writable)

10F200, 10F202, 10F204, 10F206, 12F508, 12F509

14-bit core OTP (One Time Programmable)

12C671, 12C672, 12CE673, 12CE674, 16C61, 16C62, 16C62A, 16C62B

16C63, 16C63A, 16C64, 16C64A, 16C65, 16C65A, 16C65B, 16C66, 16C67

16C71, 16C71A, 16C72, 16C72A, 16C73, 16C73A, 16C73B, 16C73C, 16C74

16C74A, 16C76, 16C77, 16C554, 16C554A, 16C558, 16C558A, 16C641

16C642, 16C661, 16C662, 16C710, 16C711, 16C712, 16C715, 16C716

16C745, 16C765, 16C770, 16C771

14-bit core FLASH (Re-Writable)

12F675, 12F629, 16F630, 16C84, 16CR84, 16F72, 16F73, 16F74, 16F76, 16F77

16F83, 16F84, 16F84A, 16F87, 16F88, 16F627, 16F628, 16F627A, 16F628A, 16F648A

16F676, 16F684, 16F688, 16F737, 16F747, 16F767, 16F777, 16F818, 16F819, 16F870

16F871, 16F872, 16F873, 16F873A, 16F874, 16F874A, 16F876, 16F876A, 16F877, 16F877A

16-bit core OTP (One Time Programmable)

18C242, 18C252, 18C442, 18C452, 18C658, 18C858

16-bit FLASH (Re-Writable)

18F1220, 18F1320, 18F2220, 18F2320, 18F2439, 18F2539, 18F242, 18F248, 18F252, 18F258

18F442, 18F448, 18F452, 18F458, 18F4220, 18F4320, 18F4439, 18F4539, 18F4525, 18F6620

18F6720, 18F8620, 18F8720

DEVICE should be the first command placed in the program.

If you are unsure if the device you wish to use is supported by PROTON+ , then check if it highlight's in bold blue text. If it does, then it is supported.

If the DEVICE directive is not used in the BASIC program, the code produced will default to the ever-popular (but now dated) 16F84 device.


DIG

Syntax

Variable = DIG Value , Digit number

Availability

All devices.

Overview

Returns the value of a decimal digit.

Operators

Value is a constant, variable, or expression, from which the digit number is to be extracted.

Digit number is a constant, variable, or expression, that represents the digit to extract from value. (0 - 9 with 0 being the rightmost digit).

Example

DIM VAR1 as BYTE

DIM VAR2 as BYTE

VAR1 = 124

VAR2 = DIG VAR1 , 1	' Extract the second digit's value

PRINT @VAR2	' Display the value, which is 2

Because this version of the DIG command is unique to the PROTON+ compiler, it also supports DWORD variables.


DIM

Syntax

DIM Variable { as } { Size }

Availability

All devices.

Overview

All user-defined variables must be declared using the DIM statement.

Operators

Variable can be any alphanumeric character or string.

as is required when the size of the variable is stated.

Size is the physical size of the variable, it  may be BIT, BYTE, WORD, DWORD, or FLOAT.

Example 1

' Declare the variables all as BYTE sized

DIM A , B , My_VAR1 , fred , cat , zz

Example 1 only applies to BYTE sized variables, and is merely a left over from a previous version of the compiler. But is too commonly used to remove it.

Example 2

' Declare different sized variables

 	DIM VAR1 AS BYTE	' Declare an 8-bit BYTE sized variable

 	DIM WRD1 AS WORD	' Declare a 16-bit WORD sized variable

DIM DWRD1 AS DWORD	' Declare a 32-bit DWORD sized variable

DIM BITVAR AS BIT	' Declare a 1-bit BIT sized variable

 	DIM FLT AS FLOAT	' Create a 32-bit floating point variable

Notes

Any variable that is declared without the 'AS' text after it, will assume an 8-bit BYTE type.

For and explanation of creating BYTE ARRAY,or WORD ARRAY variables see Creating and using Arrays,.

DIM should be placed near the beginning of the program. Any references to variables not declared or before they are declared may, in some cases, produce errors.

Variable names, as in the case or labels, may freely mix numeric content and underscores.

DIM MyVar AS BYTE

or

DIM MY_VAR AS WORD

or

DIM My_Var2 AS BIT

Variable names may start with an underscore, but must NOT start with a number. They can be no more than 32 characters long. Any characters after this limit will be ignored.

DIM 2MyVar 	is NOT allowed.

Variable names are case insensitive, which means that the variable: -

DIM MYVAR

Is the same as…

DIM MYVAR

DIM can also be used to create constants i.e. numbers: -

DIM Num AS 100	' NUM now represents the value 100

DIM BigNum AS 1000	' BIGNUM now represents 1000

 	DIM VeryBigNum AS 1000000 	' VERYBIGNUM now represents 1000,000

Constant values differ to their variable counterparts because they do not take up any RAM space. They are simply ALIAS's to numbers.

Numeric constants may contain complex equations: -

DIM Complex AS (( 2000 / 54 ) << 2) & 255)

Floating point constants may also be created using DIM by simply adding a decimal point to a value.

DIM PI AS 3.14	' Create a floating point constant named PI

DIM FL_NUM AS 5.0	' Create a floating point constant holding the value 5

Floating point constant can also be created using expressions.

DIM QUANTA AS 5.0 / 1024	' Create a floating point constant holding the result of the expression

DIM can also be used to create ALIAS's to other variables or constants: -

DIM VAR1 AS BYTE	' Declare a BYTE sized variable

DIM VAR_Bit AS VAR1.1	' VAR_BIT now represents Bit-1 of VAR1

ALIAS's, as in the case of constants, do not require any RAM space, because they point to a variable, or part of a variable that has already been declared.

RAM space required.

Each type of variable requires differing amounts of RAM memory for its allocation. The list below illustrates this.

FLOAT	Requires 4 bytes of RAM.

DWORD	Requires 4 bytes of RAM.

WORD	Requires 2 bytes of RAM.

BYTE	Requires 1 byte of RAM.

BIT	Requires 1 byte of RAM for every 8 BIT variables used.

Each type of variable may hold a different minimum and maximum value.

FLOAT type variables may theoretically hold a value from -1e37 to +1e38, as well as fractional values, making this the most accurate of the variable family types. However, more so than DWORD types, this comes at a price as FLOAT calculations and comparisons will use more code space within the PICmicro. Use this type of variable sparingly, and only when strictly necessary. Smaller floating point values offer more accuracy.

DWORD type variables may hold a value from -2147483648 to +2147483647. This comes at a price however, as DWORD calculations and comparisons will use more code space within the PICmicro. Use this type of variable sparingly, and only when necessary.

WORD type variables may hold a value from 0 to 65535, which is usually large enough for most applications. It still uses more memory, but not nearly as much as a DWORD type.

BYTE type variables may hold a value for 0 to 255, and are the usual work horses of most programs. Code produced for BYTE sized variables is very low compared to WORD , or DWORD types, and should be chosen if the program requires faster, or more efficient operation.

BIT type variables may hold a 0 or a 1. These are created 8 at a time, therefore declaring a single BIT type variable in a program will not save RAM space, but it will save code space, as BIT type variables produce the most efficient use of code for comparisons etc.

There are modifiers that may also be used with variables. These are HIGHBYTE, LOWBYTE, BYTE0, BYTE1, BYTE2, and BYTE3.

BYTE2, and BYTE3 may only be used in conjunction with a 32-bit DWORD type variable.

HIGHBYTE and BYTE1 are one and the same thing, when used with a WORD type variable, they refer to the High byte of a WORD type variable: -

DIM WRD AS WORD	' Declare a WORD sized variable

DIM WRD_HI AS WRD.HIGHBYTE	' WRD_HI now represents the HIGHBYTE of variable WRD

Variable WRD_HI is now accessed as a BYTE sized type, but any reference to it actually alters the high byte of WRD.

However, if BYTE1 is used in conjunction with a DWORD type variable, it will extract the second byte. HIGHBYTE will still extract the high byte of the variable, as will BYTE3.

The same is true of LOWBYTE and BYTE0, but they refer to the Low Byte of a WORD type variable: -

DIM WRD AS WORD	' Declare a WORD sized variable

DIM WRD_LO AS WRD.LOWBYTE	' WRD_LO now represents the LOWBYTE of variable WRD

Variable WRD_LO is now accessed as a BYTE sized type, but any reference to it actually alters the low byte of WRD.

The modifier BYTE2 will extract the 3rd byte from a 32-bit DWORD type variable, as an alias. Likewise BYTE3 will extract the high byte of a 32-bit variable.

RAM space for variables is allocated within the PICmicro in the order that they are placed in the BASIC code. For example: -

DIM VAR1 AS BYTE

DIM VAR2 AS BYTE

Places VAR1 first, then VAR2: -

VAR1 EQU n

VAR2 EQU n

This means that on a PICmicro with more than one BANK, the first n variables will always be in BANK0 (the value of n depends on the specific PICmicro used).

The position of the variable within BANKs is usually of little importance if BASIC code is used, however, if assembler routines are being implemented, always assign any variables used within them first.

Problems may also arise if a WORD, or DWORD variable crosses a BANK boundary. If this happens, a warning message will be displayed in the error window. Most of the time, this will not cause any problems, however, to err on the side of caution, try and ensure that WORD, or DWORD type variables are fully inside a BANK. This is easily accomplished by placing a dummy BYTE variable before the offending WORD, or DWORD type variable, or relocating the offending variable within the list of DIM statements.

WORD type variables have a low byte and a high byte. The high byte may be accessed by simply adding the letter H to the end of the variable's name. For example: -

DIM WRD AS WORD

Will produce the assembler code: -

WRD EQU n

WRDH EQU n

To access the high byte of variable WRD, use: -

WRDH = 1

This is especially useful when assembler routines are being implemented, such as: -

MOVLW 1

MOVWF WRDH 	; Load the high byte of WRD with 1

DWORD type variables have a low, mid1, mid2, and hi byte. The high byte may be accessed by adding three letter H's to the variable's name. For example: -

DIM DWD AS DWORD

Will produce the assembler code: -

DWD EQU n

DWDH EQU n

DWDHH EQU n

DWDHHH EQU n

To access the high byte of variable WRD, use: -

DWDHHH = 1

or

DWD.HIGHBYTE = 1

The low, and mid bytes may be similarly accessed by adding or removing the "H" after the variable's name.

See Also : ALIASES, DECLARING ARRAYS, ARRAYS, CONSTANTS Floating Point MathSYMBOL, SYMBOLS.


DTMFOUT

Syntax

DTMFOUT Pin , { OnTime } , { OffTime, } [ Tone {, Tone…} ]

Availability

14-bit and 16-bit core devices.

Overview

Produce a DTMF Touch Tone sequence on Pin.

Operators

Pin is a PORT.BIT constant that specifies the I/O pin to use. This pin will be set to output during generation of tones and set to input after the command is finished.

OnTime is an optional variable, constant, or expression (0 - 65535) specifying the duration, in ms, of the tone. If the OnTime parameter is not used, then the default time is 200ms

OffTime is an optional variable, constant, or expression (0 - 65535) specifying the length of silent delay, in ms, after a tone (or between tones, if multiple tones are specified). If the OffTime parameter is not used, then the default time is 50ms

Tone may be a variable, constant, or expression (0 - 15) specifying the DTMF tone to generate. Tones 0 through 11 correspond to the standard layout of the telephone keypad, while 12 through 15 are the fourth-column tones used by phone test equipment and in some radio applications.

Example

DTMFOUT PORTA.0 , [ 6 , 6 , 6 , 7 , 0 , 9 ] 	' Call Crownhill.

If the PICmicro was connected to the phone line correctly, the above command would dial 666-709. If you wanted to slow down the dialling in order to break through a noisy phone line or radio link, you could use the optional OnTime and OffTime values: -

'Set the OnTime to 500ms and OffTime to 100ms

DTMFOUT PORTA.0 , 500 , 100 , [ 6 , 6 , 6 , 7 , 0 , 9 ] 	' Call Crownhill Slowly.

Notes

DTMF tones are used to dial a telephone, or remotely control pieces of radio equipment. The PICmicro can generate these tones digitally using the DTMFOUT command. However, to achieve the best quality tones, a higher crystal frequency is required. A 4MHz type will work but the quality of the sound produced will suffer.

A word of caution. Connecting any device to the phone line in the UK is frowned upon by the authorities without approval. Both Crownhill Associates, and myself do not condone unauthorized telephone connections, and will not be held responsible for any aforementioned authorised or unauthorized connections.

The PICmicro is a digital device, however, DTMF tones are analogue waveforms, consisting of a mixture of two sine waves at different audio frequencies. So how can a digital device generate an analogue output? The PICmicro creates and mixes two sine waves mathematically, then uses the resulting stream of numbers to control the duty cycle of an extremely fast pulse-width modulation (PWM) routine. Therefore, what's actually being produced from the I/O pin is a rapid stream of pulses. The purpose of the filtering arrangements illustrated above is to smooth out the high-frequency PWM, leaving behind only the lower frequency audio.

You should keep this in mind if you wish to interface the PICmicro's DTMF output to radios and other equipment that could be adversely affected by the presence of high-frequency noise on the input. Make sure to filter the DTMF output scrupulously.

See also : FREQOUT, SOUND, SOUND2.


EDATA

Syntax

EDATA Constant1 { ,...Constantn etc }

Availability

14-bit and 16-bit core devices.

Overview

Places constants or strings directly into the on-board eeprom memory of compatible PICmicros

Operators

Constant1,Constantn are values that will be stored in the on-board eeprom. When using an EDATA statement, all the values specified will be placed in the eeprom starting at location 0. The EDATA statement does not allow you to specify an eeprom address other than the beginning location at 0. To specify a location to write or read data from the eeprom other than 0 refer to the EREAD, EWRITE commands.

Example

' Stores the values 1000,20,255,15, and the ASCII values for

' H','e','l','l','o' in the eeprom starting at memory position 0.

EDATA 1000 , 20 , $FF , %00001111 , "Hello"

Notes

16-bit, 32-bit and floating point values may also be placed into eeprom memory. These are placed LSB first (LOWEST SIGNIFICANT BYTE). For example, if 1000 is placed into an EDATA statement, then the order is: -

EDATA 1000

In eeprom it looks like 232, 03

Alias's to constants may also be used in an EDATA statement: -

SYMBOL ALIAS = 200

EDATA ALIAS , 120 , 254 , "Hello World"

Addressing an EDATA table.

Eeprom data starts at address 0 and works up towards the maximum amount that the PICmicro will allow. However, it is rarely the case that the information stored in eeprom memory is one continuous piece of data. Eeprom memory is normally used for storage of several values or strings of text, so a method of accessing each piece of data is essential. Consider the following piece of code: -

EDATA "HELLO"

EDATA "WORLD"

Now we know that eeprom memory starts at 0, so the text "HELLO" must be located at address 0, and we also know that the text "HELLO" is built from 5 characters with each character occupying  a byte of eeprom memory, so the text "WORLD" must start at address 5 and also contains 5 characters, so the next available piece of eeprom memory is located at address 10. To access the two separate text strings we would need to keep a record of the start and end address's of each character placed in the tables. Counting the amount of eeprom memory used by each piece of data is acceptable if only a few EDATA tables are used in the program, but it can become tedious if multiple values and strings are needing to be stored, and can lead to program glitches if the count is wrong.

Placing an identifying name before the EDATA table will allow the compiler to do the byte counting for you. The compiler will store the eeprom address associated with the table in the identifying name as a constant value. For example: -

HELLO_TEXT 	EDATA "HELLO"

WORLD_TEXT	EDATA "WORLD"

The name HELLO_TEXT is now recognised as a constant with the value of 0, referring to address 0 that the text string "HELLO" starts at. The WORLD_TEXT is a constant holding the value 5, which refers to the address that the text string "WORLD" starts at.

Note that the identifying text MUST be located on the same line as the EDATA directive or a syntax error will be produced. It must also NOT contain a postfix colon as does a line label or it will be treat as a line label. Think of it as an alias name to a constant.

Any EDATA directives MUST be placed at the head of the BASIC program as is done with SYMBOLS, so that the name is recognised by the rest of the program as it is parsed. There is no need to jump over EDATA directives as you have to with LDATA or CDATA, because they do not occupy code memory, but reside in high DATA memory.

The example program below illustrates the use of eeprom addressing.

' Display two text strings held in eeprom memory

Include "PROTON_4.INC"	' Demo on a PROTON development board

    	Dim CHAR as Byte	' Holds the character read from eeprom

    	Dim CHARPOS as Byte	' Holds the address within eeprom memory

HELLO	EDATA "HELLO ",0	' Create a string of text in eeprom memory. NULL terminated

WORLD	EDATA "WORLD",0	' Create another string of text in eeprom memory. NULL terminated

Delayms 200	' Wait for the PICmicro to stabilise

 	Cls	' Clear the LCD

CHARPOS = HELLO	' Point CHARPOS to the start of text "HELLO"

Gosub DISPLAY_TEXT	' Display the text "HELLO"

 	CHARPOS = WORLD	' Point CHARPOS to the start of text "WORLD"

Gosub DISPLAY_TEXT	' Display the text "WORLD"

Stop	' We're all done

' Subroutine to read and display the text held at the address in CHARPOS

DISPLAY_TEXT:

While 1 = 1	' Create an infinite loop

CHAR = EREAD CHARPOS	' Read the eeprom data

If CHAR = 0 Then Break	' Exit when NULL found

 	Print CHAR	' Display the character

Inc CHARPOS	' Move up to the next address

 	Wend	' Close the loop

Return	' Exit the subroutine

Formatting an EDATA table.

Sometimes it is necessary to create a data table with a known format for its values. For example all values may need to occupy 4 bytes of data space even though the value itself would only occupy 1 or 2 bytes.

EDATA 100000 , 10000 , 1000 , 100 , 10 , 1

The above line of code would produce an uneven data space usage, as each value requires a different amount of data space to hold the values. 100000 would require 4 bytes of eeprom space, 10000 and 1000  would both require 2 bytes, but 100, 10, and 1 would only require 1 byte.

Reading these values using EREAD would cause problems because there is no way of knowing the amount of bytes to read in order to increment to the next valid value.

The answer is to use formatters in order to ensure that a value occupies a predetermined amount of bytes. These are: -

BYTE

WORD

DWORD

FLOAT

Placing one of these formatters before the value in question will force a given length.

EDATA DWORD 100000 , DWORD 10000 , DWORD  1000 , DWORD  100 , DWORD 10 , DWORD 1

BYTE will force the value to occupy one byte of eeprom space, regardless of it's value. Any values above 255 will be truncated to the least significant byte.

WORD will force the value to occupy 2 bytes of eeprom space, regardless of its value. Any values above 65535 will be truncated to the two least significant bytes. Any value below 255 will be padded to bring the memory count to 2 bytes.

DWORD will force the value to occupy 4 bytes of eeprom space, regardless of its value. Any value below 65535 will be padded to bring the memory count to 4 bytes. The line of code shown above uses the DWORD formatter to ensure all the values in the EDATA table occupy 4 bytes of eeprom space.

FLOAT will force a value to its floating point equivalent, which always takes up 4 bytes of eeprom space.

If all the values in an EDATA table are required to occupy the same amount of bytes, then a single formatter will ensure that this happens.

EDATA AS DWORD 100000 , 10000 , 1000 , 100 , 10 , 1

The above line has the same effect as the formatter previous example using seperate DWORD formatters, in that all values will occupy 4 bytes, regardless of their value. All four formatters can be used with the AS keyword.

The example below illustrates the formatters in use.

' Convert a DWORD value into a string array

' Using only BASIC commands

' Similar principle to the STR$ command

Include "PROTON_4.INC"

Dim P10 as Dword	' Power of 10 variable

Dim CNT as Byte

Dim J as Byte

Dim VALUE as Dword	' Value to convert

Dim STRING1[11] as Byte	' Holds the converted value

Dim PTR as Byte	' Pointer within the Byte array

Delayms 500	' Wait for PICmicro to stabilise

Cls	' Clear the LCD

Clear	' Clear all RAM before we start

VALUE = 1234576	' Value to convert

Gosub DWORD_TO_STR	' Convert VALUE to string

Print STR STRING1	' Display the result

Stop

'-------------------------------------------------------------

' Convert a DWORD value into a string array

' Value to convert is placed in 'VALUE'

' Byte array 'STRING1' is built up with the ASCII equivalent

DWORD_TO_STR:

PTR = 0

J = 0

Repeat

P10 = EREAD J * 4

CNT = 0

While VALUE >= P10

VALUE = VALUE - P10

Inc CNT

Wend

If CNT <> 0 Then

STRING1[PTR] = CNT + "0"

Inc PTR

Endif

Inc J

Until J > 8

STRING1[PTR] = VALUE + "0"

Inc PTR

STRING1[PTR] = 0	' Add the NULL to terminate the string

Return

' EDATA table is formatted for all 32 bit values.

' Which means each value will require 4 bytes of eeprom space

EDATA  AS DWORD 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10

Label names as pointers in an EDATA table.

If a label's name is used in the list of values placed in an EDATA table, the label's address will be entered into eeprom memory. This is useful for accessing other tables of data using their address from a lookup table. See example below.

' Display text from two CDATA tables

' Based on their address located in a separate EDATA table

       	 Include "PROTON_4.INC"	' Use a 14-bit core device

       	 Dim ADDRESS as Word

       	 Dim DATA_BYTE as Byte

       	Delayms 200	' Wait for PICmicro to stabilise

        	Cls	' Clear the LCD

        	ADDRESS = EREAD 0	' Locate the address of the first string

       	While 1 = 1	' Create an infinite loop

        	DATA_BYTE = CREAD ADDRESS	' Read each character from the CDATA string

            If DATA_BYTE = 0 Then EXIT_LOOP	' Exit if NULL found

        	Print DATA_BYTE	' Display the character

            Inc ADDRESS	' Next character

        	Wend	' Close the loop

EXIT_LOOP:

        	Cursor 2,1	' Point to line 2 of the LCD

ADDRESS = EREAD 2	' Locate the address of the second string

       	While 1 = 1	' Create an infinite loop

        	DATA_BYTE = CREAD ADDRESS	' Read each character from the CDATA string

            If DATA_BYTE = 0 Then EXIT_LOOP2 	' Exit if NULL found

        	Print DATA_BYTE	' Display the character

            Inc ADDRESS	' Next character

        	Wend	' Close the loop

EXIT_LOOP2:

        	Stop

' Table of address's located in eeprom memory

EDATA AS WORD STRING1, STRING2

STRING1:

CDATA "HELLO",0

STRING2:

CDATA "WORLD",0

See also : CDATA, CREAD, DATA, EREAD, EWRITE , Creating and using VIRTUAL STRINGS with CDATA, Creating and using VIRTUAL STRINGS with EDATA.


END

Syntax

END

Availability

All devices.

Overview

The END statement stops compilation of source, and creates an infinite loop.

Notes

END stops the PICmicro processing by placing it into a continuous loop. The port pins remain the same and the device is placed in low power mode.

See also : STOP, SLEEP, SNOOZE.


EREAD

Syntax

Variable = EREAD Address

Availability

14-bit and 16-bit core devices.

Overview

Read information from the on-board eeprom available on some PICmicro types.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Address is a constant, variable, or expression, that contains the address of interest within eeprom memory.

Example

DEVICE 16F84	' A PICmicro with on-board eeprom

DIM VAR1 as BYTE

DIM WRD1 as WORD

DIM DWRD1 as DWORD

EDATA 10 , 354 , 123456789	' Place some data into the eeprom

VAR1 = EREAD 0	' Read the 8-bit value from address 0

WRD1= EREAD 1	' Read the 16-bit value from address 1

DWRD1 = EREAD 3	' Read the 32-bit value from address 3

Notes

If a FLOAT, or DWORD type variable is used as the assignment variable, then 4-bytes will be read from the eeprom. Similarly, if a  WORD type variable is used as the assignment variable, then a 16-bit value (2-bytes)will be read from eeprom, and if a BYTE type variable is used, then 8-bits will be read. To read an 8-bit value while using a WORD sized variable, use the LOWBYTE modifier: -

WRD1.LOWBYTE = EREAD 0	' Read an 8-bit value

WRD1.HIGHBYTE = 0	' Clear the high byte of WRD

If a 16-bit (WORD) size value is read from the eeprom, the address must be incremented by two for the next read. Also, if a FLOAT or DWORD type variable is read, then the address must be incremented by 4.

Most of the Flash PICmicro types have a portion of memory set aside for storage of information. The amount of memory is specific to the individual PICmicro type, some, such as the 16F84, has 64 bytes, the 16F877 device has 256 bytes, and some of the 16-bit core devices have upwards of 512 bytes.

Eeprom memory is non-volatile, and is an excellent place for storage of long-term information, or tables of values.

Reading data with the EREAD command is almost instantaneous, but writing data to the eeprom can take up to 10ms per byte.

See also : EDATA, EWRITE


EWRITE

Syntax

EWRITE Address , [ Variable {, Variable…etc } ]

Availability

14-bit and 16-bit core devices.

Overview

Write information to the on-board eeprom available on some PICmicro types.

Operators

Address is a constant, variable, or expression, that contains the address of interest within eeprom memory.

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT, or  a constant value.

Example

DEVICE 16F628	' A PICmicro with on-board eeprom

DIM VAR1 as BYTE

DIM WRD1 as WORD

DIM Address as BYTE

VAR1 = 200

WRD1= 2456

Address = 0	' Point to address 0 within the eeprom

EWRITE Address , [ WRD , VAR1 ]	' Write a 16-bit then an 8-bit value

Notes

If a DWORD type variable is used, then a 32-bit value (4-bytes) will be written to the eeprom. Similarly, if a  WORD type variable is used, then a 16-bit value (2-bytes) will be written to eeprom, and if a BYTE type variable is used, then 8-bits will be written. To write an 8-bit value while using a WORD sized variable, use the LOWBYTE modifier: -

EWRITE Address , [ WRD.LOWBYTE , VAR1 ]

If a 16-bit (WORD) size value is written to the eeprom, the address must be incremented by two before the next write: -

FOR Address = 0 TO 64 STEP 2

EWRITE Address , [ WRD ]

NEXT

Most of the Flash PICmicro types have a portion of memory set aside for storage of information. The amount of memory is specific to the individual PICmicro type, some, such as the 16F84, has 64 bytes, while the newer 16F877, and 18FXXX devices have 256 bytes.

Eeprom memory is non-volatile, and is an excellent place for storage of long-term information, or tables of values.

Writing data with the EWRITE command can take up to 10ms per byte, but reading data from the eeprom is almost instantaneous,.

See also : EDATA, EREAD


FOR...NEXT...STEP

Syntax

FOR Variable = Startcount TO Endcount [ STEP { Stepval } ]

{code body}

NEXT

Availability

All devices.

Overview

The FOR…NEXT loop is used to execute a statement, or series of statements a predetermined amount of times.

Operators

Variable refers to an index variable used for the sake of the loop. This index variable can itself be used in the code body but beware of altering its value within the loop as this can cause many problems.

Startcount is the start number of the loop, which will initially be assigned to the variable. This does not have to be an actual number - it could be the contents of another variable.

Endcount is the number on which the loop will finish. This does not have to be an actual number - it could be the contents of another variable, or an expression.

Stepval is an optional constant or variable by which the variable increases or decreases with each trip through the FOR-NEXT loop. If startcount is larger than endcount, then a minus sign must precede stepval.

Example 1

' Display in decimal, all the values of WRD within an upward loop

DIM WRD as WORD

FOR WRD = 0 TO 2000 STEP 2	' Perform an upward loop

PRINT @WRD ," "	' Display the value of WRD

NEXT	' Close the loop

Example 2

' Display in decimal, all the values of WRD within a downward loop

DIM WRD as WORD

 	FOR WRD = 2000 TO 0 STEP -2	' Perform a downward loop

 	PRINT @WRD ," "	' Display the value of WRD

 	NEXT	' Close the loop

Example 3

' Display in decimal, all the values of DWRD within a downward loop

DIM DWRD as DWORD

 	FOR DWRD = 200000 TO 0 STEP -200	' Perform a downward loop

 	PRINT @DWRD ,"         "	' Display the value of DWRD

 	NEXT	' Close the loop

Example 3

' Display in decimal, all the values of WRD1 using a expressions as parts of the FOR-NEXT construct

DIM WRD1 as WORD

 	DIM WRD2 as WORD

WRD2 = 1000

FOR WRD1= WRD2 + 10 TO WRD2 +1000	' Perform a  loop

 	PRINT @WRD1," "	' Display the value of WRD1

 	NEXT	' Close the loop

Notes

You may have noticed from the above examples, that no variable is present after the NEXT command. A variable after NEXT is purely optional.

FOR-NEXT loops may be nested as deeply as the memory on the PICmicro will allow. To break out of a loop you may use the GOTO command without any ill effects.

See also :	BREAK, WHILE...WEND, REPEAT...UNTIL.


FREQOUT

Syntax

FREQOUT Pin , Period , Freq1 { , Freq2}

Availability

14-bit and 16-bit core devices.

Overview

Generate one or two sine-wave tones, of differing or the same frequencies, for a specified period.

Operators

Pin is a PORT-BIT combination that specifies which I/O pin to use.

Period may be a variable, constant, or expression (0 - 65535) specifying the amount of time to generate the tone(s).

Freq1 may be a variable, constant, or expression (0 - 32767) specifying frequency of the first tone.

Freq2 may be a variable, constant, or expression (0 - 32767) specifying frequency of the second tone. When specified, two frequencies will be mixed together on the same I/O pin.

Example

' Generate a 2500Hz (2.5KHz) tone for 1 second (1000 ms) on bit 0 of PORTA.

FREQOUT PORTA.0 , 1000 , 2500

' Play two tones at once for 1000ms. One at 2.5KHz, the other at 3KHz.

FREQOUT PORTA.0 , 1000 , 2500 , 30000

Notes

FREQOUT generates one or two sine waves using a pulse-width modulation algorithm. FREQOUT will work with a 4MHz crystal, however, it is best used with higher frequency crystals, and operates best with a 20MHz type. The raw output from FREQOUT requires filtering, to eliminate most of the switching noise. The circuits shown below will filter the signal in order to play the tones through a speaker or audio amplifier.

The two circuits work by filtering out the high-frequency PWM used to generate the sine waves. FREQOUT works over a very wide range of frequencies (0 to 32767KHz) so at the upper end of its range, the PWM filters will also filter out most of the desired frequency. You may need to reduce the values of the parallel capacitors shown in the circuit, or to create an active filter for your application.

DEVICE 16F877

DECLARE XTAL 20

DIM Loop AS BYTE 	' Counter for notes.

DIM Freq1 AS WORD 	' Frequency1.

DIM Freq2 AS WORD 	' Frequency2

SYMBOL C = 2092 	' C note

SYMBOL D = 2348 	' D note

SYMBOL E = 2636 	' E note

SYMBOL G = 3136 	' G note

SYMBOL R = 0 	' Silent pause.

SYMBOL Pin = PORTA.0	' Sound output pin

ADCON1 = 7	' Set PORTA and PORTE to all digital

Loop = 0

REPEAT 	' Create a loop for 29 notes within the LOOKUPL table.

Freq1 = LOOKUPL Loop , [E,D,C,D,E,E,E,R,D,D,D,R,E,G,G,R,E,D,C,D,E,E,E,E,D,D,E,D,C]

IF Freq1 = 0 THEN Freq2 = 0 : ELSE Freq2 = Freq1 - 8

FREQOUT Pin , 225 , Freq1 , Freq2

INC Loop

UNTIL Loop > 28

STOP

See also : DTMFOUT, SOUND, SOUND2.


GETBIT

Syntax

Variable = GETBIT Variable , Index

Availability

All devices.

Overview

Examine a bit of a variable, or register.

Operators

Variable is a user defined variable, of type BYTE, WORD, or DWORD.

Index is a constant, variable, or expression that points to the bit within Variable that requires examining.

Example

' Examine and display each bit of variable EX_VAR

DEVICE = 16F877

XTAL = 4

DIM EX_VAR AS BYTE

DIM INDEX AS BYTE

DIM VAR1 AS BYTE

EX_VAR = %10110111

AGAIN:

CLS

PRINT AT 1,1,BIN8 EX_VAR	' Display the original variable

    	CURSOR 2,1	' Position the cursor at line 2

FOR INDEX = 7 TO 0 STEP -1	' Create a loop for 8 bits

VAR1 = GETBIT EX_VAR,INDEX 	' Examine each bit of EX_VAR

PRINT DEC1 VAR1	' Display the binary result

DELAYMS 100	' Slow things down to see what's happening

NEXT	' Close the loop

GOTO AGAIN	' Do it forever

See also : CLEARBIT, LOADBIT, SETBIT


GOSUB

Syntax

GOSUB Label

or

GOSUB Label [Variable, {Variable, Variable... etc}] , Receipt Variable

Availability

All devices. But parameters are only supported with 16-bit core devices.

Overview

GOSUB jumps the program to a defined label and continues execution from there. Once the program hits a RETURN command the program returns to the instruction following the GOSUB that called it and continues execution from that point.

Example 1

' Implement a standard subroutine call

GOTO Start	' Jump over the subroutines

SubA:	{ subroutine A code

……

……

}

RETURN

SubB:	{ subroutine B code

……

……

}

RETURN

' Actual start of the main program

Start: 	GOSUB SubA

GOSUB SubB

STOP

See also : CALL, GOTO .


GOTO

Syntax

GOTO Label

Availability

All devices.

Overview

Jump to a defined label and continue execution from there.

Operators

Label is a user-defined label placed at the beginning of a line which must have a colon':' directly after it.

Example

IF VAR1 = 3 THEN GOTO Jumpover

{

code here executed only if VAR1<>3

……

……

}

Jumpover:

{continue code execution}

In this example, if VAR1=3 then the program jumps over all the code below it until it reaches the label JUMPOVER where program execution continues as normal.

The GOTO command adds PAGE and BANK switching instructions prior to actually jumping a routine, however, if GOTO is used in an all assembler environment, the extra mnemonics preceding the command can interfere with carefully sculptured code such as bit tests etc. By wrapping the destination's name in parenthasis, the BANK and PAGE instructions are suppressed, and the GOTO command becomes the GOTO mnemonic.

GOTO (ROUTINES_NAME)

Only use the mnemonic variation of GOTO, if you know that your destination is within the same PAGE as the section of code jumping it. This is not an issue if using 16-bit core devices, as they have a more linear memory organisation.

See also : CALL, GOSUB


HBSTART

Syntax

HBSTART

Availability

14-bit and 16-bit core devices.

Overview

Send a START condition to the I2C bus using the PICmicro's MSSP module.

Notes

Because of the subtleties involved in interfacing to some I2C devices, the compiler's standard HBUSIN, and HBUSOUT commands were found lacking. Therefore, individual pieces of the I2C protocol may be used in association with the new structure of HBUSIN, and HBUSOUT. See relevant sections for more information.

Example

' Interface to a 24LC32 serial eeprom

DEVICE = 16F877	' Use a device with an MSSP module

DIM Loop AS BYTE

DIM Array[10] AS BYTE

' Transmit bytes to the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

FOR LOOP = 48 TO 57	' Create a loop containing ASCII 0 to 9

HBUSOUT LOOP	' Send the value of LOOP to the eeprom

NEXT	' Close the loop

HBSTOP	' Send a STOP condition

DELAYMS 10	' Wait for the data to be entered into eeprom matrix

' Receive bytes from the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBRESTART	' Send a RESTART condition

HBUSOUT %10100001	' Target an eeprom, and send a READ command

FOR Loop = 0 TO 9	' Create a loop

Array[Loop] = HBUSIN	' Load an array with bytes received

IF Loop = 9 THEN HBSTOP : ELSE HBUSACK	' ACK or STOP ?

NEXT	' Close the loop

PRINT AT 1,1, STR Array	' Display the Array as a STRING

See also : HBUSACK,  HBRESTART, HBSTOP, HBUSIN, HBUSOUT.


HBSTOP

Syntax

HBSTOP

Availability

14-bit and 16-bit core devices.

Overview

Send a STOP condition to the I2C bus using the PICmicro's MSSP module.

Notes

Because of the subtleties involved in interfacing to some I2C devices, the compiler's standard HBUSIN, and HBUSOUT commands were found lacking. Therefore, individual pieces of the I2C protocol may be used in association with the new structure of HBUSIN, and HBUSOUT. See relevant sections for more information.

Example

' Interface to a 24LC32 serial eeprom

DEVICE = 16F877	' Use a device with an MSSP module

DIM Loop AS BYTE

DIM Array[10] AS BYTE

' Transmit bytes to the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

FOR LOOP = 48 TO 57	' Create a loop containing ASCII 0 to 9

HBUSOUT LOOP	' Send the value of LOOP to the eeprom

NEXT	' Close the loop

HBSTOP	' Send a STOP condition

DELAYMS 10	' Wait for the data to be entered into eeprom matrix

' Receive bytes from the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBRESTART	' Send a RESTART condition

HBUSOUT %10100001	' Target an eeprom, and send a READ command

FOR Loop = 0 TO 9	' Create a loop

Array[Loop] = HBUSIN	' Load an array with bytes received

IF Loop = 9 THEN HBSTOP : ELSE HBUSACK	' ACK or STOP ?

NEXT	' Close the loop

PRINT AT 1,1, STR Array	' Display the Array as a STRING

See also : HBUSACK,  HBRESTART, HBSTART, HBUSIN, HBUSOUT.


HBRESTART

Syntax

HBRESTART

Availability

14-bit and 16-bit core devices.

Overview

Send a RESTART condition to the I2C bus using the PICmicro's MSSP module.

Notes

Because of the subtleties involved in interfacing to some I2C devices, the compiler's standard HBUSIN, and HBUSOUT commands were found lacking. Therefore, individual pieces of the I2C protocol may be used in association with the new structure of HBUSIN, and HBUSOUT. See relevant sections for more information.

Example

' Interface to a 24LC32 serial eeprom

DEVICE = 16F877	' Use a device with an MSSP module

DIM Loop AS BYTE

DIM Array[10] AS BYTE

' Transmit bytes to the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

FOR LOOP = 48 TO 57	' Create a loop containing ASCII 0 to 9

HBUSOUT LOOP	' Send the value of LOOP to the eeprom

NEXT	' Close the loop

HBSTOP	' Send a STOP condition

DELAYMS 10	' Wait for the data to be entered into eeprom matrix

' Receive bytes from the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBRESTART	' Send a RESTART condition

HBUSOUT %10100001	' Target an eeprom, and send a READ command

FOR Loop = 0 TO 9	' Create a loop

Array[Loop] = HBUSIN	' Load an array with bytes received

IF Loop = 9 THEN HBSTOP : ELSE HBUSACK	' ACK or STOP ?

NEXT	' Close the loop

PRINT AT 1,1, STR Array	' Display the Array as a STRING

See also : HBUSACK,  HBSTART, HBSTOP, HBUSIN, HBUSOUT.


HBUSACK

Syntax

HBUSACK

Availability

14-bit and 16-bit core devices.

Overview

Send an ACKNOWLEDGE condition to the I2C bus using the PICmicro's MSSP module.

Notes

Because of the subtleties involved in interfacing to some I2C devices, the compiler's standard HBUSIN, and HBUSOUT commands were found lacking. Therefore, individual pieces of the I2C protocol may be used in association with the new structure of HBUSIN, and HBUSOUT. See relevant sections for more information.

Example

' Interface to a 24LC32 serial eeprom

DEVICE = 16F877	' Use a device with an MSSP module

DIM Loop AS BYTE

DIM Array[10] AS BYTE

' Transmit bytes to the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

FOR LOOP = 48 TO 57	' Create a loop containing ASCII 0 to 9

HBUSOUT LOOP	' Send the value of LOOP to the eeprom

NEXT	' Close the loop

HBSTOP	' Send a STOP condition

DELAYMS 10	' Wait for the data to be entered into eeprom matrix

' Receive bytes from the I2C bus

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBRESTART	' Send a RESTART condition

HBUSOUT %10100001	' Target an eeprom, and send a READ command

FOR Loop = 0 TO 9	' Create a loop

Array[Loop] = HBUSIN	' Load an array with bytes received

IF Loop = 9 THEN HBSTOP : ELSE HBUSACK	' ACK or STOP ?

NEXT	' Close the loop

PRINT AT 1,1, STR Array	' Display the Array as a STRING

See also : HBSTART,  HBRESTART, HBSTOP, HBUSIN, HBUSOUT.


HBUSIN

Syntax

Variable = HBUSIN Control , { Address }

or

Variable = HBUSIN

or

HBUSIN Control , { Address }, [ Variable {, Variable…} ]

or

HBUSIN Variable

Availability

14-bit and 16-bit core devices.

Overview

Receives a value from the I2C bus using the MSSP module, and places it into variable/s. If structures TWO or FOUR (see above) are used, then NO ACKNOWLEDGE, or STOP is sent after the data. Structures ONE and THREE first send the control and optional address out of the clock pin (SCL), and data pin (SDA).

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Control may be a constant value or a BYTE sized variable expression.

Address may be a constant value or a variable expression.

The four variations of the HBUSIN command may be used in the same BASIC program. The SECOND and FOURTH types are useful for simply receiving a single byte from the bus, and must be used in conjunction with one of the low level commands. i.e. HBSTART, HBRESTART, HBUSACK, or HBSTOP. The FIRST, and THIRD types may be used to receive several values and designate each to a separate variable, or variable type.

The HBUSIN command operates as an I2C master, using the PICmicro's MSSP module, and may be used to interface with any device that complies with the 2-wire I2C protocol.

The most significant 7-bits of control byte contain the control code and the slave address of the device being interfaced with. Bit-0 is the flag that indicates whether a read or write command is being implemented.

For example, if we were interfacing to an external eeprom such as the 24C32, the control code would be %10100001 or $A1. The most significant 4-bits (1010) are the eeprom's unique slave address. Bits 2 to 3 reflect the three address pins of the eeprom. And bit-0 is set to signify that we wish to read from the eeprom. Note that this bit is automatically set by the HBUSIN command, regardless of its initial setting.

Example

' Receive a byte from the I2C bus and place it into variable VAR1.

DIM VAR1 as BYTE	' We'll only read 8-bits

DIM Address as WORD	' 16-bit address required

SYMBOL Control %10100001	' Target an eeprom

Address = 20	' Read the value at address 20

VAR1 = HBUSIN Control , Address	' Read the byte from the eeprom

or

HBUSIN Control , Address, [ VAR1 ]	' Read the byte from the eeprom

Address, is an optional parameter that may be an 8-bit or 16-bit value. If a variable is used in this position, the size of address is dictated by the size of the variable used (BYTE or WORD). In the case of the previous eeprom interfacing, the 24C32 eeprom requires a 16-bit address. While the smaller types require an 8-bit address. Make sure you assign the right size address for the device interfaced with, or you may not achieve the results you intended.

The value received from the bus depends on the size of the variables used, except for variation three, which only receives a BYTE (8-bits). For example: -

DIM WRD as WORD	' Declare a WORD size variable

WRD = HBUSIN Control , Address

Will receive a 16-bit value from the bus. While: -

DIM VAR1 as BYTE	' Declare a BYTE size variable

VAR1 = HBUSIN Control , Address

Will receive an 8-bit value from the bus.

Using the THIRD variation of the HBUSIN command allows differing variable assignments. For example: -

DIM VAR1 as BYTE

DIM WRD as WORD

HBUSIN Control , Address , [ VAR1 , WRD ]

Will receive two values from the bus, the first being an 8-bit value dictated by the size of variable VAR1 which has been declared as a byte. And a 16-bit value, this time dictated by the size of the variable WRD which has been declared as a word. Of course, BIT type variables may also be used, but in most cases these are not of any practical use as they still take up a byte within the eeprom.

The SECOND and FOURTH variations allow all the subtleties of the I2C protocol to be exploited, as each operation may be broken down into its constituent parts. It is advisable to refer to the datasheet of the device being interfaced to fully understand its requirements. See section on HBSTART, HBRESTART, HBUSACK, or HBSTOP, for example code.

Declare

DECLARE HBUS_BITRATE Constant 100, 400, 1000

The standard speed for the I2C bus is 100KHz. Some devices use a higher bus speed of 400KHz. The above DECLARE allows the I2C bus speed to be increased or decreased. Use this DECLARE with caution, as too high a bit rate may exceed the device's specs, which will result in intermittent transactions, or in some cases, no transactions at all. The datasheet for the device used will inform you of its bus speed. The default bit rate is the standard 100KHz.

Notes

Not all PICmicro devices contain an MSSP module, some only contain an SSP type, which only allows I2C SLAVE operations. These types of devices may not be used with any of the HBUS commands. Therefore, always read and understand the datasheet for the PICmicro device used.

When the HBUSIN command is used, the appropriate SDA and SCL Port and Pin are automatically setup as inputs. The SDA, and SCL lines are predetermined as hardware pins on the PICmicro i.e. For a 16F877 device, the SCL pin is PORTC.3, and SDA is PORTC.4. Therefore, there is no need to pre-declare these.

Because the I2C protocol calls for an open-collector interface, pull-up resistors are required on both the SDA and SCL lines. Values of 4.7KΩ to 10KΩ will suffice.

STR modifier with HBUSIN

Using the STR modifier allows variations THREE and FOUR of the HBUSIN command to transfer the bytes received from the I2C bus directly into a byte array. If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. An example of each is shown below: -

DIM Array[10] AS BYTE	' Define an array of 10 bytes

DIM Address AS BYTE	' Create a word sized variable

HBUSIN %10100000 , Address , [ STR Array]	' Load data into all the array

HBUSIN %10100000 , Address , [ STR Array\5] 	' Load data into only the first 5 elements of the array

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBRESTART	' Send a RESTART condition

HBUSOUT %10100001	' Target an eeprom, and send a READ command

HBUSIN STR Array	' Load all the array with bytes received

HBSTOP	' Send a STOP condition

An alternative ending to the above example is: -

HBUSIN STR Array\5	' Load data into only the first 5 elements of the array

HBSTOP	' Send a STOP condition

See also : HBUSACK,  HBRESTART, HBSTOP, HBSTART, HBUSOUT.


HBUSOUT

Syntax

HBUSOUT Control , { Address } , [ OutputData ]

or

HBUSOUT Variable

Availability

14-bit and 16-bit core devices.

Overview

Transmit a value to the I2C bus using the PICmicro's on-board MSSP module, by first sending the control and optional address out of the clock pin (SCL), and data pin (SDA). Or alternatively, if only one operator is included after the HBUSOUT command, a single value will be transmitted, along with an ACK reception.

Operators

Control may be a constant value or a BYTE sized variable expression.

Address may be a constant, variable, or expression.

OutputData is list of variables, constants, expressions and modifiers that informs HBUSOUT how to format outgoing data. HBUSOUT can transmit individual or repeating bytes, convert values into decimal, hex or binary text representations, or transmit strings of bytes from variable arrays. These actions can be combined in any order in the OutputData list.

HBUSOUT has most of the modifiers that HRSOUT, RSOUT, SEROUT and PRINT has. These are listed below: -

Modifier 	Operation

BIN{1..32} 	Send binary digits

DEC{1..10} 	Send decimal digits

HEX{1..8} 	Send hexadecimal digits

SBIN{1..32} 	Send signed binary digits

SDEC{1..10} 	Send signed decimal digits

SHEX{1..8} 	Send signed hexadecimal digits

IBIN{1..32} 	Send binary digits with a preceding '%' identifier

IDEC{1..10} 	Send decimal digits with a preceding '#' identifier

IHEX{1..8} 	Send hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Send signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Send signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Send signed hexadecimal digits with a preceding '$' identifier

The HBUSOUT command operates as an I2C master and may be used to interface with any device that complies with the 2-wire I2C protocol.

The most significant 7-bits of control byte contain the control code and the slave address of the device being interfaced with. Bit-0 is the flag that indicates whether a read or write command is being implemented.

For example, if we were interfacing to an external eeprom such as the 24C32, the control code would be %10100000 or $A0. The most significant 4-bits (1010) are the eeprom's unique slave address. Bits 2 to 3 reflect the three address pins of the eeprom. And Bit-0 is clear to signify that we wish to write to the eeprom. Note that this bit is automatically cleared by the HBUSOUT command, regardless of its initial value.

Example

' Send a byte to the I2C bus.

DIM VAR1 as BYTE	' We'll only read 8-bits

DIM Address as WORD	' 16-bit address required

SYMBOL Control = %10100000	' Target an eeprom

Address = 20	' Write to address 20

VAR1 = 200	' The value place into address 20

HBUSOUT Control , Address , [ VAR1 ]	' Send the byte to the eeprom

DELAYMS 10	' Allow time for allocation of byte

Address, is an optional parameter that may be an 8-bit or 16-bit value. If a variable is used in this position, the size of address is dictated by the size of the variable used (BYTE or WORD). In the case of the above eeprom interfacing, the 24C32 eeprom requires a 16-bit address. While the smaller types require an 8-bit address. Make sure you assign the right size address for the device interfaced with, or you may not achieve the results you intended.

The value sent to the bus depends on the size of the variables used. For example: -

DIM WRD as WORD	' Declare a WORD size variable

HBUSOUT Control , Address , [ WRD ]

Will send a 16-bit value to the bus. While: -

DIM VAR1 as BYTE	' Declare a BYTE size variable

HBUSOUT Control , Address , [ VAR1 ]

Will send an 8-bit value to the bus.

Using more than one variable within the brackets allows differing variable sizes to be sent. For example: -

DIM VAR1 as BYTE

DIM WRD as WORD

HBUSOUT Control , Address , [ VAR1 , WRD ]

Will send two values to the bus, the first being an 8-bit value dictated by the size of variable VAR1 which has been declared as a byte. And a 16-bit value, this time dictated by the size of the variable WRD which has been declared as a word. Of course, BIT type variables may also be used, but in most cases these are not of any practical use as they still take up a byte within the eeprom.

A string of characters can also be transmitted, by enclosing them in quotes: -

HBUSOUT Control , Address , [ "Hello World" , VAR1 , WRD ]

Using the second variation of the HBUSOUT command, necessitates using the low level commands i.e. HBSTART, HBRESTART, HBUSACK, or HBSTOP.

Using the HBUSOUT command with only one value after it, sends a byte of data to the I2C bus, and returns holding the ACKNOWLEDGE reception. This acknowledge indicates whether the data has been received by the slave device.

The ACK reception is returned in the PICmicro's CARRY flag, which is STATUS.0, and also SYSTEM variable PP4.0. A value of zero indicates that the data was received correctly, while a one indicates that the data was not received, or that the slave device has sent a NACK return. You must read and understand the datasheet for the device being interfacing to, before the ACK return can be used successfully. An code snippet is shown below: -

' Transmit a byte to a 24LC32 serial eeprom

DIM PP4 as BYTE

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBUSOUT "A"	' Send the value 65 to the bus

IF PP4.0 = 1 THEN GOTO Not_Received	' Has ACK been received OK ?

HBSTOP	' Send a STOP condition

DELAYMS 10	' Wait for the data to be entered into eeprom matrix

STR modifier with HBUSOUT.

The STR modifier is used for transmitting a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that sends four bytes from an array: -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = "A"	' Load the first 4 bytes of the array

MYARRAY [1] = "B"	' With the data to send

MYARRAY [2] = "C"

MYARRAY [3] = "D"

HBUSOUT %10100000 , Address , [ STR MYARRAY \4 ] 	' Send 4-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the program would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 4 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE 	' Create a 10-byte array.

STR MYARRAY = "ABCD"	' Load the first 4 bytes of the array

HBSTART	' Send a START condition

HBUSOUT %10100000	' Target an eeprom, and send a WRITE command

HBUSOUT 0	' Send the HIGHBYTE of the address

HBUSOUT 0	' Send the LOWBYTE of the address

HBUSOUT STR MYARRAY \4 	' Send 4-byte string.

HBSTOP	' Send a STOP condition

The above example, has exactly the same function as the previous one. The only differences are that the string is now constructed using the STR as a command instead of a modifier, and the low-level HBUS commands have been used.

Declare

DECLARE HBUS_BITRATE Constant 100, 400, 1000

The standard speed for the I2C bus is 100KHz. Some devices use a higher bus speed of 400KHz. The above DECLARE allows the I2C bus speed to be increased or decreased. Use this DECLARE with caution, as too high a bit rate may exceed the device's specs, which will result in intermittent transactions, or in some cases, no transactions at all. The datasheet for the device used will inform you of its bus speed. The default bit rate is the standard 100KHz.

Notes

Not all PICmicro devices contain an MSSP module, some only contain an SSP type, which only allows I2C SLAVE operations. These types of devices may not be used with any of the HBUS commands. Therefore, always read and understand the datasheet for the PICmicro device used.

When the HBUSOUT command is used, the appropriate SDA and SCL Port and Pin are automatically setup as inputs. The SDA, and SCL lines are predetermined as hardware pins on the PICmicro i.e. For a 16F877 device, the SCL pin is PORTC.3, and SDA is PORTC.4. Therefore, there is no need to pre-declare these.

Because the I2C protocol calls for an open-collector interface, pull-up resistors are required on both the SDA and SCL lines. Values of 4.7K to 10K will suffice.

You may imagine that it's limiting having a fixed set of pins for the I2C interface, but you must remember that several different devices may be attached to a single bus, each having a unique slave address. Which means there is usually no need to use up more than two pins on the PICmicro, in order to interface to many devices.

See also : HBUSACK,  HBRESTART, HBSTOP, HBUSIN, HBSTART.


HIGH

Syntax

HIGH  Port or Port.Bit

Availability

All devices.

Overview

Place a Port or bit in a output high state. For a Port, this means filling it with 1's. For a bit this means setting it to 1.

Operators

Port can be any valid port.

Port.Bit can be any valid port and bit combination, i.e. PORTA.1

Example

SYMBOL LED = PORTB.4

HIGH LED

See also : DIM, LOW, CLEAR, SET, SYMBOL.


HPWM

Syntax

HPWM Channel , Dutycycle , Frequency

Availability

14-bit and 16-bit core devices.

Overview

Output a pulse width modulated pulse train using the CCP modules PWM hardware, available on some PICmicros. The PWM pulses produced can run continuously in the background while the program is executing other instructions.

Operators

Channel is a constant value that specifies specifies which hardware PWM channel to use. Some devices have 1, 2 or 3 PWM channels. On devices with 2 channels, the Frequency must be the same on both channels. It must be noted, that this is a limitation of the PICmicro not the compiler. The data sheet for the particular device used shows the fixed hardware pin for each Channel. For example, for a PIC16F877, Channel 1 is CCP1 which is pin PORTC.2. Channel 2 is CCP2 which is pin PORTC.1. But these pins differ on various PICmicro devices therefore always read the datasheet for the device of choice.

Dutycycle is a variable, constant (0-255), or expression that specifies the on/off (high/low) ratio of the signal. It ranges from 0 to 255, where 0 is off (low all the time) and 255 is on (high) all the time. A value of 127 gives a 50% duty cycle (square wave).

Frequency is a variable, constant (0-32767), or expression that specifies the desired frequency of the PWM signal. Not all frequencies are available at all oscillator settings. The highest frequency at any oscillator speed is 32767Hz. The lowest usable HPWM Frequency at each oscillator setting is shown in the table below: -

XTAL frequency	Lowest useable PWM frequency

4MHz	145Hz

8MHz	489Hz

10MHz	611Hz

12MHz	733Hz

16MHz	977Hz

20MHz	1221Hz

24MHz	1465Hz

33MHz	2015Hz

40MHz	2442Hz

Example

DEVICE = 16F877

XTAL = 20

CCP1_PIN = PORTC.1	' PORTC.1 is the CCP1 pin on the 16F877 device

HPWM 1,127,1000 	' Send a 50% duty cycle PWM signal at 1KHz

DELAYMS 500

HPWM 1,64,2000 	' Send a 25% duty cycle PWM signal at 2KHz

STOP

Notes

Not all PICmicros use the same pins for their CCP modules, some devices, such as the PIC16F62x, and PIC18F4xx, have alternate pins that may be used for HPWM. The following DECLARES allow the use of different pins: -

DECLARE CCP1_PIN PORT . PIN  	' Select HPWM port and bit for CCP1 module. i.e. channel 1

DECLARE CCP2_PIN PORT . PIN  	' Select HPWM port and bit for CCP2 module. i.e. channel 2

If the DECLARES are not issued in the BASIC program, then the default values are CCP1_PIN as PORTB.2, and CCP2_PIN as PORTC.1.

See also : PWM, PULSEOUT, SERVO.


HRSIN
HRSIN / HRSIN2

Syntax

Variable = HRSIN , { Timeout , Timeout Label }

or

HRSIN { Timeout , Timeout Label } , { Parity Error Label } , Modifiers , Variable {, Variable... }

Bold Curly Braces are a requirement if timeouts are used.

Availability

14-bit and 16-bit core devices.

Overview

Receive one or more values from the serial port on devices that contain a hardware USART.

HRSIN2 has exactly the same syntax and operation as HRSIN, but uses the second USART available on some PICmicro devices.

Operators

Timeout is an OPTIONAL value for the length of time the HRSIN command will wait before jumping to label TIMEOUT LABEL. Timeout is specified in 1 millisecond units.

Timeout Label is an OPTIONAL valid BASIC label where HRSIN will jump to in the event that a character has not been received within the time specified by TIMEOUT.

Parity Error Label is an OPTIONAL valid BASIC label where HRSIN will jump to in the event that a PARITY error is received. Parity is set using DECLARES. Parity Error detecting is not supported in the inline version of HRSIN (first syntax example above).

Modifier is one of the many formatting modifiers, explained below.

Variable is a BIT, BYTE, WORD DWORD, or FLOAT variable, that will be loaded by HRSIN.

Example

' Receive values serially and timeout if no reception after 1 second (1000ms).

DEVICE 16F877

XTAL = 4

HSERIAL_BAUD = 9600	' Set baud rate to 9600

HSERIAL_RCSTA = %10010000	' Enable serial port and continuous receive

HSERIAL_TXSTA = %00100000	' Enable transmit and asynchronous mode

HSERIAL_CLEAR = ON	' Optionally clear the buffer before receiving

DIM VAR1 AS BYTE

Loop:	VAR1 = HRSIN , {1000 , Timeout}	' Receive a byte serially into VAR1

PRINT DEC VAR1 , " "	' Display the byte received

GOTO Loop	' Loop forever

Timeout:

CLS

PRINT "TIMED OUT"	' Display an error if HRSIN timed out

STOP

HRSIN MODIFIERS.

As we already know, HRSIN will wait for and receive a single byte of data, and store it in a variable . If the PICmicro were connected to a PC running a terminal program and the user pressed the "A" key on the keyboard, after the HRSIN command executed, the variable would contain 65, which is the ASCII code for the letter "A"

What would happen if the user pressed the "1" key? The result would be that the variable would contain the value 49 (the ASCII code for the character "1"). This is an important point to remember: every time you press a character on the keyboard, the computer receives the ASCII value of that character. It is up to the receiving side to interpret the values as necessary. In this case, perhaps we actually wanted the variable to end up with the value 1, rather than the ASCII code 49.

The HRSIN command provides a modifier, called the decimal modifier, which will interpret this for us. Look at the following code: -

DIM SERDATA AS BYTE

HRSIN DEC SERDATA

Notice the decimal modifier in the HRSIN command that appears just to the left of the SERDATA variable. This tells HRSIN to convert incoming text representing decimal numbers into true decimal form and store the result in SERDATA. If the user running the terminal software pressed the "1", "2" and then "3" keys followed by a space or other non-numeric text, the value 123 will be stored in the variable SERDATA, allowing the rest of the program to perform any numeric operation on the variable.

Without the decimal modifier, however, you would have been forced to receive each character ("1", "2" and "3") separately, and then would still have to do some manual conversion to arrive at the number 123 (one hundred twenty three) before you can do the desired calculations on it.

The decimal modifier is designed to seek out text that represents decimal numbers. The characters that represent decimal numbers are the characters "0" through "9". Once the HRSIN command is asked to use the decimal modifier for a particular variable, it monitors the incoming serial data, looking for the first decimal character. Once it finds the first decimal character, it will continue looking for more (accumulating the entire multi-digit number) until is finds a non-decimal numeric character. Remember that it will not finish until it finds at least one decimal character followed by at least one non-decimal character.

To illustrate this further, examine the following examples (assuming we're using the same code example as above): -

Serial input:	"ABC"

Result: The program halts at the HRSIN command, continuously waiting for decimal text.

Serial input:	"123" (with no characters following it)

Result: The program halts at the HRSIN command. It recognises the characters "1", "2" and "3" as the number one hundred twenty three, but since no characters follow the "3", it waits continuously, since there's no way to tell whether 123 is the entire number or not.

Serial input:	"123" (followed by a space character)

Result: Similar to the above example, except once the space character is received, the program knows the entire number is 123, and stores this value in SERDATA. The HRSIN command then ends, allowing the next line of code to run.

Serial input:	"123A"

Result: Same as the example above. The "A" character, just like the space character, is the first non-decimal text after the number 123, indicating to the program that it has received the entire number.

Serial input: "ABCD123EFGH"

Result: Similar to examples 3 and 4 above. The characters "ABCD" are ignored (since they're not decimal text), the characters "123" are evaluated to be the 	number 123 and the following character, "E", indicates to the program that it has received the entire number.

The decimal modifier is only one of a family of conversion modifiers available with HRSIN See below for a list of available conversion modifiers. All of the conversion modifiers work similar to the decimal modifier (as described above). The modifiers receive bytes of data, waiting for the first byte that falls within the range of characters they accept (e.g., "0" or "1" for binary, "0" to "9" for decimal, "0" to "9" and "A" to "F" for hex. Once they receive a numeric character, they keep accepting input until a non-numeric character arrives, or in the case of the fixed length modifiers, the maximum specified number of digits arrives.

While very effective at filtering and converting input text, the modifiers aren't completely foolproof. As mentioned before, many conversion modifiers will keep accepting text until the first non-numeric text arrives, even if the resulting value exceeds the size of the variable. After HRSIN , a BYTE variable will contain the lowest 8 bits of the value entered and a WORD (16-bits) would contain the lowest 16 bits. You can control this to some degree by using a modifier that specifies the number of digits, such as DEC2, which would accept values only in the range of 0 to 99.

Conversion Modifier 	Type of Number Numeric 	Characters Accepted

DEC{1..10} 	Decimal, optionally limited	0 through 9

to 1 - 10 digits

HEX{1..8} 	Hexadecimal, optionally limited	0 through 9,

 to 1 - 8 digits	A through F

BIN{1..32} 	Binary, optionally limited 	      0, 1

 to 1 - 32 digits

A variable preceded by BIN will receive the ASCII representation of its binary value.

For example, if BIN VAR1 is specified and "1000" is received, VAR1 will be set to 8.

A variable preceded by DEC will receive the ASCII representation of its decimal value.

For example, if DEC VAR1 is specified and "123" is received, VAR1 will be set to 123.

A variable preceded by HEX will receive the ASCII representation of its hexadecimal value.

For example, if HEX VAR1 is specified and "FE" is received, VAR1 will be set to 254.

SKIP followed by a count will skip that many characters in the input stream.

For example, SKIP 4 will skip 4 characters.

The HRSIN command can be configured to wait for a specified sequence of characters before it retrieves any additional input. For example, suppose a device attached to the PICmicro is known to send many different sequences of data, but the only data you wish to observe happens to appear right after the unique characters, "XYZ". A modifier named WAIT can be used for this purpose: -

HRSIN WAIT( "XYZ" ) , SERDATA

The above code waits for the characters "X", "Y" and "Z" to be received, in that order, then it receives the next data byte and places it into variable SERDATA.

STR modifier.

The HRSIN command also has a modifier for handling a string of characters, named STR.

The STR modifier is used for receiving a string of characters into a byte array variable.

A string is a set of characters that are arranged or accessed in a certain order. The characters "ABC" would be stored in a string with the "A" first, followed by the "B" then followed by the "C". A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" would be stored in a byte array containing three bytes (elements).

Below is an example that receives ten bytes and stores them in the 10-byte array, SERSTRING: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

HRSIN STR SerString  	' Fill the array with received data.

PRINT STR SerString 	' Display the string.

If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. For example: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

HRSIN STR SerString\5  	' Fill the first 5-bytes of the array

PRINT STR SerString\5 	' Display the 5-character string.

The example above illustrates how to fill only the first n bytes of an array, and then how to display only the first n bytes of the array. n refers to the value placed after the backslash.

Because of its complexity, serial communication can be rather difficult to work with at times. Using the guidelines below when developing a project using the HRSIN and HRSOUT commands may help to eliminate some obvious errors: -

Always build your project in steps.

Start with small, manageable pieces of code, (that deal with serial communication) and test them, one individually.

Add more and more small pieces, testing them each time, as you go.

Never write a large portion of code that works with serial communication without testing its smallest workable pieces first.

Pay attention to timing.

Be careful to calculate and overestimate the amount of time, operations should take within the PICmicro for a given oscillator frequency. Misunderstanding the timing constraints is the source of most problems with code that communicate serially. If the serial communication in your project is bi-directional, the above statement is even more critical.

Pay attention to wiring.

Take extra time to study and verify serial communication wiring diagrams. A mistake in wiring can cause strange problems in communication, or no communication at all. Make sure to connect the ground pins (Vss) between the devices that are communicating serially.

Verify port setting on the PC and in the HRSIN / HRSOUT commands.

Unmatched settings on the sender and receiver side will cause garbled data transfers or no data transfers. This is never more critical than when a line transceiver is used(i.e. MAX232). Always remember that a line transceiver inverts the serial polarity.

If the serial data received is unreadable, it is most likely caused by a baud rate setting error, or a polarity error.

If receiving data from another device that is not a PICmicro, try to use baud rates of 9600 and below, or alternatively, use a higher frequency crystal.

Because of additional overheads in the PICmicro, and the fact that the HRSIN command only offers a 2 level receive buffer for serial communication, received data may sometimes be missed or garbled. If this occurs, try lowering the baud rate, or increasing the crystal frequency. Using simple variables (not arrays) will also increase the chance that the PICmicro will receive the data properly.

Declares

There are five DECLARE directives for use with HRSIN, and five for HRSIN2. These are: -

DECLARE HSERIAL_BAUD Constant value

Sets the BAUD rate that will be used to receive a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL_RCSTA Constant value (0 to 255)

HSERIAL_RCSTA, sets the respective PICmicro hardware register RCSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register.

DECLARE HSERIAL_TXSTA Constant value (0 to 255)

HSERIAL_TXSTA, sets the respective PICmicro hardware register, TXSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate correctly.

DECLARE HSERIAL_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HRSIN and HRSOUT The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL_PARITY = ODD 	' Use if odd parity desired

DECLARE HSERIAL_CLEAR ON or OFF

Clear the overflow error bit before commencing a read.

Because the hardware serial port only has a 2-byte input buffer, it can easily overflow is characters are not read from it often enough. When this occurs, the USART stops accepting any new characters, and requires resetting. This overflow error can be reset by strobing the CREN bit within the RCSTA register. Example: -

RCSTA.4 = 0

RCSTA.4 = 1

or

CLEAR RCSTA.4

SET RCSTA.4

Alternatively, the HSERIAL_CLEAR declare can be used to automatically clear this error, even if no error occurred. However, the program will not know if an error occurred while reading, therefore some characters may be lost.

DECLARE HSERIAL_CLEAR = ON

Second USART Declares

DECLARE HSERIAL2_BAUD Constant value

Sets the BAUD rate that will be used to receive a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL2_RCSTA Constant value (0 to 255)

HSERIAL2_RCSTA, sets the respective PICmicro hardware register RCSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register.

DECLARE HSERIAL2_TXSTA Constant value (0 to 255)

HSERIAL2_TXSTA, sets the respective PICmicro hardware register, TXSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA2 register BRGH2 bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate properly.

DECLARE HSERIAL2_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HRSIN2 and HRSOUT2 The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL2_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL2_PARITY = ODD 	' Use if odd parity desired

DECLARE HSERIAL2_CLEAR ON or OFF

Clear the overflow error bit before commencing a read.

Because the hardware serial port only has a 2-byte input buffer, it can easily overflow is characters are not read from it often enough. When this occurs, the USART stops accepting any new characters, and requires resetting. This overflow error can be reset by strobing the CREN bit within the RCSTA2 register. Example: -

RCSTA2.4 = 0

RCSTA2.4 = 1

or

CLEAR RCSTA2.4

SET RCSTA2.4

Alternatively, the HSERIAL2_CLEAR declare can be used to automatically clear this error, even if no error occurred. However, the program will not know if an error occurred while reading, therefore some characters may be lost.

DECLARE HSERIAL2_CLEAR = ON

Notes

HRSIN and HRSIN2 can only be used with devices that contain a hardware USART. See the specific device's data sheet for further information concerning the serial input pin as well as other relevant parameters.

Since the serial transmission is done in hardware, it is not possible to set the levels to an inverted state to eliminate an RS232 driver. Therefore a suitable driver should be used with HRSIN and HRSIN2. Just such a circuit using a MAX232 is shown below.

A simpler, and somewhat more elegant transceiver circuit using only 5 discrete components is shown in the diagram below.

See also :	DECLARE, RSIN, RSOUT, SERIN, SEROUT, HRSOUT, HSERIN, HSEROUT.


HRSOUT
HRSOUT / HRSOUT2

Syntax

HRSOUT Item { , Item... }

Availability

14-bit and 16-bit core devices.

Overview

Transmit one or more Items from the hardware serial port (USART) on devices that support asynchronous serial communications in hardware.

HRSOUT2 has exactly the same syntax and operation as HRSOUT, but uses the second USART available on some PICmicro devices.

Operators

Item may be a constant, variable, expression, string list, or inline command.

There are no operators as such, instead there are modifiers. For example, if an at sign'@' precedes an Item, the ASCII representation for each digit is transmitted.

The modifiers are listed below: -

Modifier 	Operation

AT ypos,xpos 	Position the cursor on a serial LCD

CLS 	Clear a serial LCD (also creates a 30ms delay)

BIN{1..32} 	Send binary digits

DEC{1..10} 	Send decimal digits

HEX{1..8} 	Send hexadecimal digits

SBIN{1..32} 	Send signed binary digits

SDEC{1..10} 	Send signed decimal digits

SHEX{1..8} 	Send signed hexadecimal digits

IBIN{1..32} 	Send binary digits with a preceding '%' identifier

IDEC{1..10} 	Send decimal digits with a preceding '#' identifier

IHEX{1..8} 	Send hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Send signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Send signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Send signed hexadecimal digits with a preceding '$' identifier

REP c\n 	Send character c repeated n times

 	STR array\n	Send all or part of an array

CSTR cdata	Send string data defined in a CDATA statement.

The numbers after the BIN, DEC, and HEX modifiers are optional. If they are omitted, then the default is all the digits that make up the value will be displayed.

If a floating point variable is to be displayed, then the digits after the DEC modifier determine how many remainder digits are send.i.e. numbers after the decimal point.

DIM FLT AS FLOAT

FLT = 3.145

HRSOUT DEC2 FLT	' Send 2 values after the decimal point

The above program will send 3.14

If the digit after the DEC modifier is omitted, then 3 values will be displayed after the decimal point.

DIM FLT AS FLOAT

FLT = 3.1456

HRSOUT DEC FLT	' Send 3 values after the decimal point

The above program will send 3.145

There is no need to use the SDEC modifier for signed floating point values, as the compiler's DEC modifier will automatically display a minus result: -

DIM FLT AS FLOAT

FLT = -3.1456

HRSOUT DEC FLT	' Send 3 values after the decimal point

The above program will send -3.145

HEX or BIN modifiers cannot be used with floating point values or variables.

The Xpos and Ypos values in the AT modifier both start at 1. For example, to place the text "HELLO WORLD" on line 1, position 1, the code would be: -

HRSOUT AT 1 , 1 , "HELLO WORLD"

Example 1

DIM VAR1 AS BYTE

DIM WRD AS WORD

DIM DWD AS DWORD

 	HRSOUT "Hello World"	' Display the text "Hello World"

 	HRSOUT "VAR1= " , DEC VAR1	' Display the decimal value of VAR1

 	HRSOUT "VAR1= " , HEX VAR1	' Display the hexadecimal value of VAR1

 	HRSOUT "VAR1= " , BIN VAR1	' Display the binary value of VAR1

 	HRSOUT "VAR1= " , @VAR1	' Display the decimal value of VAR1

HRSOUT "DWD= " , HEX6 DWD 	' Display 6 hex characters of a DWORD type variable

Example 2

' Display a negative value on a serial LCD.

SYMBOL NEGATIVE = -200

HRSOUT AT 1 , 1 , SDEC NEGATIVE

Example 3

' Display a negative value on a serial LCD with a preceding identifier.

HRSOUT AT 1 , 1 , ISHEX -$1234

Example 3 will produce the text "$-1234" on the LCD.

Some PICmicros such as the 16F81x, 16F87x, and 18FXXX range have the ability to read and write to their own flash memory. And although writing to this memory too many times is unhealthy for the PICmicro, reading this memory is both fast, and harmless. Which offers a unique form of data storage and retrieval, the CDATA command proves this, as it uses the mechanism of reading and storing in the PICmicro's flash memory.

Combining the unique features of the 'self modifying PICmicro's ' with a string format, the compiler is capable of reducing the overhead of printing, or transmitting large amounts of text data. The CSTR modifier may be used in commands that deal with text processing i.e. SEROUT, HSEROUT, and PRINT etc.

The CSTR modifier is used in conjunction with the CDATA command. The CDATA command is used for initially creating the string of characters: -

STRING1: CDATA "HELLO WORLD" , 0

The above line of case will create, in flash memory, the values that make up the ASCII text "HELLO WORLD", at address STRING1. Note the NULL terminator after the ASCII text.

NULL terminated means that a zero (NULL) is placed at the end of the string of ASCII characters to signal that the string has finished.

To display, or transmit this string of characters, the following command structure could be used:

HRSOUT CSTR STRING1

The label that declared the address where the list of CDATA values resided, now becomes the string's name. In a large program with lots of text formatting, this type of structure can save quite literally hundreds of bytes of valuable code space.

Try both these small programs, and you'll see that using CSTR saves a few bytes of code: -

First the standard way of displaying text: -

DEVICE 16F877

CLS

HRSOUT "HELLO WORLD",13

HRSOUT "HOW ARE YOU?",13

HRSOUT "I AM FINE!",13

STOP

Now using the CSTR modifier: -

CLS

HRSOUT CSTR TEXT1

HRSOUT CSTR TEXT2

HRSOUT CSTR TEXT3

STOP

TEXT1: CDATA "HELLO WORLD" , 13, 0

TEXT2: CDATA "HOW ARE YOU?" , 13, 0

TEXT3: CDATA "I AM FINE!" , 13, 0

Again, note the NULL terminators after the ASCII text in the CDATA commands. Without these, the PICmicro will continue to transmit data in an endless loop.

The term 'virtual string' relates to the fact that a string formed from the CDATA command cannot be written too, but only read from.

The STR modifier is used for sending a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that displays four bytes (from a byte array): -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = "H"	' Load the first 5 bytes of the array

MYARRAY [1] = "E"	' With the data to send

MYARRAY [2] = "L"

MYARRAY [3] = "L"

MYARRAY [4] = "O"

HRSOUT STR MYARRAY \5  	' Display a 5-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the PICmicro would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 5 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE 	' Create a 10-byte array.

STR MYARRAY = "HELLO"	' Load the first 5 bytes of the array

HRSOUT STR MYARRAY \5 	' Send 5-byte string.

The above example, has exactly the same function as the previous one. The only difference is that the string is now constructed using STR as a command instead of a modifier.

Declares

There are four DECLARE directives for use with HRSOUT, and four for HRSOUT2. These are: -

DECLARE HSERIAL_BAUD Constant value

Sets the BAUD rate that will be used to transmit a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL_RCSTA Constant value (0 to 255)

HSERIAL_RCSTA, sets the respective PICmicro hardware register RCSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. Refer to the upgrade manual pages for a description of the RCSTA register.

DECLARE HSERIAL_TXSTA Constant value (0 to 255)

HSERIAL_TXSTA, sets the respective PICmicro hardware register, TXSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate correctly.

DECLARE HSERIAL_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HRSOUT and HRSIN The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL_PARITY = ODD 	' Use if odd parity desired

Second USART Declares

DECLARE HSERIAL2_BAUD Constant value

Sets the BAUD rate that will be used to transmit a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL2_RCSTA Constant value (0 to 255)

HSERIAL2_RCSTA, sets the respective PICmicro hardware register RCSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. Refer to the upgrade manual pages for a description of the RCSTA2 register.

DECLARE HSERIAL2_TXSTA Constant value (0 to 255)

HSERIAL2_TXSTA, sets the respective PICmicro hardware register, TXSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH2 bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate properly.

DECLARE HSERIAL2_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HRSOUT2 and HRSIN2 The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL2_PARITY declare.

DECLARE HSERIAL2_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL2_PARITY = ODD 	' Use if odd parity desired

Notes

HRSOUT and HRSOUT2 can only be used with devices that contain a hardware USART. See the specific device's data sheet for further information concerning the serial input pin as well as other relevant parameters.

Since the serial transmission is done in hardware, it is not possible to set the levels to an inverted state in order to eliminate an RS232 driver. Therefore a suitable driver should be used with HRSOUT. See manual for circuits.

See also :	DECLARE, RSIN, RSOUT, SERIN, SEROUT, HRSIN, HSERIN, HSEROUT.


HSERIN
HSERIN / HSERIN2

Syntax

HSERIN Timeout , Timeout Label  ,  Parity Error Label , [Modifiers , Variable {, Variable... }]

Availability

14-bit and 16-bit core devices.

Overview

Receive one or more values from the serial port on devices that contain a hardware USART. Compatible with the MELABS compiler

HSERIN2 has exactly the same syntax and operation as HSERIN , but uses the second USART available on some PICmicro devices.

Operators

Timeout is an OPTIONAL value for the length of time the HSERIN command will wait before jumping to label TIMEOUT LABEL. Timeout is specified in 1 millisecond units.

Timeout Label is an OPTIONAL valid BASIC label where HSERIN will jump to in the event that a character has not been received within the time specified by TIMEOUT.

Parity Error Label is an OPTIONAL valid BASIC label where HSERIN will jump to in the event that a PARITY error is received. Parity is set using DECLARES.

Modifier is one of the many formatting modifiers, explained below.

Variable is a BIT, BYTE, WORD DWORD, or FLOAT variable, that will be loaded by HSERIN.

Example

' Receive values serially and timeout if no reception after 1 second (1000ms).

DEVICE 16F877

XTAL = 4

HSERIAL_BAUD = 9600	' Set baud rate to 9600

HSERIAL_RCSTA = %10010000	' Enable serial port and continuous receive

HSERIAL_TXSTA = %00100000	' Enable transmit and asynchronous mode

HSERIAL_CLEAR = ON	' Optionally clear the buffer before receiving

DIM VAR1 AS BYTE

Loop:	HSERIN 1000 , Timeout , [VAR1]	' Receive a byte serially into VAR1

PRINT DEC VAR1 , " "	' Display the byte received

GOTO Loop	' Loop forever

Timeout:

CLS

PRINT "TIMED OUT"	' Display an error if HSERIN timed out

STOP

HSERIN MODIFIERS.

As we already know, HSERIN will wait for and receive a single byte of data, and store it in a variable . If the PICmicro were connected to a PC running a terminal program and the user pressed the "A" key on the keyboard, after the HSERIN command executed, the variable would contain 65, which is the ASCII code for the letter "A"

What would happen if the user pressed the "1" key? The result would be that the variable would contain the value 49 (the ASCII code for the character "1"). This is an important point to remember: every time you press a character on the keyboard, the computer receives the ASCII value of that character. It is up to the receiving side to interpret the values as necessary. In this case, perhaps we actually wanted the variable to end up with the value 1, rather than the ASCII code 49.

The HSERIN command provides a modifier, called the decimal modifier, which will interpret this for us. Look at the following code: -

DIM SERDATA AS BYTE

HSERIN [DEC SERDATA]

Notice the decimal modifier in the HSERIN command that appears just to the left of the SERDATA variable. This tells HSERIN to convert incoming text representing decimal numbers into true decimal form and store the result in SERDATA. If the user running the terminal software pressed the "1", "2" and then "3" keys followed by a space or other non-numeric text, the value 123 will be stored in the variable SERDATA, allowing the rest of the program to perform any numeric operation on the variable.

Without the decimal modifier, however, you would have been forced to receive each character ("1", "2" and "3") separately, and then would still have to do some manual conversion to arrive at the number 123 (one hundred twenty three) before you can do the desired calculations on it.

The decimal modifier is designed to seek out text that represents decimal numbers. The characters that represent decimal numbers are the characters "0" through "9". Once the HSERIN command is asked to use the decimal modifier for a particular variable, it monitors the incoming serial data, looking for the first decimal character. Once it finds the first decimal character, it will continue looking for more (accumulating the entire multi-digit number) until is finds a non-decimal numeric character. Remember that it will not finish until it finds at least one decimal character followed by at least one non-decimal character.

To illustrate this further, examine the following examples (assuming we're using the same code example as above): -

Serial input:	"ABC"

Result: The program halts at the HSERIN command, continuously waiting for decimal text.

Serial input:	"123" (with no characters following it)

Result: The program halts at the HSERIN command. It recognises the characters "1", "2" and "3" as the number one hundred twenty three, but since no characters follow the "3", it waits continuously, since there's no way to tell whether 123 is the entire number or not.

Serial input:	"123" (followed by a space character)

Result: Similar to the above example, except once the space character is received, the program knows the entire number is 123, and stores this value in SERDATA. The HSERIN command then ends, allowing the next line of code to run.

Serial input:	"123A"

Result: Same as the example above. The "A" character, just like the space character, is the first non-decimal text after the number 123, indicating to the program that it has received the entire number.

Serial input: "ABCD123EFGH"

Result: Similar to examples 3 and 4 above. The characters "ABCD" are ignored (since they're not decimal text), the characters "123" are evaluated to be the 	number 123 and the following character, "E", indicates to the program that it has received the entire number.

The decimal modifier is only one of a family of conversion modifiers available with HSERIN See below for a list of available conversion modifiers. All of the conversion modifiers work similar to the decimal modifier (as described above). The modifiers receive bytes of data, waiting for the first byte that falls within the range of characters they accept (e.g., "0" or "1" for binary, "0" to "9" for decimal, "0" to "9" and "A" to "F" for hex. Once they receive a numeric character, they keep accepting input until a non-numeric character arrives, or in the case of the fixed length modifiers, the maximum specified number of digits arrives.

While very effective at filtering and converting input text, the modifiers aren't completely foolproof. As mentioned before, many conversion modifiers will keep accepting text until the first non-numeric text arrives, even if the resulting value exceeds the size of the variable. After HSERIN , a BYTE variable will contain the lowest 8 bits of the value entered and a WORD (16-bits) would contain the lowest 16 bits. You can control this to some degree by using a modifier that specifies the number of digits, such as DEC2, which would accept values only in the range of 0 to 99.

Conversion Modifier 	Type of Number Numeric 	Characters Accepted

DEC{1..10} 	Decimal, optionally limited	0 through 9

to 1 - 10 digits

HEX{1..8} 	Hexadecimal, optionally limited	0 through 9,

 to 1 - 8 digits	A through F

BIN{1..32} 	Binary, optionally limited 	      0, 1

 to 1 - 32 digits

A variable preceded by BIN will receive the ASCII representation of its binary value.

For example, if BIN VAR1 is specified and "1000" is received, VAR1 will be set to 8.

A variable preceded by DEC will receive the ASCII representation of its decimal value.

For example, if DEC VAR1 is specified and "123" is received, VAR1 will be set to 123.

A variable preceded by HEX will receive the ASCII representation of its hexadecimal value.

For example, if HEX VAR1 is specified and "FE" is received, VAR1 will be set to 254.

SKIP followed by a count will skip that many characters in the input stream.

For example, SKIP 4 will skip 4 characters.

The HSERIN command can be configured to wait for a specified sequence of characters before it retrieves any additional input. For example, suppose a device attached to the PICmicro is known to send many different sequences of data, but the only data you wish to observe happens to appear right after the unique characters, "XYZ". A modifier named WAIT can be used for this purpose: -

HSERIN [WAIT( "XYZ" ) , SERDATA]

The above code waits for the characters "X", "Y" and "Z" to be received, in that order, then it receives the next data byte and places it into variable SERDATA.

STR modifier.

The HSERIN command also has a modifier for handling a string of characters, named STR.

The STR modifier is used for receiving a string of characters into a byte array variable.

A string is a set of characters that are arranged or accessed in a certain order. The characters "ABC" would be stored in a string with the "A" first, followed by the "B" then followed by the "C". A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" would be stored in a byte array containing three bytes (elements).

Below is an example that receives ten bytes and stores them in the 10-byte array, SERSTRING: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

HSERIN [STR SerString]  	' Fill the array with received data.

PRINT STR SerString 	' Display the string.

If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. For example: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

HSERIN [STR SerString\5]  	' Fill the first 5-bytes of the array

PRINT STR SerString\5 	' Display the 5-character string.

The example above illustrates how to fill only the first n bytes of an array, and then how to display only the first n bytes of the array. n refers to the value placed after the backslash.

Because of its complexity, serial communication can be rather difficult to work with at times. Using the guidelines below when developing a project using the HSERIN and HSEROUT commands may help to eliminate some obvious errors: -

Always build your project in steps.

Start with small, manageable pieces of code, (that deal with serial communication) and test them, one individually.

Add more and more small pieces, testing them each time, as you go.

Never write a large portion of code that works with serial communication without testing its smallest workable pieces first.

Pay attention to timing.

Be careful to calculate and overestimate the amount of time, operations should take within the PICmicro for a given oscillator frequency. Misunderstanding the timing constraints is the source of most problems with code that communicate serially. If the serial communication in your project is bi-directional, the above statement is even more critical.

Pay attention to wiring.

Take extra time to study and verify serial communication wiring diagrams. A mistake in wiring can cause strange problems in communication, or no communication at all. Make sure to connect the ground pins (Vss) between the devices that are communicating serially.

Verify port setting on the PC and in the HSERIN / HSEROUT commands.

Unmatched settings on the sender and receiver side will cause garbled data transfers or no data transfers. This is never more critical than when a line transceiver is used(i.e. MAX232). Always remember that a line transceiver inverts the serial polarity.

If the serial data received is unreadable, it is most likely caused by a baud rate setting error, or a polarity error.

If receiving data from another device that is not a PICmicro, try to use baud rates of 9600 and below, or alternatively, use a higher frequency crystal.

Because of additional overheads in the PICmicro, and the fact that the HSERIN command offers a 2 level hardware receive buffer for serial communication, received data may sometimes be missed or garbled. If this occurs, try lowering the baud rate, or increasing the crystal frequency. Using simple variables (not arrays) will also increase the chance that the PICmicro will receive the data properly.

Declares

There are five DECLARE directives for use with HSERIN, and five for HSERIN2. These are: -

DECLARE HSERIAL_BAUD Constant value

Sets the BAUD rate that will be used to receive a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL_RCSTA Constant value (0 to 255)

HSERIAL_RCSTA, sets the respective PICmicro hardware register RCSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register.

DECLARE HSERIAL_TXSTA Constant value (0 to 255)

HSERIAL_TXSTA, sets the respective PICmicro hardware register, TXSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate correctly.

DECLARE HSERIAL_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HSERIN and HSEROUT The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL_PARITY = ODD 	' Use if odd parity desired

DECLARE HSERIAL_CLEAR ON or OFF

Clear the overflow error bit before commencing a read.

Because the hardware serial port only has a 2-byte input buffer, it can easily overflow is characters are not read from it often enough. When this occurs, the USART stops accepting any new characters, and requires resetting. This overflow error can be reset by strobing the CREN bit within the RCSTA register. Example: -

RCSTA.4 = 0

RCSTA.4 = 1

or

CLEAR RCSTA.4

SET RCSTA.4

Alternatively, the HSERIAL_CLEAR declare can be used to automatically clear this error, even if no error occurred. However, the program will not know if an error occurred while reading, therefore some characters may be lost.

DECLARE HSERIAL_CLEAR = ON

Second USART Declares

DECLARE HSERIAL2_BAUD Constant value

Sets the BAUD rate that will be used to receive a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL2_RCSTA Constant value (0 to 255)

HSERIAL2_RCSTA, sets the respective PICmicro hardware register RCSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register.

DECLARE HSERIAL2_TXSTA Constant value (0 to 255)

HSERIAL2_TXSTA, sets the respective PICmicro hardware register, TXSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA2 register BRGH2 bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate properly.

DECLARE HSERIAL2_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HSERIN2 and HSEROUT2 The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL2_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL2_PARITY = ODD 	' Use if odd parity desired

DECLARE HSERIAL2_CLEAR ON or OFF

Clear the overflow error bit before commencing a read.

Because the hardware serial port only has a 2-byte input buffer, it can easily overflow is characters are not read from it often enough. When this occurs, the USART stops accepting any new characters, and requires resetting. This overflow error can be reset by strobing the CREN bit within the RCSTA2 register. Example: -

RCSTA2.4 = 0

RCSTA2.4 = 1

or

CLEAR RCSTA2.4

SET RCSTA2.4

Alternatively, the HSERIAL2_CLEAR declare can be used to automatically clear this error, even if no error occurred. However, the program will not know if an error occurred while reading, therefore some characters may be lost.

DECLARE HSERIAL2_CLEAR = ON

Notes

HSERIN and HSERIN2 can only be used with devices that contain a hardware USART. See the specific device's data sheet for further information concerning the serial input pin as well as other relevant parameters.

Since the serial transmission is done in hardware, it is not possible to set the levels to an inverted state to eliminate an RS232 driver. Therefore a suitable driver should be used with HSERIN . Just such a circuit using a MAX232 is shown below.

A simpler, and somewhat more elegant transceiver circuit using only 5 discrete components is shown in the diagram below.

See also :	DECLARE, HSEROUT,  HRSIN, HRSOUT, RSIN, RSOUT, SERIN, SEROUT.


HSEROUT
HSEROUT / HSEROUT2

Syntax

HSEROUT [Item { , Item... }]

Availability

14-bit and 16-bit core devices.

Overview

Transmit one or more Items from the hardware serial port on devices that support asynchronous serial communications in hardware.

HSEROUT2 has exactly the same syntax and operation as HSEROUT, but uses the second USART available on some PICmicro devices.

Operators

Item may be a constant, variable, expression, string list, or inline command.

There are no operators as such, instead there are modifiers. For example, if an at sign'@' precedes an Item, the ASCII representation for each digit is transmitted.

The modifiers are listed below: -

Modifier 	Operation

AT ypos,xpos 	Position the cursor on a serial LCD

CLS 	Clear a serial LCD (also creates a 30ms delay)

BIN{1..32} 	Send binary digits

DEC{1..10} 	Send decimal digits

HEX{1..8} 	Send hexadecimal digits

SBIN{1..32} 	Send signed binary digits

SDEC{1..10} 	Send signed decimal digits

SHEX{1..8} 	Send signed hexadecimal digits

IBIN{1..32} 	Send binary digits with a preceding '%' identifier

IDEC{1..10} 	Send decimal digits with a preceding '#' identifier

IHEX{1..8} 	Send hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Send signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Send signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Send signed hexadecimal digits with a preceding '$' identifier

REP c\n 	Send character c repeated n times

 	STR array\n	Send all or part of an array

CSTR cdata	Send string data defined in a CDATA statement.

The numbers after the BIN, DEC, and HEX modifiers are optional. If they are omitted, then the default is all the digits that make up the value will be displayed.

If a floating point variable is to be displayed, then the digits after the DEC modifier determine how many remainder digits are send.i.e. numbers after the decimal point.

DIM FLT AS FLOAT

FLT = 3.145

HSEROUT [DEC2 FLT]	' Send 2 values after the decimal point

The above program will send 3.14

If the digit after the DEC modifier is omitted, then 3 values will be displayed after the decimal point.

DIM FLT AS FLOAT

FLT = 3.1456

HSEROUT [DEC FLT]	' Send 3 values after the decimal point

The above program will send 3.145

There is no need to use the SDEC modifier for signed floating point values, as the compiler's DEC modifier will automatically display a minus result: -

DIM FLT AS FLOAT

FLT = -3.1456

HSEROUT [DEC FLT]	' Send 3 values after the decimal point

The above program will send -3.145

HEX or BIN modifiers cannot be used with floating point values or variables.

The Xpos and Ypos values in the AT modifier both start at 1. For example, to place the text "HELLO WORLD" on line 1, position 1, the code would be: -

HSEROUT [AT 1 , 1 , "HELLO WORLD"]

Example 1

DIM VAR1 AS BYTE

DIM WRD AS WORD

DIM DWD AS DWORD

 	HSEROUT ["Hello World"	' Display the text "Hello World"

 	HSEROUT ["VAR1= " , DEC VAR1]	' Display the decimal value of VAR1

 	HSEROUT ["VAR1= " , HEX VAR1]	' Display the hexadecimal value of VAR1

 	HSEROUT ["VAR1= " , BIN VAR1]	' Display the binary value of VAR1

 	HSEROUT ["VAR1= " , @VAR1]	' Display the decimal value of VAR1

HSEROUT ["DWD= " , HEX6 DWD] 	' Display 6 hex characters of a DWORD type variable

Example 2

' Display a negative value on a serial LCD.

SYMBOL NEGATIVE = -200

HSEROUT [AT 1 , 1 , SDEC NEGATIVE]

Example 3

' Display a negative value on a serial LCD with a preceding identifier.

HSEROUT [AT 1 , 1 , ISHEX -$1234]

Example 3 will produce the text "$-1234" on the LCD.

Some PICmicros such as the 16F818, 16F87x, and 18FXXX range have the ability to read and write to their own flash memory. And although writing to this memory too many times is unhealthy for the PICmicro, reading this memory is both fast, and harmless. Which offers a unique form of data storage and retrieval, the CDATA command proves this, as it uses the mechanism of reading and storing in the PICmicro's flash memory.

Combining the unique features of the 'self modifying PICmicro's ' with a string format, the compiler is capable of reducing the overhead of printing, or transmitting large amounts of text data. The CSTR modifier may be used in commands that deal with text processing i.e. SEROUT, HRSOUT, and PRINT etc.

The CSTR modifier is used in conjunction with the CDATA command. The CDATA command is used for initially creating the string of characters: -

STRING1: CDATA "HELLO WORLD" , 0

The above line of case will create, in flash memory, the values that make up the ASCII text "HELLO WORLD", at address STRING1. Note the NULL terminator after the ASCII text.

NULL terminated means that a zero (NULL) is placed at the end of the string of ASCII characters to signal that the string has finished.

To display, or transmit this string of characters, the following command structure could be used:

HSEROUT [CSTR STRING1]

The label that declared the address where the list of CDATA values resided, now becomes the string's name. In a large program with lots of text formatting, this type of structure can save quite literally hundreds of bytes of valuable code space.

Try both these small programs, and you'll see that using CSTR saves a few bytes of code: -

First the standard way of displaying text: -

DEVICE 16F877

CLS

HSEROUT ["HELLO WORLD",13]

HSEROUT ["HOW ARE YOU?",13]

HSEROUT ["I AM FINE!",13]

STOP

Now using the CSTR modifier: -

CLS

HSEROUT [CSTR TEXT1]

HSEROUT [CSTR TEXT2]

HSEROUT [CSTR TEXT3]

STOP

TEXT1: CDATA "HELLO WORLD" , 13, 0

TEXT2: CDATA "HOW ARE YOU?" , 13, 0

TEXT3: CDATA "I AM FINE!" , 13, 0

Again, note the NULL terminators after the ASCII text in the CDATA commands. Without these, the PICmicro will continue to transmit data in an endless loop.

The term 'virtual string' relates to the fact that a string formed from the CDATA command cannot be written too, but only read from.

The STR modifier is used for sending a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that displays four bytes (from a byte array): -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = "H"	' Load the first 5 bytes of the array

MYARRAY [1] = "E"	' With the data to send

MYARRAY [2] = "L"

MYARRAY [3] = "L"

MYARRAY [4] = "O"

HSEROUT [STR MYARRAY \5]  	' Display a 5-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the PICmicro would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 5 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE 	' Create a 10-byte array.

STR MYARRAY = "HELLO"	' Load the first 5 bytes of the array

HSEROUT [STR MYARRAY \5] 	' Send 5-byte string.

The above example, has exactly the same function as the previous one. The only difference is that the string is now constructed using STR as a command instead of a modifier.

Declares

There are four DECLARE directives for use with HSEROUT, and five for HSEROUT2. These are: -

DECLARE HSERIAL_BAUD Constant value

Sets the BAUD rate that will be used to transmit a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL_RCSTA Constant value (0 to 255)

HSERIAL_RCSTA, sets the respective PICmicro hardware register RCSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. Refer to the upgrade manual pages for a description of the RCSTA register.

DECLARE HSERIAL_TXSTA Constant value (0 to 255)

HSERIAL_TXSTA, sets the respective PICmicro hardware register, TXSTA, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate properly.

DECLARE HSERIAL_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HSEROUT and HSERIN The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL_PARITY declare.

DECLARE HSERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL_PARITY = ODD 	' Use if odd parity desired

Second USART Declares

DECLARE HSERIAL2_BAUD Constant value

Sets the BAUD rate that will be used to transmit a value serially. The baud rate is calculated using the XTAL frequency declared in the program. The default baud rate if the DECLARE is not included in the program listing is 2400 baud.

DECLARE HSERIAL2_RCSTA Constant value (0 to 255)

HSERIAL2_RCSTA, sets the respective PICmicro hardware register RCSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. Refer to the upgrade manual pages for a description of the RCSTA2 register.

DECLARE HSERIAL2_TXSTA Constant value (0 to 255)

HSERIAL2_TXSTA, sets the respective PICmicro hardware register, TXSTA2, to the value in the DECLARE. See the Microchip data sheet for the device used for more information regarding this register. The TXSTA register BRGH2 bit (bit 2) controls the high speed mode for the baud rate generator. Certain baud rates at certain oscillator speeds require this bit to be set to operate properly.

DECLARE HSERIAL2_PARITY ODD or EVEN

Enables/Disables parity on the serial port. For both HSEROUT2 and HSERIN2 The default serial data format is 8N1, 8 data bits, no parity bit and 1 stop bit. 7E1 (7 data bits, even parity, 1 stop bit) or 7O1 (7data bits, odd parity, 1 stop bit) may be enabled using the HSERIAL2_PARITY declare.

DECLARE HSERIAL2_PARITY = EVEN 	' Use if even parity desired

DECLARE HSERIAL2_PARITY = ODD 	' Use if odd parity desired

Notes

HSEROUT and HSEROUT2 can only be used with devices that contain a hardware USART. See the specific device's data sheet for further information concerning the serial input pin as well as other relevant parameters.

Since the serial transmission is done in hardware, it is not possible to set the levels to an inverted state in order to eliminate an RS232 driver. Therefore a suitable driver should be used with HSEROUT . See HSERIN for circuit examples

See also :	DECLARE, RSIN, RSOUT, SERIN, SEROUT, HRSIN.


IF..THEN..ELSEIF..ELSE..ENDIF

Syntax

IF Comparison THEN Instruction : { Instruction }

Or, you can use the single line form syntax:

IF Comparison THEN Instruction : { Instruction } : ELSEIF Comparison THEN Instruction : ELSE Instruction

Or, you can use the block form syntax:

IF Comparison THEN

Instruction(s)

ELSEIF Comparison THEN

Instruction(s)

{

ELSEIF Comparison THEN

Instruction(s)

}

ELSE

Instruction(s)

ENDIF

The curly braces signify optional conditions.

Availability

All devices.

Overview

Evaluates the comparison and, if it fulfils the criteria, executes expression. If comparison is not fulfilled the instruction is ignored, unless an ELSE directive is used, in which case the code after it is implemented until the ENDIF is found.

When all the instruction are on the same line as the IF-THEN statement, all the instructions on the line are carried out if the condition is fulfilled.

Operators

Comparison is composed of variables, numbers and comparators.

Instruction is the statement to be executed should the comparison fulfil the IF criteria

Example 1

SYMBOL LED = PORTB.4

VAR1 = 3

LOW LED

IF VAR1 > 4 THEN HIGH LED : DELAYMS 500 : LOW LED

In the above example, VAR1 is not greater than 4 so the IF criteria isn't fulfilled. Consequently, the HIGH LED statement is never executed leaving the state of port pin PORTB.4 low.

However, if we change the value of variable VAR1 to 5, then the LED will turn on for 500ms then off, because VAR1 is now greater than 4, so fulfils the comparison criteria.

A second form of IF, evaluates the expression and if it is true then the first block of instructions is executed. If it is false then the second block (after the ELSE) is executed. The program continues after the ENDIF instruction.

The ELSE is optional. If it is missed out then if the expression is false the program continues after the ENDIF line.

Example 2

IF X & 1 = 0 THEN

A = 0

B = 1

ELSE

A = 1

ENDIF

IF Z = 1 THEN

A = 0

B = 0

ENDIF

Example 3

IF X = 10 THEN

HIGH LED1

ELSEIF X = 20 THEN

HIGH LED2

ELSE

HIGH LED3

ENDIF

A forth form of IF, allows the ELSE or ELSEIF to be placed on the same line as the IF: -

IF X = 10 THEN HIGH LED1 : ELSEIF X = 20 THEN HIGH LED2 : ELSE HIGH LED3

Notice that there is no ENDIF instruction. The comparison is automatically terminated by the end of line condition. So in the above example, if X is equal to 10 then LED1 will illuminate, if X equals 20 then LED will illuminate, otherwise, LED3 will illuminate.

The IF statement allows any type of variable, register or constant to be compared. A common use for this is checking a Port bit: -

IF PORTA.0 = 1 THEN HIGH LED : ELSE : LOW LED

Any commands on the same line after THEN will only be executed if the comparison if fulfilled: -

IF VAR1 = 1 THEN HIGH LED : DELAYMS 500 : LOW LED

Notes

A GOTO command is optional after the THEN: -

IF PORTB.0 = 1 THEN LABEL

THEN operand always required.

The PROTON+ compiler relies heavily on the THEN part. Therefore, if the THEN part of a construct is left out of the code listing, a SYNTAX ERROR will be produced.

See also : Boolean Logic Operators, Relational Operators, SELECT..CASE..ENDSELECT.


INCLUDE

Syntax

INCLUDE "Filename"

Availability

All devices.

Overview

Include another file at the current point in the compilation. All the lines in the new file are compiled as if they were in the current file at the point of the INCLUDE command.

A Common use for the include command is shown in the example below. Here a small master document is used to include a number of smaller library files which are all compiled together to make the overall program.

Operators

Filename is any valid PROTON+ file.

Example

' Main Program INCLUDES sub files

INCLUDE "STARTCODE.BAS"

INCLUDE "MAINCODE.BAS"

INCLUDE "ENDCODE.BAS"

Notes

The file to be included into the BASIC listing may be in one of three places on the hard drive.

1… Within the INC folder of the compiler's current directory.

2… Within the Compiler's current directory.

3… Within the BASIC program's directory.

 The list above also shows the order in which they are searched for.

Using INCLUDE files to tidy up your code.

If the include file contains assembler subroutines then it must always be placed at the beginning of the program. This allows the subroutine/s to be placed within the first bank of memory (0..2048), thus avoiding any bank boundary errors. Placing the include file at the beginning of the program also allows all of the variables used by the routines held within it to be pre-declared. This again makes for a tidier program, as a long list of variables is not present in the main program.

There are some considerations that must be taken into account when writing code for an include file, these are: -

1). Always jump over the subroutines.

When the include file is placed at the top of the program this is the first place that the compiler starts, therefore, it will run the subroutine/s first and the RETURN command will be pointing to a random place within the code. To overcome this, place a GOTO statement just before the subroutine starts.

For example: -

GOTO OVER_THIS_SUBROUTINE	' Jump over the subroutine

' The subroutine is placed here

OVER_THIS_SUBROUTINE:	' Jump to here first

2). Variable and Label names should be as meaningful as possible.

For example. Instead of naming a variable LOOP, change it to ISUB_LOOP. This will help eliminate any possible duplication errors, caused by the main program trying to use the same variable or label name. However, try not to make them too obscure as your code will be harder to read and understand, it might make sense at the time of writing, but come back to it after a few weeks and it will be meaningless.

3). Comment, Comment, and Comment some more.

This cannot be emphasized enough. ALWAYS place a plethora of remarks and comments. The purpose of the subroutine/s within the include file should be clearly explained at the top of the program, also, add comments after virtually every command line, and clearly explain the purpose of all variables and constants used. This will allow the subroutine to be used many weeks or months after its conception. A rule of thumb that I use is that I can understand what is going on within the code by reading only the comments to the right of the command lines.


INC

Syntax

INC Variable

Availability

All devices.

Overview

Increment a variable i.e. VAR1 = VAR1 + 1

Operators

Variable is a user defined variable of type BYTE, WORD, DWORD, or FLOAT.

Example

VAR1 = 1

REPEAT

PRINT @VAR1 , " "

DELAYMS 200

INC VAR1

UNTIL VAR1 > 10

The above example shows the equivalent to the FOR-NEXT loop: -

FOR VAR1 = 1 TO 10 : NEXT

See also :	DEC.


DEC

Syntax

DEC Variable

Availability

All devices.

Overview

Decrement a variable i.e. VAR1 = VAR1 - 1

Operators

Variable is a user defined variable of type BYTE, WORD, DWORD, or FLOAT.

Example

VAR1 = 10

REPEAT

PRINT @VAR1 , " "

DELAYMS 200

DEC VAR1

UNTIL VAR1 = 0

The above example shows the equivalent to the FOR-NEXT loop: -

FOR VAR1 = 10 TO 0 STEP -1 : NEXT

See also :	INC.


INKEY

Syntax

Variable = INKEY

Availability

All devices.

Overview

Scan a keypad and place the returned value into variable

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Example

DIM VAR1 as BYTE

VAR1 = INKEY	' Scan the keypad

DELAYMS 50	' Debounce by waiting 50ms

PRINT @VAR1 , " "	' Display the result on the LCD

Notes

INKEY will return a value between 0 and 16. If no key is pressed, the value returned is 16.

Using a LOOKUP command, the returned values can be re-arranged to correspond with the legends printed on the keypad: -

VAR1 = INKEY

KEY = LOOKUP VAR1, [255,1,4,7,"*",2,5,8,0,3,6,9,"#",0,0,0]

The above example is only a demonstration, the values inside the LOOKUP command will need to be re-arranged for the type of keypad used, and it's connection configuration.

Declare

DECLARE KEYPAD_PORT PORT

 Assigns the Port that the keypad is attached to.

The keypad routine requires pull-up resistors, therefore, the best Port for this device is PORTB, which comes equipped with internal pull-ups. If the DECLARE is not used in the program, then PORTB is the default Port.

The above diagram illustrates a typical connection of a 12-button keypad to a PIC16F84. If a 16-button type is used, then COLUMN 4 will connect to PORTB.7 (RB7).


INPUT

Syntax

INPUT Port . Pin

Availability

All devices.

Overview

Makes the specified Port or Pin an input.

Operators

Port.Pin must be a Port, or Port.Pin constant declaration.

Example

INPUT PORTA.0	' Make bit-0 of PORTA an input

INPUT PORTA	' Make all of PORTA an input

Notes

An Alternative method for making a particular pin an input is by directly modifying the TRIS register: -

TRISB.0 = 1	' Set PORTB, bit-0 to an input

All of the pins on a port may be set to inputs by setting the whole TRIS register at once: -

TRISB = %11111111	' Set all of PORTB to inputs

In the above examples, setting a TRIS bit to 1 makes the pin an input, and conversely, setting the bit to 0 makes the pin an output.

See also :	OUTPUT.


LET

Syntax

{LET} Variable = Expression

Availability

All devices.

Overview

Assigns an expression, command result, variable, or constant, to a variable

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD,or FLOAT.

Expression is one of many options - these can be a combination of variables, expressions, constants, or other command calls.

Example 1

LET A = 1

A = 1

Both the above statements are the same

Example 2

A = B + 3

Example 3

A = A << 1

Example 4

LET B = EREAD C + 8

Notes

The LET command is optional, and is a leftover from earlier BASICs.

See also : DIM, SYMBOL


LCDREAD

Syntax

Variable = LCDREAD Line Number , Xpos

Availability

14-bit and 16-bit core devices.

Overview

Read a byte from a graphic LCD.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Line Number may be a constant, variable or expression within the range of 0 to 7. This corresponds to the line number of the LCD, with 0 being the top row.

Xpos may be a constant, variable or expression with a value of 0 to 127. This corresponds to the X position of the LCD, with 0 being the far left column.

Example

' Read and display the top row of the LCD

DEVICE 16F877

LCD_TYPE = GRAPHIC	' Target a graphic LCD

DIM VAR1 as BYTE

DIM Xpos as BYTE

CLS	' Clear the LCD

PRINT "Testing 1 2 3"

FOR Xpos = 0 TO 127	' Create a loop of 128

VAR1 = LCDREAD 0 , Xpos	' Read the LCD's top line

PRINT AT 1 , 0 , "Chr= " , @VAR1," "

DELAYMS 100

NEXT

STOP

Notes

The graphic LCDs that are compatible with PROTON+ are non- intelligent types based on the Samsung S6B0108 chipset. These have a pixel resolution of 64 x 128. The 64 being the Y axis, made up of 8 lines each having 8-bits. The 128 being the X axis, made up of 128 positions. See LCDWRITE.

As with LCDWRITE, the graphic LCD must be targeted using the LCD_TYPE DECLARE directive before this command may be used.

See also : LCDWRITE, PLOT, UNPLOT, see PRINT for LCD connections.


LCDWRITE

Syntax

LCDWRITE Line number , Xpos , [ Value ,{ Value etc…} ]

Availability

14-bit and 16-bit core devices.

Overview

Write a byte to a graphic LCD.

Operators

Line Number may be a constant, variable or expression within the range of 0 to 7. This corresponds to the line number of the LCD, with 0 being the top row.

Xpos may be a constant, variable or expression within the value of 0 to 127. This corresponds to the X position of the LCD, with 0 being the far left column.

Value may be a constant, variable, or expression, within the range of 0 to 255 (byte).

Example

'Display a line on the top row of the LCD

DEVICE 16F877

LCD_TYPE = GRAPHIC	' Target a graphic LCD

DIM Xpos as BYTE

CLS	' Clear the LCD

FOR Xpos = 0 TO 127	' Create a loop of 128

LCDWRITE 0 , Xpos, [%00001111 ]	' Write to the LCD's top line

DELAYMS 100

NEXT

STOP

Notes

The graphic LCDs that are compatible with PROTON+ are non- intelligent types based on the Samsung S6B0108 chipset. These have a pixel resolution of 64 x 128. The 64 being the Y axis, made up of 8 lines each having 8-bits. The 128 being the X axis, made up of 128 positions. See below: -

 The diagram illustrates the position of one byte at position 0,0 on the LCD screen. The least significant bit is located at the top. The byte displayed has a value of 149 (10010101).

See also : LCDREAD, PLOT, UNPLOT, see PRINT for LCD connections.


LDATA

Syntax

LDATA { alphanumeric data }

Availability

14-bit and 16-bit core devices.

Overview

Place information into code memory using the RETLW  instruction when used with 14-bit core devices, and FLASH memory when using a 16-bit core device. For access by LREAD.

Operators

alphanumeric data can be a 8,16, 32 bit value, or floating point values, or any alphabetic character or string enclosed in quotes.

Example

DEVICE 16F877

DIM CHAR AS BYTE

DIM LOOP AS BYTE

CLS

FOR LOOP = 0 TO 9	' Create a loop of 10

CHAR = LREAD LABEL + LOOP	' Read memory location LABEL + LOOP

PRINT CHAR 	' Display the value read

NEXT

STOP

LABEL: LDATA "HELLO WORLD"	' Create a string of text in code memory

The program above reads and displays 10 values from the address located by the LABEL accompanying the LDATA command. Resulting in "HELLO WORL" being displayed.

LDATA is not simply used for character storage, it may also hold 8, 16, 32 bit, or floating point values. The example below illustrates this: -

DEVICE = 16F628

DIM VAR1 AS BYTE

DIM WRD1 AS WORD

DIM DWD1 AS DWORD

DIM FLT1 AS FLOAT

CLS

VAR1 = LREAD BIT8_VAL	' Read the 8-bit value

PRINT DEC VAR1,"  "

WRD1= LREAD BIT16_VAL	' Read the 16-bit value

PRINT DEC WRD1

DWD1 = LREAD BIT32_VAL	' Read the 32-bit value

PRINT AT 2,1, DEC DWD1,"  "

FLT1 = LREAD FLT_VAL	' Read the floating point value

PRINT DEC FLT1

STOP

BIT8_VAL: LDATA 123

BIT16_VAL: LDATA 1234

BIT32_VAL: LDATA 123456

FLT_VAL: LDATA 123.456

Floating point examples.

14-bit core example

' 14-bit read floating point data from a table and display the results

DEVICE = 16F877

DIM FLT AS FLOAT	' Declare a FLOATING POINT variable

DIM F_COUNT AS BYTE

CLS	' Clear the LCD

F_COUNT = 0	' Clear the table counter

REPEAT	' Create a loop

FLT = LREAD FL_TABLE + F_COUNT	' Read the data from the LDATA table

PRINT AT 1 , 1 , DEC3 FLT	' Display the data read

F_COUNT = F_COUNT + 4	' Point to next value, by adding 4 to counter

DELAYMS 1000	' Slow things down

UNTIL FLT = 0.005	' Stop when 0.005 is read

STOP

FL_TABLE: LDATA AS FLOAT 3.14 , 65535.123 , 1234.5678 , -1243.456 , -3.14 , 998999.12 , 0.005

16-bit core example

' 16-bit read floating point data from a table and display the results

DEVICE = 18F452

DIM FLT AS FLOAT	' Declare a FLOATING POINT variable

DIM F_COUNT AS BYTE

CLS	' Clear the LCD

F_COUNT = 0	' Clear the table counter

REPEAT	' Create a loop

FLT = LREAD FL_TABLE + F_COUNT	' Read the data from the LDATA table

PRINT AT 1 , 1 , DEC3 FLT	' Display the data read

F_COUNT = F_COUNT + 2	' Point to next value, by adding 2 to counter

DELAYMS 1000	' Slow things down

UNTIL FLT = 0.005	' Stop when 0.005 is read

STOP

FL_TABLE: LDATA AS FLOAT 3.14 , 65535.123 , 1234.5678 , -1243.456 , -3.14 , 998999.12 , 0.005

Notes

LDATA tables should be placed at the end of the BASIC program. If an LDATA table is placed at the beginning of the program, then a GOTO command must jump over the tables, to the main body of code.

GOTO OVER_DATA_TABLE

LDATA 1,2,3,4,5,6

OVER_DATA_TABLE:

{ rest of code here}

With 14-bit core devices, an 8-bit value (0 - 255)  in an LDATA statement will occupy a single code space, however, 16-bit data (0 - 65535) will occupy two spaces, 32-bit and floating point values will occupy 4 spaces. This must be taken into account when using the LREAD command. See 14-bit floating point example above.

With 16-bit core devices, an 8, and 16-bit value in an LDATA statement will occupy a single code space, however, 32-bit and floating point values will occupy 2 spaces. This must be taken into account when using the LREAD command. See 16-bit floating point example above.

The compiler has a 64K limit to its LDATA tables, therefore ensure that the BASIC program does not exceed the first 64k bytes of code memory.

Formatting an LDATA table.

Sometimes it is neseccary to create a data table with an known format for its values. For example all values will occupy 4 bytes of code space even though the value itself would only occupy 1 or 2 bytes. I use the name BYTE loosely, as 14-bit core devices use 14-bit Words, as opposed to 16-bit core devices that do actually use Bytes.

LDATA 100000 , 10000 , 1000 , 100 , 10 , 1

The above line of code would produce an uneven code space usage, as each value requires a different amount of code space to hold the values. 100000 would require 4 bytes of code space, 10000 and 1000  would require 2 bytes, but 100, 10, and 1 would only require 1 byte.

Reading these values using LREAD would cause problems because there is no way of knowing the amount of bytes to read in order to increment to the next valid value.

The answer is to use formatters to ensure that a value occupies a predetermined amount of bytes. These are: -

BYTE

WORD

DWORD

FLOAT

Placing one of these formatters before the value in question will force a given length.

LDATA DWORD 100000 , DWORD 10000 , DWORD  1000 , DWORD  100 , DWORD 10 , DWORD 1

BYTE will force the value to occupy one byte of code space, regardless of it's value. Any values above 255 will be truncated to the least significant byte.

WORD will force the value to occupy 2 bytes of code space, regardless of its value. Any values above 65535 will be truncated to the two least significant bytes. Any value below 255 will be padded to bring the memory count to 2 bytes.

DWORD will force the value to occupy 4 bytes of code space, regardless of its value. Any value below 65535 will be padded to bring the memory count to 4 bytes. The line of code shown above uses the DWORD formatter to ensure all the values in the LDATA table occupy 4 bytes of code space.

FLOAT will force a value to its floating point equivalent, which always takes up 4 bytes of code space.

If all the values in an LDATA table are required to occupy the same amount of bytes, then a single formatter will ensure that this happens.

LDATA AS DWORD 100000 , 10000 , 1000 , 100 , 10 , 1

The above line has the same effect as the formatter previous example using seperate DWORD formatters, in that all values will occupy 4 bytes, regardless of their value. All four formatters can be used with the AS keyword.

The example below illustrates the formatters in use.

' Convert a DWORD value into a string array

' Using only BASIC commands

' Similar principle to the STR$ command

Include "PROTON_4.INC"

Dim P10 as Dword	' Power of 10 variable

Dim CNT as Byte

Dim J as Byte

Dim VALUE as Dword	' Value to convert

Dim STRING1[11] as Byte	' Holds the converted value

Dim PTR as Byte	' Pointer within the Byte array

Delayms 500	' Wait for PICmicro to stabilise

Cls	' Clear the LCD

Clear	' Clear all RAM before we start

VALUE = 1234576	' Value to convert

Gosub DWORD_TO_STR	' Convert VALUE to string

Print STR STRING1	' Display the result

Stop

'-------------------------------------------------------------

' Convert a DWORD value into a string array

' Value to convert is placed in 'VALUE'

' Byte array 'STRING1' is built up with the ASCII equivalent

DWORD_TO_STR:

PTR = 0

J = 0

Repeat

P10 = LREAD DWORD_TBL + (J * 4)

CNT = 0

While VALUE >= P10

VALUE = VALUE - P10

Inc CNT

Wend

If CNT <> 0 Then

STRING1[PTR] = CNT + "0"

Inc PTR

Endif

Inc J

Until J > 8

STRING1[PTR] = VALUE + "0"

Inc PTR

STRING1[PTR] = 0	' Add the NULL to terminate the string

Return

' LDATA table is formatted for all 32 bit values.

' Which means each value will require 4 bytes of code space

DWORD_TBL:

LDATA  AS DWORD 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10

Label names as pointers.

If a label's name is used in the list of values in an LDATA table, the label's address will be used. This is useful for accessing other tables of data using their address from a lookup table. See example below.

' Display text from two LDATA tables

' Based on their address located in a separate table

       	 Include "PROTON_4.INC"	' Use a 14-bit core device

       	 Dim ADDRESS as Word

       	 Dim DATA_BYTE as Byte

       	Delayms 200	' Wait for PICmicro to stabilise

        	Cls	' Clear the LCD

        	ADDRESS = LREAD ADDR_TABLE	' Locate the address of the first string

       	While 1 = 1	' Create an infinite loop

        	DATA_BYTE = LREAD ADDRESS	' Read each character from the LDATA string

            If DATA_BYTE = 0 Then EXIT_LOOP	' Exit if NULL found

        	Print DATA_BYTE	' Display the character

            Inc ADDRESS	' Next character

        	Wend	' Close the loop

EXIT_LOOP:

        	Cursor 2,1	' Point to line 2 of the LCD

ADDRESS = LREAD ADDR_TABLE + 2	' Locate the address of the second string

       	While 1 = 1	' Create an infinite loop

        	DATA_BYTE = LREAD ADDRESS	' Read each character from the LDATA string

            If DATA_BYTE = 0 Then EXIT_LOOP2 	' Exit if NULL found

        	Print DATA_BYTE	' Display the character

            Inc ADDRESS	' Next character

        	Wend	' Close the loop

EXIT_LOOP2:

        	Stop

ADDR_TABLE:	' Table of address's

LDATA AS WORD STRING1, STRING2

STRING1:

LDATA "HELLO",0

STRING2:

LDATA "WORLD",0

See also : CDATA, CREAD, DATA, EDATA, LREAD, READ, RESTORE


LREAD

Syntax

Variable = LREAD Label

Availability

14-bit and 16-bit core devices.

Overview

Read a value from an LDATA table and place into Variable

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Label is a label name preceding the LDATA statement, or expression containing the Label name.

Example

DEVICE 16F877

DIM CHAR AS BYTE

DIM LOOP AS BYTE

CLS

FOR LOOP = 0 TO 9	' Create a loop of 10

CHAR = LREAD LABEL + LOOP	' Read memory location LABEL + LOOP

PRINT CHAR 	' Display the value read

NEXT

STOP

LABEL: LDATA "HELLO WORLD"	' Create a string of text in code memory

The program above reads and displays 10 values from the address located by the LABEL accompanying the LDATA statement. Resulting in "HELLO WORL" being displayed.

LDATA is not simply used for character storage, it may also hold 8, 16, 32 bit, or floating point values. The example below illustrates this: -

DEVICE = 16F628

DIM VAR1 AS BYTE

DIM WRD1 AS WORD

DIM DWD1 AS DWORD

DIM FLT1 AS FLOAT

CLS

VAR1 = LREAD BIT8_VAL	' Read the 8-bit value

PRINT DEC VAR1,"  "

WRD1= LREAD BIT16_VAL	' Read the 16-bit value

PRINT DEC WRD1

DWD1 = LREAD BIT32_VAL	' Read the 32-bit value

PRINT AT 2,1, DEC DWD1,"  "

FLT1 = LREAD FLT_VAL	' Read the floating point value

PRINT DEC FLT1

STOP

BIT8_VAL: LDATA 123

BIT16_VAL: LDATA 1234

BIT32_VAL: LDATA 123456

FLT_VAL: LDATA 123.456

Floating point examples.

14-bit core example

' 14-bit read floating point data from a table and display the results

DEVICE = 16F877

DIM FLT AS FLOAT	' Declare a FLOATING POINT variable

DIM F_COUNT AS BYTE

CLS	' Clear the LCD

F_COUNT = 0	' Clear the table counter

REPEAT	' Create a loop

FLT = LREAD FL_TABLE + F_COUNT	' Read the data from the LDATA table

PRINT AT 1 , 1 , DEC3 FLT	' Display the data read

F_COUNT = F_COUNT + 4	' Point to next value, by adding 4 to counter

DELAYMS 1000	' Slow things down

UNTIL FLT = 0.005	' Stop when 0.005 is read

STOP

FL_TABLE:  LDATA AS FLOAT 3.14 , 65535.123 , 1234.5678 , -1243.456 , -3.14 , 998999.12 , 0.005

16-bit core example

' 16-bit read floating point data from a table and display the results

DEVICE = 18F452

DIM FLT AS FLOAT	' Declare a FLOATING POINT variable

DIM F_COUNT AS BYTE

CLS	' Clear the LCD

F_COUNT = 0	' Clear the table counter

REPEAT	' Create a loop

FLT = LREAD FL_TABLE + F_COUNT	' Read the data from the LDATA table

PRINT AT 1 , 1 , DEC3 FLT	' Display the data read

F_COUNT = F_COUNT + 2	' Point to next value, by adding 2 to counter

DELAYMS 1000	' Slow things down

UNTIL FLT = 0.005	' Stop when 0.005 is read

STOP

FL_TABLE: LDATA AS FLOAT 3.14 , 65535.123 , 1234.5678 , -1243.456 , -3.14 , 998999.12 , 0.005

Notes

LDATA tables should be placed at the end of the BASIC program. If an LDATA table is placed at the beginning of the program, then a GOTO command must jump over the tables, to the main body of code.

GOTO OVER_DATA_TABLE

LDATA 1,2,3,4,5,6

OVER_DATA_TABLE:

{ rest of code here}

With 14-bit core devices, an 8-bit value (0 - 255)  in an LDATA statement will occupy a single code space, however, 16-bit data (0 - 65535) will occupy two spaces, 32-bit and floating point values will occupy 4 spaces. This must be taken into account when using the LREAD command. See 14-bit floating point example above.

With 16-bit core devices, an 8, and 16-bit value in an LDATA statement will occupy a single code space, however, 32-bit and floating point values will occupy 2 spaces. This must be taken into account when using the LREAD command. See 16-bit floating point example above.

Calculating an offset into an LDATA table can also be a simple multiplication of 2 or 4. For example, to read the second value in a 16-bit LDATA table, the following code could be used: -

' Calculate the offset in a 16-bit LDATA table

DEVICE = 16F877

DIM OFFSET AS BYTE	' Declare a BYTE size variable for the offset

DIM RESULT AS WORD	' Declare a WORD size variable to hold the result

CLS	' Clear the LCD

OFFSET = 1	' Point to the second value in the LDATA table

RESULT = LREAD WORD_TABLE + (OFFSET * 2)	' Read the value pointed to by OFFSET multiplied by 2

PRINT DEC RESULT	' Display the decimal result on the LCD

STOP

WORD_TABLE: LDATA AS WORD 1234 , 5678

In order to calculate the offset in a 32-bit LDATA table, the same method can be used, but a multiplication of 4 is carried out instead of 2. This also applied for an LDATA table containing floating point values, as these also contain 4-bytes per value.

' Calculate the offset in a 32-bit LDATA table

DEVICE = 16F877

DIM OFFSET AS BYTE	' Declare a BYTE size variable for the offset

DIM RESULT AS DWORD	' Declare a DWORD size variable to hold the result

CLS	' Clear the LCD

OFFSET = 1	' Point to the second value in the LDATA table

RESULT = LREAD DWORD_TABLE + (OFFSET * 4)	' Read the value pointed to by OFFSET multiplied by 4

PRINT DEC RESULT	' Display the decimal result on the LCD

STOP

DWORD_TABLE: LDATA AS DWORD 123456 , 567890

Remember that the offset starts at 0 for the first value in the LDATA table, so the second value is actually an offset of 1. The same method as adopted for arrays and strings.

For a more efficient method of accessing values within an LDATA table, see LREAD8, LREAD16, and LREAD32.

See also : CDATA, CREAD, DATA, LDATA, LREAD8, LREAD16, LREAD32, READ, RESTORE.


LREAD8, LREAD16, LREAD32

Syntax

Variable = LREAD8 Label [ Offset Variable ]

or

Variable = LREAD16 Label [ Offset Variable ]

or

Variable = LREAD32 Label [ Offset Variable ]

Availability

14-bit and 16-bit core devices.

Overview

Read an 8, 16, or 32-bit value from an LDATA table using an offset of Offset Variable and place into Variable, with more efficiency than using LREAD.

LREAD8 will access 8-bit values from an LDATA table.

LREAD16 will access 16-bit values from an LDATA table.

LREAD32 will access 32-bit values from an LDATA table, this also includes floating point values.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Label is a label name preceding the LDATA statement of which values will be read from.

Offset Variable can be a constant value, variable, or expression that points to the location of interest within the LDATA table.

LREAD8 Example

' Extract the second value from within an 8-bit LDATA table

DEVICE = 16F877

DIM OFFSET AS BYTE	' Declare a BYTE size variable for the offset

DIM RESULT AS BYTE	' Declare a BYTE size variable to hold the result

CLS	' Clear the LCD

OFFSET = 1	' Point to the second value in the LDATA table

RESULT = LREAD8 BYTE_TABLE [OFFSET]	' Read the 8-bit value pointed to by OFFSET

PRINT DEC RESULT	' Display the decimal result on the LCD

STOP

' Create a table containing only 8-bit values

BYTE_TABLE: LDATA AS BYTE 100 , 200

LREAD16 Example

' Extract the second value from within a 16-bit LDATA table

DEVICE = 16F877

DIM OFFSET AS BYTE	' Declare a BYTE size variable for the offset

DIM RESULT AS WORD	' Declare a WORD size variable to hold the result

CLS	' Clear the LCD

OFFSET = 1	' Point to the second value in the LDATA table

RESULT = LREAD16 WORD_TABLE [OFFSET]	' Read the 16-bit value pointed to by OFFSET

PRINT DEC RESULT	' Display the decimal result on the LCD

STOP

' Create a table containing only 16-bit values

WORD_TABLE: LDATA AS WORD 1234 , 5678

LREAD32 Example

' Extract the second value from within a 32-bit LDATA table

DEVICE = 16F877

DIM OFFSET AS BYTE	' Declare a BYTE size variable for the offset

DIM RESULT AS DWORD	' Declare a DWORD size variable to hold the result

CLS	' Clear the LCD

OFFSET = 1	' Point to the second value in the LDATA table

RESULT = LREAD32 DWORD_TABLE [OFFSET]	' Read the 32-bit value pointed to by OFFSET

PRINT DEC RESULT	' Display the decimal result on the LCD

STOP

' Create a table containing only 32-bit values

DWORD_TABLE: LDATA AS DWORD 12340 , 56780

Notes

Data storage in any program is of paramount importance, and although the standard LREAD command can access multi-byte values from an LDATA table, it was not originally indended as such, and is more suited to accessing character data or single 8-bit values. However, the LREAD8, LREAD16, and LREAD32 commands are specifically written in order to efficiently read data from an LDATA table, and use the least amount of code space in doing so, thus increasing the speed of operation. Which means that wherever possible, LREAD should be replaced by LREAD8, LREAD16, or LREAD32.

See also : CDATA, CREAD, DATA, LDATA, LREAD, READ, RESTORE.


LOADBIT

Syntax

LOADBIT Variable , Index , Value

Availability

All devices.

Overview

Clear, or Set a bit of a variable or register using a variable index to point to the bit of interest.

Operators

Variable is a user defined variable, of type BYTE, WORD, or DWORD.

Index is a constant, variable, or expression that points to the bit within Variable that requires accessing.

Value is a constant, variable, or expression that will be placed into the bit of interest. Values greater than 1 will set the bit

Example

 	' Copy variable EX_VAR bit by bit into variable PT_VAR

DEVICE = 16F877

XTAL = 4

DIM EX_VAR AS WORD

DIM INDEX AS BYTE

DIM VALUE AS BYTE

DIM PT_VAR AS WORD

AGAIN:

PT_VAR = %0000000000000000

EX_VAR = %1011011000110111

CLS

FOR INDEX = 0 TO 15	' Create a loop for 16 bits

VALUE = GETBIT EX_VAR , INDEX	' Examine each bit of variable EX_VAR

LOADBIT PT_VAR , INDEX , VALUE 	' Set or Clear each bit of PT_VAR

PRINT AT 1,1,BIN16 EX_VAR	' Display the original variable

    	PRINT AT 2,1,BIN16 PT_VAR	' Display the copied variable

DELAYMS 100	' Slow things down to see what's happening

NEXT	' Close the loop

GOTO AGAIN	' Do it forever

Notes

There are many ways to clear or set a bit within a variable, however, each method requires a certain amount of manipulation, either with rotates, or alternatively, the use of indirect addressing using the FSR, and INDF registers. Each method has its merits, but requires a certain amount of knowledge to accomplish the task correctly. The LOADBIT command makes this task extremely simple by taking advantage of the indirect method using FSR, and INDF, however, this is not necessarily the quickest method, or the smallest, but it is the easiest. For speed and size optimisation, there is no shortcut to experience.

To CLEAR a known constant bit of a variable or register, then access the bit directly using PORT.n.

PORTA.1 = 0

or

VAR1.4 = 0

To SET a known constant bit of a variable or register, then access the bit directly using PORT.n.

PORTA.1 = 1

or

VAR1.4 = 1

If a PORT is targeted by LOADBIT, the TRIS register is NOT affected.

See also : CLEARBIT, GETBIT, SETBIT


LOOKDOWN

Syntax

Variable = LOOKDOWN Index , [ Constant { , Constant…etc } ]

Availability

All devices.

Overview

Search constants(s) for index value. If index matches one of the constants, then store the matching constant's position (0-N) in variable. If no match is found, then the variable is unaffected.

Operators

Variable is a user define variable that holds the result of the search.

Index is the variable/constant being sought.

Constant(s),... is a list of values. The target value is compared to these values. A maximum of 255 values may be placed between the square brackets, 256 if using a 16-bit core device.

Example

DIM Value as BYTE

DIM Result as BYTE

Value = 177	' The value to look for in the list

Result = 255	' Default to value 255

Result = LOOKDOWN Value , [75,177,35,1,8,29,245]

PRINT "Value matches " , @Result , " in list"

In the above example, PRINT displays, "Value matches 1 in list" because VALUE (177) matches item 1 of [75,177,35,1,8,29,245]. Note that index numbers count up from 0, not 1; that is in the list [75,177,35,1,8,29,245], 75 is item 0.

If the value is not in the list, then RESULT is unchanged.

Notes

LOOKDOWN is similar to the index of a book. You search for a topic and the index gives you the page number. LOOKDOWN searches for a value in a list, and stores the item number of the first match in a variable.

LOOKDOWN also supports text phrases, which are basically lists of byte values, so they are also eligible for Lookdown searches:

DIM Value as BYTE

DIM Result as BYTE

Value = 101	' ASCII "e". the value to look for in the list

Result = 255	' Default to value 255

Result = LOOKDOWN Value , ["Hello World"]

In the above example, RESULT will hold a value of 1, which is the position of character 'e'

See also : CDATA, DATA, EDATA, LOOKDOWNL, LOOKUP, LOOKUPL, CREAD, EREAD, READ, RESTORE.


LOOKDOWNL

Syntax

Variable = LOOKDOWNL Index , {Operator} [ Value { , Value…etc } ]

Availability

14-bit and 16-bit core devices.

Overview

A comparison is made between index and value; if the result is true, 0 is written into variable. If that comparison was false, another comparison is made between value and value1; if the result is true, 1 is written into variable. This process continues until a true is yielded, at which time the index is written into variable, or until all entries are exhausted, in which case variable is unaffected.

Operators

Variable is a user define variable that holds the result of the search.

Index is the variable/constant being sought.

Value(s) can be a mixture of 16-bit constants, string constants and variables. Expressions may not be used in the Value list, although they may be used as the index value. A maximum of 85 values may be placed between the square brackets, 256 if using a 16-bit core device.

Operator is an optional comparison operator and may be one of the following: -

= equal

<> not equal

> greater than

< less than

>= greater than or equal to

<= less than or equal to

The optional operator can be used to perform a test for other than equal to ("=") while searching the list. For example, the list could be searched for the first Value greater than the index parameter by

using ">" as the operator. If operator is left out, "=" is assumed.

Example

VAR1 = LOOKDOWNL WRD , [ 512 , WRD1, 1024 ]

VAR1 = LOOKDOWNL WRD , < [ 10 , 100 , 1000 ]

Notes

Because LOOKDOWNL is more versatile than the standard LOOKDOWN command, it generates larger code. Therefore, if the search list is made up only of 8-bit constants and strings, use LOOKDOWN.

See also : CDATA, DATA, EDATA, LOOKDOWN, LOOKUP, LOOKUPL, CREAD, EREAD, READ, RESTORE.


LOOKUP

Syntax

Variable = LOOKUP Index , [ Constant { , Constant…etc } ]

Availability

All devices.

Overview

Look up the value specified by the index and store it in variable. If the index exceeds the highest index value of the items in the list, then variable remains unchanged.

Operators

Variable may be a constant, variable, or expression. This is where the retrieved value will be stored.

Index may be a constant of variable. This is the item number of the value to be retrieved from the list.

Constant(s) may be any 8-bit value (0-255). A maximum of 255 values may be placed between the square brackets, 256 if using a 16-bit core device.

Example

' Create an animation of a spinning line.

DIM INDEX as BYTE

DIM Frame as BYTE

CLS	' Clear the LCD

Rotate:

FOR INDEX = 0 TO 3	' Create a loop of 4

 	Frame = LOOKUP INDEX , [ "|\-/" ]	' Table of animation characters

PRINT AT 1 , 1 , Frame	' Display the character

DELAYMS 200	' So we can see the animation

NEXT	' Close the loop

 	GOTO Rotate	' Repeat forever

Notes

index starts at value 0. For example, in the LOOKUP command below. If the first value (10) is required, then index will be loaded with 0, and 1 for the second value (20) etc.

 VAR1 = LOOKUP INDEX , [ 10 , 20 , 30 ]

See also : CDATA, DATA, EDATA, LOOKUPL , LOOKDOWN, LOOKDOWNL, CREAD, EREAD, READ, RESTORE.


LOOKUPL

Syntax

Variable = LOOKUPL Index , [ Value { , Value…etc } ]

Availability

14-bit and 16-bit core devices.

Overview

Look up the value specified by the index and store it in variable. If the index exceeds the highest index value of the items in the list, then variable remains unchanged. Works exactly the same as LOOKUP, but allows variable types or constants in the list of values.

Operators

Variable may be a constant, variable, or expression. This is where the retrieved value will be stored.

Index may be a constant of variable. This is the item number of the value to be retrieved from the list.

Value(s) can be a mixture of 16-bit constants, string constants and variables. A maximum of 85 values may be placed between the square brackets, 256 if using a 16-bit core device.

Example

DIM VAR1 as BYTE

DIM WRD as WORD

DIM INDEX as BYTE

DIM Assign as WORD

VAR1 = 10

WRD = 1234

INDEX = 0	' Point to the first value in the list (WRD)

Assign = LOOKUPL INDEX , [ WRD , VAR1 , 12345 ]

Notes

Expressions may not be used in the Value list, although they may be used as the Index value.

Because LOOKUPL is capable of processing any variable and constant type, the code produced is a lot larger than that of LOOKUP. Therefore, if only 8-bit constants are required in the list, use LOOKUP instead.

See also : CDATA, DATA, EDATA, LOOKUP, LOOKDOWN, LOOKDOWNL, CREAD, EREAD, READ, RESTORE.


LOW

Syntax

LOW Port or Port.Bit

Availability

All devices.

Overview

Place a Port or bit in an output low state. For a port, this means filling it with 0's. For a bit this means setting it to 0.

Operators

Port can be any valid port.

Port.Bit can be any valid port and bit combination, i.e. PORTA.1

Example

SYMBOL LED = PORTB.4

LOW LED

LOW PORTB.0	' Clear PORTB bit 0

LOW PORTB	' Clear all of PORTB

See also : DIM, HIGH, SYMBOL


LINE

Syntax

LINE Set_Clear , Xpos Start , Ypos Start , Xpos End , Ypos End

Availability

14-bit and 16-bit core devices.

Overview

Draw a straight line in any direction on a graphic LCD.

Operators

Set_Clear may be a constant or variable that determines if the line will set or clear the pixels. A value of 1 will set the pixels and draw a line, while a value of 0 will clear any pixels and erase a line.

Xpos Start may be a constant or variable that holds the X position for the start of the line. Can be a value from 0 to 127.

Ypos Start may be a constant or variable that holds the Y position for the start of the line. Can be a value from 0 to 63.

Xpos End may be a constant or variable that holds the X position for the end of the line. Can be a value from 0 to 127.

Ypos End may be a cconstant or variable that holds the Y position for the end of the line. Can be a value from 0 to 63.

Example

' Draw a line from 0,0 to 120,34

INCLUDE "PROTON_G4.INT"

DIM XPOS_START as BYTE

DIM XPOS_END as BYTE

DIM YPOS_START as BYTE

DIM YPOS_END as BYTE

DIM SET_CLR as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

XPOS_START = 0

YPOS_START = 0

XPOS_END = 120

YPOS_END = 34

SET_CLR = 1

LINE SET_CLR , XPOS_START , YPOS_START , XPOS_END , YPOS_END

STOP

See Also :	BOX, CIRCLE, LINETO.


LINETO

Syntax

LINETO Set_Clear , Xpos End , Ypos End

Availability

14-bit and 16-bit core devices.

Overview

Draw a straight line in any direction on a graphic LCD, starting from the previous LINE command's end position.

Operators

Set_Clear may be a constant or variable that determines if the line will set or clear the pixels. A value of 1 will set the pixels and draw a line, while a value of 0 will clear any pixels and erase a line.

Xpos End may be a constant or variable that holds the X position for the end of the line. Can be a value from 0 to 127.

Ypos End may be a cconstant or variable that holds the Y position for the end of the line. Can be a value from 0 to 63.

Example

' Draw a line from 0,0 to 120,34. Then from 120,34 to 0,63

INCLUDE "PROTON_G4.INT"

DIM XPOS_START as BYTE

DIM XPOS_END as BYTE

DIM YPOS_START as BYTE

DIM YPOS_END as BYTE

DIM SET_CLR as BYTE

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

XPOS_START = 0

YPOS_START = 0

XPOS_END = 120

YPOS_END = 34

SET_CLR = 1

LINE SET_CLR , XPOS_START , YPOS_START , XPOS_END , YPOS_END

XPOS_END = 0

YPOS_END = 63

LINETO SET_CLR , XPOS_END , YPOS_END

STOP

Notes

The LINETO command uses the compiler's internal system variables to obtain the end position of a previous LINE command. These X and Y coordinates are then used as the starting X and Y coordinates of the LINETO command.

For this reason, you must ensure that a LINETO command follows a LINE command, so that the X and Y position variables are not destroyed by any subsequent commands. As shown in the above example, loading and assigning variables is permitted so long as they do not alter system variables PP3 or GENH. You can find this out by examining the ASM file produced.

See Also :	BOX, CIRCLE, LINE.


ON_INTERRUPT

Syntax

ON_INTERRUPT {Goto} Label

or

ON_HARDWARE_INTERRUPT {Goto} Label

Note that the Goto text is optional.

Availability

14-bit and 16-bit core devices.

Overview

Jump to a subroutine when a HARDWARE interrupt occurs

Operators

Label is a valid identifier

Example

' Flash an LED attached to PORTB.0 at a different rate to the

' LED attached to PORTB.1

DEVICE 16F84

ON_HARDWARE_INTERRUPT GOTO Flash

' Assign some Interrupt associated aliases

SYMBOL T0IE = INTCON.5 	' TMR0 Overflow Interrupt Enable

SYMBOL T0IF = INTCON.2 	' TMR0 Overflow Interrupt Flag

SYMBOL GIE = INTCON.7	' Global Interrupt Enable

SYMBOL PS0 = OPTION_REG.0	' Prescaler ratio bit-0

SYMBOL PS1 = OPTION_REG.1	' Prescaler ratio bit-1

SYMBOL PS2 = OPTION_REG.2	' Prescaler ratio bit-2

SYMBOL PSA = OPTION_REG.3	' Prescaler Assignment (1=assigned to WDT 0=assigned to oscillator)

SYMBOL T0CS = OPTION_REG.5	' Timer0 Clock Source Select (0=Internal clock 1=External PORTA.4)

SYMBOL LED = PORTB.1

GOTO Over_interrupt	' Jump over the interrupt subroutine

' Interrupt routine starts here

Flash:

' XOR PORTB with 1, Which will turn on with one interrupt

' and turn off with the next the LED connected to PORTB.0

PORTB = PORTB ^ 1

T0IF = 0 	' Clear the TMR0 overflow flag

CONTEXT RESTORE	' Restore the registers and exit the interrupt

Over_interrupt :

TRISB = %00000000 	' Configure PORTB as outputs

PORTB = 0	' Clear PORTB

' Initiate the interrupt

GIE = 0 	' Turn off global interrupts

PSA = 0 	' Assign the prescaler to external oscillator

PS0 = 1 	' Set the prescaler

PS1 = 1 	' to increment TMR0

PS2 = 1 	' every 256th instruction cycle

T0CS = 0 	' Assign TMR0 clock to internal source

TMR0 = 0 	' Clear TMR0 initially

T0IE = 1 	' Enable TMR0 overflow interrupt

GIE = 1 	' Enable global interrupts

Inf:

LOW LED

DELAYMS 500

HIGH LED

DELAYMS 500

GOTO Inf

Initiating a TMR0 interrupt on a 14-bit core device.

Before we can change any bits that correspond to interrupts we need to make sure that global interrupts are disabled. This is done by clearing the GIE  bit of INTCON  (INTCON.7). Sometimes an interrupt may occur while the GIE  bit is being cleared, which means that the bit is not actually cleared and global interrupts are not disabled. To make sure that the GIE  bit is actually cleared we must poll it. This can be accomplished by a simple loop: -

GIE = 0	' Disable global interrupts

WHILE GIE = 1	' Make sure they are off

GIE = 0	' Continue to clear GIE

WEND	' Exit when GIE is clear

The prescaler attachment to TMR0 is controlled by bits 0:2 of the OPTION_REG (PS0, 1, 2). The table below shows their relationship to the prescaled ratio applied. But before the prescaler can be calculated we must inform the PICmicro as to what clock governs TMR0. This is done by setting or clearing the PSA bit of OPTION_REG (OPTION_REG.3). If PSA is cleared then TMR0 is attached to the external crystal oscillator. If it is set then it is attached to the watchdog timer, which uses the internal RC oscillator. This is important to remember; as the prescale ratio differs according to which oscillator it is attached to.

PS2	PS1	PS0	PSA=0 (External crystal OSC)	PSA=1 (Internal WDT OSC)

0	0	0	1 : 2	1 : 1

0	0	1	1 : 4	1 : 2

0	1	0	1 : 8	1 : 4

0	1	1	1 : 16	1 : 8

1	0	0	1 : 32	1 : 16

1	0	1	1 : 64	1 : 32

1	1	0	1 : 128	1 : 64

1	1	1	1 : 256	1 : 128

TMR0 prescaler ratio configurations.

As can be seen from the above table, if we require TMR0 to increment on every instruction cycle (4/OSC) we must clear PS2..0 and set PSA, which would attach it to the watchdog timer. This will cause an interrupt to occur every 256us (assuming a 4MHz crystal). If the same values were placed into PS2..0 and PSA was cleared (attached to the external oscillator) then TMR0 would increment on every 2nd instruction cycle and cause an interrupt to occur every 512us.

There is however, another way TMR0 may be incremented. By setting the T0CS bit of the OPTION_REG (OPTION_REG.5) a rising or falling transition on PORTA.0 will also increment TMR0. Setting T0CS will attach TMR0 to PORTA.0 and clearing TOCS will attach it to the oscillators. If PORTA.0 is chosen then an associated bit, T0SE (OPTION_REG.4) must be set or cleared. Clearing T0SE will increment TMR0 with a low to high transition, while setting T0SE will increment TMR0 with a high to low transition.

The prescaler's ratio is still valid when PORTA.0 is chosen as the source, so that every nth transition on PORTA.0 will increment TMR0. Where n is the prescaler ratio.

Before the interrupt is enabled, TMR0 itself should be assigned a value, as any variable should be when first starting a program. In most cases clearing TMR0 will suffice. This is necessary because, when the PICmicro is first powered up the value of TMR0 could be anything from 0 to 255

We are now ready to allow TMR0 to trigger an interrupt. This is accomplished by setting the T0IE bit of INTCON  (INTCON.5). Setting this bit will not cause a global interrupt to occur just yet, but will inform the PICmicro that when global interrupts are enabled, TMR0 will be one possible cause. When TMR0 overflows (rolls over from 255 to 0) the T0IF (INTCON.2) flag is set. This is not important yet but will become crucial in the interrupt handler subroutine.

The final act is to enable global interrupts by setting the GIE  bit of the INTCON  register (INTCON.7).

Format of the interrupt handler on a 14-bit core device.

The interrupt handler subroutine must always follow a fixed pattern. First, the contents of the STATUS, PCLATH, FSR, and Working register (WREG) must be saved, this is termed context saving, and is performed automatically by the compiler, and variable space is automatically allocated for the registers in the shared portion of memory located at the top of BANK 0.

When the interrupt handler was called, the GIE  bit was automatically cleared by hardware, disabling any more interrupts. If this were not the case, another interrupt might occur while the interrupt handler was processing the first one, which would lead to disaster.

Now the T0IF (TMR0 overflow) flag becomes important. Because, before exiting the interrupt handler it must be cleared to signal that we have finished with the interrupt and are ready for another one.

T0IF = 0 	' Clear the TMR0 overflow flag

But this only applies if a (TMR0 overflow triggered the interrupt in the first place.

The STATUS, PCLATH, FSR, and Working register (WREG) must be returned to their original conditions (context restoring). The CONTEXT RESTORE command may be used for this. i.e. CONTEXT RESTORE.

The CONTEXT RESTORE command also returns the PICmicro back to the main body code where the interrupt was called from. In other words it performs a RETFIE instruction.

Note that on PICmicro devices that contain only 1 PAGE of code memory, the PCLATH register is not saved or restored. This is because it is not required to point to pages above the first.

ICD disturbance with 14-bit core device.

If ICD2 support is enabled along with a hardware interrupt, the compiler cannot allocate context saving/restoring space in the shared portion of RAM because the ICD requires this memory for its own exclusive use. So the compiler adopts a different RAM allocation strategy.

The first 4 bytes of RAM in BANK0 are left clear for saving the WREG, STATUS, FSR, and PCLATH. Subsequentially, every first byte of RAM in banks 1,2 or 3 (if available) are also reserved for WREG saving. This is required because an interrupt may occur while the PICmicro is pointing to a BANK other than 0.

The RAM usage will be reflected in the amount of RAM available on the PICmicro.

Format of the interrupt handler on a 16-bit core device.

The interrupt handler subroutine on a 16-bit core device follows the same rules as on a 14-bit device, but there are some subtle differences. First, the contents of the STATUS, BSR, WREG (Working register), and sometimes FSR0L and FSR0H, may need to be saved, this is termed context saving, and unlike the 14-bit core devices, it is NOT performed automatically by the compiler. Issuing the CONTEXT SAVE command will store the registers in Access RAM. I say "may need saving" because the 16-bit core devices can automatically save the STATUS, BSR and WREG in shadow registers before entering an interrupt handler, and restore them upon exiting. See the appropriate PICmicro's datasheet for more details on this, because Microchip, in their wisdom, may change its operation in future devices (it has happened before!).

When the interrupt handler is called, the GIE  bit is automatically cleared by hardware, disabling any more interrupts. If this were not the case, another interrupt might occur while the interrupt handler was processing the first one, which would lead to disaster.

Once the interrupt subroutine is finished, the STATUS, BSR, WREG and the FSR0L/H (if saved) must be returned to their original conditions (context restoring). The CONTEXT RESTORE command may be used for this. i.e. CONTEXT RESTORE.

The CONTEXT RESTORE command also returns the PICmicro back to the main body code where the interrupt was called from. In other words it performs a RETFIE instruction.

If automatic register saving is performed, then issuing a RETFIE FAST will automatically restore the registers and exit the interrupt.

Precautions.

Because a hardware interrupt may occur at any time, It cannot be fully guaranteed that a SYSTEM variable will not be disturbed while inside the interrupt handler, therefore, the safest way to use a HARDWARE interrupt is to write the code in assembler, or to implement a SOFTWARE interrupt using the ON INTERRUPT directive. This will guarantee that no system variables are being altered. Alternatively, the assembler code may be viewed in order to ascertain whether any system variables are being used. Some of these are: -

PP0, PP0H, PP1, PP1H, PP2, PP2H, PP3, PP3H, PP4, PP4H, PP5, PP5H, PP6, PP6H, PP7, PP7H, GEN, GENH, GEN2, GEN2H, GEN3, GEN3H, GEN4, GEN4H, GPR, BPF.

If an unrecognised or undeclared variable name is seen within the interrupt handler's assembler code, then it will be a SYSTEM variable, and the program may fail, either subtly or disasterously.

The code within the interrupt handler should be as quick and efficient as possible because, while it's processing the code the main program is halted.

When using assembler interrupts, care should be taken to ensure that the watchdog timer does not time-out. Placing a CLRWDT instruction at regular intervals within the code will prevent this from happening. An alternative approach would be to disable the watchdog timer altogether at programming time.

Interrupt Declare

DECLARE FSR_CONTEXT_SAVE = ON or OFF, or TRUE or FALSE, or 1, 0

When using HARDWARE interrupts, it is not always neseccary to save the FSR register. So in order to save code space and time spent within the interrupt handler, the FSR_CONTEXT_SAVE DECLARE can enable or disable the auto CONTEXT saving and resoring of the FSR register.

For 16-bit core devices, this will enable/disable FSR0 context handling. And FSR2L/H registers will be saved/restored if a stack is implemented.

See also :	ON_LOW_INTERRUPT, ON INTERRUPT (i.e. SOFTWARE INTERRUPTS in BASIC).


ON_LOW_INTERRUPT

Syntax

ON_LOW_INTERRUPT Label

Availability

16-bit core devices.

Overview

Jump to a subroutine when a LOW PRIORITY HARDWARE interrupt occurs on a 16-bit core device.

Operators

Label is a valid identifier

Example

' This program uses TIMER1 and TIMER3 to demonstrate the use of interrupt priority.

' TIMER1 is configured for high-priority interrupts and TIMER3 is configured for low-priority interrupts.

' By writing to the PORTD LEDS, it is shown that a high-priority interrupts override low-priority interrupts.

' Connect three LEDs to PORTD pins 0,1, and 7

' LEDs 0, 7 flash in the background using interrupts, while the LED connected to PORTD.1

' Flashes slowly in the foreground

' Note the use of assembler commands without the ASM-ENDASM directives

DEVICE = 18F452

XTAL = 4

SYMBOL TIMER1 = TMR1L.WORD	' Create a WORD variable from two hardware registers

SYMBOL TIMER3 = TMR3L.WORD	' Create a WORD variable from two hardware registers

SYMBOL IPEN = RCON.7

SYMBOL TMR1IP = IPR1.0

SYMBOL TMR3IP = IPR2.1

SYMBOL TMR1IF = PIR1.0

SYMBOL TMR3IF = PIR2.1

SYMBOL TMR1IE = PIE1.0

SYMBOL TMR3IE = PIE2.1

SYMBOL GIEH = INTCON.7

SYMBOL GIEL = INTCON.6

SYMBOL TMR1ON = T1CON.0

SYMBOL TMR3ON = T3CON.0

' Declare interrupt Vectors

ON_INTERRUPT GOTO TMR1_ISR	' Point to the HIGH priority interrupt subroutine

ON_LOW_INTERRUPT GOTO TMR3_ISR	' Point to the LOW priority interrupt subroutine

GOTO OVER_INTERRUPTS	' Jump over the interrupt subroutines

'---------------------------------------------------------------------------

' HIGH PRIORITY INTERRUPT

TMR1_ISR:

CLEAR TMR1IF	' Clear the Timer1 interrupt flag.

CLEAR PORTD.0	' Turn off PORTD.0 to indicate high priority interrupt has overridden low priority.

SET PORTD.7	' Turn on PORTD.7 to indicate high priority interrupt is occurring.

BTFSS TMR1IF	' Poll TMR11 interrupt flag to wait for another TMR1 overflow.

BRA $ - 2

CLEAR TMR1IF	' Clear the Timer1 interrupt flag again.

CLEAR PORTD.7	' Turn off PORTD.7 to indicate the high-priority ISR is over.

RETFIE FAST

'---------------------------------------------------------------------------

' LOW PRIORITY INTERRUPT

TMR3_ISR:

CLEAR TMR3IF	' Clear the TMR3 interrupt flag.

TIMER3 = $F000	' Load TMR3 with the value $F000

SET PORTD.0	' Turn on PORTD.0 to indicate low priority interrupt is occurring.

BTFSS TMR3IF	' Poll TMR3 interrupt flag to wait for another TMR3 overflow.

BRA $ - 2

TIMER3 = $F000	' Load TMR3 with the value $F000 again.

CLEAR TMR3IF	' Clear the Timer3 interrupt flag again.

CLEAR PORTD.0	' Turn off PORTD.0. to indicate the low-priority ISR is over.

RETFIE

'---------------------------------------------------------------------------

' MAIN PROGRAM STARTS HERE

OVER_INTERRUPTS:

LOW	PORTD	' Setup PORTD for outputs

'Set up priority interrupts.

IPEN = 1	' Enable priority interrupts.

TMR1IP = 1	' Set Timer1 as a high priority interrupt source

TMR3IP = 0	' Set Timer3 as a low priority interrupt source

TMR1IF = 0	' Clear the Timer1 interrupt flag

TMR3IF = 0	' Clear the Timer3 interrupt flag

TMR1IE = 1	' Enable Timer1 interrupts

TMR3IE = 1	' Enable Timer3 interrupts

GIEH = 1	' Set the global interrupt enable bits

GIEL = 1

'TIMER1 setup

T1CON = 0

TIMER1 = 0	' Clear TIMER 1

TMR1ON = 1	' Turn on Timer1

'TIMER3 setup

T3CON = 0

TIMER3 = $F000	' Write $F000 to Timer3

TMR3ON = 1	' Turn on Timer3

' Flash the LED on PORTB.1

WHILE 1 = 1

HIGH PORTD.1

DELAYMS 300

LOW PORTD.1

DELAYMS 300

WEND

See also :	ON_INTERRUPT,  SOFTWARE INTERRUPTS in BASIC).


ON GOTO

Syntax

ON Index Variable GOTO Label1 {,...Labeln }

Availability

All devices.

Overview

Cause the program to jump to different locations based on a variable index. On a PICmicro device with only one page of memory. Exactly the same funtionality as BRANCH.

Operators

Index Variable is a constant, variable, or expression, that specifies the label to jump to.

Label1...Labeln are valid labels that specify where to branch to.

Example

DEVICE = 16F84

DIM INDEX as BYTE

CLS	' Clear the LCD

INDEX = 2 	' Assign INDEX a value of 2

START:

ON INDEX GOTO LABEL_0, LABEL_1, LABEL_2	' Jump to label 2 (LABEL_2) because INDEX = 2

LABEL_0:

INDEX = 2 	' INDEX now equals 2

PRINT AT 1,1,"LABEL 0" 	' Display the LABEL name on the LCD

DELAYMS 500	' Wait 500ms

GOTO START	' Jump back to START

LABEL_1:

INDEX = 0 	' INDEX now equals 0

PRINT AT 1,1,"LABEL 1" 	' Display the LABEL name on the LCD

DELAYMS 500	' Wait 500ms

GOTO START	' Jump back to START

LABEL_2:

INDEX = 1 	' INDEX now equals 1

PRINT AT 1,1,"LABEL 2" 	' Display the LABEL name on the LCD

DELAYMS 500	' Wait 500ms

GOTO START	' Jump back to START

The above example we first assign the index variable a value of 2, then we define our labels. Since the first position is considered 0 and the variable INDEX equals 2 the ON GOTO command will cause the program to jump to the third label in the list, which is LABEL_2.

Notes

ON GOTO is useful when you want to organise a structure such as: -

IF VAR1 = 0 THEN GOTO LABEL_0 	' VAR1 = 0: go to label "LABEL_0"

IF VAR1 = 1 THEN GOTO LABEL_1 	' VAR1 = 1: go to label "LABEL_1"

IF VAR1 = 2 THEN GOTO LABEL_2 	' VAR1 = 2: go to label "LABEL_2"

You can use ON GOTO to organise this into a single statement: -

ON VAR1 GOTO LABEL_0 , LABEL_1, LABEL_2

This works exactly the same as the above IF...THEN example. If the value is not in range (in this case if VAR1 is greater than 2), ON GOTO does nothing. The program continues with the next instruction..

The ON GOTO command is primarily for use with PICmicro devices that have one page of memory (0-2047). If larger PICmicros are used and you suspect that the branch label will be over a page boundary, use the ON GOTOL command instead.

See also : BRANCH, BRANCHL, ON GOTOL, ON GOSUB.


ON GOTOL

Syntax

ON Index Variable GOTOL Label1 {,...Labeln }

Availability

All devices.

Overview

Cause the program to jump to different locations based on a variable index. On a PICmicro device with more than one page of memory, or 16-bit core devices. Exactly the same funtionality as BRANCHL.

Operators

Index Variable is a constant, variable, or expression, that specifies the label to jump to.

Label1...Labeln are valid labels that specify where to branch to.

Example

DEVICE = 16F877	' Use a larger PICmicro device

DIM INDEX as BYTE

CLS	' Clear the LCD

INDEX = 2 	' Assign INDEX a value of 2

START:

ON INDEX GOTOL LABEL_0, LABEL_1, LABEL_2	' Jump to label 2 (LABEL_2) because INDEX = 2

LABEL_0:

INDEX = 2 	' INDEX now equals 2

PRINT AT 1,1,"LABEL 0" 	' Display the LABEL name on the LCD

DELAYMS 500	' Wait 500ms

GOTO START	' Jump back to START

LABEL_1:

INDEX = 0 	' INDEX now equals 0

PRINT AT 1,1,"LABEL 1" 	' Display the LABEL name on the LCD

DELAYMS 500	' Wait 500ms

GOTO START	' Jump back to START

LABEL_2:

INDEX = 1 	' INDEX now equals 1

PRINT AT 1,1,"LABEL 2" 	' Display the LABEL name on the LCD

DELAYMS 500	' Wait 500ms

GOTO START	' Jump back to START

The above example we first assign the index variable a value of 2, then we define our labels. Since the first position is considered 0 and the variable INDEX equals 2 the ON GOTOL command will cause the program to jump to the third label in the list, which is LABEL_2.

Notes

The ON GOTOL command is mainly for use with PICmicro devices that have more than one page of memory (greater than 2048). It may also be used on any PICmicro device, but does produce code that is larger than ON GOTO.

See also : BRANCH, BRANCHL, ON GOTO, ON GOSUB.


ON GOSUB

Syntax

ON Index Variable GOSUB Label1 {,...Labeln }

Availability

16-bit core devices.

Overview

Cause the program to Call a subroutine based on an index value. A subsequent RETURN will continue the program immediately after the ON GOSUB command.

Operators

Index Variable is a constant, variable, or expression, that specifies the label to call.

Label1...Labeln are valid labels that specify where to call.

Example

DEVICE = 18F452	' Use a 16-bit core PICmicro

DIM INDEX as BYTE

CLS	' Clear the LCD

WHILE 1 = 1	' Create an infinite loop

  FOR INDEX = 0 TO 2	' Create a loop to call all the labels

    ON INDEX GOSUB LABEL_0, LABEL_1, LABEL_2	' Call the label depending on the value of INDEX

 	    DELAYMS 500	' Wait 500ms after the subroutine has returned

  NEXT

WEND	' Do it forever

LABEL_0:

PRINT AT 1,1,"LABEL 0" 	' Display the LABEL name on the LCD

RETURN

LABEL_1:

PRINT AT 1,1,"LABEL 1" 	' Display the LABEL name on the LCD

RETURN

LABEL_2:

PRINT AT 1,1,"LABEL 2" 	' Display the LABEL name on the LCD

RETURN

The above example, a loop is formed that will load the variable INDEX with values 0 to 2. The ON GOSUB command will then use that value to call each subroutine in turn. Each subroutine will RETURN to the DELAYMS command, ready for the next scan of the loop.

Notes

ON GOSUB is useful when you want to organise a structure such as: -

IF VAR1 = 0 THEN GOSUB LABEL_0 	' VAR1 = 0: call label "LABEL_0"

IF VAR1 = 1 THEN GOSUB LABEL_1 	' VAR1 = 1: call label "LABEL_1"

IF VAR1 = 2 THEN GOSUB LABEL_2 	' VAR1 = 2: call label "LABEL_2"

You can use ON GOSUB to organise this into a single statement: -

ON VAR1 GOSUB LABEL_0 , LABEL_1, LABEL_2

This works exactly the same as the above IF...THEN example. If the value is not in range (in this case if VAR1 is greater than 2), ON GOSUB does nothing. The program continues with the next instruction..

ON GOSUB is only supported with 16-bit core devices because they are the only PICmicro devices that allow code access to their return stack, which is required for the computed RETURN address.

See also : BRANCH, BRANCHL, ON GOTO, ON GOTOL.


OUTPUT

Syntax

OUTPUT Port  or Port . Pin

Availability

All devices.

Overview

Makes the specified Port  or Port.Pin an output.

Operators

Port.Pin must be a Port.Pin constant declaration.

Example

OUTPUT PORTA.0	' Make bit-0 of PORTA an output

 	OUTPUT PORTA	' Make all of PORTA an output

Notes

An Alternative method for making a particular pin an output is by directly modifying the TRIS: -

TRISB.0 = 0	' Set PORTB, bit-0 to an output

All of the pins on a port may be set to output by setting the whole TRIS register at once: -

TRISB = %00000000	' Set all of PORTB to outputs

In the above examples, setting a TRIS bit to 0 makes the pin an output, and conversely, setting the bit to 1 makes the pin an input.

See also :	INPUT.


ORG

Syntax

ORG Value

Availability

All devices.

Overview

Set the program origin for subsequent code at the address defined in Value

Operators

Value can be any constant value within the range of the particular PICmicro's memory.

Example

DEVICE 16F877

ORG 2000	' Set the origin to address 2000

CDATA 120 , 243 , "Hello"	' Place data starting at address 2000

or

SYMBOL Address = 2000

ORG Address + 1	' Set the origin to address 2001

CDATA 120 , 243 , "Hello"	' Place data starting at address 2001

Notes

If more complex values are required after the ORG directive, such as assembler variables etc. Use : -

@ ORG { assembler variables etc }

See CDATA for an alternative method for locating the address of a CDATA table.


OREAD

Syntax

OREAD Pin , Mode , [ Inputdata ]

Availability

14-bit and 16-bit core devices.

Overview

Receive data from a device using the Dallas Semiconductor 1-wire protocol.

The 1-wire protocol is a form of asynchronous serial communication developed by Dallas Semiconductor. It requires only one I/O pin which may be shared between multiple 1-wire devices.

Operators

Pin is a PORT-BIT combination that specifies which I/O pin to use. 1-wire devices require only one I/O pin (normally called DQ) to communicate. This I/O pin will be toggled between output and input mode during the OREAD command and will be set to input mode by the end of the OREAD command.

Mode is a numeric constant (0 - 7) indicating the mode of data transfer. The Mode argument control's the placement of reset pulses and detection of presence pulses, as well as byte or bit input. See notes below.

Inputdata is a list of variables or arrays to store the incoming data into.

The STR modifier may also be used to store the incoming data into an array.

Example

DIM Result AS BYTE

SYMBOL DQ = PORTA.0

OREAD DQ, 1 , [ Result ]

The above example code will transmit a 'reset' pulse to a 1-wire device (connected to bit 0 of PORTA) and will then detect the device's 'presence' pulse and receive one byte and store it in the variable Result.

Notes

The Mode operator is used to control placement of reset pulses (and detection of presence pulses) and to designate byte or bit input. The table below shows the meaning of each of the 8 possible value combinations for Mode.

Mode Value	Effect
0	No Reset, Byte mode
1	Reset before data, Byte mode
2	Reset after data, Byte mode
3	Reset before and after data, Byte mode
4	No Reset, Bit mode
5	Reset before data, Bit mode
6	Reset after data, Bit mode
7	Reset before and after data, Bit mode

The correct value for Mode depends on the 1-wire device and the portion of the communication that is being dealt with. Consult the data sheet for the device in question to determine the correct value for Mode. In many cases, however, when using the OREAD command, Mode should be set for either No Reset (to receive data from a transaction already started by an OWRITE command) or a Reset after data (to terminate the session after data is received). However, this may vary due to device and application requirements.

When using the Bit (rather than Byte) mode of data transfer, all variables in the InputData argument will only receive one bit. For example, the following code could be used to receive two bits using this mode: -

DIM BITVAR1 AS BIT

DIM BITVAR2 AS BIT

OREAD PORTA.0 , 6 , [ BITVAR1, BITVAR2 ]

In the example code shown, a value of 6 was chosen for Mode. This sets Bit transfer and Reset after data mode.

We could also have chosen to make the BITVAR1 and BITVAR2 variables each a BYTE type, however, they would still only have received one bit each in the OREAD command, due to the Mode that was chosen.

The compiler also has a modifier for handling a string of data, named STR.

The STR modifier is used for receiving data and placing it directly into a byte array variable.

A string is a set of bytes that are arranged or accessed in a certain order. The values 1 , 2 , 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1 2 3 would be stored in a byte array containing three bytes (elements).

Below is an example that receives ten bytes through a 1-wire interface and stores them in the 10-byte array, MYARRAY: -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

OREAD DQ, 1 , [STR MYARRAY]

PRINT DEC STR MYARRAY	' Display the values.

If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. For example: -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

OREAD DQ, 1 , [ STR MYARRAY \5 ] 	' Fill the first 5-bytes of the array with  received data.

PRINT STR MYARRAY \5 	' Display the 5-value string.

The example above illustrates how to fill only the first n bytes of an array, and then how to display only the first n bytes of the array. n refers to the value placed after the backslash.

DALLAS 1-WIRE PROTOCOL.

The 1-wire protocol has a well defined standard for transaction sequences. Every transaction sequence consists of four parts: -

Initialisation.

ROM Function Command.

Memory Function Command.

Transaction / Data.

Additionally, the ROM Function Command and Memory Function Command are always 8 bits wide and are sent least-significant-bit first (LSB).

The Initialisation consists of a reset pulse (generated by the master) that is followed by a presence pulse (generated by all slave devices).

The reset pulse is controlled by the lowest two bits of the Mode argument in the OREAD command. It can be made to appear before the ROM Function Command (Mode = 1), after the Transaction / Data portion (Mode = 2), before and after the entire transaction (Mode = 3) or not at all (Mode = 0).

1-wire ROM Function Commands.

Following the Initialisation, comes the ROM Function Command. The ROM Function Command is used to address the desired 1-wire device. The above table shows a few common ROM Function Commands. If only a single 1 wire device is connected, the Match ROM command can be used to address it. If more than one 1-wire device is attached, the PICmicro will ultimately have to address them individually using the Match ROM command.

The third part, the Memory Function Command, allows the PICmicro to address specific memory locations, or features, of the 1-wire device. Refer to the 1-wire device's data sheet for a list of the available Memory Function Commands.

Finally, the Transaction / Data section is used to read or write data to the 1-wire device. The OREAD command  will read data at this point in the transaction. A read is accomplished by generating a brief low-pulse and sampling the line within 15us of the falling edge of the pulse. This is called a 'Read Slot'.

The program below demonstrates interfacing to a Dallas Semiconductor DS1820 1-wire Digital Thermometer device using the compiler's 1-wire commands. The code reads the Counts Remaining and Counts per Degree Centigrade registers within the DS1820 device in order to provide a more accurate temperature (down to 1/10th of a degree).

DEVICE 16F84

DECLARE XTAL 4

SYMBOL DQ = PORTA.1 	' Place the DS1820 on bit-1 of PORTA

DIM Temp AS WORD 	' Holds the temperature value

DIM C AS BYTE 	' Holds the counts remaining value

DIM CPerD AS BYTE 	' Holds the Counts per degree C value

CLS 	' Clear the LCD before we start

Again:

OWRITE DQ, 1, [$CC, $44] 	' Send Calculate Temperature command

REPEAT

DELAYMS 25 	' Wait until conversion is complete

OREAD DQ, 4, [C] 	' Keep reading low pulses until

UNTIL C <> 0 	' the DS1820 is finished.

OWRITE DQ, 1, [$CC, $BE] 	' Send Read ScratchPad command

OREAD DQ, 2,[Temp.LOWBYTE,Temp.HIGHBYTE, C, C, C, C, C, CPerD]

' Calculate the temperature in degrees Centigrade

Temp = (((Temp >> 1) * 100) - 25) + (((CPerD - C) * 100) / CPerD)

PRINT AT 1,1, DEC Temp / 100, ".", DEC2 Temp," ", AT 1,8,"C"

GOTO Again

NOTE: The equation used in the program above will not work correctly with negative temperatures. Also note that the 4.7kΩ pull-up resistor (R1) is required for correct operation.

Inline OREAD Command.

The standard structure of the OREAD command is: -

OREAD Pin , Mode , [ Inputdata ]

However, this did not allow it to be used in conditions such as IF-THEN, WHILE-WEND etc. Therefore, there is now an additional structure to the OREAD command: -

VAR1 = OREAD Pin , Mode

Operands Pin and Mode have not changed their function, but the result from the 1-wire read is now placed directly into the assignment variable.

OREAD - OWRITE Presence Detection.

Another important addition to both the OREAD and OWRITE commands is the ability to jump to a section of the program if a presence is not detected on the 1-wire bus.

The new structure is: -

OWRITE Pin , Mode , Label , [ Outputdata ]

OREAD Pin , Mode , Label , [ Inputdata ]

VAR1 = OREAD Pin , Mode, Label

The LABEL operand is an optional condition, but if used, it must reference a valid BASIC label.

' Skip ROM search & do temp conversion

OWRITE DQ, 1, NO_PRES, [$CC, $44]

WHILE OREAD DQ, 4, NO_PRES != 0 : WEND 	' Read busy-bit,' Still busy..?

' Skip ROM search & read scratchpad memory

OWRITE DQ, 1, NO_PRES, [$CC, $BE]

OREAD DQ, 2, NO_PRES, [Temp.Lowbyte, Temp.Highbyte] ' Read two bytes

RETURN

NO_PRES:

PRINT "No Presence"

STOP

See also : OWRITE


OWRITE

Syntax

OWRITE Pin , Mode , [ Outputdata ]

Availability

14-bit and 16-bit core devices.

Overview

Send data to a device using the Dallas Semiconductor 1-wire protocol.

The 1-wire protocol is a form of asynchronous serial communication developed by Dallas Semiconductor. It requires only one I/O pin which may be shared between multiple 1-wire devices.

Operators

Pin is a PORT-BIT combination that specifies which I/O pin to use. 1-wire devices require only one I/O pin (normally called DQ) to communicate. This I/O pin will be toggled between output and input mode during the OWRITE command and will be set to input mode by the end of the OWRITE command.

Mode is a numeric constant (0 - 7) indicating the mode of data transfer. The Mode operator control's the placement of reset pulses and detection of presence pulses, as well as byte or bit input. See notes below.

Outputdata is a list of variables or arrays transmit individual or repeating bytes. The STR modifier may also be used to transmit strings of bytes from variable arrays.

Example

 SYMBOL DQ = PORTA.0

OWRITE DQ, 1 , [ $4E ]

The above example will transmit a 'reset' pulse to a 1-wire device (connected to bit 0 of PORTA) and will then detect the device's 'presence' pulse and transmit one byte (the value $4E).

Notes

The Mode operator is used to control placement of reset pulses (and detection of presence pulses) and to designate byte or bit input. The table below shows the meaning of each of the 8 possible value combinations for Mode.

The correct value for Mode depends on the 1-wire device and the portion of the communication you're dealing with. Consult the data sheet for the device in question to determine the correct value for Mode. In many cases, however, when using the OWRITE command, Mode should be set for a Reset before data (to initialise the transaction). However, this may vary due to device and application requirements.

When using the Bit (rather than Byte) mode of data transfer, all variables in the InputData argument will only receive one bit. For example, the following code could be used to receive two bits using this mode: -

DIM BITVAR1 AS BIT

DIM BITVAR2 AS BIT

OWRITE PORTA.0 , 6 , [ BITVAR1, BITVAR2 ]

In the example code shown, a value of 6 was chosen for Mode. This sets Bit transfer and Reset after data mode. We could also have chosen to make the BITVAR1 and BITVAR2 variables each a BYTE type, however, they would still only use their lowest bit (BIT0) as the value to transmit in the OWRITE command, due to the Mode value chosen.

The STR Modifier

The STR modifier is used for transmitting a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that sends four bytes (from a byte array) through bit-0 of PORTA: -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = $CC	' Load the first 4 bytes of the array

MYARRAY [1] = $44	' With the data to send

MYARRAY [2] = $CC

MYARRAY [3] = $4E

OWRITE PORTA.0 , 1 , [ STR MYARRAY \4 ] 	' Send 4-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the PICmicro would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 4 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE 	' Create a 10-byte array.

STR MYARRAY = $CC,$44,$CC,$4E	' Load the first 4 bytes of the array

OWRITE PORTA.0 , 1 , [ STR MYARRAY \4 ] 	' Send 4-byte string.

The above example, has exactly the same function as the previous one. The only difference is that the string is now constructed using the STR as a command instead of a modifier.

See also : OREAD for example code, and 1-wire protocol.


PEEK

Syntax

Variable = PEEK Address

Availability

All devices.

Overview

Retrieve the value of a register and place into a variable

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Address can be a constant or a variable, pointing to the address of a register.

Example 1

A = PEEK 15

Variable A will contain the value of Register 15. If the device is a 16F84, for example, this register is one of the 68 general-purpose registers (RAM).

Example 2

B = 15

A = PEEK B

Same function as example 1

Notes

Use of the PEEK command is not recommended. A more efficient way of retrieving the value from a register is by accessing the register directly: -

VARIABLE = REGISTER

See also : POKE


PIXEL

Syntax

Variable = PIXEL Ypos , Xpos

Availability

14-bit and 16-bit core devices.

Overview

Read the condition of an individual pixel on a 64x128 element graphic LCD. The returned value will be 1 if the pixel is set, and 0 if the pixel is clear.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Xpos can be a constant, variable, or expression, pointing to the X-axis location of the pixel to examine. This must be a value of 0 to 127. Where 0 is the far left row of pixels.

Ypos can be a constant, variable, or expression, pointing to the Y-axis location of the pixel to examine. This must be a value of 0 to 63. Where 0 is the top column of pixels.

Example

DEVICE 16F877

LCD_TYPE = GRAPHIC 	' Use a Graphic LCD

INTERNAL_FONT = OFF	' Use an external chr set

FONT_ADDR = 0	' Eeprom's address is 0

 	' Graphic LCD Pin Assignments

LCD_DTPORT = PORTD

LCD_RSPIN = PORTC.2

LCD_RWPIN = PORTE.0

LCD_ENPIN = PORTC.5

LCD_CS1PIN = PORTE.1

LCD_CS2PIN = PORTE.2

 	' Character set eeprom Pin Assignments

SDA_PIN = PORTC.4

SCL_PIN = PORTC.3

DIM Xpos as BYTE

DIM Ypos as BYTE

DIM Result as BYTE

CLS

PRINT AT 0 , 0 , "TESTING 1-2-3"

' Read the top row and display the result

FOR Xpos = 0 TO 127

Result = PIXEL 0 , Xpos	' Read the top row

PRINT AT 1 , 0 , @Result

DELAYMS 400

NEXT

STOP

See also : LCDREAD, LCDWRITE, PLOT, UNPLOT. See PRINT for circuit.


PLOT

Syntax

PLOT Ypos , Xpos

Availability

14-bit and 16-bit core devices.

Overview

Set an individual pixel on a 64x128 element graphic LCD.

Operators

Xpos can be a constant, variable, or expression, pointing to the X-axis location of the pixel to set. This must be a value of 0 to 127. Where 0 is the far left row of pixels.

Ypos can be a constant, variable, or expression, pointing to the Y-axis location of the pixel to set. This must be a value of 0 to 63. Where 0 is the top column of pixels.

Example

DEVICE 16F877

LCD_TYPE = GRAPHIC 	' Use a Graphic LCD

' Graphic LCD Pin Assignments

LCD_DTPORT = PORTD

LCD_RSPIN = PORTC.2

LCD_RWPIN = PORTE.0

LCD_ENPIN = PORTC.5

LCD_CS1PIN = PORTE.1

LCD_CS2PIN = PORTE.2

DIM Xpos as BYTE

ADCON1 = 7	' Set PORTA and PORTE to all digital

' Draw a line across the LCD

Again:

FOR Xpos = 0 TO 127

PLOT 20 , Xpos

DELAYMS 10

NEXT

' Now erase the line

FOR Xpos = 0 TO 127

UNPLOT 20 , Xpos

DELAYMS 10

NEXT

GOTO Again

 See also : LCDREAD, LCDWRITE, PIXEL, UNPLOT. See PRINT for circuit.


POKE

Syntax

POKE Address , Variable

Availability

All devices.

Overview

Assign a value to a register.

Operators

Address can be a constant or a variable, pointing to the address of a register.

Variable can be a constant or a variable.

Example

A = 15

POKE 12 , A	' Register 12 will be assigned the value 15.

POKE A , 0	' Register 15 will be assigned the value 0

Notes

Use of the POKE command is not recommended. A more efficient way of assigning a value to a register is by accessing the register directly: -

REGISTER = VALUE

See also : PEEK


POT

Syntax

Variable = POT Pin , Scale

Availability

All devices.

Overview

Read a potentiometer, thermistor, photocell, or other variable resistance.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT. .

Pin is a Port.Pin constant that specifies the I/O pin to use.

Scale is a constant, variable, or expression, used to scale the instruction's internal 16-bit result. The 16- bit reading is multiplied by (scale/ 256), so a scale value of 128 would reduce the range by approximately 50%, a scale of 64 would reduce to 25%, and so on.

Example

DIM VAR1 as BYTE

Loop:

VAR1 = POT PORTB.0 , 100 	' Read potentiometer on pin 0 of PORTB.

PRINT @VAR1 , " " 	' Display the potentiometer reading

GOTO Loop 	' Repeat the process.

Notes

Internally, the POT instruction calculates a 16-bit value, which is scaled down to an 8-bit value. The amount by which the internal value must be scaled varies with the size of the resistor being used.

1

The pin specified by POT must be connected to one side of a resistor, whose other side is connected through a capacitor to ground. A resistance measurement is taken by timing how long it takes to discharge the capacitor through the resistor.

The value of scale must be determined by experimentation, however, this is easily accomplished as follows: -

Set the device under measure, the pot in this instance, to maximum resistance and read it with scale set to 255. The value returned in VAR1 can now be used as scale: -

VAR1 = POT PORTB.0 , 255

See also : ADIN, RCIN


PRINT

Syntax

PRINT Item { , Item... }

Availability

All devices.

Overview

Send Text to an LCD module using the Hitachi 44780 controller or a graphic LCD based on the Samsung S6B0108 chipset.

Operators

Item may be a constant, variable, expression, modifier, or string list.

There are no operators as such, instead there are modifiers. For example, if an at sign'@' precedes an Item, the ASCII representation for each digit is sent to the LCD.

The modifiers are listed below: -

Modifier	Operation

AT ypos (1 to n),xpos(1 to n) 	Position the cursor on the LCD

CLS 	Clear the LCD (also creates a 30ms delay)

BIN{1..32} 	Display binary digits

DEC{1..10} 	Display decimal digits

HEX{1..8} 	Display hexadecimal digits

SBIN{1..32} 	Display signed binary digits

SDEC{1..10} 	Display signed decimal digits

SHEX{1..8} 	Display signed hexadecimal digits

IBIN{1..32} 	Display binary digits with a preceding '%' identifier

IDEC{1..10} 	Display decimal digits with a preceding '#' identifier

IHEX{1..8} 	Display hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Display signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Display signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Display signed hexadecimal digits with a preceding '$' identifier

REP c\n 	Display character c repeated n times

 	STR array\n	Display all or part of an array

CSTR cdata	Display string data defined in a CDATA statement.

The numbers after the BIN, DEC, and HEX modifiers are optional. If they are omitted, then the default is all the digits that make up the value will be displayed.

If a floating point variable is to be displayed, then the digits after the DEC modifier determine how many remainder digits are printed.i.e. numbers after the decimal point.

DIM FLT AS FLOAT

FLT = 3.145

PRINT DEC2 FLT	' Display 2 values after the decimal point

The above program will display 3.14

If the digit after the DEC modifier is omitted, then 3 values will be displayed after the decimal point.

DIM FLT AS FLOAT

FLT = 3.1456

PRINT DEC FLT	' Display 3 values after the decimal point

The above program will display 3.145

There is no need to use the SDEC modifier for signed floating point values, as the compiler's DEC modifier will automatically display a minus result: -

DIM FLT AS FLOAT

FLT = -3.1456

PRINT DEC FLT	' Display 3 values after the decimal point

The above program will display -3.145

HEX or BIN modifiers cannot be used with floating point values or variables.

The Xpos and Ypos values in the AT modifier both start at 1. For example, to place the text "HELLO WORLD" on line 1, position 1, the code would be: -

PRINT AT 1 , 1 , "HELLO WORLD"

Example 1

DIM VAR1 AS BYTE

DIM WRD AS WORD

DIM DWD AS DWORD

 	PRINT "Hello World"	' Display the text "Hello World"

 	PRINT "VAR1= " , DEC VAR1	' Display the decimal value of VAR1

 	PRINT "VAR1= " , HEX VAR1	' Display the hexadecimal value of VAR1

 	PRINT "VAR1= " , BIN VAR1	' Display the binary value of VAR1

 	PRINT "VAR1= " , @VAR1	' Display the decimal value of VAR1

PRINT "DWD= " , HEX6 DWD ' Display 6 hex characters of a DWORD type variable

Example 2

' Display a negative value on the LCD.

SYMBOL NEGATIVE = -200

PRINT AT 1 , 1 , SDEC NEGATIVE

Example 3

' Display a negative value on the LCD with a preceding identifier.

PRINT AT 1 , 1 , ISHEX -$1234

Example 3 will produce the text "$-1234" on the LCD.

Some PICmicros such as the 16F87x, and 18FXXX range have the ability to read and write to their own flash memory. And although writing to this memory too many times is unhealthy for the PICmicro, reading this memory is both fast, and harmless. Which offers a unique form of data storage and retrieval, the CDATA command proves this, as it uses the mechanism of reading and storing in the PICmicro's flash memory.

Combining the unique features of the 'self modifying PICmicro's ' with a string format, the compiler is capable of reducing the overhead of printing, or transmitting large amounts of text data. The CSTR modifier may be used in commands that deal with text processing i.e. SEROUT, HRSOUT, and RSOUT etc.

The CSTR modifier is used in conjunction with the CDATA command. The CDATA command is used for initially creating the string of characters: -

STRING1: CDATA "HELLO WORLD" , 0

The above line of case will create, in flash memory, the values that make up the ASCII text "HELLO WORLD", at address STRING1. Note the NULL terminator after the ASCII text.

NULL terminated means that a zero (NULL) is placed at the end of the string of ASCII characters to signal that the string has finished.

To display, or transmit this string of characters, the following command structure could be used:

PRINT CSTR STRING1

The label that declared the address where the list of CDATA values resided, now becomes the string's name. In a large program with lots of text formatting, this type of structure can save quite literally hundreds of bytes of valuable code space.

Try both these small programs, and you'll see that using CSTR saves a few bytes of code: -

First the standard way of displaying text: -

DEVICE 16F877

CLS

PRINT "HELLO WORLD"

PRINT "HOW ARE YOU?"

PRINT "I AM FINE!"

STOP

Now using the CSTR modifier: -

CLS

PRINT CSTR TEXT1

PRINT CSTR TEXT2

PRINT CSTR TEXT3

STOP

TEXT1: CDATA "HELLO WORLD" , 0

TEXT2: CDATA "HOW ARE YOU?" , 0

TEXT3: CDATA "I AM FINE!" , 0

Again, note the NULL terminators after the ASCII text in the CDATA commands. Without these, the PICmicro will continue to transmit data in an endless loop.

The term 'virtual string' relates to the fact that a string formed from the CDATA command cannot be written too, but only read from.

The STR modifier is used for sending a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that displays four bytes (from a byte array): -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = "H"	' Load the first 5 bytes of the array

MYARRAY [1] = "E"	' With the data to send

MYARRAY [2] = "L"

MYARRAY [3] = "L"

MYARRAY [4] = "O"

PRINT STR MYARRAY \5  	' Display a 5-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the PICmicro would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 5 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE 	' Create a 10-byte array.

STR MYARRAY = "HELLO"	' Load the first 5 bytes of the array

PRINT STR MYARRAY \5 	' Send 5-byte string.

The above example, has exactly the same function as the previous one. The only difference is that the string is now constructed using STR as a command instead of a modifier.

Declares

There are six DECLARES for use with an alphanumeric LCD and PRINT: -

DECLARE LCD_TYPE 1 or 0 , GRAPHIC or ALPHA

Inform the compiler as to the type of LCD that the PRINT command will output to. If GRAPHIC or 1 is chosen then any output by the PRINT command will be directed to a graphic LCD based on the Samsung S6B0108 chipset. A value of 0 or ALPHA, or if the DECLARE is not issued will target the standard alphanumeric LCD type

Targeting the graphic LCD will also enable commands such as PLOT, UNPLOT, LCDREAD, and LCDWRITE.

DECLARE LCD_DTPIN PORT . PIN

Assigns the Port and Pins that the LCD's DT (data) lines will attach to.

The LCD may be connected to the PICmicro using either a 4-bit bus or an 8-bit bus. If an 8-bit bus is used, all 8 bits must be on one port. If a 4-bit bus is used, it must be connected to either the bottom 4 or top 4 bits of one port. For example: -

DECLARE LCD_DTPIN PORTB.4	' Used for 4-line interface.

DECLARE LCD_DTPIN PORTB.0	' Used for 8-line interface.

In the examples above, PORTB is only a personal preference. The LCD's DT lines may be attached to any valid port on the PICmicro. If the DECLARE is not used in the program, then the default Port and Pin is PORTB.4, which assumes a 4-line interface.

DECLARE LCD_ENPIN PORT . PIN

Assigns the Port and Pin that the LCD's EN line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.2.

DECLARE LCD_RSPIN PORT . PIN

Assigns the Port and Pins that the LCD's RS line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.3.

DECLARE LCD_INTERFACE 4 or 8

Inform the compiler as to whether a 4-line or 8-line interface is required by the LCD.

If the DECLARE is not used in the program, then the default interface is a 4-line type.

DECLARE LCD_LINES 1 , 2 , or 4

Inform the compiler as to how many lines the LCD has.

LCD's come in a range of sizes, the most popular being the 2 line by 16 character types. However, there are 4-line types as well. Simply place the number of lines that the particular LCD has, into the declare.

If the DECLARE is not used in the program, then the default number of lines is 2.

Notes

If no modifier precedes an item in a PRINT command, then the characters value is sent to the LCD. This is useful for sending control codes to the LCD. For example: -

PRINT $FE , 128

Will move the cursor to line 1, position 1 (HOME).

Below is a list of useful control commands: -

Control Command 	Operation

$FE, 1 	Clear display

$FE, 2 	Return home (beginning of first line)

$FE, $0C 	Cursor off

$FE, $0E 	Underline cursor on

$FE, $0F 	Blinking cursor on

$FE, $10 	Move cursor left one position

$FE, $14 	Move cursor right one position

$FE, $C0 	Move cursor to beginning of second line

$FE, $94 	Move cursor to beginning of third line

$FE, $D4 	Move cursor to beginning of fourth line

Note that if the command for clearing the LCD is used, then a small delay should follow it: -

PRINT $FE , 1 : DELAYMS 30

The above diagram shows the default connections for an alphanumeric LCD module. In this instance, connected to the 16F84 PICmicro.

Using a Graphic LCD.

Once a graphic LCD has been chosen using the DECLARE LCD_TYPE directive, all PRINT outputs will be directed to that LCD.

The standard modifiers may also be used with the graphics LCD: -

AT ypos (0 to 7),xpos (0 to 20) 	Position the cursor on the LCD

CLS 	Clear the LCD

BIN{1..32} 	Display binary digits

DEC{1..10} 	Display decimal digits

HEX{1..8} 	Display hexadecimal digits

SBIN{1..32} 	Display signed binary digits

SDEC{1..10} 	Display signed decimal digits

SHEX{1..8} 	Display signed hexadecimal digits

IBIN{1..32} 	Display binary digits with a preceding '%' identifier

IDEC{1..10} 	Display decimal digits with a preceding '#' identifier

IHEX{1..8} 	Display hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Display signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Display signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Display signed hexadecimal digits with a preceding '$' identifier

REP c\n 	Display character c repeated n times

 	STR array\n	Display all or part of an array

CSTR cdata	Display string data defined in a CDATA statement.

Most of the above modifiers still work in the expected manner, however, the AT modifier now starts at Ypos 0 and Xpos 0, where values 0,0 will be the top left corner of the LCD.

There are also four new modifiers. These are: -

FONT 0 to n 	Choose the nth font, if available

INVERSE 0-1 	Invert the characters sent to the LCD

OR 0-1 	OR the new character with the original

XOR 0-1 	XOR the new character with the original

Once one of the four new modifiers has been enabled, all future PRINT commands will use that particular feature until the modifier is disabled. For example: -

' Enable inverted characters from this point

PRINT AT 0 , 0 , INVERSE 1 , "HELLO WORLD"

PRINT AT 1 , 0 , "STILL INVERTED"

' Now use normal characters

PRINT AT 2 , 0 , INVERSE 0 , "NORMAL CHARACTERS"

If no modifiers are present, then the character's ASCII representation will be displayed: -

' Print characters A and B

PRINT AT 0 , 0 , 65 , 66

Declares

There are six declares associated with a graphic LCD.

DECLARE LCD_DTPORT PORT

Assign the port that will output the 8-bit data to the graphic LCD.

If the DECLARE is not used, then the default port is PORTD.

DECLARE LCD_RWPIN PORT . PIN

Assigns the Port and Pin that the graphic LCD's RW line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PortE.0.

DECLARE LCD_CS1PIN PORT . PIN

Assigns the Port and Pin that the graphic LCD's CS1 line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTC.0.

DECLARE LCD_CS2PIN PORT . PIN

Assigns the Port and Pin that the graphic LCD's CS2 line will attach to.

If the DECLARE is not used in the program, then the default Port and Pin is PORTC.2.

Note

Along with the new declares, two of the existing LCD declares must also be used. Namely, RS_PIN and EN_PIN.

DECLARE INTERNAL_FONT ON - OFF, 1 or 0

The graphic LCDs that are compatible with PROTON+ are non-intelligent types, therefore, a separate character set is required. This may be in one of two places, either externally, in an I2C eeprom, or internally in a CDATA table.

If the DECLARE is omitted from the program, then an external font is the default setting.

If an external font is chosen, the I2C eeprom must be connected to the specified SDA and SCL pins (as dictated by DECLARE SDA and DECLARE SCL).

If an internal font is chosen, it must be on a PICmicro device that has self modifying code features, such as the 16F87X range.

The CDATA table that contains the font must have a label, named FONT: preceding it. For example: -

FONT:- { data for characters 0 to 64 }

CDATA $7E , $11 , $11 , $11 , $7E , $0' Chr 65 "A"

 	CDATA $7F , $49 , $49 , $49 , $36 , $0' Chr 66 "B"

 	{ rest of font table }

Notice the dash after the font's label, this disables any bank switching code that may otherwise disturb the location in memory of the CDATA table.

The font table may be anywhere in memory, however, it is best placed after the main program code.

The font is built up of an 8x6 cell, with only 5 of the 6 rows, and 7 of the 8 columns being used for alphanumeric characters. See the diagram in manual. However, if a graphic character is chosen (chr 0 to 31), the whole of the 8x6 cell is used. In this way, large fonts and graphics may be easily constructed.

A list of the graphic characters is shown at the end of the PRINT description in the manual.

The character set itself is 128 characters long (0 -127). Which means that all the ASCII characters are present, including $, %, &, # etc.

There are two programs on the compiler's CDROM, that are for use with internal and external fonts. INT_FONT.BAS, contains a CDATA table that may be cut and pasted into your own program if an internal font is chosen. EXT_FONT.BAS, writes the character set to a 24C32 I2C eeprom for use with an external font. Both programs are fully commented.

DECLARE FONT_ADDR 0 to 7

Set the slave address for the I2C eeprom that contains the font.

When an external source for the font is used, it may be on any one of 8 eeproms attached to the I2C bus. So as not to interfere with any other eeproms attached, the slave address of the eeprom carrying the font code may be chosen.

If the DECLARE is omitted from the program, then address 0 is the default slave address of the font eeprom.

DECLARE GLCD_CS_INVERT ON - OFF, 1 or 0

Some graphic LCD types have inverters on the CS lines. Which means that the LCD displays lefthand data on the right side, and vise-versa. The GLCD_CS_INVERT DECLARE, adjusts the library LCD handling subroutines to take this into account.

DECLARE GLCD_STROBE_DELAY 0 to 65535 microseconds (us).

If a noisy circuit layout is unavoidable when using a graphic LCD, then the above DECLARE may be used. This will create a delay between the ENABLE line being strobed. This can ease random data being produced on the LCD's screen. See below for more details on circuit layout for graphic LCDs.

If the DECLARE is not used in the program, then no delay is created between strobes, and the LCD is accessed at full efficiency.

Important

Because of the complexity involved with interfacing to the graphic LCD, six of the eight stack levels available on the 14-bit core devices, are used when the PRINT command is issued with an external font. Therefore, be aware that if PRINT is used within a subroutine, you must limit the amount of subroutine nesting that may take place.

If an internal font is implemented, then only four stack levels are used.

If the default setting of PORTE is used for the LCD's CS1, CS2, and RW pin connections, then these pins must be set to digital by issuing the following line of code near the beginning of the program: -

ADCON1 = 7	' Set PORTA and PORTE to all digital

or alternatively, you may use the directive: -

ALL_DIGITAL = TRUE

You will need to refer to the PICmicro's datasheet for ADCON1 settings if PORTA is to be used for analogue inputs.

The diagram shows the connections required for an external font. The eeprom has a slave address of 0.

If an internal font is used, then the eeprom may be omitted.

The below diagram lists the graphic characters available. For example, to display a single horizontal bar, the BASIC code would be: -

PRINT AT 0 , 0 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8

Any of the character set may be altered to suit your personal needs, however, characters 26 to 31 are left blank to be used for user defined characters.


PULSIN

Syntax

Variable = PULSIN Pin , State

Availability

All devices.

Overview

Change the specified pin to input and measure an input pulse.

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT.

Pin is a Port.Pin constant that specifies the I/O pin to use.

State is a constant (0 or 1) or name HIGH - LOW that specifies which edge must occur before beginning the measurement.

Example

DIM VAR1 as BYTE

Loop:

VAR1 = PULSIN PORTB.0 , 1 	' Measure a pulse on pin 0 of PORTB.

PRINT @VAR1 , " " 	' Display the reading

GOTO Loop 	' Repeat the process.

Notes

PULSIN acts as a fast clock that is triggered by a change in state (0 or 1) on the specified pin. When the state on the pin changes to the state specified, the clock starts counting. When the state on the pin changes again, the clock stops. If the state of the pin doesn't change (even if it is already in the state specified in the PULSIN instruction), the clock won't trigger. PULSIN waits a maximum of 0.65535 seconds for a trigger, then returns with 0 in variable.

The variable can be either a WORD or a BYTE . If the variable is a word, the value returned by PULSIN can range from 1 to 65535 units.

The units are dependant on the frequency of the crystal used. If a 4MHz crystal is used, then each unit is 10us, while a 20MHz crystal produces a unit length of 2us.

If the variable is a byte and the crystal is 4MHz, the value returned can range from 1 to 255 units of 10µs. Internally, PULSIN always uses a 16-bit timer. When your program specifies a byte, PULSIN stores the lower 8 bits of the internal counter into it. Pulse widths longer than 2550µs will give false, low readings with a byte variable. For example, a 2560µs pulse returns a reading of 256 with a word variable and 0 with a byte variable.

See also : COUNTER, PULSOUT


PULSOUT

Syntax

PULSOUT Pin , Period, { Initial State }

Availability

All devices.

Overview

Generate a pulse on Pin of specified Period. The pulse is generated by toggling the pin twice, thus the initial state of the pin determines the polarity of the pulse. Or alternatively, the initial state may be set by using HIGH-LOW or 1-0 after the Period. Pin is automatically made an output.

Operators

Pin is a Port.Pin constant that specifies the I/O pin to use.

Period can be a constant of user defined variable. See notes.

State is an optional constant (0 or 1) or name HIGH - LOW that specifies the state of the outgoing pulse.

Example

' Send a high pulse 1ms long (at 4MHz) to PORTB Pin5

LOW PORTB.5

PULSOUT PORTB.5 , 100

' Send a high pulse 1ms long (at 4MHz) to PORTB Pin5

PULSOUT PORTB.5 , 100 , HIGH

Notes

The resolution of PULSOUT is dependent upon the oscillator frequency. If a 4MHz oscillator is used, the Period of the generated pulse will be in 10us increments. If a 20MHz oscillator is used, Period will have a 2us resolution. Declaring an XTAL value has no effect on PULSOUT. The resolution always changes with the actual oscillator speed.

See also : COUNTER , PULSIN


PWM

Syntax

PWM Pin , Duty , Cycles

Availability

All devices.

Overview

Output pulse-width-modulation on a pin, then return the pin to input state.

Operators

Pin is a Port.Pin constant that specifies the I/O pin to use.

Duty is a variable, constant (0-255), or expression, which specifies the analogue level desired (0-5 volts).

Cycles is a variable or constant (0-255) which specifies the number of cycles to output. Larger capacitors require multiple cycles to fully charge. Cycle time is dependant on Xtal frequency. If a 4MHz crystal is used, then cycle takes approx 5 ms. If a 20MHz crystal is used, then cycle takes approx 1 ms.

Notes

PWM can be used to generate analogue voltages (0-5V) through a pin connected to a resistor and capacitor to ground; the resistor-capacitor junction is the analogue output (see circuit). Since the capacitor gradually discharges, PWM should be executed periodically to refresh the analogue voltage.

PWM emits a burst of 1s and 0s whose ratio is proportional to the duty value you specify. If duty is 0, then the pin is continuously low (0); if duty is 255, then the pin is continuously high. For values in between, the proportion is duty/255. For example, if duty is 100, the ratio of 1s to 0s is 100/255 = 0.392, approximately 39 percent.

When such a burst is used to charge a capacitor arranged, the voltage across the capacitor is equal to:-

(duty/ 255) * 5.

So if duty is 100, the capacitor voltage is

(100/255) * 5 = 1.96 volts.

This voltage will drop as the capacitor discharges through whatever load it is driving. The rate of discharge is proportional to the current drawn by the load; more current = faster discharge. You can reduce this effect in software by refreshing the capacitor's charge with frequent use of the PWM command. You can also buffer the output using an op-amp to greatly reduce the need for frequent PWM cycles.

See also : HPWM, PULSEOUT, SERVO.


RANDOM

Syntax

Variable = RANDOM

or

RANDOM Variable

Availability

All devices.

Overview

Generate a pseudo-randomisation on Variable. Variable should be a 16-bit variable.

Operators

Variable to store the result. The pseudo-random algorithm used has a working length of 1 to 65535 (only zero is not produced).

Example

VAR1 = RANDOM	' Get a random number into VAR1

RANDOM VAR1	' Get a random number into VAR1

See also: SEED.


RCIN

Syntax

Variable = RCIN Pin , State

Availability

All devices.

Overview

Count time while pin remains in state, usually used to measure the charge/ discharge time of resistor/capacitor (RC) circuit.

Operators

Pin is a Port.Pin constant that specifies the I/O pin to use. This pin will be placed into input mode and left in that state when the instruction finishes.

State is a variable or constant (1 or 0) that will end the Rcin period. Text, HIGH or LOW may also be used instead of 1 or 0.

Variable is a variable in which the time measurement will be stored.

Example

DIM Result as WORD 	' Word variable to hold result.

HIGH PORTB.0 	' Discharge the cap

DELAYMS 1 	' Wait for 1 ms.

Result = RCIN PORTB.0 , High 	' Measure RC charge time.

PRINT @Result , " " 	' Display the value on an LCD.

Notes

The resolution of RCIN is dependent upon the oscillator frequency. If a 4MHz oscillator is used, the time in state is returned in 10us increments. If a 20MHz oscillator is used, the time in state will have a 2us resolution. Declaring an XTAL value has no effect on RCIN. The resolution always changes with the actual oscillator speed. If the pin never changes state 0 is returned.

RCIN can be used to measure the charge or discharge time of a resistor/capacitor circuit. This allows measurement of resistance or capacitance, use R or C sensors such as thermistors or capacitive humidity sensors or respond to user input through a potentiometer. In a broader sense, RCIN can also serve as a fast, precise stopwatch for events of very short duration.

When RCIN executes, it starts a counter. The counter stops as soon as the specified pin is no longer in State (0 or 1). If pin is not in State when the instruction executes, RCIN will return 1 in Variable, since the instruction requires one timing cycle to discover this fact. If pin remains in State longer than 65535 timing cycles RCIN returns 0.

See also : ADIN, POT


READ

Syntax

READ Variable

Availability

14-bit and 16-bit core devices.

Overview

READ the next value from a DATA table and place into variable

Operators

Variable is a user defined variable of type BIT, BYTE, BYTE_ARRAY, WORD, WORD_ARRAY, DWORD, or FLOAT. .

Example 1

DIM VAR1 AS BYTE

DATA 5 , 8 , "fred" , 12

RESTORE

READ VAR1  	' VAR1 will now contain the value 5

READ VAR1  	' VAR1 will now contain the value 8

RESTORE 3 	' Pointer now placed at location 4 in our data table i.e. "r"

READ VAR1 	' VAR1 will now contain the value 114 i.e. the 'r' character in decimal

The data table is defined with the values 5,8,102,114,101,100,12 as "fred" equates to f:102,r:114,e:101,d:100 in decimal. The table pointer is immediately restored to the beginning of the table. This is not always required but as a general rule, it is a good idea to prevent table reading from overflowing.

The first READ VAR1 takes the first item of data from the table and increments the table pointer. The next READ VAR1 therefore takes the second item of data.

RESTORE 3 moves the table pointer to the fourth location in the table, in this case where the letter 'r' is. READ VAR1 now retrieves the decimal equivalent of 'r' which is 114.

Example 2

DEVICE 16F877

DIM CHAR AS BYTE

DIM LOOP AS BYTE

DATA "HELLO WORLD"	' Create a string of text in code memory

CLS

FOR LOOP = 0 TO 9	' Create a loop of 10

RESTORE LOOP	' Point to position within the DATA statement

READ CHAR	' Read data into CHAR

PRINT CHAR 	' Display the value read

NEXT

STOP

The program above reads and displays 10 values from the accompanying DATA statement. Resulting in "HELLO WORL" being displayed.

DATA is not simply used for character storage, it may also hold 8, 16, 32 bit, or floating point values. The example below illustrates this: -

DEVICE = 16F628

DIM VAR1 AS BYTE

DIM WRD1 AS WORD

DIM DWD1 AS DWORD

DIM FLT1 AS FLOAT

DATA 123 , 1234 , 123456 , 123.456

CLS

RESTORE	' Point to first location within DATA

READ VAR1 	' Read the 8-bit value

PRINT DEC VAR1,"  "

READ WRD1	' Read the 16-bit value

PRINT DEC WRD1

READ DWD1 	' Read the 32-bit value

PRINT AT 2,1, DEC DWD1,"  "

READ FLT1 	' Read the floating point value

PRINT DEC FLT1

STOP

Floating point examples.

14-bit core example

' 14-bit read floating point data from a table and display the results

DEVICE = 16F877

DIM FLT AS FLOAT	' Declare a FLOATING POINT variable

DATA 3.14 , 65535.123 , 1234.5678 , -1243.456 , -3.14 , 998999.12 , 0.005

CLS	' Clear the LCD

RESTORE	' Point to first location within DATA

REPEAT	' Create a loop

READ FLT 	' Read the data from the DATA table

PRINT AT 1 , 1 , DEC3 FLT	' Display the data read

DELAYMS 1000	' Slow things down

UNTIL FLT = 0.005	' Stop when 0.005 is read

STOP

16-bit core example

' 16-bit read floating point data from a table and display the results

DEVICE = 18F452

DIM FLT AS FLOAT	' Declare a FLOATING POINT variable

DATA 3.14 , 65535.123 , 1234.5678 , -1243.456 , -3.14 , 998999.12 , 0.005

CLS	' Clear the LCD

RESTORE	' Point to first location within DATA

REPEAT	' Create a loop

READ FLT 	' Read the data from the DATA table

PRINT AT 1 , 1 , DEC3 FLT	' Display the data read

DELAYMS 1000	' Slow things down

UNTIL FLT = 0.005	' Stop when 0.005 is read

STOP

Notes

If a FLOAT,  DWORD, or WORD size variable is used in the READ command, then a 32, or 16-bit (respectively) value is read from the data table. Consequently, if a BYTE size variable is used, then 8-bits are read. BIT sized variables also read 8-bits from the table, but any value greater than 0 is treated as a 1.

Attempts to read past the end of the table will result in errors and undetermined results.

READ has now been largely superceded by LREAD, LREAD8, LREAD16, LREAD32, and CREAD using LDATA or CDATA tables, therefore it is not recommended in new programs.

See also : CDATA, CREAD, CWRITE, DATA, LDATA, LREAD, LREAD8, LDEAD16, LREAD32, LOOKUP, RESTORE


REM

Syntax

REM Comments or ' Comments or ; Comments

Availability

All devices.

Overview

Insert reminders in your BASIC source code. These lines are not compiled and are used merely to provide information to the person viewing the source.

Operators

Comments can be any alphanumeric text.

Example

DIM A , B , C

A = 12 : B = 4

REM Now add them together

C = A + B

' Now subtract them

C = A - B' They are now subtracted

Notes

Semicolon ; single quote' and REM are the same.

Remarks in the assembler listing are turned off by default. To turn them on, use the following command near the top of your program: -

REMARKS ON

To turn off the remarks, use OFF instead of ON.


REPEAT...UNTIL

Syntax

REPEAT Condition

Instructions

Instructions

UNTIL Condition

or

REPEAT { Instructions : } UNTIL Condition

Availability

All devices.

Overview

Execute a block of instructions until a condition is true.

Example

VAR1 = 1

REPEAT

PRINT AT 1,1,DEC VAR1

DELAYMS 200

INC VAR1

UNTIL VAR1 > 10

or

REPEAT HIGH LED : UNTIL PORTA.0 = 1	' Wait for a Port change

Notes

The REPEAT-UNTIL loop differs from the WHILE-WEND type in that, the REPEAT loop will carry out the instructions within the loop at least once, then continuously until the condition is true, but the WHILE loop only carries out the instructions if the condition is true.

The REPEAT-UNTIL loop is an ideal replacement to a FOR-NEXT loop, and actually takes less code space, thus performing the loop faster.

Two commands have been added especially for a REPEAT loop, these are INC and DEC.

INC. Increment a variable i.e. VAR1 = VAR1 + 1

DEC. Decrement a variable i.e. VAR1 = VAR1 - 1

The above example shows the equivalent to the FOR-NEXT loop: -

FOR VAR1 = 1 TO 10 : NEXT

See also : BREAK, FOR...NEXT...STEP, RELATIONAL OPERATORS, WHILE...WEND.


RESTORE

Syntax

RESTORE Value

Availability

14-bit and 16-bit core devices.

Overview

Moves the pointer in a DATA table to the position specified by value

Operators

Value can be a constant, variable, or expression.

Example

DIM VAR1

DATA 5 , 8 , "fred" , 12

RESTORE

READ VAR1

' VAR1  will now contain the value 5

READ VAR1

' VAR1 will now contain the value 8

RESTORE 3

' Pointer now placed at location 4 in our data table i.e. "r"

READ VAR1

'VAR1  will now contain the value 114 i.e. the 'r' character in decimal

The data table is defined with the values 5,8,102,114,101,100,12 as "fred" equates to f:102,r:114,e:101,d:100 in decimal. The table pointer is immediately restored to the beginning of the table. This is not always required but as a general rule, it is a good idea to prevent table reading from overflowing.

The first READ VAR1 takes the first item of data from the table and increments the table pointer. The next READ VAR1  therefore takes the second item of data.

RESTORE 3 moves the table pointer to the fourth location (first location is pointer position 0) in the table - in this case where the letter 'r' is. READ VAR1 now retrieves the decimal equivalent of 'r' which is 114.

See also : CDATA, CREAD, CWRITE, DATA, LOOKUP, READ


RETURN

Syntax

RETURN

Availability

All devices.

Overview

Return from a subroutine.

Notes

RETURN resumes execution at the statement following the GOSUB which called the subroutine.

See also : CALL, GOSUB.


RSIN

Syntax

Variable = RSIN , { Timeout Label }

 or

RSIN { Timeout Label }, Modifier..Variable { , Modifier.. Variable...}

Availability

All devices.

Overview

Receive one or more bytes from a predetermined pin at a predetermined baud rate in standard asynchronous format using 8 data bits, no parity and 1 stop bit (8N1). The pin is automatically made an input.

Operators

Modifiers may be one of the serial data modifiers explained below.

Variable is a BIT, BYTE, WORD DWORD, or FLOAT variable, that will be loaded by RSIN.

An optional Timeout Label may be included to allow the program to continue if a character is not received within a certain amount of time. Timeout is specified in units of 1 millisecond and is specified by using a DECLARE directive.

Example

RSIN_TIMEOUT = 2000	' Timeout after 2 seconds

DIM VAR1 as BYTE

DIM WRD as WORD

VAR1 = RSIN , {Label}

RSIN VAR1 , WRD

RSIN { Label } , VAR1 , WRD

Label: { do something when timed out }

Declares

There are four DECLARES for use with RSIN. These are : -

DECLARE RSIN_PIN PORT . PIN

Assigns the Port and Pin that will be used to input serial data by the RSIN command. This may be any valid port on the PICmicro.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.1.

DECLARE RSIN_MODE INVERTED , TRUE or 1 , 0

Sets the serial mode for the data received by RSIN. This may be inverted or true. Alternatively, a value of 1 may be substituted to represent inverted, and 0 for true.

If the DECLARE is not used in the program, then the default mode is INVERTED.

DECLARE SERIAL_BAUD 0 to 65535 bps (baud)

Informs the RSIN and RSOUT routines as to what baud rate to receive and transmit data.

Virtually any baud rate may be transmitted and received, but there are standard bauds, namely: -

300, 600, 1200, 2400, 4800, 9600, and 19200.

When using a 4MHz crystal, the highest baud rate that is reliably achievable is 9600. However, an increase in the oscillator speed allows higher baud rates to be achieved, including 38400 baud.

If the DECLARE is not used in the program, then the default baud is 9600.

DECLARE RSIN_TIMEOUT 0 to 65535 milliseconds (ms)

Sets the time, in milliseconds, that RSIN will wait for a start bit to occur.

RSIN waits in a tight loop for the presence of a start bit. If no timeout value is used, then it will wait forever. The RSIN command has the option of jumping out of the loop if no start bit is detected within the time allocated by timeout.

If the DECLARE is not used in the program, then the default timeout value is 10000ms or 10 seconds.

RSIN MODIFIERS.

As we already know, RSIN will wait for and receive a single byte of data, and store it in a variable . If the PICmicro were connected to a PC running a terminal program and the user pressed the "A" key on the keyboard, after the RSIN command executed, the variable would contain 65, which is the ASCII code for the letter "A"

What would happen if the user pressed the "1" key? The result would be that the variable would contain the value 49 (the ASCII code for the character "1"). This is an important point to remember: every time you press a character on the keyboard, the computer receives the ASCII value of that character. It is up to the receiving side to interpret the values as necessary. In this case, perhaps we actually wanted the variable to end up with the value 1, rather than the ASCII code 49.

The RSIN command provides a modifier, called the decimal modifier, which will interpret this for us. Look at the following code: -

DIM SERDATA AS BYTE

RSIN DEC SERDATA

Notice the decimal modifier in the RSIN command that appears just to the left of the SERDATA variable. This tells RSIN to convert incoming text representing decimal numbers into true decimal form and store the result in SERDATA. If the user running the terminal software pressed the "1", "2" and then "3" keys followed by a space or other non-numeric text, the value 123 will be stored in the variable SERDATA, allowing the rest of the program to perform any numeric operation on the variable.

Without the decimal modifier, however, you would have been forced to receive each character ("1", "2" and "3") separately, and then would still have to do some manual conversion to arrive at the number 123 (one hundred twenty three) before you can do the desired calculations on it.

The decimal modifier is designed to seek out text that represents decimal numbers. The characters that represent decimal numbers are the characters "0" through "9". Once the RSIN command is asked to use the decimal modifier for a particular variable, it monitors the incoming serial data, looking for the first decimal character. Once it finds the first decimal character, it will continue looking for more (accumulating the entire multi-digit number) until is finds a non-decimal numeric character. Remember that it will not finish until it finds at least one decimal character followed by at least one non-decimal character.

To illustrate this further, examine the following examples (assuming we're using the same code example as above): -

Serial input:	"ABC"

Result: The program halts at the RSIN command, continuously waiting for decimal text.

Serial input:	"123" (with no characters following it)

Result: The program halts at the RSIN command. It recognises the characters "1", "2" and "3" as the number one hundred twenty three, but since no characters follow the "3", it waits continuously, since there's no way to tell whether 123 is the entire number or not.

Serial input:	"123" (followed by a space character)

Result: Similar to the above example, except once the space character is received, the program knows the entire number is 123, and stores this value in SERDATA. The RSIN command then ends, allowing the next line of code to run.

Serial input:	"123A"

Result: Same as the example above. The "A" character, just like the space character, is the first non-decimal text after the number 123, indicating to the program that it has received the entire number.

Serial input: "ABCD123EFGH"

Result: Similar to examples 3 and 4 above. The characters "ABCD" are ignored (since they're not decimal text), the characters "123" are evaluated to be the 	number 123 and the following character, "E", indicates to the program that it has received the entire number.

The decimal modifier is only one of a family of conversion modifiers available with RSIN See below for a list of available conversion modifiers. All of the conversion modifiers work similar to the decimal modifier (as described above). The modifiers receive bytes of data, waiting for the first byte that falls within the range of characters they accept (e.g., "0" or "1" for binary, "0" to "9" for decimal, "0" to "9" and "A" to "F" for hex. Once they receive a numeric character, they keep accepting input until a non-numeric character arrives, or in the case of the fixed length modifiers, the maximum specified number of digits arrives.

While very effective at filtering and converting input text, the modifiers aren't completely foolproof. As mentioned before, many conversion modifiers will keep accepting text until the first non-numeric text arrives, even if the resulting value exceeds the size of the variable. After RSIN , a BYTE variable will contain the lowest 8 bits of the value entered and a WORD (16-bits) would contain the lowest 16 bits. You can control this to some degree by using a modifier that specifies the number of digits, such as DEC2, which would accept values only in the range of 0 to 99.

Conversion Modifier 	Type of Number Numeric 	Characters Accepted

DEC{1..10} 	Decimal, optionally limited	0 through 9

to 1 - 10 digits

HEX{1..8} 	Hexadecimal, optionally limited	0 through 9,

 to 1 - 8 digits	A through F

BIN{1..32} 	Binary, optionally limited 	      0, 1

 to 1 - 32 digits

A variable preceded by BIN will receive the ASCII representation of its binary value.

For example, if BIN VAR1 is specified and "1000" is received, VAR1 will be set to 8.

A variable preceded by DEC will receive the ASCII representation of its decimal value.

For example, if DEC VAR1 is specified and "123" is received, VAR1 will be set to 123.

A variable preceded by HEX will receive the ASCII representation of its hexadecimal value.

For example, if HEX VAR1 is specified and "FE" is received, VAR1 will be set to 254.

SKIP followed by a count will skip that many characters in the input stream.

For example, SKIP 4 will skip 4 characters.

The RSIN command can be configured to wait for a specified sequence of characters before it retrieves any additional input. For example, suppose a device attached to the PICmicro is known to send many different sequences of data, but the only data you wish to observe happens to appear right after the unique characters, "XYZ". A modifier named WAIT can be used for this purpose: -

RSIN WAIT( "XYZ" ) , SERDATA

The above code waits for the characters "X", "Y" and "Z" to be received, in that order, then it receives the next data byte and places it into variable SERDATA.

STR modifier.

The RSIN command also has a modifier for handling a string of characters, named STR.

The STR modifier is used for receiving a string of characters into a byte array variable.

A string is a set of characters that are arranged or accessed in a certain order. The characters "ABC" would be stored in a string with the "A" first, followed by the "B" then followed by the "C". A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" would be stored in a byte array containing three bytes (elements).

Below is an example that receives ten bytes and stores them in the 10-byte array, SERSTRING: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

RSIN STR SerString  	' Fill the array with received data.

PRINT STR SerString 	' Display the string.

If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. For example: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

RSIN STR SerString\5  	' Fill the first 5-bytes of the array

PRINT STR SerString\5 	' Display the 5-character string.

The example above illustrates how to fill only the first n bytes of an array, and then how to display only the first n bytes of the array. n refers to the value placed after the backslash.

Because of its complexity, serial communication can be rather difficult to work with at times. Using the guidelines below when developing a project using the RSIN and RSOUT commands may help to eliminate some obvious errors: -

Always build your project in steps.

Start with small, manageable pieces of code, (that deal with serial communication) and test them, one individually.

Add more and more small pieces, testing them each time, as you go.

Never write a large portion of code that works with serial communication without testing its smallest workable pieces first.

Pay attention to timing.

Be careful to calculate and overestimate the amount of time, operations should take within the PICmicro for a given oscillator frequency. Misunderstanding the timing constraints is the source of most problems with code that communicate serially. If the serial communication in your project is bi-directional, the above statement is even more critical.

Pay attention to wiring.

Take extra time to study and verify serial communication wiring diagrams. A mistake in wiring can cause strange problems in communication, or no communication at all. Make sure to connect the ground pins (Vss) between the devices that are communicating serially.

Verify port setting on the PC and in the RSIN / RSOUT commands.

Unmatched settings on the sender and receiver side will cause garbled data transfers or no data transfers. This is never more critical than when a line transceiver is used(i.e. MAX232). Always remember that a line transceiver inverts the serial polarity.

If the serial data received is unreadable, it is most likely caused by a baud rate setting error, or a polarity error.

If receiving data from another device that is not a PICmicro, try to use baud rates of 9600 and below, or alternatively, use a higher frequency crystal.

Because of additional overheads in the PICmicro, and the fact that the RSIN command offers no hardware receive buffer for serial communication, received data may sometimes be missed or garbled. If this occurs, try lowering the baud rate, or increasing the crystal frequency. Using simple variables (not arrays) will also increase the chance that the PICmicro will receive the data properly.

Notes

RSIN is oscillator independent as long as the crystal frequency is declared at the top of the program. If no XTAL DECLARE is used, then RSIN defaults to a 4MHz crystal frequency for its bit timing.

See also : DECLARE, RSOUT, SERIN, SEROUT, HRSIN, HRSOUT, HSERIN, HSEROUT.


RSOUT

Syntax

RSOUT Item { , Item... }

Availability

All devices.

Overview

Send one or more Items to a predetermined pin at a predetermined baud rate in standard asynchronous format using 8 data bits, no parity and 1 stop bit (8N1). The pin is automatically made an output.

Operators

Item may be a constant, variable, expression, or string list.

There are no operators as such, instead there are modifiers. For example, if an at sign'@' precedes an Item, the ASCII representation for each digit is transmitted.

The modifiers are listed below: -

Modifier 	Operation

AT ypos,xpos 	Position the cursor on a serial LCD

CLS 	Clear a serial LCD (also creates a 30ms delay)

BIN{1..32} 	Send binary digits

DEC{1..10} 	Send decimal digits

HEX{1..8} 	Send hexadecimal digits

SBIN{1..32} 	Send signed binary digits

SDEC{1..10} 	Send signed decimal digits

SHEX{1..8} 	Send signed hexadecimal digits

IBIN{1..32} 	Send binary digits with a preceding '%' identifier

IDEC{1..10} 	Send decimal digits with a preceding '#' identifier

IHEX{1..8} 	Send hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Send signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Send signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Send signed hexadecimal digits with a preceding '$' identifier

REP c\n 	Send character c repeated n times

 	STR array\n	Send all or part of an array

CSTR cdata	Send string data defined in a CDATA statement.

The numbers after the BIN, DEC, and HEX modifiers are optional. If they are omitted, then the default is all the digits that make up the value will be displayed.

If a floating point variable is to be displayed, then the digits after the DEC modifier determine how many remainder digits are send.i.e. numbers after the decimal point.

DIM FLT AS FLOAT

FLT = 3.145

RSOUT DEC2 FLT	' Send 2 values after the decimal point

The above program will send 3.14

If the digit after the DEC modifier is omitted, then 3 values will be displayed after the decimal point.

DIM FLT AS FLOAT

FLT = 3.1456

RSOUT DEC FLT	' Send 3 values after the decimal point

The above program will send 3.145

There is no need to use the SDEC modifier for signed floating point values, as the compiler's DEC modifier will automatically display a minus result: -

DIM FLT AS FLOAT

FLT = -3.1456

RSOUT DEC FLT	' Send 3 values after the decimal point

The above program will send -3.145

HEX or BIN modifiers cannot be used with floating point values or variables.

The Xpos and Ypos values in the AT modifier both start at 1. For example, to place the text "HELLO WORLD" on line 1, position 1, the code would be: -

RSOUT AT 1 , 1 , "HELLO WORLD"

Example 1

DIM VAR1 AS BYTE

DIM WRD AS WORD

DIM DWD AS DWORD

 	RSOUT "Hello World"	' Display the text "Hello World"

 	RSOUT "VAR1= " , DEC VAR1	' Display the decimal value of VAR1

 	RSOUT "VAR1= " , HEX VAR1	' Display the hexadecimal value of VAR1

 	RSOUT "VAR1= " , BIN VAR1	' Display the binary value of VAR1

 	RSOUT "VAR1= " , @VAR1	' Display the decimal value of VAR1

RSOUT "DWD= " , HEX6 DWD 	' Display 6 hex characters of a DWORD type variable

Example 2

' Display a negative value on a serial LCD.

SYMBOL NEGATIVE = -200

RSOUT AT 1 , 1 , SDEC NEGATIVE

Example 3

' Display a negative value on a serial LCD with a preceding identifier.

RSOUT AT 1 , 1 , ISHEX -$1234

Example 3 will produce the text "$-1234" on the LCD.

Some PICmicros such as the 16F87x, and 18FXXX range have the ability to read and write to their own flash memory. And although writing to this memory too many times is unhealthy for the PICmicro, reading this memory is both fast, and harmless. Which offers a unique form of data storage and retrieval, the CDATA command proves this, as it uses the mechanism of reading and storing in the PICmicro's flash memory.

Combining the unique features of the 'self modifying PICmicro's ' with a string format, the compiler is capable of reducing the overhead of printing, or transmitting large amounts of text data. The CSTR modifier may be used in commands that deal with text processing i.e. SEROUT, HRSOUT, and PRINT etc.

The CSTR modifier is used in conjunction with the CDATA command. The CDATA command is used for initially creating the string of characters: -

STRING1: CDATA "HELLO WORLD" , 0

The above line of case will create, in flash memory, the values that make up the ASCII text "HELLO WORLD", at address STRING1. Note the NULL terminator after the ASCII text.

NULL terminated means that a zero (NULL) is placed at the end of the string of ASCII characters to signal that the string has finished.

To display, or transmit this string of characters, the following command structure could be used:

RSOUT CSTR STRING1

The label that declared the address where the list of CDATA values resided, now becomes the string's name. In a large program with lots of text formatting, this type of structure can save quite literally hundreds of bytes of valuable code space.

Try both these small programs, and you'll see that using CSTR saves a few bytes of code: -

First the standard way of displaying text: -

DEVICE 16F877

CLS

RSOUT "HELLO WORLD"

RSOUT "HOW ARE YOU?"

RSOUT "I AM FINE!"

STOP

Now using the CSTR modifier: -

CLS

RSOUT CSTR TEXT1

RSOUT CSTR TEXT2

RSOUT CSTR TEXT3

STOP

TEXT1: CDATA "HELLO WORLD" , 13, 0

TEXT2: CDATA "HOW ARE YOU?" , 13, 0

TEXT3: CDATA "I AM FINE!" , 13, 0

Again, note the NULL terminators after the ASCII text in the CDATA commands. Without these, the PICmicro will continue to transmit data in an endless loop.

The term 'virtual string' relates to the fact that a string formed from the CDATA command cannot be written too, but only read from.

The STR modifier is used for sending a string of bytes from a byte array variable. A string is a set of bytes sized values that are arranged or accessed in a certain order. The values 1, 2, 3 would be stored in a string with the value 1 first, followed by 2 then followed by the value 3. A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string 1,2,3 would be stored in a byte array containing three bytes (elements).

Below is an example that displays four bytes (from a byte array): -

DIM MYARRAY[10] AS BYTE 	' Create a 10-byte array.

MYARRAY [0] = "H"	' Load the first 5 bytes of the array

MYARRAY [1] = "E"	' With the data to send

MYARRAY [2] = "L"

MYARRAY [3] = "L"

MYARRAY [4] = "O"

RSOUT STR MYARRAY \5  	' Display a 5-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the PICmicro would try to keep sending characters until all 10 bytes of the array were transmitted. Since we do not wish all 10 bytes to be transmitted, we chose to tell it explicitly to only send the first 5 bytes.

The above example may also be written as: -

DIM MYARRAY [10] AS BYTE 	' Create a 10-byte array.

STR MYARRAY = "HELLO"	' Load the first 5 bytes of the array

RSOUT STR MYARRAY \5 	' Send 5-byte string.

The above example, has exactly the same function as the previous one. The only difference is that the string is now constructed using STR as a command instead of a modifier.

Declares

There are four DECLARES for use with RSOUT. These are : -

DECLARE RSOUT_PIN PORT . PIN

Assigns the Port and Pin that will be used to output serial data from the RSOUT command. This may be any valid port on the PICmicro.

If the DECLARE is not used in the program, then the default Port and Pin is PORTB.0.

DECLARE RSOUT_MODE INVERTED , TRUE or 1 , 0

Sets the serial mode for the data transmitted by RSOUT. This may be inverted or true. Alternatively, a value of 1 may be substituted to represent inverted, and 0 for true.

If the DECLARE is not used in the program, then the default mode is INVERTED.

DECLARE SERIAL_BAUD 0 to 65535 bps (baud)

Informs the RSIN and RSOUT routines as to what baud rate to receive and transmit data.

Virtually any baud rate may be transmitted and received, but there are standard bauds, namely: -

300, 600, 1200, 2400, 4800, 9600, and 19200.

When using a 4MHz crystal, the highest baud rate that is reliably achievable is 9600. However, an increase in the oscillator speed allows higher baud rates to be achieved, including 38400 baud.

If the DECLARE is not used in the program, then the default baud is 9600.

DECLARE RSOUT_PACE 0 to 65535 microseconds (us)

Implements a delay between characters transmitted by the RSOUT command.

On occasion, the characters transmitted serially are in a stream that is too fast for the receiver to catch, this results in missed characters. To alleviate this, a delay may be implemented between each individual character transmitted by RSOUT.

If the DECLARE is not used in the program, then the default is no delay between characters.

Notes

RSOUT is oscillator independent as long as the crystal frequency is declared at the top of the program. If no declare is used, then RSOUT defaults to a 4MHz crystal frequency for its bit timing.

The AT and CLS modifiers are primarily intended for use with serial LCD modules. Using the following command sequence will first clear the LCD, then display text at position 5 of line 2: -

RSOUT CLS , AT 2 , 5 , "HELLO WORLD"

The values after the AT modifier may also be variables.

See also : DECLARE, RSIN , SERIN, SEROUT, HRSIN, HRSOUT, HSERIN, HSEROUT.


RESET_BANK

Syntax

RESET_BANK

Availability

All devices.

Overview

Forces the compiler to reset RAM banks to zero.

Notes

If an anomaly has been located that relates to bank switching, the bank resets on every BASIC label can be disabled by removing the LABEL_BANK_RESETS DECLARE, and the suspect label name can force a bank reset. This allows a narrowing down of any anomalies and allows the program to continue working without a significant code increase.

If an anomaly has definately been found by a process of elimination, please report it to me by email to ljohnson@crownhill.co.uk.

See also :	LINE LABELS.


SEED

Syntax

SEED Value

Availability

All devices.

Overview

Seed the random number generator, in order to obtain a more random result.

Operators

Value can be a variable, constant or expression, with a value from 1 to 65535. A value of $0345 is a good starting point.

Example

' Create and display a RANDOM number

DEVICE = 16F877

XTAL = 4

DIM RND AS WORD

SEED $0345

CLS

AGAIN:

RND = RANDOM

PRINT AT 1,1,DEC RND, "     "

DELAYMS 500

GOTO AGAIN

See also: RANDOM.


SELECT..CASE..ENDSELECT

Syntax

SELECT Expression

CASE Condition(s)

 Instructions

{

CASE Condition(s)

 Instructions

CASE ELSE

 Statement(s)

}

ENDSELECT

The curly braces signify optional conditions.

Click here for working example code.

Availability

All devices.

Overview

Evaluate an Expression then continually execute a block of BASIC code based upon comparisons to Condition(s). After executing a block of code, the program continues at the line following the ENDCASE. If no conditions are found to be True and a CASE ELSE block is included, the code after the CASE ELSE leading to the ENDSELECT will be executed.

Operators

Expression can be any valid variable, constant, expression or inline command that will be compared to the Conditions.

Condition(s)  is a statement that can evaluate as True or False. The Condition can be a simple or complex relationship, as described below. Multiple conditions within the same CASE can be separated by commas.

Instructions can be any valid BASIC command that will be operated on if the CASE condition produces a True result.

Example

' Load variable RESULT according to the contents of variable VAR1

' Result will return a value of 255 if no valid condition was met

INCLUDE "PROTON_4.INC"	' Use the PROTON development board for the demo

DIM VAR1 AS BYTE

DIM RESULT AS BYTE

DELAYMS 300	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

RESULT = 0	' Clear the result variable before we start

VAR1 = 1	' Variable to base the conditions upon

SELECT VAR1

    CASE 1	' Is VAR1 equal to 1 ?

RESULT = 1	' Load RESULT with 1 if yes

    CASE 2	' Is VAR1 equal to 2 ?

RESULT = 2	' Load RESULT with 2 if yes

    CASE 3	' Is VAR1 equal to 3 ?

RESULT = 3	' Load RESULT with 3 if yes

    CASE ELSE	' Otherwise...

RESULT = 255	' Load RESULT with 255

ENDSELECT

PRINT DEC RESULT	' Display the result

STOP

Notes

SELECT..CASE is simply an advanced form of the IF..THEN..ELSEIF..ELSE construct, in which multiple ELSEIF statements are executed by the use of the CASE command.

Taking a closer look at the CASE command: -

CASE Conditional_Op Expression

Where Conditional_Op can be an = operator (which is implied if absent), or one of the standard comparison operators <>, <, >, >= or <=. Multiple conditions within the same CASE can be separated by commas. If, for example, you wanted to run a CASE block based on a value being less than one or greater than nine, the syntax would look like: -

CASE <1, >9

Another way to implement CASE is: -

CASE value1 TO value2

In this form, the valid range is from Value1 to Value2, inclusive. So if you wished to run a CASE block on a value being between the values 1 AND 9 inclusive, the syntax would look like: -

CASE 1 TO 9

For those of you that are familiar with C or Java, you will know that in those languages the statements in a CASE block fall through to the next CASE block unless the keyword break is encountered. In BASIC however, the code under an executed CASE block jumps to the code immediately after ENDSELECT.

Shown below is a typical SELECT CASE structure with its corresponding IF..THEN equivalent code alongside.

      SELECT VAR1

      	 CASE 6, 9, 99, 66

     	' IF VAR1 = 6 OR VAR1 = 9 OR VAR1 = 99 OR VAR1 = 66 THEN

        	PRINT "OR VALUES"

CASE 110 TO 200

' ELSEIF VAR1 >= 110 AND VAR1 <= 200 THEN

PRINT "AND VALUES"

       	CASE 100

     	' ELSEIF VAR1 = 100 THEN

        	PRINT "EQUAL VALUE"

CASE >300

     	' ELSEIF VAR1 > 300 THEN

        	PRINT "GREATER VALUE"

       	CASE ELSE

     	' ELSE

        	PRINT "DEFAULT VALUE"

      ENDSELECT

     ' ENDIF

See also : IF..THEN..ELSEIF..ELSE..ENDIF,  RELATIONAL OPERATORS.


SERIN

Syntax

SERIN Rpin { \ Fpin } , Baudmode , { Plabel, } { Timeout , Tlabel, } [ InputData ]

Availability

14-bit and 16-bit core devices.

Overview

Receive asynchronous serial data (i.e. RS232 data).

Operators

Rpin is a PORT.BIT constant that specifies the I/O pin through which the serial data will be received. This pin will be set to input mode.

Fpin is an optional PORT.BIT constant that specifies the I/O pin to indicate flow control status on. This pin will be set to output mode.

Baudmode may be a variable, constant, or expression (0 - 65535) that specifies serial timing and configuration.

Plabel is an optional label indicating where the program should jump to in the event of a parity error. This argument should only be provided if Baudmode indicates that parity is required.

Timeout is an optional constant (0 - 65535) that informs SERIN how long to wait for incoming data. If data does not arrive in time, the program will jump to the address specified by Tlable.

Tlabel is an optional label that must be provided along with Timeout, indicating where the program should go in the event that data does not arrive within the period specified by Timeout.

InputData is list of variables and modifiers that informs SERIN what to do with incoming data. SERIN may store data in a variable or array. Or an array acting as a string using the STR modifier.

Notes

One of the most popular forms of communication between electronic devices is serial communication. There are two major types of serial communication; asynchronous and synchronous. The HRSIN, HRSOUT, HSERIN, HSEROUT, RSIN, RSOUT, SERIN and SEROUT commands are all used to send and receive asynchronous serial data. While the SHIN and SHOUT commands are for use with synchronous communications.

The term asynchronous means 'no clock.' More specifically, 'asynchronous serial communication' means data is transmitted and received without the use of a separate 'clock' line. Data can be sent using as few as two wires; one for data and one for ground. The PC's serial ports (also called COM ports or RS232 ports) use asynchronous serial communication. Note: the other kind of serial communication, synchronous, uses at least three wires; one for clock, one for data and one for ground.

RS232 is the electrical specification for the signals that PC serial ports use. Unlike standard TTL logic, where 5 volts is a logic 1 and 0 volts is logic 0, RS232 uses -12 volts for logic 1 and +12 volts for logic 0. This specification allows communication over longer wire lengths without amplification. Most circuits that work with RS232 use a line driver / receiver (transceiver). This component does two things: -

Convert the ±12 volts of RS-232 to TTL compatible 0 to 5 volt levels.

Invert the voltage levels, so that 5 volts = logic 1 and 0 volts = logic 0.

Because of the excellent IO capabilities of the PICmicro range of devices, and the adoption of TTL levels on most modern PC serial ports, a line driver is often unnecessary unless long distances are involved between the transmitter and the receiver. Instead a simple current limiting resistor is all that's required.

You should remember that when using a line transceiver such as the MAX232, the serial mode (polarity) is inverted in the process of converting the signal levels, however, if using the direct connection, the mode is untouched. This is the single most common cause of errors when connecting serial devices, therefore you must make allowances for this within your software.

Asynchronous serial communication relies on precise timing. Both the sender and receiver must be set for identical timing, this is commonly expressed in bits per second (bps) called baud. SERIN requires a value called Baudmode that informs it of the relevant characteristics of the incoming serial data; the bit period, number of data and parity bits, and polarity.

The Baudmode argument for SERIN accepts a 16-bit value that determines its characteristics: 1-stop bit, 8-data bits/no-parity or 7-data bits/even-parity and virtually any speed from as low as 300 baud to greater than 38K baud (depending on the crystal frequency used). The list below shows how Baudmode is calculated, see manual for some common baudmodes for standard serial baud rates.

Step 1.	Determine the bit period. (bits 0 - 11)	(1,000,000 / baud rate) - 20

Step 2.	Data bits and parity. (bit 13)	8-bit/no-parity = step 1 + 0. 7-bit/even-parity = step 1 + 8192

Step 3.	Select polarity. (bit 14)	True (noninverted) = step 2 + 0. Inverted =  step 2 + 16384

Add the results of steps 1, 2 3, and 3 to determine the correct value for the Baudmode operator.

If communications are with existing software or hardware, its speed and mode will determine the choice of baud rate and mode. In general, 7-bit/even-parity (7E) mode is used for text, and 8-bit/no-parity (8N) for byte-oriented data. Note: the most common mode is 8-bit/no-parity, even when the data transmitted is just text. Most devices that use a 7-bit data mode do so in order to take advantage of the parity feature. Parity can detect some communication errors, but to use it you lose one data bit. This means that incoming data bytes transferred in 7E (even-parity) mode can only represent values from 0 to 127, rather than the 0 to 255 of 8N (no-parity) mode.

The compiler's serial commands SERIN and SEROUT, have the option of still using a parity bit with 4 to 8 data bits. This is through the use of a DECLARE: -

With parity disabled (the default setting): -

DECLARE SERIAL_DATA 4 	' Set SERIN and SEROUT data bits to 4

DECLARE SERIAL_DATA 5 	' Set SERIN and SEROUT data bits to 5

DECLARE SERIAL_DATA 6 	' Set SERIN and SEROUT data bits to 6

DECLARE SERIAL_DATA 7 	' Set SERIN and SEROUT data bits to 7

DECLARE SERIAL_DATA 8 	' Set SERIN and SEROUT data bits to 8 (default)

With parity enabled: -

DECLARE SERIAL_DATA 5 	' Set SERIN and SEROUT data bits to 4

DECLARE SERIAL_DATA 6 	' Set SERIN and SEROUT data bits to 5

DECLARE SERIAL_DATA 7 	' Set SERIN and SEROUT data bits to 6

DECLARE SERIAL_DATA 8 	' Set SERIN and SEROUT data bits to 7 (default)

DECLARE SERIAL_DATA 9 	' Set SERIN and SEROUT data bits to 8

SERIAL_DATA data bits may range from 4 bits to 8 (the default if no DECLARE is issued). Enabling parity uses one of the number of bits specified.

DECLARE SERIAL_PARITY ODD or EVEN

Sets the parity type for SERIN, and SEROUT. When parity is enabled, this declare chooses whether it is ODD or EVEN. If parity is enabled but the SERIAL_PARITY DECLARE is not issued in the program, the default setting is EVEN parity.

DECLARE SERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE SERIAL_PARITY = ODD 	' Use if odd parity desired

Declaring SERIAL_DATA as 9 allows 8 bits to be read and written along with a 9th parity bit.

Parity is a simple error-checking feature. When a serial sender is set for even parity (the mode the compiler supports) it counts the number of 1s in an outgoing byte and uses the parity bit to make that number even. For example, if it is sending the 7-bit value: %0011010, it sets the parity bit to 1 in order to make an even number of 1s (four).

The receiver also counts the data bits to calculate what the parity bit should be. If it matches the parity bit received, the serial receiver assumes that the data was received correctly. Of course, this is not necessarily true, since two incorrectly received bits could make parity seem correct when the data was wrong, or the parity bit itself could be bad when the rest of the data was correct.

Many systems that work exclusively with text use 7-bit/ even-parity mode. For example, to receive one data byte through bit-0 of PORTA at 9600 baud, 7E, inverted:

SERIN PORTA.0 , 24660 , [SerData]

The above example will work correctly, however it doesn't inform the program what to do in the event of a parity error.

Below, is an improved version that uses the optional Plabel argument:

SERIN PORTA.0 , 24660 , P_ERROR , [SerData]

PRINT @ SerData

STOP

P_ERROR:

PRINT "Parity Error"

If the parity matches, the program continues at the PRINT instruction after SERIN. If the parity doesn't match, the program jumps to the label P_ERROR. Note that a parity error takes precedence over other InputData specifications (as soon as an error is detected, SERIN aborts and jumps to the Plabel routine).

In the examples above, the only way to end the SERIN instruction (other than RESET or power-off) is to give SERIN the serial data it needs. If no serial data arrives, the program is stuck in an endless loop. However, you can force SERIN to abort if it doesn't receive data within a specified number of milliseconds.

For example, to receive a value through bit-0 of PORTA at 9600 baud, 8N, inverted and abort SERIN after 2 seconds (2000 ms) if no data arrives: -

SERIN PORTA.0 , 16468 , 2000 , TO_ERROR , [SerData]

PRINT CLS , @ Result

STOP

TO_ERROR:

PRINT CLS , "Timed Out"

If no serial data arrives within 2 seconds, SERIN aborts and continues at the label TO_ERROR.

Both Parity and Serial Timeouts may be combined. Below is an example to receive a value through bit-0 of PORTA at 2400 baud, 7E, inverted with a 10-second timeout:

DIM SerData AS BYTE

Again:

SERIN PORTA.0 , 24660 , P_ERROR , 10000 , TO_ERROR , [SerData]

PRINT CLS , @ SerData

GOTO Again

TO_ERROR:

PRINT CLS , "Timed Out"

GOTO Again

P_ERROR:

PRINT CLS , "Parity Error"

GOTO Again

When designing an application that requires serial communication between PICmicros, you should remember to work within these limitations: -

When the PICmicro is sending or receiving data, it cannot execute other instructions.

When the PICmicro is executing other instructions, it cannot send or receive data.

The compiler does not offer a serial buffer as there is in PCs. At lower crystal frequencies, and higher serial rates, the PICmicro cannot receive data via SERIN, process it, and execute another SERIN in time to catch the next chunk of data, unless there are significant pauses between data transmissions.

These limitations can sometimes be addressed by using flow control; the Fpin option for SERIN and SEROUT. Through Fpin, SERIN can inform another PICmicro sender when it is ready to receive data. (Fpin flow control follows the rules of other serial handshaking schemes, however most computers other than the PICmicro cannot start and stop serial transmission on a byte-by-byte basis. That is why this discussion is limited to communication between PICmicros.)

Below is an example using flow control with data through bit-0 of PORTA, and flow control through bit-1 of PORTA, 9600 baud, N8, noninverted: -

SERIN PORTA.0\PORTA.1 , 84 , [SerData]

When SERIN executes, bit-0 of PORTA (Rpin) is made an input in preparation for incoming data, and bit-1 of PORTA (Fpin) is made an output low, to signal "go" to the sender. After SERIN finishes receiving data, bit-1 of PORTA is brought high to notify the sender to stop. If an inverted BaudMode had been specified, the Fpin's responses would have been reversed. The table below illustrates the relationship of serial polarity to Fpin states.

Serial Polarity	Ready to Receive ("Go")	Not Ready to Receive ("Stop")
Inverted	Fpin is High (1)	Fpin is Low (0)
Non-inverted	Fpin is Low (0)	Fpin is High (1)

SERIN MODIFIERS.

As we already know, SERIN will wait for and receive a single byte of data, and store it in a variable . If the PICmicro were connected to a PC running a terminal program and the user pressed the "A" key on the keyboard, after the SERIN command executed, the variable would contain 65, which is the ASCII code for the letter "A"

What would happen if the user pressed the "1" key? The result would be that the variable would contain the value 49 (the ASCII code for the character "1"). This is an important point to remember: every time you press a character on the keyboard, the computer receives the ASCII value of that character. It is up to the receiving side to interpret the values as necessary. In this case, perhaps we actually wanted the variable to end up with the value 1, rather than the ASCII code 49.

The SERIN command provides a modifier, called the decimal modifier, which will interpret this for us. Look at the following code: -

DIM SERDATA AS BYTE

SERIN PORTA.1, 16780, [DEC SERDATA]

Notice the decimal modifier in the SERIN command that appears just to the left of the SERDATA variable. This tells SERIN to convert incoming text representing decimal numbers into true decimal form and store the result in SERDATA. If the user running the terminal software pressed the "1", "2" and then "3" keys followed by a space or other non-numeric text, the value 123 will be stored in the variable SERDATA, allowing the rest of the program to perform any numeric operation on the variable.

Without the decimal modifier, however, you would have been forced to receive each character ("1", "2" and "3") separately, and then would still have to do some manual conversion to arrive at the number 123 (one hundred twenty three) before you can do the desired calculations on it.

The decimal modifier is designed to seek out text that represents decimal numbers. The characters that represent decimal numbers are the characters "0" through "9". Once the SERIN command is asked to use the decimal modifier for a particular variable, it monitors the incoming serial data, looking for the first decimal character. Once it finds the first decimal character, it will continue looking for more (accumulating the entire multi-digit number) until is finds a non-decimal numeric character. Remember that it will not finish until it finds at least one decimal character followed by at least one non-decimal character.

To illustrate this further, examine the following examples (assuming we're using the same code example as above): -

Serial input:	"ABC"

Result: The program halts at the SERIN command, continuously waiting for decimal text.

Serial input:	"123" (with no characters following it)

Result: The program halts at the SERIN command. It recognises the characters "1", "2" and "3" as the number one hundred twenty three, but since no 	characters follow the "3", it waits continuously, since there's no way to tell whether 123 is the entire number or not.

Serial input:	"123" (followed by a space character)

Result: Similar to the above example, except once the space character is received, the program knows the entire number is 123, and stores this value in SERDATA. The SERIN command then ends, allowing the next line of code to run.

Serial input:	"123A"

Result: Same as the example above. The "A" character, just like the space character, is the first non-decimal text after the number 123, indicating to the program that it has received the entire number.

Serial input: "ABCD123EFGH"

Result: Similar to examples 3 and 4 above. The characters "ABCD" are ignored (since they're not decimal text), the characters "123" are evaluated to be the 	number 123 and the following character, "E", indicates to the program that it has received the entire number.

The final result of the DEC modifier is limited to 16 bits (up to the value 65535). If a value larger than this is received by the decimal modifier, the end result will be incorrect because the result rolled-over the maximum 16-bit value. Therefore, SERIN modifiers may not (at this time) be used to load DWORD (32-bit) variables.

The decimal modifier is only one of a family of conversion modifiers available with SERIN See below for a list of available conversion modifiers. All of the conversion modifiers work similar to the decimal modifier (as described above). The modifiers receive bytes of data, waiting for the first byte that falls within the range of characters they accept (e.g., "0" or "1" for binary, "0" to "9" for decimal, "0" to "9" and "A" to "F" for hex. Once they receive a numeric character, they keep accepting input until a non-numeric character arrives, or in the case of the fixed length modifiers, the maximum specified number of digits arrives.

While very effective at filtering and converting input text, the modifiers aren't completely foolproof. As mentioned before, many conversion modifiers will keep accepting text until the first non-numeric text arrives, even if the resulting value exceeds the size of the variable. After SERIN, a BYTE variable will contain the lowest 8 bits of the value entered and a WORD (16-bits) would contain the lowest 16 bits. You can control this to some degree by using a modifier that specifies the number of digits, such as DEC2, which would accept values only in the range of 0 to 99.

Conversion Modifier 	Type of Number Numeric 	Characters Accepted

DEC{1..5} 	Decimal, optionally limited	0 through 9

to 1 - 10 digits

HEX{1..4} 	Hexadecimal, optionally limited	0 through 9,

 to 1 - 8 digits	A through F

BIN{1..16} 	Binary, optionally limited 	      0, 1

 to 1 - 32 digits

A variable preceded by BIN will receive the ASCII representation of its binary value.

For example, if BIN VAR1 is specified and "1000" is received, VAR1 will be set to 8.

A variable preceded by DEC will receive the ASCII representation of its decimal value.

For example, if DEC VAR1 is specified and "123" is received, VAR1 will be set to 123.

A variable preceded by HEX will receive the ASCII representation of its hexadecimal value.

For example, if HEX VAR1 is specified and "FE" is received, VAR1 will be set to 254.

SKIP followed by a count will skip that many characters in the input stream.

For example, SKIP 4 will skip 4 characters.

The SERIN command can be configured to wait for a specified sequence of characters before it retrieves any additional input. For example, suppose a device attached to the PICmicro is known to send many different sequences of data, but the only data you wish to observe happens to appear right after the unique characters, "XYZ". A modifier named WAIT can be used for this purpose: -

SERIN PORTA.0 , 16468, [ WAIT( "XYZ" ) , SERDATA]

The above code waits for the characters "X", "Y" and "Z" to be received, in that order, then it receives the next data byte and places it into variable SERDATA.

STR modifier.

The compiler also has a modifier for handling a string of characters, named STR.

The STR modifier is used for receiving a string of characters into a byte array variable.

A string is a set of characters that are arranged or accessed in a certain order. The characters "ABC" would be stored in a string with the "A" first, followed by the "B" then followed by the "C". A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" would be stored in a byte array containing three bytes (elements).

Below is an example that receives ten bytes through bit-0 of PORTA at 9600 bps, N81/inverted, and stores them in the 10-byte array, SERSTRING: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

SERIN PORTA.0 , 16468, [ STR SerString ] 	' Fill the array with received data.

PRINT STR SerString 	' Display the string.

If the amount of received characters is not enough to fill the entire array, then a formatter may be placed after the array's name, which will only receive characters until the specified length is reached. For example: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

SERIN PORTA.0 , 16468, [ STR SerString\5 ] 	' Fill the first 5-bytes of the array

PRINT STR SerString\5 	' Display the 5-character string.

The example above illustrates how to fill only the first n bytes of an array, and then how to display only the first n bytes of the array. n refers to the value placed after the backslash.

Because of its complexity, serial communication can be rather difficult to work with at times. Using the guidelines below when developing a project using the SERIN and SEROUT commands may help to eliminate some obvious errors: -

Always build your project in steps.

Start with small, manageable pieces of code, (that deal with serial communication) and test them, one individually.

Add more and more small pieces, testing them each time, as you go.

Never write a large portion of code that works with serial communication without testing its smallest workable pieces first.

Pay attention to timing.

Be careful to calculate and overestimate the amount of time, operations should take within the PICmicro for a given oscillator frequency. Misunderstanding the timing constraints is the source of most problems with code that communicate serially. If the serial communication in your project is bi-directional, the above statement is even more critical.

Pay attention to wiring.

Take extra time to study and verify serial communication wiring diagrams. A mistake in wiring can cause strange problems in communication, or no communication at all. Make sure to connect the ground pins (Vss) between the devices that are communicating serially.

Verify port setting on the PC and in the SERIN / SEROUT commands.

Unmatched settings on the sender and receiver side will cause garbled data transfers or no data transfers. This is never more critical than when a line transceiver is used(i.e. MAX232). Always remember that a line transceiver inverts the serial polarity.

If the serial data received is unreadable, it is most likely caused by a baud rate setting error, or a polarity error.

If receiving data from another device that is not a PICmicro, try to use baud rates of 9600 and below, or alternatively, use a higher frequency crystal.

Because of additional overheads in the PICmicro, and the fact that the SERIN command offers no hardware receive buffer for serial communication, received data may sometimes be missed or garbled. If this occurs, try lowering the baud rate, or increasing the crystal frequency. Using simple variables (not arrays) will also increase the chance that the PICmicro will receive the data properly.

See also :	RSIN, RSOUT, HRSIN, HRSOUT, HSERIN, HSEROUT, SEROUT.


SEROUT

Syntax

SEROUT Tpin { \ Fpin } , Baudmode , { Pace, } { Timeout , Tlabel, } [ OutputData ]

Availability

14-bit and 16-bit core devices.

Overview

Transmit asynchronous serial data (i.e. RS232 data).

Operators

Tpin is a PORT.BIT constant that specifies the I/O pin through which the serial data will be transmitted. This pin will be set to output mode while operating. The state of this pin when finished is determined by the driver bit in Baudmode.

Fpin is an optional PORT.BIT constant that specifies the I/O pin to monitor for flow control status. This pin will be set to input mode. NOTE: Fpin must be specified in order to use the optional Timeout and Tlabel operators in the SEROUT command.

Baudmode may be a variable, constant, or expression (0 - 65535) that specifies serial timing and configuration.

Pace is an optional variable, constant, or expression (0 - 65535) that determines the length of the delay between transmitted bytes. NOTE: Pace cannot be used simultaneously with Timeout.

Timeout is an optional variable or constant (0 - 65535) that informs SEROUT how long to wait for Fpin permission to send. If permission does not arrive in time, the program will jump to the address specified by Tlable. NOTE: Fpin must be specified in order to use the optional Timeout and Tlabel operators in the SEROUT command.

Tlabel is an optional label that must be provided along with Timeout. Tlabel indicates where the program should jump to in the event that permission to send data is not granted within the period specified by Timeout.

OutputData is list of variables, constants, expressions and modifiers that informs SEROUT how to format outgoing data. SEROUT can transmit individual or repeating bytes, convert values into decimal, hex or binary text representations, or transmit strings of bytes from variable arrays, and CDATA constructs. These actions can be combined in any order in the OutputData list.

Notes

One of the most popular forms of communication between electronic devices is serial communication. There are two major types of serial communication; asynchronous and synchronous. The RSIN, RSOUT, SERIN and SEROUT commands are all used to send and receive asynchronous serial data. While the SHIN and SHOUT commands are for use with synchronous communications.

The term asynchronous means 'no clock.' More specifically, 'asynchronous serial communication' means data is transmitted and received without the use of a separate 'clock' line. Data can be sent using as few as two wires; one for data and one for ground. The PC's serial ports (also called COM ports or RS232 ports) use asynchronous serial communication. Note: the other kind of serial communication, synchronous, uses at least three wires; one for clock, one for data and one for ground.

RS232 is the electrical specification for the signals that PC serial ports use. Unlike standard TTL logic, where 5 volts is a logic 1 and 0 volts is logic 0, RS232 uses -12 volts for logic 1 and +12 volts for logic 0. This specification allows communication over longer wire lengths without amplification.

Most circuits that work with RS232 use a line driver / receiver (transceiver). This component does two things: -

Convert the ±12 volts of RS-232 to TTL compatible 0 to 5 volt levels.

Invert the voltage levels, so that 5 volts = logic 1 and 0 volts = logic 0.

By far, the most common line driver device is the MAX232 from MAXIM semiconductor. With the addition of a few capacitors, a complete 2-way level converter is realised.

The MAX232 is not the only device available, there are other types that do not require any external capacitors at all. Visit Maxim's excellent web site at www.maxim.com <http://www.maxim.com>, and download one of their many detailed datasheets.

Because of the excellent IO capabilities of the PICmicro range of devices, and the adoption of TTL levels on most modern PC serial ports, a line driver is often unnecessary unless long distances are involved between the transmitter and the receiver. Instead a simple current limiting resistor is all that's required.

You should remember that when using a line transceiver such as the MAX232, the serial mode (polarity) is inverted in the process of converting the signal levels, however, if using the direct connection, the mode is untouched. This is the single most common cause of errors when connecting serial devices, therefore you must make allowances for this within your software.

Asynchronous serial communication relies on precise timing. Both the sender and receiver must be set for identical timing, this is commonly expressed in bits per second (bps) called baud. SEROUT requires a value called Baudmode that informs it of the relevant characteristics of the incoming serial data; the bit period, number of data and parity bits, and polarity.

The Baudmode argument for SEROUT accepts a 16-bit value that determines its characteristics: 1-stop bit, 8-data bits/no-parity or 7-data bits/even-parity and virtually any speed from as low as 300 baud to greater than 38K baud (depending on the crystal frequency used). Table 2 below shows how Baudmode is calculated, while table 3 shows some common baudmodes for standard serial baud rates.

Step 1.	Determine the bit period. (bits 0 - 11)	(1,000,000 / baud rate) - 20
Step 2.	data bits and parity. (bit 13)	8-bit/no-parity = step 1 + 0 7-bit/even-parity = step 1 + 8192
Step 3.	Select polarity. (bit 14)	True (noninverted) = step 2 + 0 Inverted = step 2 + 16384
Step 4.	Select driven or open output (bit 15)	Driven = step 3 + 0 Open = step 3 + 32768
BaudRate	8-bit no-parity  inverted	8-bit no-parity true	7-bit even-parity inverted	7-bit even-parity true
300	19697	3313	27889	11505
600	18030	1646	26222	9838
1200	17197	813	25389	9005
2400	16780	396	24972	8588
4800	16572	188	24764	8380
9600	16468	84	24660	8276

Note

For 'open' baudmodes used in networking, add 32768 to the values from the table above.

If communications are with existing software or hardware, its speed and mode will determine the choice of baud rate and mode. In general, 7-bit/even-parity (7E) mode is used for text, and 8-bit/no-parity (8N) for byte-oriented data. Note: the most common mode is 8-bit/no-parity, even when the data transmitted is just text. Most devices that use a 7-bit data mode do so in order to take advantage of the parity feature. Parity can detect some communication errors, but to use it you lose one data bit. This means that incoming data bytes transferred in 7E (even-parity) mode can only represent values from 0 to 127, rather than the 0 to 255 of 8N (no-parity) mode.

The compiler's serial commands SEROUT and SERIN, have the option of still using a parity bit with 4 to 8 data bits. This is through the use of a DECLARE: -

With parity disabled (the default setting): -

DECLARE SERIAL_DATA 4 	' Set SEROUT and SERIN data bits to 4

DECLARE SERIAL_DATA 5 	' Set SEROUT and SERIN data bits to 5

DECLARE SERIAL_DATA 6 	' Set SEROUT and SERIN data bits to 6

DECLARE SERIAL_DATA 7 	' Set SEROUT and SERIN data bits to 7

DECLARE SERIAL_DATA 8 	' Set SEROUT and SERIN data bits to 8 (default)

With parity enabled: -

DECLARE SERIAL_DATA 5 	' Set SEROUT and SERIN data bits to 4

DECLARE SERIAL_DATA 6 	' Set SEROUT and SERIN data bits to 5

DECLARE SERIAL_DATA 7 	' Set SEROUT and SERIN data bits to 6

DECLARE SERIAL_DATA 8 	' Set SEROUT and SERIN data bits to 7  (default)

DECLARE SERIAL_DATA 9 	' Set SEROUT and SERIN data bits to 8

SERIAL_DATA data bits may range from 4 bits to 8 (the default if no DECLARE is issued). Enabling parity uses one of the number of bits specified.

DECLARE SERIAL_PARITY ODD or EVEN

Sets the parity type for SERIN, and SEROUT. When parity is enabled, this declare chooses whether it is ODD or EVEN. If parity is enabled but the SERIAL_PARITY DECLARE is not issued in the program, the default setting is EVEN parity.

DECLARE SERIAL_PARITY = EVEN 	' Use if even parity desired

DECLARE SERIAL_PARITY = ODD 	' Use if odd parity desired

Declaring SERIAL_DATA as 9 allows 8 bits to be read and written along with a 9th parity bit.

Parity is a simple error-checking feature. When the SEROUT command's Baudmode is set for even parity (compiler default) it counts the number of 1s in the outgoing byte and uses the parity bit to make that number even. For example, if it is sending the 7-bit value: %0011010, it sets the parity bit to 1 in order to make an even number of 1s (four).

The receiver also counts the data bits to calculate what the parity bit should be. If it matches the parity bit received, the serial receiver assumes that the data was received correctly. Of course, this is not necessarily true, since two incorrectly received bits could make parity seem correct when the data was wrong, or the parity bit itself could be bad when the rest of the data was correct. Parity errors are only detected on the receiver side.

Normally, the receiver determines how to handle an error. In a more robust application, the receiver and transmitter might be set up in such that the receiver can request a re-send of data that was received with a parity error.

SEROUT Modifiers.

The example below will transmit a single byte through bit-0 of PORTA at 2400 baud, 8N1, inverted: -

SEROUT PORTA.0 , 16780 , [ 65 ]

In the above example, SEROUT will transmit a byte equal to 65 (the ASCII value of the character "A" ) through PORTA.0. If the PICmicro was connected to a PC running a terminal program such as Hyper terminal set to the same baud rate, the character "A" would appear on the screen. Always remembering that the polarity will differ if a line transceiver such as the MAX232 is used.

What if you wanted the value 65 to appear on the PC's screen? As was stated earlier, it is up to the receiving side (in serial communication) to interpret the values. In this case, the PC is interpreting the byte-sized value to be the ASCII code for the character "A". Unless you're also writing the software for the PC, you cannot change how the PC interprets the incoming serial data, therefore to solve this problem, the data needs to be translated before it is sent.

The SEROUT command provides a modifier which will translate the value 65 into two ASCII codes for the characters "6" and "5" and then transmit them: -

SEROUT PORTA.0 , 16780 , [ @ 65 ]

or

SEROUT PORTA.0 , 16780 , [ DEC 65 ]

Notice that the decimal modifier in the SEROUT command is the character @ or word DEC, both these modifiers do the same thing, which is to inform SEROUT to convert the number into separate ASCII characters which represent the value in decimal form. If the value 65 in the code were changed to 123, the SEROUT command would send three bytes (49, 50 and 51) corresponding to the characters "1", "2" and "3".

This is exactly the same modifier that is used in the RSOUT and PRINT commands.

As well as the DEC modifier, SEROUT may use HEX, or BIN modifiers, again, these are the same as used in the RSOUT and PRINT commands. Therefore, please refer to the RSOUT or PRINT command descriptions for an explanation of these. The SEROUT command sends quoted text exactly as it appears in the OutputData list:

SEROUT PORTA.0 , 16780 , [ "HELLO WORLD" , 13 ]

SEROUT PORTA.0 , 16780 , [ "Num = " , DEC 100 ]

The above code will display "HELLO WORLD" on one line and "Num = 100" on the next line. Notice that you can combine data to output in one SEROUT command, separated by commas. In the example above, we could have written it as one line of code: -

SEROUT PORTA.0 , 16780 , [ "HELLO WORLD" , 13 , "Num = " , DEC 100 ]

SEROUT also has some other modifiers. These are listed below: -

Modifier 	Operation

AT ypos,xpos 	Position the cursor on a serial LCD

CLS 	Clear a serial LCD (also creates a 30ms delay)

BIN{1..32} 	Send binary digits

DEC{1..10} 	Send decimal digits

HEX{1..8} 	Send hexadecimal digits

SBIN{1..32} 	Send signed binary digits

SDEC{1..10} 	Send signed decimal digits

SHEX{1..8} 	Send signed hexadecimal digits

IBIN{1..32} 	Send binary digits with a preceding '%' identifier

IDEC{1..10} 	Send decimal digits with a preceding '#' identifier

IHEX{1..8} 	Send hexadecimal digits with a preceding '$' identifier

ISBIN{1..32} 	Send signed binary digits with a preceding '%' identifier

ISDEC{1..10} 	Send signed decimal digits with a preceding '#' identifier

ISHEX{1..8} 	Send signed hexadecimal digits with a preceding '$' identifier

REP c\n 	Send character c repeated n times

If a floating point variable is to be displayed, then the digits after the DEC modifier determine how many remainder digits are printed.i.e. numbers after the decimal point.

DIM FLT AS FLOAT

FLT = 3.145

SEROUT PORTA.0 , 16780 , [DEC2 FLT]	' Send 2 values after the decimal point

The above program will send 3.14

If the digit after the DEC modifier is omitted, then 3 values will be displayed after the decimal point.

DIM FLT AS FLOAT

FLT = 3.1456

SEROUT PORTA.0 , 16780 , [DEC FLT]	' Send 3 values after the decimal point

The above program will send 3.145

There is no need to use the SDEC modifier for signed floating point values, as the compiler's DEC modifier will automatically display a minus result: -

DIM FLT AS FLOAT

FLT = -3.1456

SEROUT PORTA.0 , 16780 , [DEC FLT]	' Send 3 values after the decimal point

The above program will send -3.145

HEX or BIN modifiers cannot be used with floating point values or variables.

Using Strings with SEROUT.

The STR modifier is used for transmitting a string of characters from a byte array variable. A string is a set of characters that are arranged or accessed in a certain order. The characters "ABC" would be stored in a string with the "A" first, followed by the "B" then followed by the "C". A byte array is a similar concept to a string; it contains data that is arranged in a certain order. Each of the elements in an array is the same size. The string "ABC" would be stored in a byte array containing three bytes (elements).

Below is an example that transmits five bytes (from a byte array) through bit-0 of PORTA at 9600 bps, N81/inverted: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

SerString[0] = "H"	' Load the first 5 bytes of the array

SerString[1] = "E"	' With the word "HELLO"

SerString[2] = "L"

SerString[3] = "L"

SerString[4] = "O"

SEROUT PORTA.0 , 16468 , [ STR SerString\5 ] 	' Send 5-byte string.

Note that we use the optional \n argument of STR. If we didn't specify this, the PICmicro would try to keep sending characters until all 10 bytes of the array were transmitted, or it found a byte equal to 0 (a NULL terminator). Since we didn't specify a last byte of 0 in the array, and we do not wish the last five bytes to be transmitted, we chose to tell it explicitly to only send the first 5 characters.

The above example may also be written as: -

DIM SerString[10] AS BYTE 	' Create a 10-byte array.

STR SerString = "HELLO" , 0	' Load the first 6 bytes of the array

SEROUT PORTA.0 , 16468 , [ STR SerString] 	' Send first 5-bytes of string.

In the above example, we specifically added a NULL terminator to the end of the string (a zero). Therefore, the STR modifier within the SEROUT command will output data until this is reached. An alternative to this would be to create the array exactly the size of the text. In our example, the array would have been 5 elements in length.

Another form of string is used by the CSTR modifier. NOTE: Because this uses the CDATA command to create the individual elements it is only for use with PICmicros that support self-modifying features, such as the 16F87x range of devices.

Below is an example of using the CSTR modifier. It's function is the same as the above examples, however, no RAM is used for creating arrays.

SEROUT PORTA.0 , 16468 , [ CSTR SerString]

SerString: CDATA "HELLO" , 0

The CSTR modifier will always be terminated by a NULL (i.e. zero at the end of the text or data). If the NULL is omitted, then the SEROUT command will continue transmitting characters forever.

The SEROUT command can also be configured to pause between transmitted bytes. This is the purpose of the optional Pace operator. For example (9600 baud N8, inverted): -

SEROUT PORTA.0 , 16468 , 1000 , [ "Send this message Slowly" ]

Here, the PICmicro transmits the message "Send this message Slowly" with a 1 second delay between each character.

A good reason to use the Pace feature is to support devices that require more than one stop bit. Normally, the PICmicro sends data as fast as it can (with a minimum of 1 stop bit between bytes). Since a stop bit is really just a resting state in the line (no data transmitted), using the Pace option will effectively add multiple stop bits. Since the requirement for 2 or more stop bits (on some devices) is really just a minimum requirement, the receiving side should receive this data correctly.

SEROUT Flow Control.

When designing an application that requires serial communication between PICmicros, you need to work within these limitations: -

When the PICmicro is sending or receiving data, it cannot execute other instructions.

When the PICmicro is executing other instructions, it cannot send or receive data.

The compiler does not offer a serial buffer as there is in PCs. At lower crystal frequencies, and higher serial rates, the PICmicro cannot receive data via SERIN, process it, and execute another SERIN in time to catch the next chunk of data, unless there are significant pauses between data transmissions.

These limitations can sometimes be addressed by using flow control; the Fpin option for SEROUT and SERIN. Through Fpin, SERIN can inform another PICmicro sender when it is ready to receive data and SEROUT (on the sender) will wait for permission to send. Fpin flow control follows the rules of other serial handshaking schemes, however most computers other than the PICmicro cannot start and stop serial transmission on a byte-by-byte basis. That is why this discussion is limited to communication between PICmicros.

Below is an example using flow control with data through bit-0 of PORTA, and flow control through bit-1 of PORTA, 9600 baud, N8, noninverted: -

SEROUT PORTA.0\PORTA.1 , 84 , [SerData]

When SERIN executes, bit-0 of PORTA (Tpin) is made an output in preparation for sending data, and bit-1 of PORTA (Fpin) is made an input, to wait for the "go" signal from the receiver. The table below illustrates the relationship of serial polarity to Fpin states.

Serial Polarity	Ready to Receive ("Go")	Not Ready to Receive ("Stop")
Inverted	Fpin is High (1)	Fpin is Low (0)
Non-inverted	Fpin is Low (0)	Fpin is High (1)

See update manual for a flow control circuit.

The SEROUT command supports open-drain and open-source output, which makes it possible to network multiple PICmicros on a single pair of wires. These 'open baudmodes' only actively drive the Tpin in one state (for the other state, they simply disconnect the pin; setting it to an input mode). If two PICmicros in a network had their SEROUT lines connected together (while a third device listened on that line) and the PICmicros were using always-driven baudmodes, they could simultaneously output two opposite states (i.e. +5 volts and ground). This would create a short circuit. The heavy current flow would likely damage the I/O pins or the PICmicros themselves. Since the open baudmodes only drive in one state and float in the other, there's no chance of this kind of short happening.

The polarity selected for SEROUT determines which state is driven and which is open as shown in the table below.

Serial Polarity	State(0)	State(1)	Resistor Pulled to:
Inverted	Open	Driven	Gnd (Vss)
Non-inverted	Driven	Open	+5V (Vdd)

Since open baudmodes only drive to one state, they need a resistor to pull the networked line into the opposite state, as shown in the above table and in the circuits below. Open baudmodes allow the PICmicro to share a line, however it is up to your program to resolve other networking issues such as who talks when, and how to detect, prevent and fix data errors.

See also :	RSIN, RSOUT, HRSIN, HRSOUT, HSERIN, HSEROUT, SERIN.


SERVO

Syntax

SERVO Pin , Rotation Value

Availability

All devices.

Overview

Control a remote control type servo motor.

Operators

Pin is a Port.Pin constant that specifies the I/O pin for the attachment of the motor's control terminal.

Rotation Value is a 16-bit (0-65535) constant or WORD variable that dictates the position of the motor. A value of approx 500 being a rotation to the farthest position in a direction and approx 2500 being the farthest rotation in the opposite direction. A value of 1500 would normally centre the servo but this depends on the motor type.

Example

' Control a servo motor attached to pin 3 of PORTA

DEVICE 16F628	' We'll use the new PICmicro

DIM Pos as WORD 	' Servo Position

SYMBOL Pin = PORTA.3 	' Alias the servo pin

CMCON = 7 	' PORTA to digital

CLS	' Clear the LCD

Pos = 1500 	' Centre the servo

PORTA = 0 	' PORTA lines low to read buttons

TRISA = %00000111 	' Enable the button pins as inputs

' ** Check any button pressed to move servo **

Main:

IF PORTA.0 = 0 Then IF Pos < 3000 Then Pos = Pos + 1 	' Move servo left

IF PORTA.1 = 0 Then Pos = 1500 	' Centre servo

 	IF PORTA.2 = 0 Then IF Pos > 0 Then Pos = Pos - 1 	' Move servo right

 	SERVO Pin , Pos

 	DELAYMS 5 	' Servo update rate

 	PRINT AT 1 , 1 , "Position=" , @Pos , " "

 	GOTO Main

Notes

Servos of the sort used in radio-controlled models are finding increasing applications in this robotics age we live in. They simplify the job of moving objects in the real world by eliminating much of the mechanical design. For a given signal input, you get a predictable amount of motion as an output.

To enable a servo to move it must be connected to a 5 Volt power supply capable of delivering an ampere or more of peak current. It then needs to be supplied with a positioning signal. The signal is normally a 5 Volt, positive-going pulse between 1 and 2 milliseconds (ms) long, repeated approximately 50 times per second.

The width of the pulse determines the position of the servo. Since a servo's travel can vary from model to model, there is not a definite correspondence between a given pulse width and a particular servo angle, however most servos will move to the centre of their travel when receiving 1.5ms pulses.

Servos are closed-loop devices. This means that they are constantly comparing their commanded position (proportional to the pulse width) to their actual position (proportional to the resistance of an internal potentiometer mechanically linked to the shaft). If there is more than a small difference between the two, the servo's electronics will turn on the motor to eliminate the error. In addition to moving in response to changing input signals, this active error correction means that servos will resist mechanical forces that try to move them away from a commanded position. When the servo is unpowered or not receiving positioning pulses, the output shaft may be easily turned by hand. However, when the servo is powered and receiving signals, it won't move from its position.

Driving servos with PROTON+ is extremely easy. The SERVO command generates a pulse in 1microsecond (µs) units, so the following code would command a servo to its centred position and hold it there: -

Again:

SERVO PORTA.0 , 1500

DELAYMS 20

GOTO Again

The 20ms delay ensures that the program sends the pulse at the standard 50 pulse-per-second rate. However, this may be lengthened or shortened depending on individual motor characteristics.

The SERVO command is oscillator independent and will always produce 1us pulses regardless of the crystal frequency used.


SET_OSCCAL

Syntax

SET_OSCCAL

Availability

12-bit and14-bit core devices.

Overview

Calibrate the on-chip oscillator found on some PICmicro devices.

Notes

Some PICmicro devices, such as the PIC12C50x, PIC12C67x, PIC12F6xx and 16F62x range, have on-chip RC oscillators. These devices contain an oscillator calibration factor in the last location of code space. The on-chip oscillator may be fine-tuned by reading the data from this location and moving it into the OSCCAL register. The command SET_OSCAL has been specially created to perform this task automatically each time the program starts: -

DEVICE 12C671

SET_OSCCAL 	' Set OSCCAL for 1K device 12C671

Add this command near the beginning of the program to perform the setting of OSCCAL.

If a UV erasable (windowed) device has been erased, the value cannot be read from memory. To set the OSCCAL register on an erased part, add the following line near the beginning of the program: -

OSCCAL = $C0 ' Set OSCCAL register to $C0

The value $C0 is only an example. The part would need to be read before it is erased to obtain the actual OSCCAL value for that particular device.

Always refer to the Microchip data sheets for more information on OSCCAL.


SET

Syntax

SET Variable or Variable.Bit

Availability

All devices.

Overview

Place a variable or bit in a high state. For a variable, this means filling it with 1's. For a bit this means setting it to 1.

Operators

Variable can be any variable or register.

Variable.Bit can be any variable and bit combination.

Example

SET VAR1.3	' Set bit 3 of VAR1

SET VAR1	' Load VAR1 with the value of 255

SET STATUS.0	' Set the carry flag high

Notes

SET does not alter the TRIS register if a PORT is targeted.

See also :	CLEAR, HIGH, LOW.


SHIN

Syntax

SHIN dpin , cpin , mode , [ result { \bits } { ,result { \bits }...} ]

or

Var = SHIN dpin , cpin , mode , shifts

Availability

All devices.

Overview

Shift data in from a synchronous-serial device.

Operators

Dpin is a Port.Pin constant that specifies the I/O pin that will be connected to the synchronous-serial device's data output. This pin's I/O direction will be changed to input and will remain in that state after the instruction is completed.

Cpin is a Port.Pin constant that specifies the I/O pin that will be connected to the synchronous-serial device's clock input. This pin's I/O direction will be changed to output.

Mode is a constant that tells SHIN the order in which data bits are to be arranged and the relationship of clock pulses to valid data. Below are the symbols, values, and their meanings: -

Symbol	Value	Description
MSBPRE  MSBPRE_L	0	Shift data in highest bit first.  Read data before sending clock. Clock idles low
LSBPRE  LSBPRE_L	1	Shift data in lowest bit first.  Read data before sending clock. Clock idles low
MSBPOST  MSBPOST_L	2	Shift data in highest bit first.  Read data after sending clock. Clock idles low
LSBPOST  LSBPOST_L	3	Shift data in highest bit first.  Read data after sending clock. Clock idles low
MSBPRE_H	4	Shift data in highest bit first.  Read data before sending clock. Clock idles high
LSBPRE_H	5	Shift data in lowest bit first.  Read data before sending clock. Clock idles high
MSBPOST_H	6	Shift data in highest bit first.  Read data after sending clock. Clock idles high
LSBPOST_H	7	Shift data in lowest bit first.  Read data after sending clock. Clock idles high

Result is a bit, byte, or word variable in which incoming data bits will be stored.

Bits is an optional constant specifying how many bits (1-16) are to be input by SHIN. If no bits entry is given, SHIN defaults to 8 bits.

Shifts informs the SHIN command as to how many bit to shift in to the assignment variable, when used in the inline format.

Notes

SHIN provides a method of acquiring data from synchronous-serial devices, without resorting to the hardware SPI modules resident on some PICmicro types. Data bits may be valid after the rising or falling edge of the clock line. This kind of serial protocol is commonly used by controller peripherals such as ADCs, DACs, clocks, memory devices, etc.

The SHIN instruction causes the following sequence of events to occur: -

·	Makes the clock pin (cpin) output low.

·	Makes the data pin (dpin) an input.

·	Copies the state of the data bit into the msb(lsb- modes) or lsb(msb modes) either before (-pre modes) or after (-post modes) the clock pulse.

·	Pulses the clock pin high.

·	Shifts the bits of the result left (msb- modes) or right (lsb-modes).

·	Repeats the appropriate sequence of getting data bits, pulsing the clock pin, and shifting the result until the specified number of bits is shifted into the variable.

Making SHIN work with a particular device is a matter of matching the mode and number of bits to that device's protocol. Most manufacturers use a timing diagram to illustrate the relationship of clock and data.

SYMBOL CLK = PORTB.0

SYMBOL DTA = PORTB.1

SHIN DTA , CLK , MSBPRE , [VAR1]	' Shiftin msb-first, pre-clock.

In the above example, both SHIN instructions are set up for msb-first operation, so the first bit they acquire ends up in the msb (leftmost bit) of the variable.

The post-clock Shift in, acquires its bits after each clock pulse. The initial pulse changes the data line from 1 to 0, so the post-clock Shiftin returns %01010101.

By default, SHIN acquires eight bits, but you can set it to shift any number of bits from 1 to 16 with an optional entry following the variable name. In the example above, substitute this for the first SHIN instruction:

SHIN DTA , CLK , MSBPRE , [VAR1 \ 4] 'Shift in 4 bits.

Some devices return more than 16 bits. For example, most 8-bit shift registers can be daisy-chained together to form any multiple of 8 bits; 16, 24, 32, 40... You can use a single SHIN instruction with multiple variables.

Each variable can be assigned a particular number of bits with the

backslash (\) option. Modify the previous example: -

' 5 bits into VAR1; 8 bits into VAR2.

SHIN DTA , CLK , MSBPRE , [ VAR1 \ 5 , VAR2 ]

PRINT "1st variable: " , BIN8 VAR1

PRINT "2nd variable: " , BIN8 VAR2

Inline SHIN Command.

The structure of the INLINE SHIN command is: -

Var = SHIN dpin , cpin , mode , shifts

DPIN, CPIN, and MODE have not changed in any way, however, the INLINE structure has a new operand, namely SHIFTS. This informs the SHIN command as to how many bit to shift in to the assignment variable. For example, to shift in an 8-bit value from a serial device, we would use: -

VAR1 = SHIN DT , CK , MSBPRE , 8

To shift 16-bits into a WORD variable: -

WRD = SHIN DT , CK , MSBPRE , 16

See also : SHOUT


SHOUT

Syntax

SHOUT Dpin, Cpin, Mode, [OutputData {\Bits} {,OutputData {\Bits}..} ]

Availability

All devices.

Overview

Shift data out to a synchronous serial device.

Operators

Dpin is a Port.Pin constant that specifies the I/O pin that will be connected to the synchronous serial device's data input. This pin will be set to output mode.

Cpin is a Port.Pin constant that specifies the I/O pin that will be connected to the synchronous serial device's clock input. This pin will be set to output mode.

Mode is a constant that tells SHOUT the order in which data bits are to be arranged. Below are the symbols, values, and their meanings: -

Symbol	Value	Description

LSBFIRST	0	Shift data out lowest bit first.  Clock idles low

LSBFIRST _L	0	Same as above

MSBFIRST	1	Shift data out highest bit first.  Clock idles low

MSBFIRST_L	1	Same as above

LSBFIRST _H	4	Shift data out lowest bit first.  Clock idles high

MSBFIRST_H	5	Shift data out highest bit first.  Clock idles high

OutputData is a variable, constant, or expression containing the data to be sent.

Bits is an optional constant specifying how many bits are to be output by SHOUT. If no Bits entry is given, SHOUT defaults to 8 bits.

Notes

SHIN and SHOUT provide a method of acquiring data from synchronous serial devices. Data bits may be valid after the rising or falling edge of the clock line. This kind of serial protocol is commonly used by controller peripherals like ADCs, DACs, clocks, memory devices, etc.

At their heart, synchronous-serial devices are essentially shift-registers; trains of flip flops that receive data bits in a bucket brigade fashion from a single data input pin. Another bit is input each time the appropriate edge (rising or falling, depending on the device) appears on the clock line.

The SHOUT instruction first causes the clock pin to output low and the data pin to switch to output mode. Then, SHOUT sets the data pin to the next bit state to be output and generates a clock pulse. SHOUT continues to generate clock pulses and places the next data bit on the data pin for as many data bits as are required for transmission.

Making SHOUT work with a particular device is a matter of matching the mode and number of bits to that device's protocol. Most manufacturers use a timing diagram to illustrate the relationship of clock and data. One of the most important items to look for is which bit of the data should be transmitted first; most significant bit (MSB) or least significant bit (LSB).

Example

SHOUT DTA , CLK , MSBFIRST , [ 250 ]

In the above example, the SHOUT command will write to I/O pin DTA (the Dpin) and will generate a clock signal on I/O CLK (the Cpin). The SHOUT command will generate eight clock pulses while writing each bit (of the 8-bit value 250) onto the data pin (Dpin). In this case, it will start with the most significant bit first as indicated by the Mode value of MSBFIRST.

By default, SHOUT transmits eight bits, but you can set it to shift any number of bits from 1 to 16 with the Bits argument. For example: -

SHOUT DTA , CLK , MSBFIRST , [ 250 \ 4 ]

Will only output the lowest 4 bits (%0000 in this case). Some devices require more than 16 bits. To solve this, you can use a single SHOUT command with multiple values. Each value can be assigned a particular number of bits with the Bits argument. As in: -

SHOUT DTA , CLK , MSBFIRST , [ 250 \ 4 , 1045 \ 16]

The above code will first shift out four bits of the number 250 (%1111) and then 16 bits of the number 1045 (%0000010000010101). The two values together make up a 20 bit value.

See also : SHIN


SNOOZE

Syntax

SNOOZE Period

Availability

All devices.

Overview

Enter sleep mode for a short period. Power consumption is reduced to

about 50 µA assuming no loads are being driven.

Operators

Period is a variable or constant that determines the duration of the reduced power nap. The duration is (2^period) * 18 ms. (Read as "2 raised to the power of 'period', times 18 ms.") Period can range from 0 to 7, resulting in the following snooze lengths:

Period 	Length of SNOOZE

0 - 1 	18ms

1 - 2 	36ms

2 - 4 	72ms

3 - 8 	144ms

4 - 16 	288ms

5 - 32 	576ms

6 - 64 	1152ms (1.152 seconds)

7 - 128 	2304ms (2.304 seconds)

Example

SNOOZE 6	'Low power mode for approx 1.152 seconds

Notes

SNOOZE intervals are directly controlled by the watchdog timer without compensation. Variations in temperature, supply voltage, and manufacturing tolerance of the PICmicro chip you are using can cause the actual timing to vary by as much as -50, +100 percent

See also : SLEEP


SLEEP

Syntax

SLEEP { Length }

Availability

All devices.

Overview

Places the PICmicro into low power mode for approx n seconds. i.e. power down but leaves the port pins in their previous states.

Operators

Length is an optional variable or constant (1-65535) that specifies the duration of sleep in seconds. If length is omitted, then the SLEEP command is assumed to be the assembler mnemonic, which means the PICmicro will sleep continuously, or until the Watchdog timer wakes it up.

Example

SYMBOL LED = PORTA.0

Again:

HIGH LED	' Turn LED on.

DELAYMS 1000	' Wait 1 second.

LOW LED	' Turn LED off.

SLEEP 60	' Sleep for 1 minute.

GOTO Again

Notes

SLEEP will place the PICmicro into a low power mode for the specified period of seconds. Period is 16 bits, so delays of up to 65,535 seconds are the limit (a little over 18 hours) SLEEP uses the Watchdog Timer so it is independent of the oscillator frequency. The smallest units is about 2.3 seconds and may vary depending on specific environmental conditions and the device used.

The SLEEP command is used to put the PICmicro in a low power mode without resetting the registers. Allowing continual program execution upon waking up from the SLEEP period.

Waking the PICmicro from SLEEP

All the PICmicro range have the ability to be placed into a low power mode, consuming micro Amps of current.

The command for doing this is SLEEP. The compiler's SLEEP command or the assembler's SLEEP instruction may be used. The compiler's SLEEP command differs somewhat to the assembler's in that the compiler's version will place the PICmicro into low power mode for n seconds (where n is a value from 0 to 65535). The assembler's version still places the PICmicro into low power mode, however, it does this forever, or until an internal or external source wakes it. This same source also wakes the PICmicro when using the compiler's command.

Many things can wake the PICmicro from its sleep, the WATCHDOG TIMER is the main cause and is what the compiler's SLEEP command uses.

Another method of waking the PICmicro is an external one, a change on one of the port pins. We will examine more closely the use of an external source.

There are two main ways of waking the PICmicro using an external source. One is a change on bits 4..7 of PORTB. Another is a change on bit-0 of PORTB. We shall first look at the wake up on change of PORTB,bits-4..7.

As its name suggests, any change on these pins either high to low or low to high will wake the PICmicro. However, to setup this mode of operation several bits within registers INTCON  and OPTION_REG need to be manipulated. One of the first things required is to enable the weak PORTB pull-up resistors. This is accomplished by clearing the RBPU bit of OPTION_REG (OPTION_REG.7). If this was not done, then the pins would be floating and random input states would occur waking the PICmicro up prematurely.

Although technically we are enabling a form of interrupt, we are not interested in actually running an interrupt handler. Therefore, we must make sure that GLOBAL interrupts are disabled, or the PICmicro will jump to an interrupt handler every time a change occurs on PORTB. This is done by clearing the GIE  bit of INTCON  (INTCON.7).

The interrupt we are concerned with is the RB port change type. This is enabled by setting the RBIE bit of the INTCON  register (INTCON.3). All this will do is set a flag whenever a change occurs (and of course wake up the PICmicro). The flag in question is RBIF, which is bit-0 of the INTCON  register. For now we are not particularly interested in this flag, however, if global interrupts were enabled, this flag could be examined to see if it was the cause of the interrupt. The RBIF flag is not cleared by hardware so before entering SLEEP it should be cleared. It must also be cleared before an interrupt handler is exited.

The SLEEP command itself is then used. Upon a change of PORTB, bits 4..7 the PICmicro will wake up and perform the next instruction (or command) after the SLEEP command was used.

A second external source for waking the PICmicro is a pulse applied to PORTB.0. This interrupt is triggered by the edge of the pulse, high to low or low to high. The INTEDG bit of OPTION_REG (OPTION_REG.6) determines what type of pulse will trigger the interrupt. If it is set, then a low to high pulse will trigger it, and if it is cleared then a high to low pulse will trigger it.

To allow the PORTB.0 interrupt to wake the PICmicro the INTE bit must be set, this is bit-4 of the INTCON  register. This will allow the flag INTF (INTCON.1) to be set when a pulse with the right edge is sensed.

This flag is only of any importance when determining what caused the interrupt. However, it is not cleared by hardware and should be cleared before the SLEEP command is used (or the interrupt handler is exited).

The program below will wake the PICmicro when a change occurs on PORTB, bits 4-7.

XTAL = 4 	' Set Xtal Frequency

SYMBOL LED = PORTB.0 	' Assign the LED's pin

SYMBOL RBIF = INTCON.0	' PORTB[4..7] Change Interrupt Flag

SYMBOL RBIE = INTCON.3	' PORTB[4..7] Change Interrupt Enable

SYMBOL RBPU = OPTION_REG.7 	' PortB pull-ups

SYMBOL GIE = INTCON.7 	' Global interrupt enable/disable

' ** THE MAIN PROGRAM STARTS HERE **

Main:

GIE = 0 	' Turn OFF global interrupts

WHILE GIE = 1 : GIE = 0 : WEND 	' And make sure they are off

TRISB.4 = 1 	' Set PORTB.4 as an Input

RBPU = 0 	' Enable PORTB Pull-up Resistors

RBIE = 1 	' Enable PORTB[4..7] interrupt

Again:

DELAYMS 100

LOW LED 	' Turn off the LED

RBIF = 0 	' Clear the PORTB[4..7] interrupt flag

SLEEP 	' Put the PICmicro to sleep

DELAYMS 100 	' When it wakes up, delay for 100ms

HIGH LED 	' Then light the LED

GOTO Again 	' Do it forever

See also : SNOOZE


SOUND

Syntax

SOUND Pin, [ Note,Duration {,Note,Duration...} ]

Availability

All devices.

Overview

Generates tone and/or white noise on the specified Pin. Pin is automatically made an output.

Operators

Pin is a Port.Pin constant that specifies the output pin on the PICmicro.

Note can be an 8-bit variable or constant. 0 is silence. Notes 1-127 are tones. Notes 128-255 are white noise. Tones and white noises are in ascending order (i.e. 1 and 128 are the lowest frequencies, 127 and 255 are the highest). Note 1 is approx 78.74Hz and Note 127 is approx 10,000Hz.

Duration can be an 8-bit variable or constant that determines how long the Note is played in approx 10ms increments.

Example

' Star Trek The Next Generation...Theme and ship take-off

DEVICE 16F877

XTAL = 4

DIM LOOP AS BYTE

SYMBOL PIN = PORTB.0

THEME:

SOUND PIN, [50,60,70,20,85,120,83,40,70,20,50,20,70,20,90,120,90,20,98,160]

DELAYMS 500

FOR LOOP = 128 TO 255	' Ascending white noises

       	SOUND PIN, [LOOP,2]             	' For warp drive sound

NEXT

SOUND PIN, [43,80,63,20,77,20,71,80,51,20,_

90,20,85,140,77,20,80,20,85,20,_

                    	90,20,80,20,85,60,90,60,92,60,87,_

                    	60,96,70,0,10,96,10,0,10,96,10,0,_

                    	10,96,30,0,10,92,30,0,10,87,30,0,_

                    	10,96,40,0,20,63,10,0,10,63,10,0,_

                    	10,63,10,0,10,63,20]

DELAYMS 10000

GOTO THEME

Notes

With the excellent I/O characteristics of the PICmicro, a speaker can be driven through a capacitor directly from the pin of the PICmicro. The value of the capacitor should be determined based on the frequencies of interest and the speaker load. Piezo speakers can be driven directly.

See also :	FREQOUT, DTMFOUT, SOUND2.


SOUND2

Syntax

SOUND2 Pin2, Pin2, [ Note1\Note2\Duration {,Note1,Note2\Duration...} ]

Availability

14-bit and 16-bit core devices.

Overview

Generate specific notes one on each of the two defined pins.With the SOUND2 command more complex notes can be played by the PICmicro.

Operators

Pin1 and Pin2 are Port.Pin constants that specifies the output pins on the PICmicro.

Note is a variable or constant specifying frequency in hertz (Hz, 0 to 16000) of the tones.

Duration can be a variable or constant that determines how long the Notes are played. In approx 1ms increments (0 to 65535).

Example 1

' Generate a 2500Hz tone and a 3500Hz tone for 1 second.

' The 2500Hz note is played from the first pin specified (PORTB.0),

' and the 3500Hz note is played from the second pin specified (PORTB.1).

DEVICE = 16F877

XTAL = 20

SYMBOL PIN1 = PORTB.0

SYMBOL PIN2 = PORTB.1

SOUND2 PIN1 , PIN2 , [2500 \ 3500 \ 1000]

STOP

Example 2

' Play two sets of notes 2500Hz and 3500Hz for 1 second

' and the second two notes, 2500Hz and 3500Hz for 2 seconds.

DEVICE = 16F877

XTAL = 20

SYMBOL PIN1 = PORTB.0

SYMBOL PIN2 = PORTB.1

SOUND2 PIN1 , PIN2 , [2500 \ 3500 \ 1000 ,  2500 \ 3500 \ 2000 ]

STOP

Notes

SOUND2 generates two pulses at the required frequency one on each pin specified. The SOUND2 command can be used to play tones through a speaker or audio amplifier. SOUND2 can also be used to play more complicated notes.

By generating two frequencies on separate pins, a more defined sound can be produced.

SOUND2 does not require any filtering on the output, and produces a cleaner not than FREQOUT. However, unlike FREQOUT, the note is not a SINE wave. See diagram below: -

See also :	FREQOUT, DTMFOUT, SOUND.


STOP

Syntax

STOP

Availability

All devices.

Overview

STOP halts program execution by sending the PICmicro into an infinite loop.

Example

IF A > 12 THEN STOP

{ code data }

If variable A contains a value greater than 12 then stop program execution. code data will not be executed.

Notes

Although STOP halts the PICmicro in its tracks it does not prevent any code listed in the BASIC source after it being compiled. To do this, use the END command.

See also : END, SLEEP, SNOOZE


STRN

Syntax

STRN Byte Array = Item

Availability

14-bit and 16-bit core devices.

Overview

Load a Byte Array with NULL terminated data, which can be likened to creating a pseudo String variable.

Operators

Byte Array is the variable that will be loaded with values.

Item can be another STRN command, a STR command, STR$ command, or a quoted character string.

Example

' Load the Byte Array STRING1 with NULL terminated characters

INCLUDE "PROTON_4.INC"	' Demonstration based on the PROTON development board

DIM STRING1[21] as BYTE	' Create a Byte array with 21 elements

DELAYMS 200	' Wait for PICmicro to stabilise

CLS	' Clear the LCD

STRN STRING1 = "HELLO WORLD"	' Load STRING1 with characters and NULL terminate it

PRINT STR STRING1	' Display the string

STOP

See also:	STR, STR$.


SWAP

Syntax

SWAP Variable , Variable

Availability

All devices.

Overview

Swap any two variable's values with each other.

Operators

Variable is the value to be swapped

Example

' If Dog = 2 and Cat = 10 then by using the swap command Dog will now equal 10 and Cat will equal 2.

VAR1 = 10	' VAR1 equals 10

VAR2 = 20	' VAR2 equals 20

SWAP VAR1 , VAR2	' VAR2 now equals 20 and VAR1 now equals 10


SYMBOL

Syntax

SYMBOL Name { = } Value

Availability

All devices.

Overview

Assign an alias to a register, variable, or constant value

Operators

Name can be any valid identifier.

Value can be any previously declared variable, system register, or a Register.Bit combination.

The equals '=' symbol is optional, and may be omitted if desired.

When creating a program it can be beneficial to use identifiers for certain values that don't change: -

SYMBOL Meter = 1

SYMBOL Centimetre = 100

SYMBOL Millimetre = 1000

This way you can keep your program very readable and if for some reason a constant changes later, you only have to make one change to the program to change all the values. Another good use of the constant is when you have values that are based on other values.

SYMBOL Meter = 1

SYMBOL Centimetre = Meter / 100

SYMBOL Millimetre = Centimetre / 10

In the example above you can see how the centimetre and millimetre were derived from the Meter.

Another use of the SYMBOL command is for assigning Port.Bit constants: -

SYMBOL LED = PORTA.0

HIGH LED

In the above example, whenever the text LED is encountered, Bit-0 of PORTA is actually referenced.

Floating point constants may also be created using SYMBOL by simply adding a decimal point to a value.

SYMBOL PI = 3.14	' Create a floating point constant named PI

SYMBOL FL_NUM = 5.0	' Create a floating point constant holding the value 5

Floating point constant can also be created using expressions.

SYMBOL QUANTA = 5.0 / 1024	' Create a floating point constant holding the result of the expression

Notes

SYMBOL cannot create new variables, it simply aliases an identifier to a previously assigned variable, or assigns a constant to an identifier.

See also :	DIM, SYMBOLS, ALIASES, ARRAYS, CONSTANTS Floating Point Math.


TOGGLE

Syntax

TOGGLE Port.Bit

Availability

All devices.

Overview

Sets a pin to output mode and reverses the output state of the pin, changing 0 to 1 and 1 to 0.

Operators

Port.Bit can be any valid Port and Bit combination.

Example

HIGH PORTB.0	' Set bit 0 of PORTB high

TOGGLE PORTB.0	' And now reverse the bit

STOP

See also :	HIGH, LOW.


UNPLOT

Syntax

UNPLOT Ypos , Xpos

Availability

14-bit and 16-bit core devices.

Overview

Clear an individual pixel on a 64x128 element graphic LCD.

Operators

Xpos can be a constant, variable, or expression, pointing to the X-axis location of the pixel to clear. This must be a value of 0 to 127. Where 0 is the far left row of pixels.

Ypos can be a constant, variable, or expression, pointing to the Y-axis location of the pixel to clear. This must be a value of 0 to 63. Where 0 is the top column of pixels.

Example

DEVICE 16F877

LCD_TYPE = GRAPHIC 	' Use a Graphic LCD

 	' Graphic LCD Pin Assignments

LCD_DTPORT = PORTD

LCD_RSPIN = PORTC.2

LCD_RWPIN = PORTE.0

LCD_ENPIN = PORTC.5

LCD_CS1PIN = PORTE.1

LCD_CS2PIN = PORTE.2

DIM Xpos as BYTE

ADCON1 = 7	' Set PORTA and PORTE to all digital

' Draw a line across the LCD

Again:

FOR Xpos = 0 TO 127

PLOT 20 , Xpos

DELAYMS 10

NEXT

' Now erase the line

FOR Xpos = 0 TO 127

UNPLOT 20 , Xpos

DELAYMS 10

NEXT

GOTO Again

See also : 	LCDREAD, LCDWRITE, PIXEL, PLOT. See PRINT for circuit.


VARPTR

Syntax

Assignment Variable = VARPTR ( Variable )

Availability

All devices.

Overview

Returns the address of the variable in RAM. Commonly known as a pointer to a variable.

Operators

Assignment Variable can be any of the compiler's variable types, and will receive the pointer to the variable's address.

Variable can be any variable name used in the BASIC program.

Notes

Be careful if using VARPTR to locate the starting address of an array when using a 14-bit device, as arrays can cross bank  boundaries, and the finishing address of the array may be in a different bank to its start address. The compiler can track bank changes internally when accessing arrays, but BASIC code generally cannot. For example, the most common use for VARPTR is when implementing indirect addressing using the PICmicro's FSR, and INDF registers. This is not the case with 16-bit core devices, as the FSR0, 1, and 2 registers can access all memory areas.

See also :  Creating and using Arrays.


WHILE...WEND

Syntax

WHILE Condition

Instructions

Instructions

WEND

or

WHILE Condition { Instructions : } WEND

Availability

All devices.

Overview

Execute a block of instructions while a condition is true.

Example

VAR1 = 1

WHILE VAR1 <= 10

PRINT @VAR1 , " "

VAR1 = VAR1 + 1

WEND

or

WHILE PORTA.0 = 1: WEND	' Wait for a change on the Port

Notes

WHILE-WEND, repeatedly executes Instructions WHILE Condition is true. When the Condition is no longer true, execution continues at the statement following the WEND. Condition may be any comparison expression.

See also : BREAK, RELATIONAL OPERATORS, REPEAT-UNTIL, FOR-NEXT.


MATH OPERATORS

The PROTON+ Compiler performs all math operations in full hierarchal order. Which means that there is precedence to the operators. For example, multiplies and divides are performed before adds and subtracts. To ensure the operations are carried out in the correct order use parenthesis to group the operations: -

A = (( B - C ) * ( D + E )) / F

All math operations are signed or unsigned depending on the variable type used, and performed with 8, 16, or 32-bit integers, or 32-bit floating point precision, again, depending on the variable types and constant values used in the expression.

The operators supported are: -

Addition '+'.	Adds variables and/or constants.

Subtraction '-'.	Subtracts variables and/or constants.

Multiply '*'.	Multiplies variables and/or constants.

Multiply HIGH '**'.	Returns the high 16 bits of the 16-bit multiply result.

Multiply MIDDLE '*/'.	Returns the middle 16 bits of the 16-bit multiply result.

Divide '/'.	Divides variables and/or constants.

Modulus '//'.	Returns the remainder left after dividing one value by another.

Bitwise AND '&'.	Returns the bitwise AND of two values.

Bitwise OR '|'.	Returns the bitwise OR of two values.

Bitwise XOR '^'.	Returns the bitwise XOR of two values.

Bitwise SHIFT LEFT '<<'. Shifts the bits of a value left a specified number of places.

Bitwise SHIFT RIGHT '>>'. Shifts the bits of a value right a specified number of places.

Complement '~'.	Reverses the bits in a variable.

ABS.	Returns the absolute value of a number.

ACOS	Returns the ARC COSINE of a value in RADIANS.

ASIN	Returns the ARC SINE of a value in RADIANS.

ATAN	Returns the ARC TANGENT of a value in RADIANS.

COS.	Returns the COSINE of a value in RADIANS.

DCD.	2 n -power decoder of a four-bit value.

DIG.	Returns the specified decimal digit of a positive value.

EXP	Deduce the exponential function of a value.

LOG	Returns the NATURAL LOG of a value.

LOG10	Returns the LOG of a value.

MAX.	Returns the maximum of two numbers.

MIN.	Returns the minimum of two numbers.

NCD.	Priority encoder of a 16-bit value.

POW	Computes a Variable to the power of anotehr variable or value.

REV.	Reverses the order of the lowest bits in a value.

SIN.	Returns the SINE of a value in RADIANS.

SQR.	Returns the SQUARE ROOT of a value.

TAN	Returns the TANGENT of a value in RADIANS.

DIV32.	15-bit x 31 bit divide. (For Melabs compatability only)


ADD

'+'.

The Addition operator (+) adds variables and/or constants, returning an 8, 16, or 32-bit result. Works exactly as you would expect with signed and unsigned integers. If the result of WORD type addition is larger than 65535, the carry bit may be lost.

DIM Value1 as WORD

DIM Value2 as WORD

Value1 = 1575

Value2 = 976

Value1 = Value1 + Value2 	' Add the numbers.

PRINT @ Value1 	' Display the result

' 32-bit addition

DIM Value1 as WORD

DIM Value2 as DWORD

Value1 = 1575

Value2 = 9763647

Value2 = Value2 + Value1 	' Add the numbers.

PRINT DEC Value1 	' Display the result


SUBTRACT

'-'.

The Subtraction operator (-) subtracts variables and/or constants, returning an 8, 16, or 32-bit result. Works exactly as you would expect with signed and unsigned integers.

DIM Value1 as WORD

DIM Value2 as WORD

Value1 = 1000

Value2 = 999

Value1 = Value1 - Value2 	' Subtract the numbers.

PRINT DEC  Value1 	' Display the result

' 32-bit subtraction

DIM Value1 as WORD

DIM Value2 as DWORD

Value1 = 1575

Value2 = 9763647

Value2 = Value2 - Value1 	' Subtract the numbers.

PRINT DEC  Value1 	' Display the result

' 32-bit signed subtraction

DIM Value1 as DWORD

DIM Value2 as DWORD

Value1 = 1575

Value2 = 9763647

Value1 = Value1 - Value2 	' Subtract the numbers.

PRINT SDEC Value1 	' Display the result


MULTIPLY

'*'.

The Multiply operator (*) multiplies variables and/or constants, returning the result. Works exactly as you would expect with signed or unsigned integers from -2147483648 to +2147483647. If the result of multiplication is larger than 2147483647, the excess bits will be lost.

DIM Value1 as WORD

DIM Value2 as WORD

Value1 = 1000

Value2 = 19

Value1 = Value1 * Value2 	' Multiply Value1 by Value2.

PRINT DEC  Value1 	' Display the result

' 32-bit multiplication

DIM Value1 as WORD

DIM Value2 as DWORD

Value1 = 100

Value2 = 10000

Value2 = Value2 * Value1 	' Multiply the numbers.

PRINT DEC  Value1 	' Display the result

Note that multiply will not produce the correct result if two DWORD variables both hold negative values.

See also : DIV32.


MULTIPLY HIGH

'**'.

The Multiply High operator (**) multiplies 8 or 16-bit variables and/or constants, returning the high 16 bits of the result. When multiplying two 16-bit values, the result can be as large as 32 bits. Since the largest variable supported by the compiler is 16-bits, the highest 16 bits of a 32-bit multiplication result are normally lost. The ** (double-star) operand produces these upper 16 bits.

For example, suppose 65000 ($FDE8) is multiplied by itself. The result is 4,225,000,000 or $FBD46240. The * (star, or normal multiplication) instruction would return the lower 16 bits, $6240. The ** instruction returns $FBD4.

DIM Value1 as WORD

DIM Value2 as WORD

Value1 = $FDE8

Value2 = Value1 ** Value1	 	' Multiply $FDE8 by itself

PRINT HEX Value2 	' Return high 16 bits.

Notes.

This operand enables compatibility with BASIC STAMP code, and melab's compiler code, but is rather obsolete considering the 32-bit capabilities of the PROTON+ compiler.

See also : DIV32.


MULTIPLY MIDDLE

'*/'.

The Multiply Middle operator (*/) multiplies variables and/or constants, returning the middle 16 bits of the 32-bit result. This has the effect of multiplying a value by a whole number and a fraction. The whole number is the upper byte of the multiplier (0 to 255 whole units) and the fraction is the lower byte of the multiplier (0 to 255 units of 1/256 each). The */ operand allows a work around for the compiler's integer-only math.

Suppose we are required to multiply a value by 1.5. The whole number, and therefore the upper byte of the multiplier, would be 1, and the lower byte (fractional part) would be 128, since 128/256 = 0.5. It may be clearer to express the */ multiplier in HEX as $0180, since hex keeps the contents of the upper and lower bytes separate. Here's an example:

DIM Value1 as WORD

Value1 = 100

Value1 = Value1 */ $0180 	' Multiply by 1.5 [1 + (128/256)]

PRINT DEC Value1 	' Show result (150).

To calculate constants for use with the */ instruction, put the whole number portion in the upper byte, then use the following formula for the value of the lower byte: -

INT(fraction * 256)

For example, take Pi (3.14159). The upper byte would be $03 (the whole number), and the lower would be INT(0.14159 * 256) = 36 ($24). So the constant Pi for use with */ would be $0324. This isn't a perfect match for Pi, but the error is only about 0.1%.

Notes.

This operand enables compatibility with BASIC STAMP code, and melab's compiler code, but is rather obsolete considering the 32-bit capabilities of the PROTON+ compiler.

See also : DIV32.


DIVIDE

'/'.

The Divide operator (/) divides variables and/or constants, returning an 8, 16, or 32-bit result depending on the variable/constant  sizes used. Works exactly as you would expect with signed or unsigned integers from -2147483648 to +2147483647.

DIM Value1 as WORD

DIM Value2 as WORD

Value1 = 1000

Value2 = 5

Value1 = Value1 / Value2 	' Divide the numbers.

PRINT DEC Value1 	' Show the result (200).

' 32-bit division

DIM Value1 as WORD

DIM Value2 as DWORD

Value1 = 100

Value2 = 10000

Value2 = Value2 / Value1 	' Divide the numbers.

PRINT DEC  Value1 	' Display the result

See also : DIV32.


MODULUS

'//'.

The Modulus operator (//) returns the remainder left after dividing one value by another. Some division problems don't have a whole-number result; they return a whole number and a fraction. For example, 1000/6 = 166.667. Integer math doesn't allow the fractional portion of the result, so 1000/6 = 166. However, 166 is an approximate answer, because 166*6 = 996. The division operation left a remainder of 4. The // returns the remainder of a given division operation. Numbers that divide evenly, such as 1000/5, produce a remainder of 0: -

DIM Value1 as WORD

DIM Value2 as WORD

Value1 = 1000

Value2 = 6

Value1 = Value1 // Value2 	' Get remainder of Value1 / Value2.

PRINT DEC  Value1 	' Show the result (4).

' 32-bit modulus

DIM Value1 as WORD

DIM Value2 as DWORD

Value1 = 100

Value2 = 99999

Value2 = Value2 // Value1 	' mod the numbers.

PRINT DEC  Value1 	' Display the result

See also : DIV32.


BITWISE AND

'&'.

The And operator (&) returns the bitwise AND of two values. Each bit of the values is subject to the following logic: -

0 AND 0 = 0

0 AND 1 = 0

1 AND 0 = 0

1 AND 1 = 1

The result returned by & will contain 1s in only those bit positions in which both input values contain 1s: -

DIM Value1 as BYTE

DIM Value2 as BYTE

DIM Result as BYTE

Value1 = %00001111

Value2 = %10101101

Result = Value1 & Value2

PRINT BIN Result 	' Display AND result (%00001101)

or

PRINT BIN ( %00001111 & %10101101 ) 	' Display AND result (%00001101)

Bitwise operations are not permissible with floating point values or variables.


BITWISE OR

'|'.

The OR operator (|) returns the bitwise OR of two values. Each bit of the values is subject to the following logic: -

0 OR 0 = 0

0 OR 1 = 1

1 OR 0 = 1

1 OR 1 = 1

The result returned by | will contain 1s in any bit positions in which one or the other (or both) input values contain 1s: -

DIM Value1 as BYTE

DIM Value2 as BYTE

DIM Result as BYTE

Value1 = %00001111

Value2 = %10101001

Result = Value1 | Value2

PRINT BIN Result 	' Display OR result (%10101111)

or

PRINT BIN ( %00001111 | %10101001 ) 	' Display OR result (%10101111)

Bitwise operations are not permissible with floating point values or variables.


BITWISE XOR

'^'.

The Xor operator (^) returns the bitwise XOR of two values. Each bit of the values is subject to the following logic: -

0 XOR 0 = 0

0 XOR 1 = 1

1 XOR 0 = 1

1 XOR 1 = 0

The result returned by ^ will contain 1s in any bit positions in which one or the other (but not both) input values contain 1s: -

DIM Value1 as BYTE

DIM Value2 as BYTE

DIM Result as BYTE

Value1 = %00001111

Value2 = %10101001

Result = Value1 ^ Value2

PRINT BIN Result 	' Display XOR result (%10100110)

or

PRINT BIN ( %00001111 ^ %10101001 ) 	' Display XOR result (%10100110)

Bitwise operations are not permissible with floating point values or variables.


BITWISE SHIFT LEFT

'<<'.

Shifts the bits of a value to the left a specified number of places. Bits shifted off the left end of a number are lost; bits shifted into the right end of the number are 0s. Shifting the bits of a value left n number of times also has the effect of multiplying that number by two to the nth power.

For example 100 << 3 (shift the bits of the decimal number 100 left three places) is equivalent to 100 * 23.

DIM Value1 as WORD

DIM Loop as BYTE

Value1 = %1111111111111111

FOR Loop = 1 TO 16 	' Repeat with b0 = 1 to 16.

PRINT BIN Value1  << Loop 	' Shift Value1 left Loop places.

NEXT

Bitwise operations are not permissible with floating point values or variables.


BITWISE SHIFT RIGHT

 '>>'.

Shifts the bits of a variable to the right a specified number of places. Bits shifted off the right end of a number are lost; bits shifted into the left end of the number are 0s. Shifting the bits of a value right n number of times also has the effect of dividing that number by two to the nth power.

For example 100 >> 3 (shift the bits of the decimal number 100 right three places) is equivalent to 100 / 23.

DIM Value1 as WORD

DIM Loop as BYTE

Value1 = %1111111111111111

FOR Loop = 1 TO 16 	' Repeat with b0 = 1 to 16.

PRINT BIN Value1 >> Loop 	' Shift Value1 right Loop places.

NEXT

Bitwise operations are not permissible with floating point values or variables.


COMPLEMENT

'~'.

The Complement operator (~) Complements (inverts) the bits of a number. Each bit that contains a 1 is changed to 0 and each bit containing 0 is changed to 1. This process is also known as a "bitwise NOT".

DIM Value1 as WORD

DIM Value2 as WORD

Value2 = %1111000011110000

Value1 = ~Value2 	' Complement Value2.

PRINT  BIN16 Value1 	' Display the result

Complementing can be carried out with all variable types except FLOATs. Attempting to complement a floating point variable will produce a syntax error.


ABS

Returns the absolute value of a number. If a byte is greater than 127 (high bit set), ABS will return 256 - value. If a word is greater than 32767 (high bit set), ABS will return 65536 - value. Its syntax is: -

VAR1 = ABS VAR2

Example

DEVICE = 16F877

DIM DWD1 AS DWORD	' Declare a DWORD variable

DIM DWD2 AS DWORD	' Declare a DWORD variable

CLS

DWD1 = -1234567	' Load DWD1 with value -1234567

DWD2 = ABS DWD1	' Extract the absolute value from DWD1

PRINT DEC DWD2	' Display the result, which is 1234567

STOP

Floating Point example

DEVICE = 16F877

DIM FLP1 AS FLOAT	' Declare a FLOAT variable

DIM FLP2 AS FLOAT	' Declare a FLOAT variable

CLS

FLP1 = -1234567	' Load FLP1 with value -1234567.123

FLP2 = ABS FLP1	' Extract the absolute value from FLP1

PRINT DEC FLP2	' Display the result, which is 1234567.123

STOP


COS

Syntax

Assignment Variable = COS Variable

Overview

Deduce the  Cosine of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the COSINE extracted. The value expected and returned by COS is in RADIANS.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to COS with

DIM FLOATOUT AS FLOAT	' Holds the result of the COS

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 123	' Load the variable

FLOATOUT = COS FLOATIN	' Extract the COS of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

With 12, and 14-bit core devices, COS returns the 8-bit cosine of a value, compatible with the BASIC Stamp syntax. The result is in two's complement form (i.e. -127 to 127). COS starts with a value in binary radians, 0 to 255, instead of the customary 0 to 359 degrees.

However, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point COSINE is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, EXP, LOG, LOG10, POW, SIN, SQR, TAN.


DCD

2 n -power decoder of a four-bit value. DCD accepts a value from 0 to 15, and returns a 16-bit number with that bit number set to 1. For example: -

WRD1= DCD 12 	' Set bit 12.

PRINT BIN16 WRD1	' Display result (%0001000000000000)

Note.

DCD does not (as yet) support DWORD, or FLOAT type variables. Therefore the highest value obtainable is 65535.


DIG

In this form, the DIG operator is compatible with the BASIC STAMP, and the melab's PICBASIC PRO compiler. DIG returns the specified decimal digit of a 16-bit positive value. Digits are numbered from 0 (the rightmost digit) to 4 (the leftmost digit of a 16- bit number; 0 to 65535). Example:

WRD1= 9742

PRINT WRD1 DIG 2 	' Display digit 2 (7)

FOR Loop = 0 TO 4

PRINT WRD1 DIG Loop 	' Display digits 0 through 4 of 9742.

NEXT

Note.

This version of DIG does not support DWORD, or FLOAT type variables, in order to keep compatability with the STAMP, and Melabs. If a DWORD DIG operation is required, use the DIG command instead.


EXP

Syntax

Assignment Variable = EXP Variable

Overview

Deduce the exponential function of a value. This is e to the power of value where e is the base of natural logarithms. EXP 1 is 2.7182818.

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to EXP with

DIM FLOATOUT AS FLOAT	' Holds the result of the EXP

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 1	' Load the variable

FLOATOUT = EXP FLOATIN	' Extract the EXP of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

EXP is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point exponentials are implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, LOG, LOG10, POW, SIN, SQR, TAN.


MAX

Returns the maximum of two numbers. Its use is to limit numbers to a specific value. Its syntax is: -

VAR2 = VAR1 MAX 100 	' Set VAR2 to the larger of VAR1 and 100 (VAR2 will lie between values ' 100 and 255)

Note.

MAX does not (as yet) support DWORD, or FLOAT type variables. Therefore the highest value obtainable is 65535.


MIN

Returns the minimum of two numbers. Its use is to limit numbers to a specific value. Its syntax is: -

VAR2 = VAR1 MIN 100 	' Set VAR2 to the smaller of VAR1 and 100 (VAR2 cannot be greater ' than 100)

Note.

MIN does not (as yet) support DWORD, or FLOAT type variables. Therefore the highest value obtainable is 65535.


NCD

Priority encoder of a 16-bit value. NCD takes a 16-bit value, finds the highest bit containing a 1 and returns the bit position plus one (1 through 16). If no bit is set, the input value is 0. NCD returns 0. NCD is a fast way to get an answer to the question "what is the largest power of two that this value is greater than or equal to?" The answer that NCD returns will be that power, plus one. Example: -

WRD1= %1101 	' Highest bit set is bit 3.

PRINT DEC NCD WRD1	' Display the NCD of WRD1(4).

Note.

NCD does not (as yet) support DWORD, or FLOAT type variables.


REV

Reverses the order of the lowest bits in a value. The number of bits to be reversed is from 1 to 32. Its syntax is: -

VAR1 = %10101100 REV 4 	' Sets VAR1 to %10100011

or

DIM DWD AS DWORD

DWD = %10101010000000001111111110101100 REV 4 ' Sets DWD to %10101010000000001111111110100011


SIN

Syntax

Assignment Variable = SIN Variable

Overview

Deduce the  Sine of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the SINE extracted. The value expected and returned by SIN is in RADIANS.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to SIN

DIM FLOATOUT AS FLOAT	' Holds the result of the SIN

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 123	' Load the variable

FLOATOUT = SIN FLOATIN	' Extract the SIN of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

With 12, and 14-bit core devices, SIN returns the 8-bit sine of a value, compatible with the BASIC Stamp syntax. The result is in two's complement form (i.e. -127 to 127). SIN starts with a value in binary radians, 0 to 255, instead of the customary 0 to 359 degrees.

However, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point SINE is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, EXP, LOG, LOG10, POW, SQR, TAN.


ATAN

Syntax

Assignment Variable = ATAN Variable

Overview

Deduce the  Arc Tangent of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the ARC TANGENT (Inverse Tangent) extracted. The value expected and returned by the floating point ATAN is in RADIANS.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to ATAN

DIM FLOATOUT AS FLOAT	' Holds the result of the ATAN

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 1	' Load the variable

FLOATOUT = ATAN FLOATIN	' Extract the ATAN of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

ATAN is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point ARC TANGENT is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, COS, EXP, LOG, LOG10, POW, SIN, SQR, TAN.


ASIN

Syntax

Assignment Variable = ASIN Variable

Overview

Deduce the  Arc Sine of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the ARC SINE (Inverse Sine) extracted. The value expected and returned by ASIN is in RADIANS. The value must be in the range of -1 to +1

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to ASIN

DIM FLOATOUT AS FLOAT	' Holds the result of the ASIN

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 0.8	' Load the variable

FLOATOUT = ASIN FLOATIN	' Extract the ASIN of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

ASIN is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point ARC SINE is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also: ACOS, COS, EXP, LOG, LOG10, POW, SIN, SQR, TAN.


TAN

Syntax

Assignment Variable = TAN Variable

Overview

Deduce the  Tangent of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the TANGENT extracted. The value expected and returned by the floating point TAN is in RADIANS.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to TAN

DIM FLOATOUT AS FLOAT	' Holds the result of the TAN

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 1	' Load the variable

FLOATOUT = TAN FLOATIN	' Extract the TAN of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

TAN is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point TANGENT is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, EXP, LOG, LOG10, SIN, SQR.


ACOS

Syntax

Assignment Variable = ACOS Variable

Overview

Deduce the  Arc Cosine of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the ARC COSINE (Inverse Cosine) extracted. The value expected and returned by the floating point ACOS is in RADIANS. The value must be in the range of -1 to +1

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to ACOS

DIM FLOATOUT AS FLOAT	' Holds the result of the ACOS

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 0.8	' Load the variable

FLOATOUT = ACOS FLOATIN	' Extract the ACOS of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

ACOS is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point ARC COSINE is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also: ASIN, COS, EXP, LOG, LOG10, SIN, SQR, TAN.


LOG

Syntax

Assignment Variable = LOG Variable

Overview

Deduce the  Natural Logarithm a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the NATURAL LOGARITHM extracted.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to LOG with

DIM FLOATOUT AS FLOAT	' Holds the result of the LOG

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 1	' Load the variable

FLOATOUT = LOG FLOATIN	' Extract the LOG of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

LOG is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point NATURAL LOGARITHMS are implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, EXP, LOG10, POW, SIN, SQR, TAN.


LOG10

Syntax

Assignment Variable = LOG10 Variable

Overview

Deduce the  Logarithm a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the LOGARITHM extracted.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM FLOATIN AS FLOAT	' Holds the value to LOG10 with

DIM FLOATOUT AS FLOAT	' Holds the result of the LOG10

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 1	' Load the variable

FLOATOUT = LOG10 FLOATIN	' Extract the LOG10 of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

LOG10 is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point LOGARITHMS are implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, EXP, LOG, POW, SIN, SQR, TAN.


SQR

Syntax

Assignment Variable = SQR Variable

Overview

Deduce the  Square Root of a value

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression that requires the SQUARE ROOT extracted.

Notes

With 12, and 14-bit core devices, SQR returns an integer square root of a value, compatible with the BASIC Stamp syntax. Remember that most square roots have a fractional part that the compiler discards in doing its integer-only math. Therefore it computes the square root of 100 as 10 (correct), but the square root of 99 as 9 (the actual is close to 9.95). Example: -

VAR1 = SQR VAR2

or

PRINT SQR 100 	' Display square root of 100 (10).

PRINT SQR 99	' Display of square root of 99 (9 due to truncation)

However, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point SQR is implemented.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DIM FLOATIN AS FLOAT	' Holds the value to SQR

DIM FLOATOUT AS FLOAT	' Holds the result of the SQR

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

FLOATIN = 600	' Load the variable

FLOATOUT = SQR FLOATIN	' Extract the SQR of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, EXP, LOG, LOG10, POW, SIN, SQR, TAN.


POW

Syntax

Assignment Variable = POW Variable , Pow Variable

Overview

Computes Variable to the power of Pow Variable.

Operators

Assignment Variable can be any valid variable type.

Variable can be a constant, variable or expression.

Pow Variable can be a constant, variable or expression.

Example

INCLUDE "PROTON18_4.INC"	' Use the PROTON board for the demo

DEVICE = 18F452	' Choose a 16-bit core device

DIM POW_OF as FLOAT

DIM FLOATIN as FLOAT	' Holds the value to POW with

DIM FLOATOUT as FLOAT	' Holds the result of the POW

DELAYMS 500	' Wait for the PICmicro to stabilise

CLS	' Clear the LCD

POW_OF = 10

FLOATIN = 2	' Load the variable

FLOATOUT = POW FLOATIN,POW_OF	' Extract the POW of the value

PRINT DEC FLOATOUT	' Display the result

STOP

Notes

POW is not implemented with 12, or 14-bit core devices, however, with the extra functionality, and more linear memory offered by the 16-bit core devices, full 32-bit floating point power of is implemented.

Floating point trigonometry is extremely memory hungry, so do not be surprised if a large chunk of the PICmicro is used with a single operator. This also means that floating point trigonometry is comparatively slow to operate.

When using floating point Trigonometry, the key to success is keeping it simple. Trigonometry is supported in expressions, but the compiler is happier if each TRIG function is implemented in a simple assigmnent, such as the one above, then the result acted upon accordingly.

See also:  ACOS, ASIN, ATAN, COS, EXP, LOG,  LOG10, SIN, SQR, TAN.


DIV32

In order to make the PROTON+ compiler more compatible with code produced for the melab's PICBASIC PRO compiler, the DIV32 operator has been added. The melab's compiler's multiply operand operates as a 16-bit x 16-bit multiply, thus producing a 32-bit result. However, since the compiler only supports a maximum variable size of 16 bits (WORD), access to the result had to happen in 2 stages: -

Var = VAR1 * VAR2 returns the lower 16 bits of the multiply

while…

Var = VAR1 ** VAR2 returns the upper 16 bits of the multiply

There was no way to access the 32-bit result as a valid single value.

In many cases it is desirable to be able to divide the entire 32-bit result of the multiply by a 16-bit number for averaging, or scaling. DIV32 is actually limited to dividing a 31-bit unsigned integer (0 - 2147483647) by a 15-bit unsigned integer (0 - 32767). This ought to be sufficient in most situations.

Because the melab's compiler only allows a maximum variable size of 16 bits (0 - 65535), DIV32 relies on the fact that a multiply was performed just prior to the DIV32 command, and that the internal compiler variables still contain the 32-bit result of the multiply. No other operation may occur between the multiply and the DIV32 or the internal variables may be altered, thus destroying the 32-bit multiplication result.

The following example demonstrates the operation of DIV32:

DIM WRD1 AS WORD

DIM WRD2 AS WORD

DIM WRD3 AS WORD

DIM Fake AS WORD	' Must be a WORD type variable for result

WRD2 = 300

WRD3 = 1000

Fake = WRD2 * WRD3 	' Operators ** or */ could also be used instead

WRD1= DIV32 100

PRINT DEC WRD1

The above program assigns WRD2 the value 300 and WRD3 the value 1000. When multiplied together, the result is 300000. However, this number exceeds the 16-bit word size of a variable (65535). Therefore, the dummy variable, FAKE, contains only the lower 16 bits of the result. DIV32 uses the compiler's internal (SYSTEM) variables as the operands.

Notes.

This operand enables a certain compatibility with melab's compiler code, but is rather obsolete considering the 32-bit, and floating point capabilities of the PROTON+ compiler.

See also : DIVIDE, MULTIPLY, MULTIPLY HIGH, MULTIPLY MIDDLE.


USBINIT

Syntax

USBINIT

Availability

14-bit core devices.

Overview

Initialise the USB hardware of the PICmicro MCU and wait until the USB bus is configured and enabled. This instruction may only be used with a PICmicro that has an on-chip USB port such as the PIC16C745 or PIC16C765.

Notes

USBINIT needs to be one of the first statements in a program that uses USB communications.

USB communications is a whole lot more complicated than synchronous (SHIN and SHOUT) and asynchronous (SERIN, SEROUT etc) communications. There is much more to know about USB operation that can possibly be described in this help file, as whole books have been written dealing with USB.

The USB subdirectory, located in the INC folder, contains the Microchip USB libraries modified for the PROTON+ Compiler. USB programs require several additional files to operate correctly, some of which may require modification for your particular application.  The files in the USB subdirectory are: -

        HIDCLASS.ASM    	Modified Microchip HID class assembler file

        MOUSDESC.ASM    	Descriptor file for mouse demo

        USB_CH9.ASM     	Modified Microchip USB chapter 9 assembler file

        USB_DEFS.INC    	Modified Microchip USB definitions file

        USB-UGV1.PDF   	Microchip USB PDF file

The modifications involved removing any linker specific operands, includes to header files and END instructions. Label names that were the same except for the case have been changed to make them unique. Variable names now have a preceding underscore to help prevent duplicate variable errors in the BASIC program.

A USB program consists of the BASIC source code along with the appropriate USB files, including HIDCLASS.ASM, USB_CH9.ASM, USB_DEFS.INC and a USB descriptor file. The BASIC program must setup an assembler interrupt handler, as most USB operations are handled by interrupts.

When the compiler sees that a PIC16C745 or PIC16C765 is required, it will automatically include the required Microchip files into the BASIC program. However, a DESCRIPTOR file must be created and loaded into the BASIC program. This is done by a DECLARE: -

DECLARE USB_DESCRIPTOR "FILENAME"

The above DECLARE will load the appropriate DESCRIPTOR file for use with the USB routines. The descriptor file may be in the BASIC program's directory, or located in the USB directory (found in the INC folder). The compiler will first look in the BASIC program's directory, and if the file is there, it will use that, otherwise, it will look in the USB directory. This allows descriptors with the same name to have unique features. If the file named in the DECLARE is not found, then an error will be produced.

There are three other DECLARES that may be used when implementing USB. These are: -

DECLARE USB_CLASS_FILE = "FILENAME"	' Point to the CLASS file

This DECLARE points to the CLASS file required. Not all USB operation use the HID class, some use a more efficient and unique communications method. However, the PICmicro is really only intended for HID class, slow speed communications, so this DECLARE may be omitted from the program, and the HIDCLASS.ASM file will automatically be loaded.

DECLARE USB_COUNT_ERRORS  TRUE/FALSE ON/OFF 1 or 0

The USB routines supplied by Microchip have some error detection pointers built into the software. The above DECLARE enables or disables these. To use the error pointers, the following ALIAS's should be created at the top of the BASIC program: -

SYMBOL USB_WRITE_ERROR = _USB_WRT_ERR.WORD

SYMBOL USB_BTO_ERROR = _USB_BTO_ERR.WORD

SYMBOL USB_OWN_ERROR = _USB_OWN_ERR.WORD

SYMBOL USB_BTS_ERROR = _USB_BTS_ERR.WORD

SYMBOL USB_DFN8_ERROR = _USB_DFN8_ERR.WORD

SYMBOL USB_CRC16_ERROR = _USB_CRC16_ERR.WORD

SYMBOL USB_CRC5_ERROR = _USB_CRC5_ERR.WORD

SYMBOL USB_PID_ERROR = _USB_PID_ERR.WORD

DECLARE USB_SHOW_ENUM  TRUE/FALSE ON/OFF 1 or 0

The Microchip USB routines can indicate the state of the bus by means of LED's attached to PORTB of the PICmicro. The above DECLARE enables or disables this feature.

USB Code and Memory Concerns.

The Microchip USB routines occupy the whole of PAGE3 within the PICmicro, and also require several RAM spaces. The variable names used by the USB routines are listed below. Make sure you do not use the same variables names in the BASIC program, or a duplicate variable error will be produced: -

_BUFFER_DESCRIPTOR

_BUFFER_DESCRIPTOR#1

_BUFFER_DESCRIPTOR#2

_BUFFER_DATA

_BUFFER_DATA#1

_BUFFER_DATA#2

_BUFFER_DATA#3

_BUFFER_DATA#4

_BUFFER_DATA#5

_BUFFER_DATA#6

_BUFFER_DATA#7

_USBMASKEDINTERRUPTS

_USB_CURR_CONFIG

_USB_STATUS_DEVICE

_USB_DEV_REQ

_USB_ADDRESS_PENDING

_USBMASKEDERRORS

_PIDS

EP0_START

EP0_STARTH

_EP0_END

_EP0_MAXLENGTH

TEMP

TEMP2

_GP_TEMP

_BUF_INDEX

_USB_INTERFACE

_USB_INTERFACE#1

_USB_INTERFACE#2

_USB_INNER

_USB_OUTER

_DEST_PTR

_SOURCE_PTR

_HID_DEST_PTR

_HID_SOURCE_PTR

_USB_COUNTER

_BYTE_COUNTER

_RP_SAVE

_IS_IDLE

_USB_USTAT

_USB_PID_ERR

_USB_PID_ERRH

_USB_CRC5_ERR

_USB_CRC5_ERRH

_USB_CRC16_ERR

_USB_CRC16_ERRH

_USB_DFN8_ERR

_USB_DFN8_ERRH

_USB_BTO_ERR

_USB_BTO_ERRH

_USB_WRT_ERR

_USB_WRT_ERRH

_USB_OWN_ERR

_USB_OWN_ERRH

_USB_BTS_ERR

_USB_BTS_ERRH

The USB information on the Microchip web site needs to be studied carefully. Also, the books "USB Complete", and "USB by example" may be helpful.

See also :	USBOUT, USBIN for an example and circuit..


USBIN

Syntax

USBIN Endpoint, Buffer, Countvar, Label

Availability

14-bit core devices.

Overview

Receive USB data from the host computer and place it into Buffer.

Operators

Endpoint is a constant value (0 - 2) that indicates which ENDPOINT to receive data from.

Buffer is a BYTE array consisting of no more than 8 elements. The USB adopted by the PICmicro, only allows 8 pieces of data to be received in a single operation.

Countvar is a constant value (2 - 8) that indicates how many bytes are transferred from the Buffer.

Label must be a valid BASIC label, that USBIN will jump to in the event that no data is available.

Example 1

DIM BUFFER[8] AS BYTE

TRY_AGAIN:

USBIN 1, BUFFER, 4, TRY_AGAIN

Example 2

' Program to demonstrate the USB commands

' Moves the computer's cursor in a small square

DEVICE =  16C765

XTAL = 24

USB_DESCRIPTOR = "MOUSDESC.ASM"	' Point to the DESCRIPTOR file

USB_CLASS_FILE = "HIDCLASS.ASM"	' Point to the CLASS file (not always required)

USB_COUNT_ERRORS = False	' Enable/Disable error monitors

USB_SHOW_ENUM = False	' Enable/Disable PORTB monitor

DIM BUFFER[8] AS Byte

DIM LOOPCNT AS Byte

DIM DIRECTION AS	 Byte

SYMBOL LED = PORTA.5	' Red LED on PORTA bit 5

' Define the hardware interrupt handler for the USB vector

ON_INTERRUPT GOTO USBINT

'-----------------------------------------------------------------------------------

        GOTO START              	' Jump over the interrupt handler

'-----------------------------------------------------------------------------------

' Assembly language interrupt handler to check interrupt source and vector to it

USBINT:

MOVLW (Service@USBInt >> 8)

MOVWF PCLATH	' Point PCLATH to the USB subroutines

BTFSC PIR1, USBIF	' Make sure it is a USB interrupt

CALL (Service@USBInt)	' Implement the USB subroutines

CONTEXT RESTORE	' Restore saved registers

'-----------------------------------------------------------------------------------

' *** THE MAIN PROGRAM LOOP STARTS HERE ***

START:

ALL_DIGITAL = True	' Make PORTA, and PORTE all digital

LOW LED

USBINIT	' Initialise USB and wait until configured

HIGH LED	' Turn on LED for USB ready

STR BUFFER = 0,0,0,0,0,0,0,0	' Clear the buffer array

' Move the computer's cursor in a small square

MOVECURSOR:

DIRECTION = 0

REPEAT

LOOPCNT = 0

REPEAT

IF DIRECTION = 0 THEN BUFFER#1 = 0 : BUFFER#2 = -2 : GOTO SENDIT

IF DIRECTION = 1 THEN BUFFER#1 = -2 : BUFFER#2 = 0 : GOTO SENDIT

IF DIRECTION = 2 THEN BUFFER#1 = 0 : BUFFER#2 = 2 : GOTO SENDIT

IF DIRECTION = 3 THEN BUFFER#1 = 2 : BUFFER#2 = 0

SENDIT:	USBOUT 1, BUFFER, 4, SENDIT  ' Send BUFFER to endpoint 1

INC LOOPCNT

UNTIL LOOPCNT = 16	' 16 steps in each direction

INC DIRECTION

UNTIL DIRECTION = 4

GOTO MOVECURSOR	' Do it forever

A suitable circuit for the above example is shown below: -

Notes

USB communications is a whole lot more complicated than synchronous (SHIN and SHOUT) and asynchronous (SERIN, SEROUT etc) communications. There is much more to know about USB operation that can possibly be described in this help file, as whole books have been written dealing with USB.

The USB information on the Microchip web site needs to be studied carefully. Also, the books "USB Complete", and "USB by example" may be helpful.

See also :	USBINIT, USBOUT.


USBOUT

Syntax

USBOUT Endpoint, Buffer, Countvar, Label

Availability

14-bit core devices.

Overview

Take Countvar number of bytes from the array variable Buffer and send them to the USB Endpoint.

Operators

Endpoint is a constant value (0 - 2) that indicates which ENDPOINT to send data to.

Buffer is a BYTE array consisting of no more than 8 elements. The USB adopted by the PICmicro, only allows 8 pieces of data to be sent in a single operation.

Countvar is a constant value (2 - 8) that indicates how many bytes are transferred to the Buffer.

Label must be a valid BASIC label, that USBOUT will jump to in the event that the USB buffer does not have room for the data because of a pending transmission.

Example

DIM BUFFER[8] AS BYTE

TRY_AGAIN:

USBOUT 1, BUFFER, 4, TRY_AGAIN

Notes

The USB subdirectory contains modified Microchip USB libraries. USB programs requires several additional files to operate, some of which will require modification for your particular application. See the text file in the USB subdirectory for more information on the USB commands.

USB communications is a whole lot more complicated than synchronous (SHIN and SHOUT) and asynchronous (SERIN, SEROUT etc) communications. There is much more to know about USB operation that can possibly be described in this help file, as whole books have been written dealing with USB.

The USB information on the Microchip web site needs to be studied carefully. Also, the books "USB Complete", and "USB by example" may be helpful.

See also :	USBINIT, USBIN for an example and circuit.


XIN

Syntax

XIN DataPin , ZeroPin , {Timeout , Timeout Label} , [Variable{,...}]

Availability

14-bit and 16-bit core devices.

Overview

Receive X-10 data and store the House Code and Key Code in a variable.

Operators

DataPin is a constant (0 - 15), port.bit, or variable, that receives the data from an X-10 interface. This pin is automatically made an input to receive data, and should be pulled up to 5 Volts with a 4.7K Ohm resistor.

ZeroPin is a constant (0 - 15), port.bit, or variable,  that is used to synchronise to a zero-cross event. This pin is automatically made an input to received the zero crossing timing, and should also be pulled up to 5 Volts with a 4.7K Ohm resistor.

Timeout is an optional value that allows program continuation if X-10 data is not received within a certain length of time. Timeout is specified in AC power line half-cycles (approximately 8.33 milliseconds).

Timeout Label is where the program will jump to upon a timeout.

Example

DIM HOUSEKEY AS WORD

CLS

LOOP:

XIN PORTA.2 , PORTA.0 , 10 , NODATA , [HOUSEKEY]	' Receive X-10 data,go to NODATA if none

' Display X-10 data on an LCD

PRINT AT 1 , 1 , "House=" , @HOUSEKEY.BYTE1 , "Key=" , @HOUSEKEY.BYTE0

GOTO LOOP	' Do it forever

NODATA:

PRINT "NO DATA"

STOP

XOUT and XIN Declares

In order to make the XIN command's results more in keeping with the BASIC Stamp interpreter,  two declares have been included for both XIN and XOUT. These are.

DECLARE XOUT_TRANSLATE = On/Off, True/False or 1/0

and

DECLARE XIN_TRANSLATE = On/Off, True/False or 1/0

Notes

XIN processes data at each zero crossing of the AC power line as received on ZeroPin. If there are no transitions on this line, XIN will effectively wait forever.

XIN is used to receive information from X-10 devices that can transmit the appropriate data. X-10 modules are available from a wide variety of sources under several trade names. An interface is required to connect the PICmicro to the AC power line. The TW-523 for two-way X-10 communications is required by XIN. This device contains the power line interface and isolates the PICmicro from the AC line.

If Variable is a WORD sized variable, then each House Code received will be stored in the upper 8-bits of the WORD. And each received Key Code will be stored in the lower 8-bits of the WORD variable. If Variable is a BYTE sized variable, then only the Key Code will be stored.

The House Code is a number between 0 and 15 that corresponds to the House Code set on the X-10 module A through P.

The Key Code can be either the number of a specific X-10 module or the function that is to be performed by a module. In normal operation, a command is first sent, specifying the X-10 module number, followed by a command specifying the desired function. Some functions operate on all modules at once so the module number is unnecessary. Key Code numbers 0-15 correspond to module numbers 1-16.

WARNING. Under no circumstances should the PICmicro be connected directly to the AC power line. Voltage potentials carried by the power line will not only instantly destroy the PICmicro, but could also pose a serious health hazard.

See also : XOUT.


XOUT

Syntax

XOUT DataPin , ZeroPin , [HouseCode\KeyCode {\Repeat} { , ...}]

Availability

14-bit and 16-bit core devices.

Overview

Transmit a HouseCode followed by a KeyCode in X-10 format.

Operators

DataPin is a constant (0 - 15), port.bit, or variable, that transmits the data to an X-10 interface. This pin is automatically made an output.

ZeroPin is a constant (0 - 15), port.bit, or variable,  that is used to synchronise to a zero-cross event. This pin is automatically made an input to received the zero crossing timing, and should be pulled up to 5 Volts with a 4.7K Ohm resistor.

HouseCode is a number between 0 and 15 that corresponds to the House Code set on the X-10 module A through P. The proper HouseCode must be sent as part of each command.

KeyCode can be either the number of a specific X-10 module, or the function that is to be performed by a module. In normal use, a command is first sent specifying the X-10 module number, followed by a command specifying the function required. Some functions operate on all modules at once so the module number is unnecessary. KeyCode numbers 0-15 correspond to module numbers 1-16.

Repeat is an optional operator, and if it is NOT included, then a repeat of 2 times (the minimum) is assumed. Repeat is normally reserved for use with the X-10 Bright and Dim commands.

Example

DIM HOUSE AS BYTE

DIM UNIT AS BYTE

' Create some aliases of the keycodes

SYMBOL UnitOn = %10010	' Turn module on

SYMBOL UnitOff = %11010	' Turn module off

SYMBOL UnitsOff = %11100	' Turn all modules off

SYMBOL LightsOn = %10100	' Turn all light modules on

SYMBOL LightsOff = %10000	' Turn all light modules off

SYMBOL Bright = %10110	' Brighten light module

SYMBOL DimIt = %11110	' Dim light module

' Create aliases for the pins used

SYMBOL DATAPIN = PORTA.1

SYMBOL ZERO_C = PORTA.0

HOUSE = 0	' Set house to 0 (A)

UNIT = 8	' Set unit to 8 (9)

XOUT DATAPIN ,ZERO_C,[HOUSE \ UNIT,HOUSE \ UnitOn ] ' Turn on unit 8 in house 0

XOUT DATAPIN ,ZERO_C,[HOUSE \ LightsOff ]	' Turn off all the lights in house 0

XOUT DATAPIN ,ZERO_C,[HOUSE \ 0]	' Blink light 0 on and off every 10 seconds

LOOP:

XOUT DATAPIN ,ZERO_C,[HOUSE \ UnitOn ]

DELAYMS 10000	' Wait 10 seconds

XOUT DATAPIN ,ZERO_C,[HOUSE \ UnitOff ]

DELAYMS 10000	' Wait 10 seconds

GOTO LOOP

XOUT and XIN Declares

In order to make the XOUT command's results more in keeping with the BASIC Stamp interpreter,  two declares have been included for both XIN and XOUT. These are.

DECLARE XOUT_TRANSLATE = On/Off, True/False or 1/0

and

DECLARE XIN_TRANSLATE = On/Off, True/False or 1/0

Notes

XOUT only transmits data at each zero crossing of the AC power line, as received on ZeroPin. If there are no transitions on this line, XOUT will effectively wait forever.

XOUT is used to transmit information from X-10 devices that can receive the appropriate data. X-10 modules are available from a wide variety of sources under several trade names. An interface is required to connect the PICmicro to the AC power line. Either the PL-513 for send only, or the TW-523 for two-way X-10 communications are required. These devices contain the power line interface and isolate the PICmicro from the AC line.

The KeyCode numbers and their corresponding operations are listed below: -

KeyCode	KeyCode No.	Operation

UnitOn	%10010	Turn module on

UnitOff	%11010	Turn module off

UnitsOff	%11100	Turn all modules off

LightsOn	%10100	Turn all light modules on

LightsOff	%10000	Turn all light modules off

Bright	%10110	Brighten light module

Dim	%11110	Dim light module

Wiring to the X-10 interfaces requires 4 connections. Output from the X-10 interface (zero crossing and receive data) are open-collector, which is the reason for the pull-up resistors on the PICmicro.

Wiring  for each type of interface is shown below: -

PL-513 Wiring

Wire No.	Wire Colour	Connection

1	Black	Zero crossing output

2	Red	Zero crossing common

3	Green	X-10 transmit common

4	Yellow	X-10 transmit input

TW-523 Wiring

Wire No.	Wire Colour	Connection

1	Black	Zero crossing output

2	Red	Common

3	Green	X-10 receive output

4	Yellow	X-10 transmit input

Obtaining these interfaces may pose a problem here in the UK, as X-10 has never been popular. However, a search on the internet should reveal several stockists.

WARNING. Under no circumstances should the PICmicro be connected directly to the AC power line. Voltage potentials carried by the power line will not only instantly destroy the PICmicro, but could also pose a serious health hazard.

See also : XIN.


Using the built-in PIC16F87x bootloader
Using the built-in bootloader

A boot loader allows the PICmicro to be programmed using a simple serial cable from the computer's COM port.

Before the bootloader may be used, the target PICmicro must be programmed conventionally with one of the bootloader hex files. This is the code that resides in the PICmicro and intercepts the serial data presented from the PC. The HEX files may be found in the LOADER_HEX folder. Each type of 16F87x and 18Fxxx PICmicro and crystal combination, requires a different hex file, for example, a 16F877 device working with a 20MHz crystal requires the PIC16F877_20.HEX file programmed. There is however, one other requirement, because the configuration fuses are not alterable by the bootloader, you must decide whether to have the watchdog timer enabled or disabled in the target PICmicro. There are two main folders in the LOADER_HEX folder, these are WDT_ON, and WDT_OFF. The WDT_ON folder contains the boot hex files with the watchdog timer enabled, and the WDT_OFF folder contains hex files with the watchdog timer disabled. Remember, the default of the compiler when using a conventional programming method is watchdog timer enabled.

Note: The 16F872 device is NOT compatible with the bootloader, as it does not incorporate a USART.

Once the target PICmicro has been loaded with the appropriate HEX file, the circuit below may be used to program it. In the circuit, a 16F877 device is used as the target PICmicro.

The MAX232 is a serial driver, allowing the PC to PICmicro communications to take place. As you can see, the circuit is extremely simple, as the PICmicro part of the circuit is a conventional setup. Note the RESET switch, this is necessary for the successful use of the bootloader.

The bootloader is chosen by clicking on the appropriate iconic button, located at the top of the editor. See below: -

You may choose one of the available serial port on the PC for the attachment of the bootloader, by selecting COM1, COM2, or COM3 in the drop down menu. The default port is COM1. The port, as well as other parameters will be remembered, so there is no need to continually alter the settings.

Other aspects of the downloader may also be altered by clicking the CONFIG menu (shown below).

The DTR CONTROL option has four settings: -

HIGH. Will set the DTR line high while writing is in progress.

LOW. Will pull the DTR line low while writing is in progress.

STROBE HIGH. Will toggle the DTR line LOW-HIGH-LOW while writing is in progress.

STROBE LOW. Will toggle the DTR line HIGH-LOW-HIGH while writing is in progress.

The RTS CONTROL option also has four settings: -

HIGH. Will set the RTS line high while writing is in progress, and keep it high afterwards

LOW. Will pull the RTS line low while writing is in progress.

STROBE HIGH. Will toggle the RTS line LOW-HIGH-LOW while writing is in progress.

STROBE LOW. Will toggle the RTS line HIGH-LOW-HIGH while writing is in progress.

PROGRAM EEPROM. Will program the on-board eeprom along with the main program code, if checked.

CLOSE ON COMPLETION. Will automatically close the bootloader window if a successful write is carried out.

In normal operation, the bootloader will automatically search for the bootloader receiver software in the PICmicro, however, for this to be found, the PICmicro must be RESET or powered up. You will then be prompted with the message shown below. Clicking on the WRITE button will also start the download process.

Once the RESET is activated, the program will download and run automatically. That's all there is to it.

What is a bootloader?

The PIC16F87x range of devices have a unique feature, they can program their own FLASH code space while running. All other PICmicro's must be programmed by a device programmer, such as the PICSTART or EPIC programmers. This self-modifying feature allows a PIC16F87x device to run a program named a bootloader.

A bootloader is a program that resides in the code space of the target PICmicro. It can be activated to allow additional program code to be written to and read from that same target PICmicro. A bootloader consists of 2 elements, connected by a serial cable.

The first part of the bootloader is a program resident on the PICmicro. This program occupies the upper 256 words of the FLASH code space. This small program must be placed into the PICmicro using a conventional programmer.

The program resident in the PICmicro communicates with the second element of the loader over a serial connection. This second program is the bootloader window within the compiler's IDE and is the user interface. It allows the compiled BASIC code to be programmed.

Only the code space and data space may be read and programmed on the target PICmicro. The ID space and CONFIGURATION fuses are not accessible to the bootloader. The configuration fuses must be set at the time the actual loader program is programmed into the PICmicro. Once they are set, they cannot be changed by the bootloader.

The bootloader software resident in the PICmicro, intercepts the reset vector. When the PICmicro powers up, it enters the loader's boot supervisor, this watches the USART's serial input pin for a start bit for 200 milliseconds (ms). If it sees activity during this period, it enters the communications section of the software to download a program. If it does not see any activity during the 200ms, it starts the user program in the PICmicro.

The interception of the reset vector is accomplished by automatically relocating the first 4 user program words from address's 0 to 3 to a reserved place in the bootloader's code space (within the top 256 words). A jump to the bootloader is then placed at locations 0 to 3. When the loader software running on the PC reads or writes these addresses the values seen are as if the bootloader was not resident and the reset code had not been moved.

The USART's serial pins used by the bootloader are only required when the loader is actually programming the PICmicro. They are unattached while the downloaded user program is running on the target and may be assigned to any other task or serial baud rate, with one exception. As we've already discussed, the bootloader checks the serial input pin at power up and reset, to determine if it should run, or if the user (downloaded) program should run. Therefore, for the user program to run, this pin must not be in the start bit condition when the device is powered up. Make sure the serial in pin (PORTC.7) is in the idle state when the PICmicro is first powered up.

The serial communication speed is set at 19200 baud. The bootloader program resident in the PICmicro can easily communicate at this speed with an oscillator frequency from 4MHz to 20MHz. This oscillator frequency is determined at the time the loader code is programmed into the target PICmicro. The target PICmicro must then only be run at this frequency in order to be able to communicate with its matching part running on the PC. The bootloader uses no PICmicro resources while the user program is running. All the data memory, RAM, and I/O pins are available to the user program.

However, there are a few considerations that should be noted when writing programs that will be loaded by the bootloader. The first is that the bootloader takes over at power up and any subsequent resets. Any time the program vectors through the reset address, the loader becomes active and watches the RX pin (PORTC.7) for any activity. If there is any action on this pin, the loader will start, and the user program will not execute. Even if there is no activity on this pin, the start of the user program will be delayed by the 200 milliseconds while the bootloader is watching the RX pin.

Another consideration is the fact that the configuration fuses are not alterable by the bootloader. If some programs require the use of the Watchdog Timer and others don't, then separate PICmicro's will be necessary. One PICmicro programmed with the WDT on and one with it off. The same is true for the Power up Timer, Brownout Detect Enable and Oscillator type. The standard programmed defaults are WATCHDOG TIMER ON, POWERUP TIMER ON, BROWNOUT DETECT ENABLE ON and HS OSCILLATOR.

The configuration fuses for code protection CANNOT be enabled. The bootloader needs to be able to freely read and write to the PICmicro's code and data space. Therefore, the device cannot be code protected. The bootloader is primarily aimed at development work, any final products that require code protection must be programmed in the conventional way.

The bootloader software occupies the last 256 words of code space. A compiled program is written starting at location 0 and grows upward so the loader's position in memory is not noticeable. You must make sure that the program code does not attempt to enter the upper 256 words of code space. The bootloader inserts its own code at the reset vector and automatically relocates the user's reset code to an area reserved within the top 256 words of memory. Normally, these locations contain a jump to the start-up routine for the user program. However, since the user code is no longer situated at these locations, the user program should not attempt to jump to, or call any routine within the code area between 0 and 3.


Protected Compiler Words

Below is a list of protected words that the compiler or assembler uses internally. Be sure not to use any of these words as variable or label names, or errors will be produced.

A

ABS,  ACOS, ACTUAL_BANKS, ADC_RESOLUTION, ADIN, ADIN_RES, ADIN_STIME, ADIN_TAD

ALL_DIGITAL, ASM, AVAILABLE_RAM, ASIN, ATAN

B

BANK0_END, BANK0_START, BANK10_END, BANK10_START, BANK11_END, BANK11_START

BANK12_END, BANK12_START, BANK13_END, BANK13_START, BANK14_END, BANK14_START

BANK15_END, BANK15_START, BANK1_END, BANK1_START, BANK2_END, BANK2_START

BANK3_END, BANK3_START, BANK4_END, BANK4_START, BANK5_END, BANK5_START

BANK6_END, BANK6_START, BANK7_END, BANK7_START, BANK8_END, BANK8_START

BANK9_END, BANK9_START, BANK_SELECT_SWITCH, BANKA_END, BANKA_START

BIN, BIN1, BIN2, BIN3, BIN4, BIN5, BIN6, BIN7, BIN8, BIN9, BIN10, BIN11, BIN12

,BIN13, BIN14, BIN15, BIN16, BIN17, BIN18, BIN19, BIN20, BIN21, BIN22, BIN23, BIN24, BIN25

,BIN26, BIN27, BIN28, BIN29, BIN30, BIT, BOOTLOADER, BOX, BRANCH

BRANCHL, BREAK, BRESTART, BSTART, BSTOP, BUS_DELAYMS, BUSACK, BUSIN, BUSOUT

BUTTON, BUTTON_DELAY, BYTE

C

CALL, CASE, CCP1_PIN, CCP2_PIN, CDATA, CERASE, CHR$, CIRCLE, CLEAR, CLEARBIT, CLS

CON, CONFIG, CONTEXT, CORE, COS, COUNT, COUNT_ERRORS, COUNTER, CREAD, CURSOR, CWRITE

D

DA, DATA, DB, DC, DCD, DE, DEC, DEC1, DEC2, DEC3, DEC4, DEC5, DEC6, DEC7, DEC8, DEC9, DEC10

DECLARE, DEBUG, DEFINE, DELAYMS, DELAYUS, DEVICE

DJC, DJNC, DJZ, DJNZ, DIG, DIM, DISABLE, DIV2, DT, DTMFOUT, DW, DWORD

E

EDATA, EEPROM_SIZE, ELSE, ELSEIF, ENABLE, END, ENDSELECT, ENDASM

ENDIF, ENDM, EQU, EREAD, ERRORLEVEL, EWRITE, EXITM, EXP, EXP10, EXPAND

EXP

F

FILE_REF, FLASH_CAPABLE, FLOAT, FONT, FONT_ADDR, FOR, FREQOUT, FSRSAVE

G

GETBIT, GLCD_CS_INVERT, GLCD_FAST_STROBE, GOSUB, GOTO

H

HBRESTART, HBSTART, HBSTOP, HBUS_BITRATE, HBUSACK

HBUSIN, HBUSOUT, HEX, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7, HEX8

HIGH, HPWM, HRSIN, HRSOUT, HSERIAL_BAUD

HSERIAL_CLEAR, HSERIAL_PARITY, HSERIAL_RCSTA, HSERIAL_SPBRG, HSERIAL_TXSTA

I

I2CREAD, I2CWRITE, IBIN, IBIN1, IBIN2, IBIN3, IBIN4, IBIN5, IBIN6, IBIN7, IBIN8, IBIN9, IBIN10, IBIN11, IBIN12

IBIN13, IBIN14, IBIN15, IBIN16, IBIN17, IBIN18, IBIN19, IBIN20, IBIN21, IBIN22, IBIN23, IBIN24, IBIN25

IBIN26, IBIN27, IBIN28, IBIN29, IBIN30,ICD, IDATA, IF

IHEX, IHEX1, IHEX2, IHEX3, IHEX4, IHEX5, IHEX6, IHEX7, IHEX8

INC, INCLUDE, INKEY, INPUT, INTERNAL_BUS, INTERNAL_FONT, IJC, IJNC, IJNZ, IJZ

ISBIN, ISBIN1, ISBIN2, ISBIN3, ISBIN4, ISBIN5, ISBIN6, ISBIN7, ISBIN8, ISBIN9, ISBIN10, ISBIN11, ISBIN12

ISBIN13, ISBIN14, ISBIN15, ISBIN16, ISBIN17, ISBIN18, ISBIN19, ISBIN20, ISBIN21, ISBIN22, ISBIN23, ISBIN24, ISBIN25

ISBIN26, ISBIN27, ISBIN28, ISBIN29, ISBIN30

ISDEC, ISDEC1, ISDEC2, ISDEC3, ISDEC4, ISDEC5, ISDEC6, ISDEC7, ISDEC8, ISDEC9, ISDEC10

ISHEX, ISHEX1, ISHEX2, ISHEX3, ISHEX4, ISHEX5, ISHEX6, ISHEX7, ISHEX8

J

K

KEYPAD_PORT

L

LCD_CS1PIN, LCD_CS2PIN, LCD_DTPIN, LCD_DTPORT, LCD_ENPIN, LCD_INTERFACE

LCD_LINES, LCD_RSPIN, LCD_RWPIN, LCD_TYPE, LCDOUT, LCDREAD, LCDWRITE

LEN, LEFT$ LET, LIBRARY, LINE, LOADBIT, LOCAL, LOG, LOG10, LOOKDOWN, LOOKDOWNL, LOOKUP, LOOKUPL, LOW

M

MACRO_PARAMS, MAX, MID$, MIN, MSSP_TYPE

N

NCD, NEXT

O

ON, ON_INTERRUPT, ON_LOW_INTERRUPT, ONBOARD_ADC, ONBOARD_UART

ONBOARD_USB, OREAD, ORG, OUTPUT, OWRITE

P

PAGE, PAGESEL, PAUSE, PAUSEUS, PEEK, PEEKCODE, PICMICRO_PAGES

PIXEL, PLOT, POKE, POKECODE, POP, PORTB_PULLUPS, POT, POW, PRINT, PSAVE

PULSIN, PULSIN_MAXIMUM, PULSOUT, PUSH, PWM

Q

R

RAM_BANK, RAM_BANKS

RANDOM, RCIN, RCTIME, READ, REM, REMARKS, REMINDERS, REP

REPEAT, RES, RESET_BANK, RESERVE_RAM, RESTORE, RESUME, RETURN, REV

RIGHT$, ROR, ROL, RSIN, RSIN_MODE, RSIN_PIN, RSIN_TIMEOUT, RSOUT

RSOUT_MODE, RSOUT_PACE, RSOUT_PIN

S

S_ASM, SBIN, SBIN1, SBIN2, SBIN3, SBIN4, SBIN5, SBIN6, SBIN7, SBIN8, SBIN9, SBIN10, SBIN11, SBIN12

SBIN13, SBIN14, SBIN15, SBIN16, SBIN17, SBIN18, SBIN19, SBIN20, SBIN21, SBIN22, SBIN23, SBIN24, SBIN25

SBIN26, SBIN27, SBIN28, SBIN29, SBIN30, SCL_PIN, SDEC, SDEC1, SDEC2, SDEC3, SDEC4, SDEC5, SDEC6

SBREAK, SDEC7, SDEC8, SDEC9, SDEC10

SDA_PIN, SERIAL_BAUD, SEED, SELECT, SERIAL_DATA

SERIN, SERIN2, SEROUT, SEROUT2, SERVO, SERIAL_PARITY

SET, SET_BANK, SETBIT, SET_DEFAULTS, SET_OSCCAL, SHIFT_DELAYUS

SHEX, SHEX1, SHEX2, SHEX3, SHEX4, SHEX5, SHEX6, SHEX7, SHEX8

SHIN, SHOUT, SIN, SLEEP, SLOW_BUS, SNOOZE

SOUND, SOUND2, SQR, SSAVE, STEP, STOP, STR, STRN, STRING, STR$

STAMP_SIN, STAMP_COS, STAMP_SQR, SWAP, SYMBOL

T

TAN, THEN, TO, TOGGLE, TOLOWER, TOUPPER

U

UDATA, UNPLOT, UNTIL, UPPER

USB_CLASS_FILE, USB_DESCRIPTOR, USB_SHOW_ENUM, USBIN, USBINIT, USBOUT

V

VAL, VAR, VARIABLE

W

WAIT, WARNINGS, WATCHDOG, WEND, WHILE, WORD, WRITE, WSAVE

X

XIN, XOUT,  XIN_TRANSLATE, XOUT_TRANSLATE, XTAL

Y

Z


EN line
ENABLE

ENABLE pin of either the GPAPHIC or ALPHANUMERIC LCD


FSR

Indirect address hardware register, used in conjunction with INDF.

Indirect addressing is a mode of addressing data memory where the data memory address in the instruction is not fixed. A hardware register is used as a pointer to the data memory location that is to be read or written. Since this pointer is in RAM, the contents can be modified by the program.

Indirect addressing is possible by using the INDF register. Any instruction using the INDF register actually accesses the register pointed to by the File Select Register, FSR. Reading the INDF register itself indirectly (FSR = 0) will read 00h. Writing to the INDF register indirectly results in a no-operation (although status bits may be affected). An effective 9-bit address is generated by the concatenation of the IRP bit (STATUS.7) with the 8-bit FSR register.


FSR0

16-bit core device Indirect address hardware register, used in conjunction with INDF0. The 16-bit core devices actually have three FSR registers; FSR0, FSR1 and FSR2.


TRIS

PORT direction hardware register.


RETFIE
RETFIE (Return from interrupt)

Assembler instruction that returns control from an interrupt.


RETLW
RETLW (Return literal in W)

Assembler instruction that returns from a subroutine with the WREG loaded.


GIE

BIT 7 of the INTCON register. Enables/Disables hardware interrupts.


INTCON

Interrupt control register. Controls aspects of interrupts.


INDF

Indirect address hardware register, used in conjunction with FSR.

Indirect addressing is a mode of addressing data memory where the data memory address in the instruction is not fixed. A hardware register is used as a pointer to the data memory location that is to be read or written. Since this pointer is in RAM, the contents can be modified by the program.

Indirect addressing is possible by using the INDF register. Any instruction using the INDF register actually accesses the register pointed to by the File Select Register, FSR. Reading the INDF register itself indirectly (FSR = 0) will read 00h. Writing to the INDF register indirectly results in a no-operation (although status bits may be affected). An effective 9-bit address is generated by the concatenation of the IRP bit (STATUS.7) with the 8-bit FSR register.


ADCON0

Analogue to Digital Converter control register.


ADCON1

Analogue to Digital Converter control register, that chooses which pin is analogue and which is digital.


BIT

Variable type that may hold a value of 0 or 1.

Requires 1 Byte of RAM per 8-bits used in the BASIC program.


BYTE

Variable type that may hold a value of 0 to 255.

Requires 1 byte of RAM.


BYTE ARRAY

A collection of up to 255 BYTE variables each sharing a single name, and indexed using a value or variable.

Syntax for declaration: -

DIM Name[ length ] AS BYTE

where Name is the variable's given name, and the new argument, [ length ], informs the compiler how many elements you want the array to contain.

Requires length bytes of RAM depending on its size.


WORD

Variable type that may hold a value of 0 to 65535.

Requires 2 bytes of RAM.


WORD ARRAY

A collection of up to 127 WORD variables each sharing a single name, and indexed using a value or variable.

Syntax for declaration: -

DIM Name[ length ] AS WORD

where Name is the variable's given name, and the new argument, [ length ], informs the compiler how many elements you want the array to contain.

Requires 2 * length bytes of RAM depending on its size.


DWORD

Variable type that may hold a value of -2147483648 to +2147483647.

Requires 4 bytes of RAM.


FLOAT

Variable type that may theoretically hold a value of -1e37 to +1e38. However, with floating point calculations, smaller values offer more accurate results.

Requires 4 bytes of RAM.


STRING

A collection of up to 255 characters identified by a single name and terminated by a NULL.

RAM usage depends on the size of the STRING. Plus 1 byte to hold the terminating NULL.


CONSTANT

A fixed numeric value that can be virtually any value depending on the variable it is associated with, or operating with.


PORTA

I/O port of the PICmicro. Also known as RA. If the PICmicro has an on-board Analogue to Digital converter, then this port contains the analogue inputs. The default of these pins at power-up is Analogue.

The RA4 pin is usually a Schmitt Trigger input and an open drain output. All other RA port pins have TTL input levels and full CMOS output drivers. All pins have data direction bits (TRIS registers) which can configure these pins as output or input.

Setting a TRISA register bit puts the corresponding output driver in a hi-impedance mode. Clearing a bit in the TRISA register puts the contents of the output latch on the selected pin(s).


PORTB

I/O port of the PICmicro. Also known as RB.

PORTB is an 8-bit wide bi-directional port. The corresponding data direction register is TRISB. Setting a bit in the TRISB register puts the corresponding output driver in a high-impedance input mode. Clearing a bit in the TRISB register puts the contents of the output latch on the selected pin(s).

Each of the PORTB pins has a weak internal pull-up. A single control bit can turn on all the pull-ups. This is performed by clearing bit RBPU (OPTION_REG.7) on 14-bit core devices, and INTCON2.7 on 16-bit core devices. The weak pull-up is automatically turned off when the port pin is configured as an output. The pull-ups are disabled on a Power-on Reset.

The compiler has a special command for disabling/enabling the pull-up resistors on PORTB, this is: -

PORTB_PULLUPS = 1/0, TRUE/FALSE, or ON/OFF


PORTC

I/O port of the PICmicro. Also known as RC.

PORTC is an 8-bit bi-directional port. Each pin is individually configurable as an input or output through the TRISC register. PORTC pins have Schmitt Trigger input buffers.

When enabling peripheral functions, care should be taken in defining TRIS bits for each PORTC pin. Some peripherals override the TRIS bit to make a pin an output, while other peripherals override the TRIS bit to make a pin an input.


PORTD

I/O port of the PICmicro. Also known as RD.

PORTD is an 8-bit port with Schmitt Trigger input buffers. Each pin is individually configurable as an input or output.


PORTE

I/O port of the PICmicro. Also known as RE. If the PICmicro has an on-board Analogue to Digital converter, then this port normally contains some of the analogue inputs. The default of these pins at power-up is Analogue.


Quoted String of Characters

A Quoted String of Characters contains one or more characters (maximum 200) and is delimited by double quotes. Such as "Hello World"

Strings are usually treated as a list of individual character values, and are used by commands such as PRINT, RSOUT, BUSOUT, EWRITE etc.


PROTON Development board

The Crownhill PROTON PICmicro Development Board is a must for developers of PICmicro applications. Whether just beginning, or a seasoned veteran, the PROTON board offers a rapid solution to be realised.

On board peripherals include, 16-button keypad, LCD (graphic or alphanumeric), LEDs (4x red, 4 x green), serial eeproms (I2C and SPI), RS232 serial port, Infra-red transmitters and receiver, and a choice of crystal frequencies.

Not to mention the PICmicro's own facilities, such as 8K program space, 368 bytes of user RAM, 256 bytes of user eeprom, Eight channel Analogue to Digital converter, USART, MSSP module offering PWM, I2C, SPI, and parallel configurations.

The choice of options is extensive enough to make the PROTON board a single solution for a multitude of challenges.

Designed to interface seamlessly to the PROTON+ compiler.


Choosing an external Programmer

When the Editor is first installed, the default programmer of choice is the melab's EPIC. However, not everyone has, or uses the EPIC programmer. Therefore, virtually any programmer capable of accepting command line parameters may be used instead.

Locate and click the OPTIONS pull down menu, and click on the PROGRAMMER PATH menu item (shown above). You will be presented with a new window (shown below). You may now add the name of the programmer, and also it's location on the computer.

The programmer's name should be written in the 'PROGRAMMER'S NAME' edit box. In the picture above, it is the MELOADER.

The programmer's location on the hard-drive should be written in the 'PROGRAMMER'S DIRECTORY PATH'. This enables the editor to find and run the EXE file associated with your particular programmer. If the location is not known, then click the BROWSE button, and locate the EXE file by looking at the hard drive.

The command line parameters that must be passed to the programmer are added in the bottom edit window. The commands are unique to the programmer of choice. To help with command passing, three keywords are included that automatically insert the current PICmicro device used in the BASIC program, as well as the HEX file that will be produced. These are outlined below: -

%PICmicro will insert the PICmicro's name i.e. -d %PICmicro will become -d 16F877 (if a PIC16F877 device was chosen for the BASIC program). The -d part is only for use with the EPIC software, and may not be required by your programmer.

%FILENAME will insert the HEX file's name only i.e.%FILENAME will become FLASH.HEX

%FULL will insert the whole path as well as the HEX file's name i.e. C:\Path\FLASH.HEX

The KEYWORDS may be used in any combination i.e. -dPIC%PICmicro %FULL. Is for EPIC

Once the programmer's path, name and parameters have been entered, you can enable that programmer as the programmer of choice whenever the program button is pressed.

Locate and click the OPTIONS pull down menu, and move the mouse pointer over 'CHOOSE PROGRAMMER'. A small menu will appear displaying your new choice of programmer, as well as the standard EPIC choice.

Clicking on the new programmer's name will make that the default programmer.

See also: Locating the EPIC Programmer, Using the built in bootloader.


Locating EPIC on the hard-drive

When the editor is first installed, it has no way of knowing where the EPIC programmer is located on the hard drive. Therefore you must inform it as to it's whereabouts using the EPIC PATH menu option, located in the OPTIONS menu. You will be greeted with a window as shown below.

The location of the EPIC programmer in the above window is C:\EPIC, and the executable filename is EPICWIN.EXE.

See also: Choosing an external Programmer, Using the built in bootloader.


TMR0

8-bit hardware timer with 12 and 14-bit core devices, 16-bit timer with 16-bit core devices.


TMR1

16-bit hardware timer


TMR3

16-bit hardware timer


ADRES

Holds result of an Analogue to Digital conversion.


PRODL

Holds the LOW byte result of an 8x8 hardware Multiply. The HIGH byte is held in PRODH. Available on 16-bit core devices only.


GPIO

General purpose I/O available on an 8-pin PICmicro


OSCCAL

Internal oscillator calibration register.


USART

Universal-Synchronous-Asynchronous-Receiver-Transmitter. A means of serial RS232 communications using the hardware capabilities found on some PICmicro devices.


14-bit core Devices

PICmicro devices that have a 14-bit architecture. These include the 12FXXX, 16CXXX, and 16FXXX devices.


16-BIT CORE DEVICES

PICmicro devices that have a 16-bit architecture. These include the 18C, and 18F devices. Because of their linear memory architecture, 16-bit core devices offer a higher degree of flexibility than their 12 and 14-bit counterparts. And because they can access all of their CODE space without resorting to PAGE switching, they also create more compact code. Extra functionality such as hardware multiply, and easy RAM access, also means that programs run faster. Add to that, their ability to work with crystal frequencies of up to 40Mhz means that these devices are highly recommended for new designs.


NULL Terminated

NULL is a term used in computer languages for zero. So a NULL terminated STRING is a collection of characters followed by a zero in order to signify the end of characters. For example, the string of characters "HELLO", would be stored as: -

"H" , "E" , "L" , "L" ,"O" , 0

Notice that the terminating NULL is the value 0 not the character "0".


MAX232 Circuit

A typical circuit using a Maxim semiconductor MAX232 serial tranceiver.


RESET

The act of restarting the PICmicro by pulling the MCLR line momentarily down to ground. Unlike a power-up, the RAM locations are not effected by a restart.


SELECT..CASE Example Code

' PROTON+ Program to identify characters: case, digit, punctuation, operand or parenthasis.

'

' To use the program, open the serial terminal program and set it up for 9600 baud

' Follow the on-screen prompt and type a character

'

' The program also demonstrates the use of the CSTR modifier for displaying strings of text held in code memory.

Include "PROTON_4.INC"	' Use the PROTON Development board for demo

Dim CHARACTER as Byte

Delayms 200	' Wait for PICmicro to stabilise

Hrsout Cstr ENTER_CHAR	' Display message "Enter a character: "

While 1 = 1	' Create an infinite loop

Hrsin CHARACTER	' Get a character from the serial port

Select CHARACTER	' Check conditions based on variable CHARACTER

Case "A" TO "Z"	' Is it A to Z ?

Hrsout Cstr CHAR_IS, Cstr UP_CASE	' Yes.. So display message "Character is an Upper case Letter"

Case "a" TO "z"	' Is it a to z ?

Hrsout Cstr CHAR_IS, Cstr LW_CASE	' Yes.. So display message "Character is a Lower case Letter"

Case "0" TO "9"	' Is it 0 to 9 ?

Hrsout Cstr CHAR_IS, Cstr DIGIT	' Yes.. So display message "Character is a Digit"

Case "!", "?", ".", ","	' Is it one of these four characters ?

Hrsout Cstr CHAR_IS, Cstr PUNCT	' Yes.. So display message "Character is a Punctuation"

Case "$", "%", "&", "|","~","^","-","+","*","/" ' Is it one of these ten characters ?

Hrsout Cstr CHAR_IS, Cstr OPERAND	' Yes.. So display message "Character is an Operand"

Case "(", ")", "{", "}", "[", "]"	' Is it one of these six characters ?

Hrsout Cstr CHAR_IS, Cstr PAREN	' Yes.. So display message "Character is a Parenthasis"

Case Else	' Default to displaying message "Character is not known. Try a different one."

Hrsout Cstr CHAR_IS, Cstr UNKNOWN

Endselect

Hrsout Cstr ANOTHER	' Display the message "Enter another character"

Wend	' Look for another character from the serial port

' Message texts held in code memory

CHAR_IS:	CDATA CR, "Character is ",0

ENTER_CHAR:	CDATA "Enter a character: ", CR,0

UP_CASE:	CDATA "an Upper case Letter", CR,0

LW_CASE:	CDATA "a Lower case Letter", CR,0

DIGIT:	CDATA "a Digit", CR,0

PUNCT:	CDATA "a Punctuation", CR,0

OPERAND:	CDATA "an Operand", CR,0

PAREN:	CDATA "a Parenthasis", CR,0

UNKNOWN:	CDATA "not known. Try a different one.",CR,0

ANOTHER:	CDATA CR,"Enter another character", CR,0


12F675 ADC Demo

' Perform an ADC conversion on the 12F675 8-pin PICmicro device

Device = 12F675

XTAL = 4

SERIAL_BAUD = 9600

RSOUT_PIN = GPIO.0

RSOUT_MODE = TRUE

RSOUT_PACE = 10

'-------[DEFINE SOME ALIAS'S TO ADC REGISTERS]---------------------------

' ANSEL register's bits

Symbol ANS0 = ANSEL.0

Symbol ANS1 = ANSEL.1

Symbol ANS2 = ANSEL.2

Symbol ANS3 = ANSEL.3

Symbol ADCS0 = ANSEL.4	' ADC conversion clock select bit

Symbol ADCS1 = ANSEL.5	' ADC conversion clock select bit

Symbol ADCS2 = ANSEL.6	' ADC conversion clock select bit

' ADCON0 register's bits

Symbol ADFM = ADCON0.7

Symbol VCFG = ADCON0.6

Symbol CHS2 = ADCON0.4	' ADC channel select bit

Symbol CHS1 = ADCON0.3	' ADC channel select bit

Symbol CHS0 = ADCON0.2	' ADC channel select bit

Symbol GO_DONE = ADCON0.1	' ADC Conversion status/ plus enable conversion-bit

Symbol ADON = ADCON0.0	' ADC Enable bit: 1 = enabled, 0 = disabled.

'-------[ASSIGN A VARIABLE FOR THE ADC RESULT]---------------------------

Dim AD_RESULT as ADRESL.WORD	' Convert the ADRESL register into a WORD variable

'-------[INITIALISE THE PICMICRO]----------------------------------------

Delayms 500	' Wait for the PICmicro to stabilise

Goto OVER_ADC_SUBS	' Jump over the subroutines

'-------[START AN ADC CONVERSION]----------------------------------------

GET_ADC:

ADON = 1	' Enable the ADC

Delayus 50              	' Wait for sample/hold capacitors to charge

GO_DONE = 1            	' Start conversion

While GO_DONE = 1 : Wend	' Poll the GO_DONE flag for completion of conversion

ADON = 0	' Disable the ADC, to save power

Return

'-------[INITIALISE THE ADC REGISTERS]----------------------------------

' Standard procedures for setting up the ADC

OVER_ADC_SUBS:

TRISIO = %11111111	' All pins set for input

ADCS0 = 1	' \

ADCS1 = 1	'   Setup ADC's clock for FRC

ADCS2 = 0	' /

VCFG = 0	' VREF is set to VDD of PICmicro

ADFM = 1	' Right justify the ADC result

ANS0 = 0	' Set AN0 (GPIO.0) as Digital input

ANS1 = 0	' Set AN1 (GPIO.1) as Digital input

ANS2 = 1	' Set AN2 (GPIO.2) as Analogue input

ANS3 = 1	' Set AN3 (GPIO.3) as Analogue input

'-------[MAIN PROGRAM LOOP STARTS HERE]----------------------------------

' Perform ADC conversions and display the result serially

While 1 = 1	' Create an infinite loop

ADCON0 = ADCON0 | (2 << 2) 	' Select the channel to read

Gosub GET_ADC	' Perform an ADC conversion

Rsout "CHANNEL 2 = " , DEC AD_RESULT,13	' Display the result serially

Delayms 500	' Wait for half a second

Wend	' Do another conversion


Running an External Program from the Editor and Capturing its Output

Some configurations required by a particular PICmicro cannot be performed by the compiler without some help from an external program. Therefore a simple method of running a helper program is added to the compiler's editor.

Configurations I'm talking about are interrupt sources, font data, timer setups etc. For example, a font converter program for use with a graphic LCD would need to create a font and build a sequence of CDATA commands for addition to the main body of the BASIC code.

In addition to running the external program, the IDE can also incorporate any code produced at the position of the cursor, thus eliminating the need for cutting and pasting the code into the BASIC code.

The method is simplicity itself to set up: -

First create a folder named EXTERNAL PROGRAMS within the compiler's INC folder. The editor will look in this folder for any EXE files and display them in the OPTIONS pull down menu, under a new menu item created when EXE files are found, named RUN.

For example, place the included executable file named TEXT_INSERT_DEMO.EXE into the newly created folder named EXTERNAL PROGRAMS, and run the compiler's editor.

Choose the menu item OPTIONS, and you will see a new menu item named RUN, at the bottom of the list. Move the mouse pointer over the RUN menu item, and a second menu will slide out from it showing the EXE files that are located in the EXTERNAL PROGRAMS folder. In this case there is only one because that's all we've placed in there for now.

Click the menu item, and a demonstration program will appear.

Type some text in the program's window and click the TRANSFER TEXT button. The program will end and the text will now be placed at the current cursor position in the editor's work space.

How does it work ?

Now you know how to run an external program, you need to know what the editor is actually looking for in order to add text. With this knowledge in hand you can create your own programs either in C, Delphi, Visual Basic or any language of your choice as long as it produces an executable file.

The editor actually looks at the contents of a text file named RES_FILE.TXT, which must be located in the EXTERNAL_PROGRAMS folder. Any text placed in this text file will be transferred to the editor's source code. It's as simple as that.

When building your own executable program, it must create or update a text file named RES_FILE.TXT, add whatever text content your program produces, and exit the program as normal. The editor will look for this file, extract any text within it, then clear the file (not delete it) ready for the next program.

For example, the TEXT_INSERT_DEMO.EXE program was written using Delphi 6. The source code for this is included along with it's executable, and virtually all of its code contents are listed below.

procedure TForm1.Button1Click(Sender: TObject);

var

RES_FILE_LOCATION: String;

    	CURRENT_DIRECTORY: String;

begin

    //

    // Extract the current directory.

    //

    CURRENT_DIRECTORY := ExtractFileDir(Application.EXEName) + '\';

    //

    // Buid up the RES_FILE.TXT filename and directory

    //

    RES_FILE_LOCATION := CURRENT_DIRECTORY + 'RES_FILE.TXT';

    //

    // Save the contents of the Memo as RES_FILE.TXT

    //

Memo1.Lines.SaveToFile(RES_FILE_LOCATION);

    //

    // Exit the program

    //

    Close();

end;

The above procedure is called on the button click event.


Error Messages

The compiler has a comprehensive system of error checking and messages. Some of the messages produced will not make full sense unless the PICmicro's architecture is understood, but most are simpler to understand.

The compiler is capable of issuing over 600 individually different error message texts, so an explanation of each one is impractical, and somewhat pointless, as  most messages are self explanatory, written in easy to understand sentences. However, some are a little more obscure by their very nature, and these are the messages explained here.

The format of a BASIC error message is as follows: -

Error at Line[Line Number]	In file[File that Error occurred in]	*** Error Message ***

For example, the error message: -

Error at Line [1]	In file [Test.bas]   *** Cannot assign a Variable to a Numeric constant! ***

will be produced from a BASIC line such as: -

123 = 123

This is self explanatory, because the assignment (text before the equals character) is clearly not a variable, therefore is incapable of holding a value.

Error messages produced by the MPASM assembler are different in format to the compiler's: -

Error [Error Number]..[Assembler File Name that contains the Error]..[Line Containing the Error]..[Error Message]

Note that the square brackets are implied in order to clarify each item, and are not always present in the error message.

Error messages produced by the assembler are many and varied, and will not be discussed here. It is recommended that the help file for MPASM, or it's manual (found on the accompanying Microchip CDROM) should be read.


Using PROTON+ within MPLAB IDE

Even though the PROTON+ compiler is now recognised by Microchip as third party software, as of yet, no high level tool suite is incorporated in the MPLAB IDE. This will change, but we all have to be patient.

In the meantime, I have created a Legacy Tool Suite that will allow the PROTON+ compiler version 2.1.5 onwards to be used in the MPLAB IDE and allow single stepping of the code on an ASM basis, or the use of the ICD2 or a Microchip Programmer.

I'll walk you through the method of operation step by step.

First, download a copy of the latest MPLAB IDE because this method will only work on versions 6.50 onwards. The release at the time of writing is 6.61, and I recommend using this version.

Locate the files TLCHILL.INI and PROTON.MTC (these may be found in the INC\MPLAB folder located within the compiler's folder) and copy them into MPLAB's folder LegacyLanguageSuites. MPLAB will default to location C:\Program Files\MPLAB IDE, so the legacy folder should be: -

C:\Program Files\MPLAB IDE\LegacyLanguageSuites.

Once these files have been copied, locate and run the file PROTON_MPLAB.REG (again, this may be found in the INC\MPLAB folder located within the compiler's folder). This will add entries into the registry that will register the PROTON+ Compiler as a toolsuite within MPLAB.

Open MPLAB, then click on the Project Wizard menu option.

And you will be presented by the intro window as shown below.

For this demonstration program, the PICmicro of choice is the 16F628A, so in the step 1 window, choose the 16F628A device.

By default the device chosen in this window will be the device that the compiler uses, regardless of a DEVICE command within the BASIC listing. The DEVICE command will be ignored (see Disabling the Automatic DEVICE Selection).

Click NEXT, then choose the Crownhill Associates PROTON+ Compiler toolsuite, and browse to where the PROTON+ compiler's executable is stored. The file used to incorporate the compiler into MPLAB is named PR_PLUS_MPLAB.EXE, so enter this file into the location window.

After clicking NEXT, a project name and location needs to be chosen in the step 3 window. The name given to the demonstration project is MPLAB_TEST, and it's located, in this case, in the compiler's source code folder. But it can be placed virtually anywhere on the hard drive as long as it is not nested too deeply.

Now we need to add the BASIC file to the project. The BASIC file for the demonstration is named MP_TEST.BAS.

Tick the box in the right hand window only if the chosen .BAS file is not located in the projects folder. In this case it is, so leave it unticked.

Clicking NEXT a few times after step 4 will create the project. But no BASIC filename has been loaded into the IDE, so right click on Source File option located in the MPLAB_TEST.MCW window, and choose the appropriate BASIC file.

For the demonstration, the program file name is MP_TEST.BAS.

That's it!

Double click on the MP_TEST.BAS text in the MPLAB_TEST.MCW window, and the BASIC file will be opened ready to compile. Choose Project then Build or (Ctrl F10) to compile the program.

Open whatever windows as you require and single step or animate the code at its source level. i.e. Assembler level.

Disabling the Automatic DEVICE Selection.

By default, MPLAB forces the compiler to ignore any DEVICE directives within the BASIC program in favour of whatever device is chosen in the Configure->Select Device Options menu. This can be disabled by right clicking on the filename within the MCW window and choosing Build Options.

You will be presented with a configuration window containing a single switch.

Untick the ON switch and click APPLY.

The device that the compiler recognises is now issued by the DEVICE directive within the BASIC program, therefore ensure that MPLAB is configured for the correct PICmicro device for any simulations of programming.

This has been a very brief explanation on how to incorporate the PROTON+ compiler into MPLAB, but it gives you the basics (Pun intended). The rest is up to you. Have fun.