SX/B Online Help

533 Menlo Drive, Suite 100
Rocklin, CA 95765

916-624-8333
916-624-8003 (FAX)

Sales: 888-512-1024 (US only)
Support: 888-99-STAMP (US only)

Visit us on the web: www.parallax.com
Comments and feedback: editor@parallax.com 		Copyright © 2004-2005 Parallax, Inc.
All Rights Reserved

Version 1.30 -- 01 JUL 2005


Copyrights and Trademarks

Copyright © 2004-2005 Parallax, Inc.
All rights reserved.

  • Ubicom is a trademark of Ubicom, Inc.
  • Windows is a registered trademark of Microsoft Corporation.
  • I2C is a registered trademark of Philips Corporation.
  • 1-Wire is a registered trademark of Maxim/Dallas Semiconductor.

    • Other brand and product names are trademarks or registered trademarks of their respective holders.


Disclaimer of Liability

Parallax, Inc. is not responsible for special, incidental, or consequential damages resulting from any breach of warranty, or under any legal theory, including lost profits, downtime, goodwill, damage to or replacement of equipment or property, and any costs of recovering, reprogramming, or reproducing any data stored in or used with Parallax products.


Support

In addition to a dynamic web site with myriad resources, Parallax maintains several public, web-based forums for Parallax products, including the SX microcontroller and SX/B programming language. Many people participate in these forums, making them a fun, fast, and free way to discuss the SX and its applications.

To subscribe to Parallax forums forum visit the Tech Support section of the Parallax web site or click on the link below.

Web Links:

  • Parallax Forums
  • Parallax SX Support Page(s)
  • Parallax Main Site
  • Parallax Tech Support


SX/B Commands

• ASM | ASM Instruction(s) ... ENDASM
• BRANCH | BRANCH Offset, Label0 {, Label1, Label2, ...}
• CLEART1 | CLEART1
• CLEART2 | CLEART2
• DATA | DATA Const0 {, Const1, Const2, ...}
• DEC | DEC ByteVar
• DJNZ | DJNZ ByteVar, Label
• DO ... LOOP | DO {WHILE | UNTIL Condition } ... LOOP {UNTIL | WHILE Condition }
• END | END
• EXIT | {IF Condition THEN} EXIT
• FOR ... NEXT | FOR ByteVar = StartVal TO EndVal {STEP {-}StepVal} ... NEXT
• FREQOUT † | FREQOUT Pin, Duration, Freq
• GET | GET Location, ByteVar {, ByteVar, ...}
• GOSUB ... RETURN | GOSUB Label ... RETURN { Value }
• GOTO | GOTO Label
• HIGH | HIGH Pin
• I2CRECV | I2CRECV Pin, ByteVar, AckBit
• I2CSEND | I2CSEND Pin, ByteVal {, AckVar}
• I2CSTART | I2CSTART Pin
• I2CSTOP | I2CSTOP Pin
• IF ... THEN | IF Condition [THEN | GOTO] [Label | EXIT]
• IF ... THEN ... ELSE | IF Condition THEN Statment(s) { ELSE Statement(s) } ENDIF
• INC | INC ByteVar
• INPUT | INPUT Pin
• INTERRUPT | INTERRUPT Instruction(s) ... RETURNINT {Cycles}
• LET | {LET} Expression
• LOOKDOWN | LOOKDOWN Target, Value0, {Value1, Value2, ...} ByteVar
• LOOKUP | LOOKUP Index, Value0, {Value1, Value2, ...} ByteVar
• LOW | LOW Pin
• OUTPUT | OUTPUT Pin
• OWRDBIT † | OWRDBIT Pin, BitVar
• OWRDBYTE † | OWRDBYTE Pin, ByteVar
• OWRESET † | OWRESET Pin {, ByteVar }
• OWWRBIT † | OWWRBIT Pin, BitVal
• OWWRBYTE † | OWWRBYTE Pin, ByteVal
• PAUSE † | PAUSE Value1 {[, | *] Value2}
• PAUSEUS † | PAUSEUS Value1 {[, | *] Value2}
• PULSIN † | PULSIN Pin, State, ByteVar {, Resolution}
• PULSOUT † | PULSOUT Pin, Duration {, Resolution}
• PUT | PUT Location, Value {, Value, ...}
• PWM † | PWM Pin, Duty, Duration
• RANDOM | RANDOM ByteVar1 {, ByteVar2}
• RCTIME † | RCTIME Pin, StartState, ByteVar {, Resolution}
• READ | READ Label {+ Offset}, ByteVar {, ByteVar, ...}
• RESETWDT | RESETWDT
• REVERSE | REVERSE Pin
• SERIN † | SERIN Pin, BaudMode, ByteVar {, Timeout, Label}
• SEROUT † | SEROUT Pin, BaudMode, Value
• SHIFTIN | SHIFTIN DPin, CPin, ShiftMode, ByteVar {\Count}
• SHIFTOUT | SHIFTOUT DPin, CPin, ShiftMode, Value {\Count}
• SLEEP | SLEEP
• SOUND † | SOUND Pin, Note, Duration
• SWAP | SWAP ByteVar
• TOGGLE | TOGGLE Pin

† Note: While all SX/B commands will run at any FREQ setting, commands that are time-sensitive (particularly PAUSEUS) have been designed for FREQ settings between 4 MHz and 50 MHz. FREQ settings outside this range (e.g. low-power applications running at 32 kHz) are not recommended when using time-sensitive instructions.


SX/B Overview

SX/B Compiler Overview

The SX/B (SX BASIC) compiler is a BASIC language compiler for the Ubicom™ SX family (SX18, SX20, SX28, SX48, and SX52) microcontroller designed to meet two specific goals:

  1. Expedite the task of the professional engineer by creating a simple, yet robust high-level language for the SX microcontroller. This allows SX-based projects to be prototyped and coded quickly.
  2. Assist the student programmer wishing to make the transition from pure high-level programming (i.e., BASIC Stamp®) to low-level programming (SX assembly language).

SX/B is an non-optimizing, inline compiler. What this means is that each BASIC language statement is converted to a block of assembly code in-line at the program location; no attempt is made to remove redundant instructions that would optimize code space. This allows the advanced programmer to modify code as required for specific projects, and -- perhaps more importantly -- provides an opportunity for the student to learn SX assembly language techniques by viewing a 1-for-1 (from BASIC to assembly language) output.

Conventions Used in this Document

In syntax descriptions, curly braces {} are used to indicate optional items. For example:

PULSOUT Pin, Duration {, Resolution}

In this case, the parameter for Resolution is optional.

In syntax descriptions, brackets [] indicate that the parameter must be one of the presented items (separated with the pipe | character). For example:

DEVICE [SX18 | SX20 | SX28 | SX48 | SX52] {, ...}

In this case, the DEVICE directive must indicate SX18, SX20, SX28, SX48, or SX52 (and may also include other optional items).

Example code is presented on a blue-tinted background:

Main:
  FOR RB = 0 TO 255
    PAUSE 100
  NEXT
  END


What's New?

What's New in SX/B?

Version 1.30 -- Release date 01 JUL 2005

  • Added ID directive
  • Subroutines can behave like functions, returning a value directly to a variable
    -- Example: someVar = SubName
  • PAUSE and PAUSEUS now allow fractional constants
  •  Allow BitVar = ByteVar
-- BitVar = 0 when ByteVar = 0;
          BitVar = 1 when ByteVar <> 0
  • Corrected BitVar = ~BitVar error

Version 1.22 -- Release date 9 MAY 2005

  • Documented DJNZ, and SWAP
  • BANK directive updated -- may be used without parameters
  • Added EXIT for FOR...NEXT and DO...LOOP
  • Corrected run-time error with LOAD

Version 1.21 -- Release date 27 APR 2005

  • Added DO...LOOP

Version 1.20 -- Release date 22 APR 2005

  • Supports all SX micros (SX18, SX20, SX28, SX48, and SX52)
  • Subroutine (SUB) declaration simplifies programming
  • Code pages handled automatically
  • Added IF...THEN...ELSE...ENDIF
  • Added commands for Philips I2C® communications (master only)
  • Added commands for Dallas/Maxim 1-Wire® communications
  • Added SWAP and DJNZ commands
  • BANK support (for SASM) -- simplifies access to non-global variables
Version 1.2 embodies major structual improvements and simplification over version 1.1, specifically in the area of declared subroutines and the automatic handling of code pages. Most programs written for version 1.1 will compile without change, however, it is recommended that these programs be updated to version 1.2 specifications to take full advantage of the SX/B compiler.

Version 1.10 -- Release date 15 DEC 2004

  • Allow BRANCH to use @ with Label
  • Allow RETURNINT ByteVar
  • Added FOR...NEXT overflow checking
  • Added NOPRESERVE option to INTERRUPT
  • Allows bits to be passed as parameters (sets __PARAMx to 0 or 1)
  • Added __RAM() system array (use with '@' RAM addresses)
  • Allows computed constants (SASM only, not for SX/B commands)
  • Improved timing accuracy of PAUSE, PAUSEUS, PULSIN, PULSOUT, SERIN, and SEROUT

Version 1.00 -- Release date 01 NOV 2004

  • Initial release


SX/B Definitions

IO Pins

IO pins are defined as variables -- either as a group, or as a single pin -- using the following syntax:

Symbol VAR Port{.Bit}

DigCtrl         VAR     RA                      ' 4 IO pins
Segments        VAR     RB                      ' 8 IO pins
Sio             VAR     RC.7                    ' 1 IO pin

On power-up or an external reset (via MCLR), an SX/B program clears all IO pins (port bits cleared to 0) and initializes them to inputs (TRIS bits set to 1).

Constants

Constant values can be declared in four ways: decimal (default), hex, binary, and ASCII using the following syntax:

Symbol CON Value

Hex numbers are preceded with a dollar sign ($), binary numbers are preceded with a percent sign (%), and ASCII values are enclosed in double quotes ("). If no special punctuation is used then the SX/B compiler will assume the value is decimal.

MaxCount        CON     4                       ' decimal
LEDmask         CON     $F0                     ' hex
SegMap          CON     %01100101               ' binary
Baud            CON     "T9600"                 ' ASCII (string)

Constant names can be any combination of letters, numbers, and underscores (_), but the first character must not be a number. Also, constant names cannot use reserved words, such as SX/B instruction names (SERIN, GOTO, etc.) and SX aliases (RA, OPTION, etc.). The maximum number of characters allowed for a constant name is 32.

As of version 1.10 you may define computed constants for use by SASM in assembly routines. For example:

B2400           CON     16                      ' 2400 Baud
B9600           CON     4                       ' 9600 Baud
BitTm           CON     B9600                   ' samples per bit
BitTm15         CON     3*BitTm/2               ' 1.5 bits

In the examples above, the first three constants may be used anywhere in the program. The final definition, for BitTm15, is a computed constant and my be used anywhere a variable is allowed. Note that computed constants may not be used where a constant value is required (e.g., the frequency parameter of FREQOUT).

String constants can be used to create "shortcuts" that ease programming, in effect, allowing the programmer to create new commands. For example:

  GOSUB RX_Byte, @serByte                       ' get command

can be replaced with:

  SERRX @serByte                                ' get command

by defining the following string constant:

SERRX           CON     "GOSUB RX_Byte, "

Using string constants in this manner has been superceded in version 1.2 by the SUB definition (for subroutine names and parameter requirements). See below for an improved method of declaring subroutines.

Variables

SX/B supports bytes, arrays of bytes, and bit variables using the following syntax:

Symbol VAR Byte{(Size)}
Symbol VAR Bit

count           VAR     Byte                    ' one byte (eight bits)
display         VAR     Byte(4)                 ' array of bytes
timer           VAR     Byte(NumTimers)         ' named constants are allowed

alarm           VAR     Bit                     ' one bit

When defining byte arrays, only constant values or named constants may be used for the Size parameter, and array elements are zero-based, that is the elements are indexed from zero to Size-1. For example, myArray(10) contains the elements myArray(0) through myArray(9). In the SX18/20/28 arrays are limited to 16 elements; in the SX48/52 arrays may have up to 212 elements.

Variable names may be aliased (renamed) for programming convenience. This also allows a group of bit variables to be included in the same byte for single-line evaluation or modification

clock           VAR     Byte(3)                 ' clock array
secs            VAR     clock(0)                ' seconds
mins            VAR     clock(1)                ' minutes
hrs             VAR     clock(2)                ' hours

flags           VAR     Byte                    ' all flags
hiTemp          VAR     flags.0                 ' high temp flag
loTemp          VAR     flags.1                 ' low temp flag

alarms          VAR     Byte(2)                 ' two bytes (16 bits)
fDoor           VAR     alarms(0).0             ' front door
bDoor           VAR     alarms(0).1             ' back door
patio           VAR     alarms(1).7

Internal SX aliases may also be renamed for improved program readability. For example:

Segs            VAR     RB                      ' display segments (anodes)
TRIS_Segs       VAR     TRIS_B                  ' segments TRIS reg
DigCtrl         VAR     RA                      ' digit control (cathode)
TRIS_Dig        VAR     TRIS_A                  ' digits TRIS reg

Variable names can be any combination of letters, numbers, and underscores (_), but the first character must not be a number. Also, variable names cannot use reserved words, such as SX/B instruction names (SERIN, GOTO, etc.) and SX aliases (RA, OPTION, etc.). The maximum number of characters allowed for a variable name is 32.

On power-up or an external reset (via MCLR), an SX/B program initializes all variables to zero unless the NOSTARTUP option is used with the PROGRAM directive.

Variables are usually passed by value using this form:

  var1 = var2                                   ' copy var2 to var1

... actually copies the value of var2 and places it into var1. The address (RAM location) of a variable may be passed by prefacing the variable name with '@':

  var1 = @var2                                  ' put address of var2 into var1

This feature is particularly useful for passing address parameters to subroutines, especially when using PUT, GET, or the __RAM() system array. Note that when assigning a bit variable a value from a byte variable, as in...

  bitVar = byteVar

... the bit variable will bet set to zero if the byte variable is zero, otherwise the bit variable will be set to one.

Variable space (bytes):

Device | General | Arrays | Max. Array
SX18/20 | 21 | 105 | 16 (each)
SX28 | 20 | 104 | 16 (each)
SX48/52 | 18 | 212 | 212

Program Labels

An SX/B program uses labels to define entry points into code sections or data tables. When used as a code entry point or data table name, label names must start in column one (not indented), end with a colon(:), and be on its own line. When used elsewhere in the program, labels are named without the colon, as in the example below:

Msg:                                            ' colon required
  DATA "SX/B makes the SX fun!", 13, 0

Start:                                          ' colon required
  idx = 0

Main:                                           ' colon required
  READ Msg + idx, char                          ' no colon required
  INC idx
  IF char = 0 THEN Start                        ' no colon required
  SEROUT Sio, Baud, char
  PAUSE 1000
  GOTO Main                                     ' no colon required

Label names can be any combination of letters, numbers, and underscores (_), but the first character must not be a number. Also, label names cannot use reserved words, such as SX/B instruction names (SERIN, GOTO, etc.) and SX aliases (RA, OPTION, etc.). The maximum number of characters allowed for a label name is 32.

Comments

Comments can be used to add additional information to a program. The apostrophe character (') begins a comment section; anything to the right of the comment character will be ignored by the compiler. This allows comments to be added to a line of code. Using the comment character is also a convenient way to disable a line of code without removing it from the program.

' Display a running counter on RB

Main:
  INC RB                                        ' update LEDs
'  INC RB                                       ' this line disabled
  PAUSE 100                                     ' insert delay
  GOTO Main                                     ' run forever

Note: For backward-compatibility with older versions of the BASIC programming language, REM may be used to define a line comment, though this style is outdated and generally discouraged.

REM This is a really old-fashioned style comment.

Inline Assembly Instructions

SX assembly instructions can be inserted into an SX/B program using the "\" (back-slash) character to preface the assembly code statement. For large blocks of assembly code ASM...ENDASM is recommended.

LEDs            VAR     RB                      ' eight LEDs on RB

countLo         VAR     Byte                    ' 16-bit counter
countHi         VAR     Byte

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  \ MOV RB, countLo                             ' copy low byte to LEDs
  PAUSE 100
  \ INC countLo                                 ' update count
  \ JB Z, Main2                                 ' jump if countLo is zero
  \ JMP Main                                    ' jump to Main

Main2:
  \ INC countHi                                 ' increment high byte
  \ JMP Main                                    ' jump to Main

Note: Array elements hold the address of a variable so they should not be used in inline assembly instructions.

Subroutine Declaration

The programming and use of subroutines is simplified by declaring the subroutine name and the parameter(s) (if any) required. Additionally, the declaration of subroutines allows them to return a value (much like a function in C). Declaring subroutines offers significant advantages to the programmer:

  • The compiler can check code for the correct number of parameters
  • GOSUB is no longer required to call the subroutine
  • The subroutine can return a direct value
    -- This is simpler than passing the variable's address (@VarName)
  • Code page management is automatically handled

SX/B subroutines are defined using the following syntax:

Label SUB {Min{, Max}}

The following short segment shows how predifined subroutines simplify SX/B program development:

TXBYTE         SUB     1, 2                     ' sub with 1 or 2 parameters

Start:
  TXBYTE "*"                                    ' send one asterisk
  TXBYTE "-", 20                                ' send 20 dashes
  TXBYTE                                        ' raises syntax error
  END

TXBYTE:
  temp1 = __PARAM1                              ' save character
  IF __PARAMCNT = 2 THEN
    temp2 = __PARAM2                            ' save repeats
  ELSE
    temp2 = 1                                   ' set to 1 if not specified
  ENDIF
  DO WHILE temp2 > 0
    SEROUT Sout, Baud, temp1                    ' send the byte
    DEC temp2                                   ' dec repeats
  LOOP
  RETURN

Subroutines can also behave like functions in other languages, returning a value directly to a variable after the subroutine call. For example:

  char = RXBYTE

The value/variable to be returned to the calling code is placed after RETURN at the end of the subroutine code:

RXBYTE:
  SERIN Sin, Baud, temp1                        ' wait for serial input
  RETURN temp1                                  ' return to caller

Note that subroutines do not have to be declared, but by doing so the subroutine code can be placed anywhere in the listing (without declaration the code must be in the first half of a code page), GOSUB is no longer needed to call the subroutine, and the compiler is able to check the for the proper number of parameters. The only requirement is that the SUB declaration(s) be placed in the first half of a code page. The advantages of the SUB declaration far outweigh the minor effort required to add the declaration.


SX/B Directives

DEVICE (Required)

DEVICE [SX18 | SX20 | SX28 | SX48 | SX52] {, ...}

The DEVICE directive specifies the device type (e.g, SX18, SX28), oscillator type, and other SX fuse settings.

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX

Consult the SX-Key Development System Manual for a complete list of SX DEVICE options.

IRC_CAL

IRC_CAL [IRC_SLOW | IRC_4MHZ | IRC_FAST]

The IRC_CAL directive specifies the calibration value for the internal RC oscillator.

When the options IRC_SLOW or IRC_FAST are specified, the IRCTRIM bits in the FUSEX device configuration register are programmed to the minimum or maximum frequency value. When the option IRC_4MHZ is specified, the SX-Key software performs a calibration procedure whenever a program is downloaded to the SX chip and adjusts the IRCTRIM bits so that the internally generated clock frequency comes close as possible to 4 MHz.

IRC_CAL         IRC_4MHZ                        ' calibrate internal RC clock

When not specified, the IRC_CAL setting is defaulted to IRC_SLOW.

FREQ {Required}

FREQ Hertz

The FREQ (frequency) directive is used to set the frequency (in Hertz) of the SX-Key's internal programmable oscillator to be used during debugging. FREQ is also used by the SX/B compiler for calculating delays in timing-sensitive instructions (PAUSE, SERIN, SEROUT, etc.), so connecting a clock source that differs from the compiled FREQ setting will affect stand-alone operation.

FREQ            4_000_000

Note that frequency can be any number from 31250 to 110000000, but debugging via the SX-Key only works with frequencies between 4000000 and 110000000. Additionally, underscore characters can be used to help make the number more readable, as in 50_000_000, which is 50 MHz.

ID

ID ID_String

The ID (identification) directive is used to write up to eight bytes of text into the ID word of the SX chip. This is used to record a version number or other unique identification for the code. This ID word can be read out of the SX chip at any time, regardless of the code protect setting. The line below will write GPXv2.1 into the ID word:

ID               'GPXv2.1'

WATCH

WATCH Variable{.Bit}, Count, Format

The WATCH directive allows the definition of format for viewing and modifying variables at runtime during debug mode. The variable's name, number of bits or bytes to view, and display format may be specified.

WATCH timer, 1, UDEC
WATCH flags.0, 1, UBIN

The table below lists the available format settings for the WATCH directive.

Format | Operation
UDEC | Displays value in unsigned decimal format
SDEC | Displays value in signed decimal format
UHEX | Displays value in unsigned hexadecimal format
SHEX | Displays value in signed hexadecimal format
UBIN | Displays value in unsigned binary format
SBIN | Displays value in signed binary format
FSTR | Displays value in fixed-length string format
ZSTR | Displays value in zero-terminated string format

Consult the SX-Key Development System Manual for additional information about the WATCH directive.

LOAD

LOAD "FileName.SXB"

The LOAD directive is used to insert an SX/B source code file at the current location.

LOAD "LCD.SXB"

INCLUDE

INCLUDE "FileName"

The INCLUDE directive is used to insert an SX assembly code file at the current location.

INCLUDE "SETUP28.INC"

INCLUDE "I2C.SRC"

PROGRAM (Required)

PROGRAM Label {NOSTARTUP}

The PROGRAM directive sets the execution start point (at a label) for the SX/B program. Note that the PROGRAM directive must appear after the (optional) INTERRUPT hander, and in the first code page ($000 - $199).

When the NOSTARTUP option is used the SX/B compiler will not insert the normal start-up code that pre-initializes all RAM addresses to zero; in this case the programmer is responsible for appropriate initialization code. Note that when the NOSTARTUP option is used the BANK (FSR register) is indeterminate at start-up, hence the programmer is cautioned to set the BANK prior to variable access.

PROGRAM Start

Msg:
  DATA  "SX/B is very cool!", 0

Start:
  TRIS_B = %00000000

Main:
  GOSUB Send_Msg
  INC RB
  PAUSE 1000
  GOTO Main

BANK

BANK {DefaultBank} {NOCODE}

The BANK directive loads the BANK (FSR) variable with DefaultBank. The value will also be reloaded after any instruction that modifies BANK (FSR). DefaultBank may be a constant or a byte variable that is in the global RAM area (location <$10). If DefaultBank is the first variable declared, it will be in the global area.

If the NOCODE option is specifed the BANK (FSR) is not changed immediately. This is useful if you know that the BANK (FSR) has ready been set, so there is no need to set it again. Since BANK is a compiler directive it's affect is strictly top-down, that is, its affect does not follow program flow if the program branches to a different section of code.

If BANK is used with no parameters, it will set the BANK (FSR) to the DefaultBank. This is useful in assembly routines, otherwise you would have to store the current FSR before using it.

BREAK

BREAK

The BREAK directive inserts a breakpoint into the assembly code which can useful during program debugging.

Start:
  TRIS_B = %00000000
  BREAK

Main:
  INC RB
  GOTO Main

Note that only one BREAK directive may be used in an SX/B program. To create the effect of multiple breakpoints, the programmer may insert the BREAK directive into a subroutine that can be called from any point in the program.

ADDRESS

ADDRESS PageAddr

The ADDRESS directive sets the starting location for the instructions that follow.

Page_1:
  ADDRESS $200

Note that as of version 1.2, it is not longer necessary for the programmer to manually set code page addresses.


SX/B Operators

Unary Operators

- (Negate)

Variable1 = -Variable2

Places the negative (two's compliment) value of Variable2 into Variable1 (Variable2 is not modified).

Main:
  RB = $0F                                      ' RB = %00001111
  RB = -RB                                      ' RB = %11110001
  END

~, NOT (Bitwise NOT)

Variable1 = ~Variable2
Variable1 = NOT Variable2

Places the bitwise inversion of Variable2 into Variable1 (Variable2 is not modified). Each result bit is subject to the following logic:

    NOT 0 = 1
    NOT 1 = 0

Main:
  xx = $F0                                      ' xx = %11110000
  RB = NOT xx                                   ' RB = %00001111
  RB = NOT RB                                   ' RB = %11110000
  RB = ~ RB                                     ' RB = %00001111
  RB.0 = ~ RB.0                                 ' RB = %00001110
  RB.1 = NOT xx.7                               ' RB = %00001100
  END

Binary Operators

+ (Addition)

ByteVar = Value1 + Value2

Adds two values (variables or constants) and places result in ByteVar. If the result is greater than 255 it will be truncated to eight bits and the Carry bit (C) will be set (1).

Main:
  RB = $0F                                      ' RB = %00001111
  RB = RB + $F0                                 ' RB = %11111111, C = 0
  RB = RB + 2                                   ' RB = %00000001, C = 1
  END

The following code fragment shows how the Carry bit can be used with a 16-bit result value.

  resultLo = resultLo + work                    ' add work to result
  resultHi = resultHi + C                       ' update high byte on carry

- (Subtraction)

ByteVar = Value1 - Value2

Subtracts Value2 from Value1 and places the result in ByteVar. If the result is less than zero, two's-compliment format is used and the Carry bit (C) will be cleared (0).

Main:
  RB = $0F                                      ' RB = %00001111 (15)
  RB = RB - 7                                   ' RB = %00001000 (8), C = 1
  RB = RB - 10                                  ' RB = %11111110 (-2), C = 0
  END

The following code fragment shows how the Carry bit can be used with a 16-bit result value. Note that the Carry bit is cleared on an underflow after a subtraction.

  resultLo = resultLo - work                    ' subtract work from result
  resultHi = resultHi - ~C                      ' update high byte on underflow

* (Multiplication)

ByteVar = Value1 * Value2

Multiplies Value1 by Value2 and places the result in ByteVar. If the result is greater than 255 it will be truncated to eight bits.

Main:
  RB = %00001111                                ' RB = %00001111 (15)
  RB = RB * 16                                  ' RB = %11110000 (240)
  RB = RB * 2                                   ' RB = %11100000 (224)
  END

/ (Division)

ByteVar = Value1 / Value2

Divides Value1 by Value2 and places the (integer) result in ByteVar.

Main:
  RB = $F0                                      ' RB = %11110000 (240)
  RB = RB / 16                                  ' RB = %00001111 (15)
  RB = RB / 4                                   ' RB = %00000011 (3)
  END

// (Modulus)

ByteVar = Value1 // Value2

Divides Value1 by Value2 and places the remainder in ByteVar.

Main:
  RB = 25                                       ' RB = %00011001 (25)
  RB = RB // 10                                 ' RB = %00000101 (5)
  END

Note: The remainder of a division (modulus) is available immediately after the division or modulus operation. This code:

  dig10 = value / 10
  dig01 = __REMAINDER

... uses half the instruction space of:

  dig10 = value / 10
  dig01 = value // 10

The only requirement for using __REMAINDER is that the assignment to another variable must be the first instruction following the division or modulus operation.

MAX

ByteVar = Value MAX Limit

Places Value into ByteVar limiting the maximum value of ByteVar to Limit.

Start:
  TRIS_B = %00000000

Main:
  FOR idx = 0 TO 15                             ' idx = 0 .. 15
    RB = idx MAX 7                              ' RB = 0 .. 7
    PAUSE 100
  NEXT idx
  GOTO Main

MIN

ByteVar = Value MIN Limit

Places Value into ByteVar forcing the minimum value of ByteVar to Limit.

Start:
  TRIS_B = %00000000

Main:
  FOR idx = 0 TO 15                             ' idx = 0 .. 15
    RB = idx MIN 7                              ' RB = 7 .. 15
    PAUSE 100
  NEXT idx
  GOTO Main

&, AND (Bitwise AND)

ByteVar = Value1 & Value2
ByteVar = Value1 AND Value2

Performs a bitwise AND operation on Value1 and Value2, then places the result in ByteVar. Each result bit is subject to the following logic:

    0 & 0 = 0
    0 & 1 = 0
    1 & 0 = 0
    1 & 1 = 1

Main:
  RB = $0F & %11111111                          ' RB = %00001111
  RB = RB AND %11111100                         ' RB = %00001100
  END

|, OR (Bitwise OR)

ByteVar = Value1 | Value2
ByteVar = Value1 OR Value2

Performs a bitwise OR operation on Value1 and Value2, then places the result in ByteVar. Each result bit is subject to the following logic:

    0 | 0 = 0
    0 | 1 = 1
    1 | 0 = 1
    1 | 1 = 1

Main:
  RB = %00001111                                ' RB = %00001111
  RB = RB | %11000000                           ' RB = %11001111
  RB = RB OR %00011111                          ' RB = %11011111
  END

^, XOR (Bitwise Exclusive OR)

ByteVar = Value1 ^ Value2
ByteVar = Value1 XOR Value2

Performs a bitwise Exclusive OR operation on Value1 and Value2, then places the result in ByteVar. Each result bit is subject to the following logic:

    0 ^ 0 = 0
    0 ^ 1 = 1
    1 ^ 0 = 1
    1 ^ 1 = 0

Main:
  RB = %00001111                                ' RB = %00001111
  RB = RB ^ %11000000                           ' RB = %11001111
  RB = RB XOR %00011111                         ' RB = %11010000
  END

<<, SHL (Shift Left)

ByteVar = Value1 << Value2
ByteVar = Value1 SHL Value2

Left shifts the bits of Value1 by the number specified in Value2. Bits shifted off the left end (MSB) of a number are lost; bits shifted into the right end of the number are zeros. Shifting the bits of a value left n number of times has the same effect as multiplying that number by 2 to the nth power. For instance 15 << 3 (shift the bits of the decimal number 15 left three places) is equivalent to 15 * 23 (15 * 8).

Main:
  RB = %00001101 << 2                           ' RB = %00110100
  RB = RB SHL 4                                 ' RB = %01000000
  END

>>, SHR (Shift Right)

ByteVar = Value1 >> Value2
ByteVar = Value1 SHR Value2

Right shifts the bits of Value1 by the number specified in Value2. Bits shifted off the right end (LSB) of a number are lost; bits shifted into the left end of the number are zeros. Shifting the bits of a value right n number of times has the same effect as dividing that number by 2 to the nth power. For instance $F0 >> 3 (shift the bits of the decimal number 240 right three places) is equivalent to 240 / 23 (240 / 8).

Main:
  RB = %10110000 >> 2                           ' RB = %00101100
  RB = RB SHR 4                                 ' RB = %00000010
  END


SX/B Aliases

SX Registers
 |  |  | SX18 | SX20 | SX28 | SX48 | SX52
• IND | Indirect Register | $00 |  |  |  |  |
• RTCC | Real Time Clock/Counter | $01 |  |  |  |  |
• PC | Program Counter | $02 |  |  |  |  |
• STATUS | Status Register | $03 |  |  |  |  |
• PA2 | Page Select bit 2 | STATUS.7 |  |  |  |  |
• PA1 | Page Select bit 1 | STATUS.6 |  |  |  |  |
• PA0 | Page Select bit 0 | STATUS.5 |  |  |  |  |
• TO | Time Out | STATUS.4 |  |  |  |  |
• PD | Power Down | STATUS.3 |  |  |  |  |
• Z | Zero | STATUS.2 |  |  |  |  |
• DC | Digit Carry | STATUS.1 |  |  |  |  |
• C | Carry | STATUS.0 |  |  |  |  |
• FSR | File Select Register | $04 |  |  |  |  |
• RA | Port A | $05 |  |  |  |  |
• RB | Port B | $06 |  |  |  |  |
• RC | Port C | $07 |  |  |  |  |
• RD | Port D | $08 |  |  |  |  |
• RE | Port E | $09 |  |  |  |  |
• PORTA | Port A | $05 |  |  |  |  |
• PORTB | Port B | $06 |  |  |  |  |
• PORTC | Port C | $07 |  |  |  |  |
• PORTD | Port D | $08 |  |  |  |  |
• PORTE | Port E | $09 |  |  |  |  |
• TRIS_A | Data Direction register for RA |  |  |  |  |  |
• TRIS_B | Data Direction register for RB |  |  |  |  |  |
• TRIS_C | Data Direction register for RC |  |  |  |  |  |
• TRIS_D | Data Direction register for RD |  |  |  |  |  |
• TRIS_E | Data Direction register for RE |  |  |  |  |  |
• PLP_A 1 | Pull-Up resistor enable for RA |  |  |  |  |  |
• PLP_B 1 | Pull-Up resistor enable for RB |  |  |  |  |  |
• PLP_C 1 | Pull-Up resistor enable for RC |  |  |  |  |  |
• PLP_D 1 | Pull-Up resistor enable for RD |  |  |  |  |  |
• PLP_E 1 | Pull-Up resistor enable for RE |  |  |  |  |  |
• LVL_A 1 | TTL/CMOS select for RA |  |  |  |  |  |
• LVL_B 1 | TTL/CMOS select for RB |  |  |  |  |  |
• LVL_C 1 | TTL/CMOS select for RC |  |  |  |  |  |
• LVL_D 1 | TTL/CMOS select for RD |  |  |  |  |  |
• LVL_E 1 | TTL/CMOS select for RE |  |  |  |  |  |
• ST_B 1 | Schmitt-Trigger enable for RB |  |  |  |  |  |
• ST_C 1 | Schmitt-Trigger enable for RC |  |  |  |  |  |
• ST_D 1 | Schmitt-Trigger enable for RD |  |  |  |  |  |
• ST_E 1 | Schmitt-Trigger enable for RE |  |  |  |  |  |
• WKEN_B 1 | Wake Up enable register |  |  |  |  |  |
• WKED_B 1 | Wake Up edge select register |  |  |  |  |  |
• WKPND_B 1, 2 | MIWU pending register |  |  |  |  |  |
• CMP_B 1, 2 | Comparator enable register |  |  |  |  |  |
• T1CPL | Low byte of Timer T1 capture register |  |  |  |  |  |
• T1CPH | High byte of Timer T1 capture register |  |  |  |  |  |
• T1R1CML | Low byte of Timer T1 compare register 1 |  |  |  |  |  |
• T1R1CMH | High byte of Timer T1 compare register 1 |  |  |  |  |  |
• T1R2CML | Low byte of Timer T1 compare register 2 |  |  |  |  |  |
• T1R2CMH | High byte of Timer T1 compare register 2 |  |  |  |  |  |
• T1CNTA | Timer T1 control register A |  |  |  |  |  |
• T1CNTB | Timer T1 control register B |  |  |  |  |  |
• T2CPL | Low byte of Timer T2 capture register |  |  |  |  |  |
• T2CPH | High byte of Timer T2 capture register |  |  |  |  |  |
• T2R1CML | Low byte of Timer T2 compare register 1 |  |  |  |  |  |
• T2R1CMH | High byte of Timer T2 compare register 1 |  |  |  |  |  |
• T2R2CML | Low byte of Timer T2 compare register 2 |  |  |  |  |  |
• T2R2CMH | High byte of Timer T2 compare register 2 |  |  |  |  |  |
• T2CNTA | Timer T2 control register A |  |  |  |  |  |
• T2CNTB | Timer T2 control register B |  |  |  |  |  |
• MODE | Mode register |  |  |  |  |  |
• M | Mode register |  |  |  |  |  |
• OPTION | Option register |  |  |  |  |  |

1 When changed (i.e., Register = Value), the SX/B compiler automatically inserts the correct Mode (M) register instruction.
2 When changed (i.e., Register = Variable), Variable is swapped with Register.

SX/B Variables
 |  |  | SX18 | SX20 | SX28 | SX48 | SX52
• __RAM() | Provides access to any RAM address | $00 |  |  |  |  |
• __PARAMCNT | Number of parameters passed to subroutine | FSR |  |  |  |  |
• __PARAM1 | First parameter | $08 / $0A * |  |  |  |  |
• __PARAM2 | Second parameter | $09 / $0B * |  |  |  |  |
• __PARAM3 | Third parameter | $0A / $0C * |  |  |  |  |
• __PARAM4 | Fourth parameter | $0B / $0E * |  |  |  |  |
• __REMAINDER | Remainder after a division | $08 / $0A * |  |  |  |  |
• __TRISA † | TRIS_A copy | $FA |  |  |  |  |
• __TRISB † | TRIS_B copy | $FB |  |  |  |  |
• __TRISC † | TRIS_C copy | $FC |  |  |  |  |
• __TRISD † | TRIS_D copy | $FD |  |  |  |  |
• __TRISE † | TRIS_E copy | $FE |  |  |  |  |
• __INTPARAMFSR | ??? | $FF |  |  |  |  |

* Note: Location depends on module used: SX18/20/28 or SX48/52
† Note: These registers must not be modified by the programmer, otherwise some instructions will be adversely affected.


Analog Comparator

Using the Analog Comparator

I/O pins 0 through 2 in port B can be set for comparator operation. This can be configured by writing to the EN and OE bits of the Comparator register (CMP_B) and monitored by reading the RES bit. The comparator mode is disabled by default. Comparator mode can be activated for all three pins, regardless of pin direction, but really matters only when pin 1 and 2 are set to input mode (pin 0 can optionally be set to output the comparative result). By configuring Comparator mode, the SX chip can quickly determine logical differences between two signals and even indicate those differences for external circuitry.

When comparator mode is activated, the RES bit in the Comparator register indicates the result of the compare. A high bit (1) indicates the voltage on pin 2 is higher than that of pin 1, a low bit (0) indicates the voltage on pin 2 is lower than that of pin 1. If the OE bit (Output Enable) of the Comparator register is cleared, output pin 0 of port B reflects the state of the RES bit.

To configure port B I/O pins 0 though 2 for Comparator mode:

  1. Set CMP_B to enable the Comparator and, optionally, the result output on pin 0.
  2. Set I/O pin directions appropriately.

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Demonstrates the use of the SX comparator and controlling RB.0 for
' external circuitry.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

result          VAR     Byte
cmpValue        VAR     result.0

Watch_List:
  WATCH cmpValue, 1, UBIN

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  CMP_B = 0                                     ' enable comparator
  TRIS_B = %11111110                            ' RB.0 is output

Main:
  CMP_B = result                                ' exchange result with CMP
  GOTO Main


Additional Resources

The following books are published by Parallax and make a great addition to your SX programming library.

SX-Key/Blitz Development System Manual
by Parallax

This guide for the SX-Key programming tool includes software installation, quick-start using the SX-Tech Board, and a thorough explanation of the SX-Key software. This is a "must have" resource for SX engineers.

Note: This book is available as a PDF download.
Exploring the SX Microcontroller
with Assembly and BASIC Programming
by Al Williams

This book by Al Williams is a compilation of the Introduction to Assembly Language Programming with SX Microcontrollers and Introduction to I/O Control with the SX Microcontroller. This new edition features improved schematics, valuable hints, new graphics, and professional formatting. The first part of the book introduces you to the internal architecture of the SX microcontroller as well as basic hardware and software concepts. Topics include: number systems, programming and debugging, flow control, math, basic I/O, interrupts, and virtual peripherals. The second half of the book covers more advanced I/O programming and advanced topics.

Note: This book is available as a PDF download.
Programming the SX Microcontroller - A Complete Guide
by Günther Daubach

If you're ready to learn assembly language microcontroller programming, this is the book for you. Programming the SX Microcontroller, a Complete Guide by Günther Daubach has not only a tutorial section for getting started, but also comprehensive reference and application sections you will reach for again and again.

Online information.


Example Projects

SX/B Example Projects SX/B Commands

  • Programming Template
  • Digital Dice
  • Clock / Timer
  • Thermometer
  • Scanning a 4x4 Keypad
  • Serial LCD
  • Quadrature Encoder Input


SX/B Programming Template

SX/B Programming Template Examples Index

The following programming template, while somewhat verbose, will help programmers new to SX/B and the SXmicro to keep things in order so that programs compile and assemble successfully. Parallax suggests that you use this template as is, removing unused sections only after your program is tested and working as desired.

' =========================================================================
'
'   File...... TEMPLATE.SXB
'   Purpose... SX/B Programming Template
'   Author....
'   E-mail....
'   Started...
'   Updated... 01 JUL 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
  INTERRUPT
' -------------------------------------------------------------------------

ISR_Start:
  ' ISR code here

ISR_Exit:
  RETURNINT ' {cycles}

' =========================================================================
  PROGRAM Start
' =========================================================================

Pgm_ID:
  DATA  "SX/B 1.3 Template", 0

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  ' initialization code here

Main:
  ' main code here
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------


SX/B Example: Digital Dice

SX/B Example: Digital Dice Examples Index

' =========================================================================
'
'   File...... DICE.SXB
'   Purpose... A Pair of Digital Dice
'   Author.... (c) Parallax, Inc. -- All Rights Reserved
'   E-mail.... support@parallax.com
'   Started...
'   Updated... 01 JUL 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Simple digital dice program.  Uses outputs from RB and RC to dice pattern
' on seven LEDs (for each port) as shown below:
'
'   (0)     (1)
'   (5) (6) (2)
'   (4)     (3)
'
' A button input on RA.3 is used to "roll" the dice.  When rolling is
' stopped, display will stay solid for at least one second, then the
' program will wait for the Roll button to be pressed again.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Roll            VAR     RA.3                    ' roll button
Die0            VAR     RB                      ' LEDs out for die #1
Die1            VAR     RC                      ' LEDs out for die #2

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

No              CON     1                       ' button not pressed
Yes             CON     0

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

d1Val           VAR     Byte                    ' value of die #1
d2Val           VAR     Byte                    ' value of die #2
pattern         VAR     Byte                    ' dice pattern

temp1           VAR     Byte                    ' work variables
temp2           VAR     Byte
temp3           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

PipPats:
  DATA  %01000000                               ' 1
  DATA  %00010010                               ' 2
  DATA  %01010010                               ' 3
  DATA  %00011011                               ' 4
  DATA  %01011011                               ' 5
  DATA  %00111111                               ' 6

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

GETDIE          SUB     1                       ' pass seed and index addr

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_B = %10000000                            ' make LED ports outputs
  TRIS_C = %10000000
  PLP_A = %1000                                 ' pull-up unused pins
  PLP_B = %01111111
  PLP_C = %01111111

  d1Val = $A5                                   ' initialize seeds
  d2Val = $5A

Main:
  DO
    Die0 = GETDIE @d1Val                        ' randomize die values
    Die1 = GETDIE @d2Val
    PAUSE 50                                    ' delay between rolls
  LOOP WHILE Roll = No                          ' wait for button
  PAUSE 1000                                    ' show dice (1 sec min)

Wait_For_Press:
  DO
    PAUSE 10
  LOOP UNTIL Roll = Yes

Wait_For_Release:
  DO WHILE Roll = Yes
    PAUSE 10
  LOOP
  PAUSE 100
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: pattern = GETDIE @seed
' -- randomizes 'seed' (must pass address as 'seed' is updated)
' -- returns die display in 'pattern'

GETDIE:
  temp1 = __PARAM1                              ' get seed address
  temp2 = __RAM(temp1)                          ' get seed value
  RANDOM temp2                                  ' randomize seed
  __RAM(temp1) = temp2                          ' replace seed
  temp2 = temp2 / 43                            ' make = 0 to 5
  READ PipPats + temp2, temp1                   ' get LED pattern
  RETURN temp1


SX/B Example: Clock / Timer

SX/B Example: Clock / Timer Examples Index

' =========================================================================
'
'   File...... TIMER.SXB
'   Purpose... Dual-Mode digital timer
'   Author.... (c) Parallax, Inc. -- All Rights Reserved
'   E-mail.... support@parallax.com
'   Started...
'   Updated... 06 APR 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Displays running clock/timer on multiplexed 7-segment display.  The
' four-digit display is multiplexed through a "virtual" driver which is
' handled in the INTERRUPT routine.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

DigCtrl         VAR     RA                      ' digit control (cathodes)
Segs            VAR     RB                      ' display segments (anodes)
TmrMode         VAR     RC.6                    ' mode: 0 = mmss, 1 = hhmm
TmrEnable       VAR     RC.7                    ' enable input, 1 = run

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Yes             CON     1
No              CON     0

MaxDigit        CON     4                       ' 4-digit display
DecPnt          CON     %10000000               ' decimal point mask

TmrMMSS         CON     1                       ' show MM.SS (no blink)
TmrHHMM         CON     0                       ' show HH.MM (blink DP)
TmrRun          CON     1                       ' run timer
TmrHold         CON     0                       ' hold timer

MaxHr           CON     24                      ' 0 .. 23 (clock mode)
                                                ' make 100 for 0 .. 99

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

clock           VAR     Byte(4)
tix             VAR     clock(0)                ' 1/200th second
secs            VAR     clock(1)                ' seconds
mins            VAR     clock(2)                ' minutes
hrs             VAR     clock(3)

display         VAR     Byte(MaxDigit)          ' multiplexed segments
digPntr         VAR     Byte                    ' digit pointer
temp1           VAR     Byte
temp2           VAR     Byte

blink           VAR     secs.0                  ' DP blink control bit

' -------------------------------------------------------------------------
  INTERRUPT
' -------------------------------------------------------------------------

' The ISR is called every 5 milliseconds, based on a 4 MHz clock, prescalar
' setting of 1:128, and interrupting every 156 RTCC cycles.
'
' If the timer is enabled (TmrEnable pin = 1), the timer values will be
' updated every 200 milliseconds, otherwise only the display will be
' refreshed (one digit per interrupt).

ISR_Start:
  IF TmrEnable = TmrHold THEN Next_Digit    	' skip clock update if 0

Update_Timer:
  INC tix                                       ' update tix counter
  IF tix = 200 THEN                  		' check for 1 second
    tix = 0
    INC secs
    IF secs = 60 THEN				' check for new minute
      secs = 0
      INC mins
      IF mins = 60 THEN				' check for new hour
        mins = 0
        INC hrs
        IF hrs = MaxHr THEN
          hrs = 0
        ENDIF
      ENDIF
    ENDIF
  ENDIF

Next_Digit:
  INC digPntr                                   ' point to next digit
  IF digPntr = MaxDigit THEN        		' check pointer
    digPntr = 0                              	' wrap if needed
  ENDIF

Update_Segs:
  Segs = %00000000                              ' blank segments
  READ DigMap + digPntr, DigCtrl                ' update digit control
  Segs = display(digPntr)                       ' output new segments

ISR_Exit:
  RETURNINT 156

' =========================================================================
  PROGRAM Start
' =========================================================================

SegMap:                                         ' segments maps
'        .gfedcba
  DATA  %00111111                               ' 0
  DATA  %00000110                               ' 1
  DATA  %01011011                               ' 2
  DATA  %01001111                               ' 3
  DATA  %01100110                               ' 4
  DATA  %01101101                               ' 5
  DATA  %01111101                               ' 6
  DATA  %00000111                               ' 7
  DATA  %01111111                               ' 8
  DATA  %01100111                               ' 9

DigMap:                                         ' digit select map
  DATA  %11111110
  DATA  %11111101
  DATA  %11111011
  DATA  %11110111

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

CLOCK_MMSS      SUB                             ' show mins & secs
CLOCK_HHMM      SUB                             ' show hrs & mins

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  DigCtrl = %1111                               ' disable all digits
  TRIS_A = %0000                                ' make dig pins outputs
  Segs = %00000000                              ' clear seg drivers
  TRIS_B = %00000000                            ' make seg pins outputs
  PLP_C = %11000000                             ' pull-up unused pins
  OPTION = $86                                  ' prescaler = 1:128

Main:
  PAUSE 250
  IF TmrMode = TmrHHMM THEN                     ' check mode
    CLOCK_HHMM
  ELSE
    CLOCK_MMSS
  ENDIF
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Display timer in MM.SS (00.00 .. 59.59) format with solid DP

CLOCK_MMSS:                                     ' display mins & secs
  temp1 = mins / 10                             ' get 10's digit
  temp2 = __REMAINDER                           ' save 1's digit
  READ SegMap + temp1, display(3)
  READ SegMap + temp2, display(2)
  display(2) = display(2) | DecPnt              ' add DP to hr01 digit
  temp1 = secs / 10
  temp2 = __REMAINDER
  READ SegMap + temp1, display(1)
  READ SegMap + temp2, display(0)
  RETURN

' Display timer in HH.MM (00.00 .. 23.59) format with blinking DP

CLOCK_HHMM:                                     ' display hours & mins
  temp1 = hrs / 10
  temp2 = __REMAINDER
  READ SegMap + temp1, display(3)
  READ SegMap + temp2, display(2)
  IF blink = Yes THEN
    display(2) = display(2) | DecPnt            ' blink DP on hr01 digit
  ENDIF
  temp1 = mins / 10
  temp2 = __REMAINDER
  READ SegMap + temp1, display(1)
  READ SegMap + temp2, display(0)
  RETURN


SX/B Example: Thermometer

SX/B Example: Thermometer Examples Index

' =========================================================================
'
'   File...... THERMOMETER.SXB
'   Purpose... Dual-mode digital thermometer
'   Author.... (c) Parallax, Inc. -- All Rights Reserved
'   E-mail.... support@parallax.com
'   Started...
'   Updated... 01 JUL 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Displays the temperature from a DS1620 thermo chip on a multiplexed 7-
' segment display.  The display is multiplexed by interrupt code so that
' no additional components are required.  A mode input allows the temper-
' ature to be displayed in Celsius or Fahrenheit.
'
' When the temperature falls below 0C (32F) "Lo" is displayed.  When the
' temp is above 49C (120 F) "Hi" is displayed.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

DQ              VAR     RC.7                    ' DS1620.1
Clock           VAR     RC.6                    ' DS1620.2
Rst             VAR     RC.5                    ' DS1620.3
DispMode        VAR     RC.4                    ' display mode, C or F
Segs            VAR     RB                      ' display segments
DigCtrl         VAR     RA                      ' digit control (cathode)

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Blank           CON     %00000000               ' blank display
Dash            CON     %01000000               ' pattern for "-"
Ltr_C           CON     %00111001               ' pattern for "C"
Ltr_F           CON     %01110001               ' pattern for "F"
Ltr_L           CON     %00111000               ' pattern for "L"
Ltr_o           CON     %01011100               ' pattern for "o"
Ltr_H           CON     %01110110               ' pattern for "H"
Ltr_i           CON     %00010000               ' pattern for "i"

TC              CON     0                       ' mode = Celsius
TF              CON     1                       ' mode = Fahrenheit

' *** DS1620 Commands ***

RdTmp           CON     $AA                     ' read temperature
WrHi            CON     $01                     ' write TH (high temp)
WrLo            CON     $02                     ' write TL (low temp)
RdHi            CON     $A1                     ' read TH
RdLo            CON     $A2                     ' read TL
StartC          CON     $EE                     ' start conversion
StopC           CON     $22                     ' stop conversion
WrCfg           CON     $0C                     ' write config register
RdCfg           CON     $AC                     ' read config register

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

display         VAR     Byte(4)                 ' multiplexed segments
digPntr         VAR     Byte                    ' digit pointer
digLimit        VAR     Byte                    ' 0 - 3
theTemp         VAR     Byte                    ' temperature
tSign           VAR     Byte                    ' sign in bit 0
work            VAR     Byte

temp1           VAR     Byte                    ' work vars
temp2           VAR     Byte

' =========================================================================
  INTERRUPT
' =========================================================================

' Points to next digit of display every 5 milliseconds.  Timing is based
' on 4 MHz clock, 1:128 prescaler, then interrupting every 156 cycles.

ISR_Start:
  INC digPntr                                   ' point to next digit
  IF digPntr < digLimit THEN Update_Segs        ' update digit
  digPntr = 0                                   ' wrap if needed

Update_Segs:
  Segs = Blank                                  ' blank segs
  READ DigMap + digPntr, DigCtrl                ' select display element
  Segs = display(digPntr)                       ' output new digit segs

ISR_Exit:
  RETURNINT 156

' =========================================================================
  PROGRAM Start
' =========================================================================

SegMap:                                         ' segments maps
'       .gfedcba
  DATA %00111111                                ' 0
  DATA %00000110                                ' 1
  DATA %01011011                                ' 2
  DATA %01001111                                ' 3
  DATA %01100110                                ' 4
  DATA %01101101                                ' 5
  DATA %01111101                                ' 6
  DATA %00000111                                ' 7
  DATA %01111111                                ' 8
  DATA %01100111                                ' 9

DigMap:                                         ' digit select map
  DATA %11111110
  DATA %11111101
  DATA %11111011
  DATA %11110111

' -------------------------------------------------------------------------
' Subroutines
' -------------------------------------------------------------------------

INIT1620        SUB                             ' initialize DS1620
RD1620          SUB                             ' get temp from DS1620
NEW_DISPLAY     SUB     2                       ' update display

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  DigCtrl = %1111                               ' disable all digits
  TRIS_A = %0000                                ' make dig pins outputs
  Segs = Blank                                  ' clear seg drivers
  TRIS_B = %00000000                            ' make seg pins outputs
  TRIS_C = %10011111                            ' clock and rst are outputs
  INIT1620
  PUT display(0), Blank, Blank, Blank, Blank    ' clear display
  digLimit = 4                                  ' use all digits (1 - 4)
  digPntr = 3
  OPTION = $86                                  ' prescaler = 1:128

Main:
  theTemp = RD1620                              ' read temperature
  NEW_DISPLAY theTemp, tSign                    ' display value
  PAUSE 1000                                    ' delay between reads
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Initialize DS1620 for free-run mode and for use with a host CPU

INIT1620:
  Rst = 1                                       ' select device
  SHIFTOUT DQ, Clock, LSBFIRST, WrCfg           ' write to config register
  SHIFTOUT DQ, Clock, LSBFIRST, %00000010       ' with CPU; free-run
  Rst = 0                                       ' deselect device
  PAUSE 10                                      ' allow DS1620 EE to write
  Rst = 1                                       ' reselect
  SHIFTOUT DQ, Clock, LSBFIRST, StartC          ' start conversion
  Rst = 0                                       ' deselect
  RETURN

' Use: theTemp = RD1620
' -- returns temp in whole degrees C in 'theTemp'

RD1620:
  Rst = 1                                       ' select device
  SHIFTOUT DQ, Clock, LSBFIRST, RdTmp           ' send read temp command
  SHIFTIN DQ, Clock, LSBPRE, temp1              ' get temp (C x 0.5)
  SHIFTIN DQ, Clock, LSBPRE, tSign\1            ' get sign bit
  Rst = 0                                       ' deselect device
  temp1 = temp1 + temp1.0                       ' round up
  temp1 = temp1 >> 1                            ' remove half bit
  RETURN temp1

' Use: NEW_DISPLAY temperature, sign
' -- puts 'temperature' in display (pass value in degrees C)
' -- display mode (C or F) controlled by RC.4 input

NEW_DISPLAY:
  temp1 = __PARAM1                              ' temperature
  temp2 = __PARAM2                              ' sign bit

  IF temp2 = 1 THEN                             ' negative temp?
    digLimit = 4
    PUT display(0), Dash, Ltr_o, Ltr_L, Dash    ' show "-Lo-"
    GOTO Display_Done
  ENDIF

  IF temp1 > 49 THEN                            ' too high?
    digLimit = 4
    PUT display(0), Dash, Ltr_i, Ltr_H, Dash    ' show "-Hi-"
    GOTO Display_Done
  ENDIF

Check_Mode:
  IF DispMode = TC THEN                         ' check mode input switch
    display(0) = Ltr_C
  ELSE
    display(0) = Ltr_F
    work = temp1 * 4                            ' convert to Fahrenheit
    work = work / 5
    temp1 = temp1 + work
    temp1 = temp1 + 32
  ENDIF

Set_Display:                                    ' blank leading zeros
  digLimit = 2                                  ' 1-digit temp
  IF temp1 < 10 THEN Show_Temp
  INC digLimit                                  ' 2-digit temp
  IF temp1 < 100 THEN Show_Temp
  INC digLimit                                  ' 3-digit temp

Show_Temp:
  work = temp1 / 100                            ' get hundreds digit
  temp1 = __REMAINDER                           ' save 10's and 1's
  READ SegMap + work, display(3)                ' get segment map 100's
  work = temp1 / 10                             ' get 10's digit
  temp1 = __REMAINDER                           ' save 1's
  READ SegMap + work, display(2)                ' get segment map for 10's
  READ SegMap + temp1, display(1)               ' get segment map for 1's

Display_Done:
  RETURN


SX/B Example: 4x4 Matrix Keypad

SX/B Example: 4x4 Matrix Keypad Examples Index

' =========================================================================
'
'   File...... KEYPAD.SXB
'   Purpose... Scanning a 4x4 Matrix Keypad
'   Author.... (c) Parallax, Inc. -- All Rights Reserved
'   E-mail.... support@parallax.com
'   Started... 08 OCT 2004
'   Updated... 01 JUL 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' This program demonstrates the scanning of a 4x4 matrix keypad. If no
' key is pressed the Get_Key routine will return a value of 16.
'
' Key values (hex):
'
'      C1    C2    C3    C4
'
' R1  [ 0 ] [ 1 ] [ 2 ] [ 3 ]
'
' R2  [ 4 ] [ 5 ] [ 6 ] [ 7 ]
'
' R3  [ 8 ] [ 9 ] [ A ] [ B ]
'
' R4  [ C ] [ D ] [ E ] [ F ]

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Keys            VAR     RC                      ' keyboard scan port
TRIS_Keys       VAR     TRIS_C
Col1            VAR     Keys.7                  ' column inputs
Col2            VAR     Keys.6
Col3            VAR     Keys.5
Col4            VAR     Keys.4

LEDs            VAR     RB
TRIS_LEDs       VAR     TRIS_B

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Yes             CON     1
No              CON     0

Dash            CON     %01000000               ' segment G only

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

theKey          VAR     Byte                    ' from keypad, 0 - 16
row             VAR     Byte                    ' keyboard scan row

temp1           VAR     Byte                    ' work vars
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' Matrix to remap keypad values

ReMap:
  DATA   1,  2,  3, $A
  DATA   4,  5,  6, $B
  DATA   7,  8,  9, $C
  DATA  $E,  0, $F, $D

' Seven-segment digit maps

Digits:
'        .gfedcba
  DATA  %00111111                               ' 0
  DATA  %00000110                               ' 1
  DATA  %01011011                               ' 2
  DATA  %01001111                               ' 3
  DATA  %01100110                               ' 4
  DATA  %01101101                               ' 5
  DATA  %01111101                               ' 6
  DATA  %00000111                               ' 7
  DATA  %01111111                               ' 8
  DATA  %01100111                               ' 9
  DATA  %01110111                               ' A
  DATA  %01111100                               ' B
  DATA  %00111001                               ' C
  DATA  %01011110                               ' D
  DATA  %01111001                               ' E
  DATA  %01110001                               ' F

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

GETKEY          SUB                             ' get key from pad
DELAY           SUB     1, 2                    ' delay in milliseconds

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  LEDs = Dash                                   ' dash in display
  TRIS_LEDs = %00000000                         ' LED pins are outputs

Main:
  theKey = GETKEY                               ' get a key
  IF theKey.4 = 0 THEN                          ' was a key pressed?
    READ ReMap + theKey, theKey                 ' yes, remap keypad
    READ Digits + theKey, LEDs                  ' output to display
    DELAY 100
  ENDIF
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' This routine works by activating each row, then scanning each column.
' If a particular row/column junction is not active (pressed), the key
' value is incremented and the scan continues.  As soon as a key is found,
' the routine exits.  If no key is pressed the routine will exit with a key
' value of 16.

' Use: aByte = GETKEY
' -- scans keyboard and places key value into 'aByte'

GETKEY:
  temp1 = 0                                     ' reset keyboard value
  row = 4                                       ' scan 4 rows
  Keys = %00001000                              ' activate first row
  TRIS_Keys = %11110000                         ' refresh IO state

  DO WHILE row > 0
    IF Col1 = Yes THEN EXIT                     ' check buttons on column
    INC temp1                                   ' update key value
    IF Col2 = Yes THEN EXIT
    INC temp1
    IF Col3 = Yes THEN EXIT
    INC temp1
    IF Col4 = Yes THEN EXIT
    INC temp1
    Keys = Keys >> 1                            ' select next row
    DEC row
  LOOP
  RETURN temp1

' Use: DELAY base {, multiplier}
' -- pause for 'base' * (optional) 'multiplier' milliseconds

DELAY:                                          ' delay x { * y } ms
  temp1 = __PARAM1
  IF __PARAMCNT = 1 THEN
    temp2 = 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSE temp1 * temp2
    ENDIF
  ENDIF
  RETURN


SX/B Example: Serial LCD

SX/B Example: Serial LCD Examples Index

' =========================================================================
'
'   File...... SERIAL_LCD.SXB
'   Purpose... Serial LCD Controller with 8 IO bits
'   Author.... (c) Parallax, Inc. -- All Rights Reserved
'   E-mail.... support@parallax.com
'   Started... 06 OCT 2004
'   Updated... 01 JUL 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Implements a simple serial LCD controller using the SX28.
'
' This controller is designed to be command-compatible with SEETRON 2x16
' LCD displays, but is fixed at 9600 baud and uses open-true serial mode.
' It also offers extended functions with RC of the SX28
'
' By sending the instruction prefix ($FE) twice, this LCD controller
' enters "extended" function mode.  The following extended functions are
' currently available:
'
' $F0, ddr  : Set IO port DDR (1 = input, 0 = output; default is %11111111)
' $F1       : Read IO port
' $F2, bits : Write bits to IO port
' $FF       : Read LCD RAM (from current cursor position)

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Sio             VAR     RA.0                    ' pull-up via 4.7K
LcdE            VAR     RA.1                    ' pull-down via 4.7K
LcdRW           VAR     RA.2
LcdRS           VAR     RA.3
TRIS_Ctrl       VAR     TRIS_A

LcdBus          VAR     RB                      ' RB.0 --> DB0, ...
TRIS_Lcd        VAR     TRIS_B

IoPort          VAR     RC
TRIS_IO         VAR     TRIS_C

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Baud            CON     "OT9600"                ' open for single wire
Cmd             CON     $FE                     ' LCD command prefix

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

serByte         VAR     Byte                    ' serial IO byte

temp1           VAR     Byte                    ' work vars
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

DELAY           SUB     1, 2                    ' delay in milliseconds
DELAYUS         SUB     1, 2                    ' delay in microseconds
LCDINIT         SUB                             ' initialize LCD
LCDCMD          SUB     1                       ' command byte --> LCD
LCDOUT          SUB     1                       ' byteVar --> LCD
LCDIN           SUB                             ' byteVar <-- LCD
RXBYTE          SUB                             ' rx from serial IO
TXBYTE          SUB     1                       ' tx to serial IO

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_Ctrl = %0001                             ' RA.0 = input (serial)
  LCDINIT

Main:
  serByte = RXBYTE                              ' wait for byte
  IF serByte = Cmd THEN Do_Command              ' command?

Do_Write:
  LCDOUT serByte                                ' no, write char byte
  GOTO Main

Do_Command:
  serByte = RXBYTE                              ' get command byte
  IF serByte = Cmd THEN Extended_Cmd            ' extended command?
  LCDCMD serByte                                ' no, write cmd byte
  GOTO Main

Extended_Cmd:
  serByte = RXBYTE                              ' get extended command

Set_IO:
  IF serByte <> $F0 THEN Read_IO                ' check command
  serByte = RXBYTE                              ' get port configuration
  TRIS_IO = serByte                             ' setup IO port
  GOTO Main

Read_IO:
  IF serByte <> $F1 THEN Write_IO
  DELAY 2                                       ' delay for host setup
  TXBYTE IoPort                                 ' send port bits to host
  GOTO Main

Write_IO:
  IF serByte <> $F2 THEN Read_Byte
  IoPort = RXBYTE                               ' put bits on the port
  GOTO Main

Read_Byte:
  IF serByte <> $FF THEN Cmd_X
  serByte = LCDIN                               ' read LCD (cursor pos)
  DELAY 2                                       ' delay for host setup
  TXBYTE serByte                                ' send byte to to host
  GOTO Main

Cmd_X:                                          ' for future expansion
  '
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: DELAY base {, multiplier}
' -- pause for 'base' * (optional) 'multiplier' milliseconds

DELAY:                                          ' delay x { * y } ms
  temp1 = __PARAM1
  IF __PARAMCNT = 1 THEN
    temp2 = 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSE temp1 * temp2
    ENDIF
  ENDIF
  RETURN

' Use: DELAYUS base {, multiplier}
' -- pause for 'base' * (optional) 'multiplier' microseconds

DELAYUS:                                        ' delay x { * y } usecs
  temp1 = __PARAM1
  IF __PARAMCNT = 1 THEN
    temp2 = 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSEUS temp1 * temp2
    ENDIF
  ENDIF
  RETURN

' Use: LCDCMD cmdByte
' -- send 'cmdByte' to LCD with RS line low

LCDCMD:                                         ' write command byte
  LcdRS = 0
  GOTO Lcd_Put

' Use: LCDOUT char
' -- send 'char' to LCD with RS line high

LCDOUT:                                         ' write character byte
  LcdRS = 1

Lcd_Put:                                        ' byte --> LCD bus
  LcdBus = __PARAM1

Blip:                                           ' move bus into LCD
  LcdE = 1
  DELAYUS 2
  LcdE = 0
  DELAYUS 40                                    ' instruction delay
  RETURN

' Use: char = LCDIN
' -- puts value at LCD cursor position in 'char'

LCDIN:
  TRIS_Lcd = %11111111                          ' make LCD bus inputs
  LcdRS = 1                                     ' character mode
  LcdRW = 1                                     ' read mode
  LcdE = 1                                      ' move byte to bus
  temp1 = LcdBus                                ' grab the byte
  LcdE = 0                                      ' complete the read
  LcdRW = 0                                     ' return to write mode
  TRIS_Lcd = %00000000                          ' make LCD bus outputs
  RETURN temp1                                  ' return byte to caller

' Use: LCDINIT
' -- initialize LCD for 8-bit, 2-line interface

LCDINIT:
  DELAY 15                                      ' power-up delay, 15 ms
  TRIS_Lcd = %00000000                          ' all outputs
  LcdBus = %00110000                            ' 8-bit interface
  GOSUB Blip
  DELAY 5                                       ' delay 4.5 ms (min)
  GOSUB Blip
  DELAYUS 100                                   ' delay 100 us
  GOSUB Blip
  LCDCMD %00111000                              ' multi-line, 5x7 font
  LCDCMD %00001100                              ' display on, no cursor
  LCDCMD %00000110                              ' auto-increment cursor
  LCDCMD %00000001                              ' clear and home LCD
  RETURN

' Use: char = RXBYTE
' -- reads byte from serial input and places in 'char'

RXBYTE:
  SERIN Sio, Baud, temp1                        ' receive a byte
  RETURN temp1                                  ' return to caller

' Use: TXBYTE char
' -- transmits 'char' over serial connnection

TXBYTE:
  temp1 = __PARAM1                              ' save byte to send
  SEROUT Sio, Baud, temp1                       ' send the byte
  RETURN


SX/B Example: Quadrature Encoder Input

SX/B Example: Quadrature Encoder Input Examples Index

' =========================================================================
'
'   File...... ENCODER.SXB
'   Purpose... Grayhill 25LB10-Q Encoder Demo
'   Author.... (c) Parallax, Inc. -- All Rights Reserved
'   E-mail.... support@parallax.com
'   Started...
'   Updated... 05 APR 2005
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Reads a Grayhill 25LB10-Q quadrature encode and displays a value on
' three 7-segment LEDs.  When the value is zero, the display reads "OFF."
' Reading the encoder and multiplexing the displays is handled in the
' "background" with an ISR.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

EncPort         VAR     RA                      ' encoder port
TRIS_Enc        VAR     TRIS_A
Cathodes        VAR     RB                      ' LED cathodes
TRIS_Cath       VAR     TRIS_B
Anodes          VAR     RC                      ' LED anodes
TRIS_Ano        VAR     TRIS_C

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Blank           CON     %00000000               ' all segs off
Ltr_O           CON     %00111111               ' pattern for "O"
Ltr_F           CON     %01110001               ' pattern for "F"

MaxVal          CON     100

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

display         VAR     Byte(3)                 ' multiplexed segments
digPntr         VAR     Byte                    ' digit pointer
digLimit        VAR     Byte                    ' 0 - 2

flags           VAR     Byte
newVal          VAR     flags.0

encOld          VAR     Byte                    ' previous encoder bits
encNew          VAR     Byte                    ' new encoder bits
encValue        VAR     Byte                    ' encoder value

temp1           VAR     Byte
temp2           VAR     Byte
temp3           VAR     Byte

' -------------------------------------------------------------------------
  INTERRUPT
' -------------------------------------------------------------------------

ISR_Start:
  encNew = EncPort & %00000011                  ' get econder bits
  temp3 = encOld XOR encNew                     ' test for change
  IF temp3 = 0 THEN Update_Display              ' if no change, exit
  encOld = encOld << 1                          ' adjust old bits
  encOld = encOld XOR encNew                    ' test direction
  IF encOld.1 = 1 THEN Enc_Up

Enc_Dn:
  IF encValue = 0 THEN Enc_Exit                 ' if 0, no change
  DEC encValue                                  ' decrease value
  newVal = 1                                    ' alert "foreground"
  GOTO Enc_Exit

Enc_Up:
  IF encValue = MaxVal THEN Enc_Exit            ' if max, no change
  INC encValue                                  ' increase value
  newVal = 1                                    ' alert "foreground"

Enc_Exit:
  encOld = encNew                               ' save last input

Update_Display:
  INC digPntr                                   ' point to next digit
  IF digPntr < digLimit THEN Update_Anodes      ' update digit
  digPntr = 0                                   ' wrap if needed

Update_Anodes:
  Anodes = Blank                                ' blank display
  READ DigCtrl + digPntr, Cathodes              ' select display element
  Anodes = display(digPntr)                     ' output new digit segs

ISR_Exit:
  RETURNINT

' =========================================================================
  PROGRAM Start
' =========================================================================

SegMaps:                                        ' segments maps
'        .gfedcba
  DATA  %00111111                               ' 0
  DATA  %00000110                               ' 1
  DATA  %01011011                               ' 2
  DATA  %01001111                               ' 3
  DATA  %01100110                               ' 4
  DATA  %01101101                               ' 5
  DATA  %01111101                               ' 6
  DATA  %00000111                               ' 7
  DATA  %01111111                               ' 8
  DATA  %01100111                               ' 9
  DATA  %01110111                               ' A
  DATA  %01111100                               ' b
  DATA  %00111001                               ' C
  DATA  %01011110                               ' d
  DATA  %01111001                               ' E
  DATA  %01110001                               ' F

DigCtrl:
  DATA  %11111110                               ' column 0 on
  DATA  %11111101
  DATA  %11111011

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

UPDATE_ABUF     SUB                             ' update anode buffer

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  Anodes = Blank                                ' clear LEDs
  TRIS_Ano = %00000000                          ' make anode ctrl outputs
  Cathodes = %111                               ' all digits off
  TRIS_Cath = %11111000                         ' make cath ctrl outputs
  encNew = EncPort & %00000011                  ' read encoder pos
  encOld = encNew                               ' copy
  encValue = 0                                  ' clear value
  UPDATE_ABUF                                   ' update display char buf
  OPTION = $88                                  ' interrupt, no prescaler

Main:
  IF newVal = 1 THEN                            ' check flag
    UPDATE_ABUF                                 ' refresh display buffer
  ENDIF
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

UPDATE_ABUF:
  IF encValue = 0 THEN
    PUT display(0), Ltr_F, Ltr_F, Ltr_O         ' if 0, show "OFF"
    digLimit = 3
  ELSE
    digLimit = 1                                ' at least one digit
    IF encValue > 9 THEN                        ' into 10s?
      INC digLimit                              ' -- yes, show another digit
    ENDIF
    IF encValue > 99 THEN                       ' into 100s?
      INC digLimit                              ' -- yes, show another digit
    ENDIF
    temp1 = encValue                            ' convert value to segments
    temp2 = temp1 / 100
    temp1 = __REMAINDER
    READ SegMaps + temp2, display(2)
    temp2 = temp1 / 10
    temp1 = __REMAINDER
    READ SegMaps + temp2, display(1)
    READ SegMaps + temp1, display(0)
  ENDIF
  newVal = 0                                    ' clear flag
  RETURN


1-Wire Example

1-Wire Example OWRESET OWRDBIT OWRDBYTE OWWRBIT OWWRBYTE

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' This program scans the 1-Wire	bus and	when a device is detected it will
' read and display its serial number.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE		SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ		4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

DQ		VAR	RB.0			' 1-Wire bus (4.7k pull-up)
Sout		VAR	RB.1			' output to SEETRON 2x16

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Baud		CON	"N9600"

LcdI		CON	$FE			' instruction
LcdCls		CON	$01			' clear	the LCD
LcdHome		CON	$02			' move cursor home
LcdCrsrL	CON	$10			' move cursor left
LcdCrsrR	CON	$14			' move cursor right
LcdDispL	CON	$18			' shift	chars left
LcdDispR	CON	$1C			' shift	chars right
LcdDDRam	CON	$80			' Display Data RAM control
LcdCGRam	CON	$40			' Character Generator RAM
LcdLine1	CON	$80			' DDRAM	address	of line	1
LcdLine2	CON	$C0			' DDRAM	address	of line	2

SearchROM	CON	$F0
ReadROM		CON	$33			' read ID, serial num, CRC

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

idx		VAR	Byte			' loop counter
char		VAR	Byte			' char for LCD
owByte		VAR	Byte			' byte for OW work
owSerial	VAR	Byte(8)			' OW serial number

regAddr		VAR	Byte			' register address
temp1		VAR	Byte			' work vars
temp2		VAR	Byte
temp3		VAR	Byte
temp4		VAR	Byte
temp5		VAR	Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

Hex_Digits:
  DATA	"0123456789ABCDEF"

Messages:

Pgm_ID:
  DATA	"SX/B 1-Wire Demo", 0

Bus_Short:
  DATA	"1-Wire	Bus short", 0

Bad_Bus:
  DATA	"Bad connection	 ", 0

Good_PP:
  DATA	"Found device	 ", 0

No_Device:
  DATA	"No device	 ", 0

' Define message offsets

Msg1		CON	Pgm_ID - Messages
Msg2		CON	Bus_Short - Messages
Msg3		CON	Bad_Bus	- Messages
Msg4		CON	Good_PP	- Messages
Msg5		CON	No_Device - Messages

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

DELAY		SUB	1, 2			' delay	t {x m}	ms
TXBYTE		SUB	1, 2			' transmit byte	{x repeats}
TXHEX2		SUB	1			' transmit byte	as HEX2
TXMSG		SUB	1			' transmit message

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  PLP_A	= %0000					' enable pull-ups
  PLP_B	= %00000011				' .. except RB.0 and RB.1
  PLP_C	= %00000000
  DELAY	250, 3					' wait 750 ms for LCD

Main:
  TXBYTE LcdI					' instruction prefix
  TXBYTE LcdCls					' clear	the LCD
  DELAY	10
  TXMSG	Msg1					' write	banner in LCD

Scan_DQ:
  TXBYTE LcdI
  TXBYTE LcdLine2

  OWRESET DQ, owByte				' reset	and sample presence

  IF owByte = %00 THEN				' bus short
    TXMSG Msg2
  ENDIF

  IF owByte = %01 THEN				' bad connection
    TXMSG Msg3
  ENDIF

  IF owByte = %10 THEN				' good presence	detection
    TXMSG Msg4
    GOTO Show_SN
  ENDIF

  IF owByte = %11 THEN				' no device
    TXMSG Msg5
  ENDIF

  GOTO Fini

Show_SN:
  DELAY	250, 4					' show found message
  TXBYTE LcdI					' move back to L2/C0
  TXBYTE LcdLine2

  OWRESET DQ, owByte				' reset	device
  OWWRBYTE DQ, ReadROM				' send read rom	command
  FOR idx = 0 TO 7				' read serial number
    OWRDBYTE DQ, owByte
    owSerial(idx) = owByte
  NEXT
  FOR idx = 7 TO 0 STEP	-1			' display on LCD
    owByte = owSerial(idx)
    TXHEX2 owbyte				' -- hex mode
  NEXT

Fini:
  DELAY	250, 8					' 2 second pause
  GOTO Scan_DQ

  END

' -------------------------------------------------------------------------
' Subroutines
' -------------------------------------------------------------------------

' Use: DELAY timing {, multiplier}
' -- pauses for	'timing' {x 'multiplier'} milliseconds

DELAY:
  temp1	= __PARAM1				' get timing
  IF __PARAMCNT	= 1 THEN			' if no	multiplier
    temp2 = 1					' - set	it to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSE temp1 * temp2
    ENDIF
  ENDIF
  RETURN

' Use: TXBYTE theByte {, repeats}
' -- transmit 'theByte'	on Sio at Baud 'repeats' times

TXBYTE:
  temp1	= __PARAM1				' get byte
  IF __PARAMCNT	= 1 THEN			' if no	repeats
    temp2 = 1					' - set	it to 1
  ELSE
    temp2 = __PARAM2				' else get repeats
  ENDIF
  DO WHILE temp2 > 0				' send char
    SEROUT Sout, Baud, temp1
    DEC	temp2
  LOOP
  RETURN

' Use: TXMSG msgOffset
' -- transmits message in data statement

TXMSG:
  idx =	__PARAM1				' get starting character
  DO
    READ Messages + idx, char			' read character
    IF char = 0	THEN EXIT			' if not zero
    TXBYTE char					' - send it
    INC	idx					' - point to next
  LOOP						' - do it again
  RETURN

' Use: TXHEX2 theByte
' -- transmit 'theByte'	in HEX2	format

TXHEX2:
  temp4	= __PARAM1				' save byte
  temp5	= temp4					' make copy
  SWAP temp5					' swap nibs
  temp5	= temp5	& %00001111			' mask high nib
  READ Hex_Digits + temp5, char			' convert high nib to character
  TXBYTE char, 1				' send it
  temp4	= temp4	& %00001111			' get low nib
  READ Hex_Digits + temp4, char			' convert low nib to character
  TXBYTE char, 1				' send it
  RETURN


ASM

ASM ... ENDASM

Syntax: ASM Instruction(s) ... ENDASM

Function
ASM allows the insertion a block of assembly language statements into the SX/B program. The assembly language block is terminated with ENDASM.

Explanation
Certain time-critical routines are best coded in straight assembly language, and while the \ symbol allows the programmer to insert a single line of assembly code, it is not convenient for large blocks.

' Use: SHIFTIO outByte, @inByte

SHIFTIO:
  ASM                                           ' start assembly block
    CLR temp1                                   ' clear input byte
    MOV idx, #8                                 ' do 8 bits

ShIO_Loop:
    MOVB ShOut, __PARAM1.0                      ' move LSB out to pin
    MOV __PARAM3, #50                           ' 50 us pause @ 4 MHz
    DJNZ __PARAM3, $
    MOVB Clock, /Clock                          ' toggle clock
    MOV __PARAM3, #50
    DJNZ __PARAM3, $
    CLC
    RR temp1                                    ' prep for input bit
    MOVB temp1.7, ShIn                          ' capture input bit (LSB)
    MOVB Clock, /Clock                          ' toggle clock
    CLC
    RR __PARAM1                                 ' prep for next output bit
    DJNZ idx, ShIO_Loop                         ' repeat for 8 bits
  ENDASM
  RETURN temp1


ASM Example

ASM Example Syntax

NOT COMPLETE


BRANCH

BRANCH Example

BRANCH Offset, Label0 {, Label1, Label2, ...}

Function
Jump to the program Label specified by Offset. Note that the value of Offset should not be greater than the number of labels - 1, otherwise the BRANCH instruction will be skipped.

  • Offset is a variable that specifies the index of the address label, in the list, to branch to. If the Offset exceeds the number of lables, the program will continue at the line following BRANCH.
  • Labels specify the possible targets for the BRANCH instruction. Using the '@' preface allows branching to an address that exists on a different code page.

Explanation
The BRANCH instruction is useful when you want to do something like this:

Test_Value:
  IF value = 0 THEN Case_0                      ' value = 0: go to label "Case_0"
  IF value = 1 THEN Case_1                      ' value = 1: go to label "Case_1"
  IF value = 2 THEN Case_2                      ' value = 2: go to label "Case_2"
  IF value = 3 THEN Case_3                      ' value = 3: go to label "Case_3"
  IF value = 4 THEN Case_4                      ' value = 4: go to label "Case_4"

You can convert a long list of IF-THEN statements to BRANCH to like this:

Test_Value:
  BRANCH value, Case_0, Case_1, Case_2, Case_3, Case_4

No_Branch:

Related instruction: IF ... THEN


BRANCH Example

BRANCH Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Controls eight channels of lights using RB.  Sequence is selected by
' switches connected to RA.0 and RA.1.  The delay between steps is fixed
' by a constant, but could easily be modified to be variable by using
' RCTIME.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Select          VAR     RA                      ' bits 0 and 1
TRIS_Sel        VAR     TRIS_A
Lights          VAR     RB
TRIS_Lights     VAR     TRIS_B

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

StepDelay       CON     100                     ' 100 ms between steps

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

choice          VAR     Byte                    ' selected sequence
maxSteps        VAR     Byte                    ' steps in sequence
idx             VAR     Byte                    ' step pointer

' =========================================================================
  PROGRAM Start
' =========================================================================

Pattern0:
  DATA  8                                       ' steps in sequence
  DATA  %00000001                               ' sequence values
  DATA  %00000010
  DATA  %00000100
  DATA  %00001000
  DATA  %00010000
  DATA  %00100000
  DATA  %01000000
  DATA  %10000000

Pattern1:
  DATA  10
  DATA  %00000000
  DATA  %10000000
  DATA  %11000000
  DATA  %01100000
  DATA  %00110000
  DATA  %00011000
  DATA  %00001100
  DATA  %00000110
  DATA  %00000011
  DATA  %00000001

Pattern2:
  DATA  5
  DATA  %00000000
  DATA  %00011000
  DATA  %00100100
  DATA  %01000010
  DATA  %10000001

Pattern3:
  DATA  5
  DATA  %11111111
  DATA  %01111110
  DATA  %00111100
  DATA  %00011000
  DATA  %00000000

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  Lights = %00000000                            ' clear lights
  TRIS_Lights = %00000000                       ' make lights outputs

Main:
  PAUSE StepDelay                               ' inter-step delay
  choice = Select & %0011                       ' get show
  BRANCH choice, Show_0, Show_1, Show_2, Show_3
  GOTO Main

Show_0:
  READ Pattern0, maxSteps                       ' get steps in sequence
  IF idx <= maxSteps THEN                       ' check idx range
    READ Pattern0 + idx, Lights                 ' get step pattern
    INC idx                                     ' point to next step
  ELSE
    idx = 1                                     ' reset idx if needed
  ENDIF
  GOTO Main

Show_1:
  READ Pattern1, maxSteps
  IF idx <= maxSteps THEN
    READ Pattern1 + idx, Lights
    INC idx
  ELSE
    idx = 1
  ENDIF
  GOTO Main

Show_2:
  READ Pattern2, maxSteps
  IF idx <= maxSteps THEN
    READ Pattern2 + idx, Lights
    INC idx
  ELSE
    idx = 1
  ENDIF
  GOTO Main

Show_3:
  READ Pattern3, maxSteps
  IF idx <= maxSteps THEN
    READ Pattern3 + idx, Lights
    INC idx
  ELSE
    idx = 1
  ENDIF
  GOTO Main


CLEART1

Syntax: CLEART1

Function
Clears the T1 timer on the SX48 or SX52. This command does not apply to the SX18, SX20, or SX28.

Related instructions: CLEART2


CLEART2

Syntax: CLEART2

Function
Clears the T2 timer on the SX48 or SX52. This command does not apply to the SX18, SX20, or SX28.

Related instructions: CLEART1


DATA

Label:
DATA Const0 {, Const1, Const2, ...}

Function
Creates a table of data values for use with the READ instruction.

  • Label is the symbolic name for the table and serves as a pointer to the location of table index zero.
  • Const is any constant (byte, ASCII character, or computed value).

Explanation
The DATA directive allows the programmer to create a table of [read only] values for use in the SX/B program. Using DATA is a convenient way to store output patterns and text messages. Note that DATA tables may not be placed in the program execution path as the SX will interpret the tables as valid code and attempt to execute them. Tables should be placed just after the PROGRAM directive and before the start of active code.

CR              CON     13

PROGRAM Start

SegMap:                                         ' segments maps
'        .gfedcba
  DATA  %00111111                               ' 0
  DATA  %00000110                               ' 1
  DATA  %01011011                               ' 2
  DATA  %01001111                               ' 3
  DATA  %01100110                               ' 4
  DATA  %01101101                               ' 5
  DATA  %01111101                               ' 6
  DATA  %00000111                               ' 7
  DATA  %01111111                               ' 8
  DATA  %01100111                               ' 9

StartMsg:
  DATA  "SX/B Really Rocks!", CR, 0

Start:
  LEDs = %00000000
  TRIS_LEDs = %00000000                         ' make leds outputs

Main:
  idx = 0

TX_Msg:
  DO
    READ StartMsg + idx, char
    IF char = 0 THEN EXIT
    SEROUT Sio, Baud, char
    INC idx
  LOOP
  ENDIF

Show_Count:
  INC counter
  IF counter = 10 THEN
    counter = 0
  ENDIF
  READ SegMap + counter, LEDs
  PAUSE 1000

  GOTO Main

Note: When defining embedded strings as in the example above, the string may be up to 128 characters.

Related instruction: READ


DATA Example

DATA Example Syntax

NOT COMPLETE


DEC

DEC ByteVar

Function
Decrement value of ByteVar by one.

  • ByteVar is any byte variable.

Explanation
The DEC instruction subtracts one from the specified byte variable. If the variable holds zero before the DEC instruction, it will roll over to 255 after. When decrementing from 1 to 0 the Z flag gets set, otherise it is cleared.

Main:
  RB = 1                                        ' RB = %00000001, Z = 0
  DEC RB                                        ' RB = %00000000, Z = 1
  DEC RB                                        ' RB = %11111111, Z = 0

Related instruction: INC and DJNZ


DEC Example

DEC Example Syntax

NOT COMPLETE


INC

DJNZ

DJNZ ByteVar, Label

Function
Decrement value of ByteVar by one and jump to Label if ByteVar is not equal to zero.

  • ByteVar is any byte variable (including an array element).
  • Label is a program label that is followed by operational code (do not use DJNZ with a DATA table label).

Explanation
The DJNZ instruction decrements ByteVar by one and if the result of that operation is not zero the program will jump to the point specified by Label.

Start:
  flashes = 5

Main:
  HIGH RA.0
  PAUSE 100
  LOW RA.0
  PAUSE 400
  DJNZ flashes, Main                     ' flash until flashes = 0
  END

Related instruction: DEC


DJNZ Example

DJNZ Example Syntax

NOT COMPLETE


DO ... LOOP

DO { WHILE | UNTIL Condition }
Statement(s)
LOOP

DO
Statement(s)
LOOP { UNTIL | WHILE Condition }

Function
Create a repeating loop that executes the program lines between DO and LOOP, optionally testing before or after the loop statements.

  • Condition is a simple statement, such as "idx = 7" that can be evaluated as True or False. Only one comparison operator is allowed (see IF...THEN for valid condition operators).
  • Statement is any valid SX/B statement.

Explanation
DO...LOOP loops let your program execute a series of instructions indefinitely, or until a specified condition terminates the loop. The simplest form is shown here:

Alarm_On:
  DO
    HIGH Alarm_LED
    PAUSE 500
    LOW Alarm_LED
    PAUSE 500
  LOOP

In this example the alarm LED will flash until the SX is reset. DO...LOOP allows for condition testing before and after the loop statements as show in the examples below.

Alarm_On:
  DO WHILE AlarmStatus = 1
    HIGH Alarm_LED
    PAUSE 500
    LOW Alarm_LED
    PAUSE 500
  LOOP
  RETURN

Alarm_On:
  DO
    HIGH Alarm_LED
    PAUSE 500
    LOW Alarm_LED
    PAUSE 500
  LOOP UNTIL AlarmStatus = 0
  RETURN

When the second form is used the loop statements will run at least once before the condition test.

Related instructions: FOR...NEXT, IF...THEN, and EXIT


END

END

Function
Ends program execution.

Explanation
END prevents the SX from executing any further instructions until it is reset, either externally (via MCLR\ pin) or by a watchdog timer timeout. END does not place the SX in low power (SLEEP) mode.

Related instructions: SLEEP and RESETWDT


EXIT

Syntax: {IF Condition THEN} EXIT

Function
Causes the immediate termination of a loop construct (FOR...NEXT or DO...LOOP) when Condition evaluates as True.

  • Condition is a simple statement, such as "x = 7" that can be evaluated as True or False.

Explanation
The EXIT command allows a program to terminate a loop construct before the loop limit test is executed. For example:

Main:
  FOR idx = 1 TO 15
    IF idx > 9 THEN EXIT
    SEROUT TX, Baud, "*"
  NEXT

In this program, the FOR idx = 1 TO 15 loop will not run past nine because the IF idx > 9 THEN EXIT contained within will force the loop to terminate when idx is greater than nine. Note that the EXIT command only terminates the loop that contains it. In the the program above, only nine asterisks will be transmitted on the TX pin.

Here is the DO...LOOP version of the same program:

Start:
  idx = 1

Main:
  DO
    IF idx > 9 THEN EXIT
    SEROUT TX, Baud, "*"
    INC idx
  LOOP WHILE idx <= 15

EXIT may also be used by itself when part of a larger IF...THEN...ENDIF block:

  IF idx > 9 THEN
    SEROUT TX, Baud, CR
    idx = 1
    EXIT
  ENDIF

Related instructions: FOR...NEXT, DO...LOOP, and IF...THEN


FOR-NEXT

FOR ... NEXT Example

FOR ByteVar = StartVal TO EndVal {STEP {-}StepVal} ... NEXT

Function
Create a repeating loop that executes the program lines between FOR and NEXT, incrementing or decrementing ByteVar according to StepVal until the value of ByteVar reaches or passes the EndVal.

  • ByteVar a byte variable used as a loop counter.
  • StartVal is a constant or variable that sets the starting value of the counter.
  • EndVal is a constant or a variable that sets the ending value of the counter.
  • StepVal is a constant or a variable which by counter is incremented or (when negative) decremented during each iteration of the loop.

Explanation
FOR...NEXT loops let your program execute a series of instructions for a specified number of repetitions (called iterations). By default, each time through the loop, ByteVar is incremented by 1. It will continue to loop until the value of the ByteVar reaches or exceeds EndVal. Also, FOR...NEXT loops always execute at least once. The simplest form is shown here:

Blink_LED:
  FOR idx = 1 TO 10                             ' blink 10 times
    HIGH LED                                    ' light the LED
    PAUSE 200                                   ' wait 0.2 secs
    LOW LED                                     ' extinguish the LED
    PAUSE 300                                   ' wait 0.3 secs
  NEXT

In this simple example, the FOR instruction initializes idx to 1. Then the HIGH, PAUSE, LOW, and PAUSE instructions are executed. At NEXT, idx is checked to see if it is less than 10. If it is, idx will be incremented by 1 and the loop instructions run again. When idx is equal to 10 the loop terminates and the program continues at the instruction after NEXT.

Related instructions: DO...LOOP and EXIT


FOR-NEXT Example

FOR-NEXT Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Demonstrates FOR-NEXT loops in SX/B with a "ping-pong" LED display.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LEDs            VAR     RB                      ' LED outputs
TRIS_LEDs       VAR     TRIS_B

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

idx             VAR     Byte                    ' loop counter

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_LEDs = %00000000                         ' make LED pins outputs

Main:
  FOR idx = 0 TO 6                              ' loop 7 times
    LEDs = 1 << idx                             ' LEDs = 1, 2, 4, 8, ...
    PAUSE 100                                   ' pause 100 ms
  NEXT
  FOR idx = 7 TO 1 STEP -1                      ' loop 7 times
    LEDs = 1 >> idx                             ' LEDs = 128, 64, 32 ...
    PAUSE 100                                   ' pause 100 ms
  NEXT
  GOTO Main                                     ' repeat forever


FREQOUT

FREQOUT Example

FREQOUT Pin, Duration, Freq

Function
Generate square wave for a specified duration.

  • Pin is any SX IO pin (RA.0 .. RA.3, RB.0 .. RB.7, RC.0 .. RC.7).
  • Duration is a variable/constant (1 - 255) specifying the amount of time to generate the tone. The unit of time for Duration is 1 millisecond.
  • Freq is a constant (1 - 65535) specifying the frequency of the square wave.

Quick Facts
 | Low Limit | High† Limit
Frequency | FREQ ÷ 500,000 | FREQ ÷ 32

† Note: For the greatest possible accuracy, limit high frequency value to FREQ ÷ 512.

Explanation
FREQOUT generates a square wave on an I/O pin. The output pin may be connected as shown in the circuits below for audio use. Other applications include IR LED modulation.

Note that the Duration can be affected by Freq parameter. For example, a frequency of 100 Hz has a period of 10 milliseconds, hence the shortest possible Duration value is 10. Even at this minimum, only one cycle would be produced and this may not be practical or useful.

When driving a Hi-Z speaker (> 40 Ω) or piezo element:

When connecting to an audio amplifier:

Related instruction: SOUND


FREQOUT Example

FREQOUT Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Uses FREQOUT to modulate an IR LED for object detection.  When object
' is detected, a tone is generated from the pieze element.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

IrLED           VAR     RB.0                    ' output to IR LED
Detect          VAR     RB.1                    ' input from IR detector
Spkr            VAR     RB.2                    ' output to piezo

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

IrMod           CON     38000                   ' modulation freq = 38 kHz

Yes             CON     0                       ' for active-low output
No              CON     1

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  DO
    FREQOUT IrLED, 1, IrMod                     ' modulate IR diode
    IF Detect = Yes THEN                        ' check detector
      SOUND Spkr, 100, 2                        ' buzz if object detected
    ENDIF
  LOOP


GET

GET Location, ByteVar {, ByteVar, ... }

Function
Copy value(s) from RAM into ByteVar(s), starting at Location.

  • Location is the starting address to be copied.
  • ByteVar is any byte variable.

Explanation
The GET instruction provides a convenient method of copy multiple consecutive values from RAM into individual byte variables. For example,

  hrs = clock(0)
  mins = clock(1)
  secs = clock(2)

... can be simplified to a single line of code:

  GET clock(0), hrs, mins, secs

Note that this works because array elements are stored as addresses.

Using GET With Subroutine Parameters
When a simple variable is passed to a subroutine by address (using @), as in:

  GOSUB Some_Routine, @aValue                   ' pass address of 'aValue'

... GET can be used to retrieve the value from that address within the subroutine:

Some_Routine:
  rtnAddr = __PARAM1                            ' save return address
  GET rtnAddr, theValue                         ' get value from address
  ...                                           ' do something with the value
  PUT rtnAddr, newValue                         ' update value at passed address
  RETURN

This technique allows the subroutine to accept (and potentially modify) any defined variable. Note that for single-parameter instances, the __RAM() system array may be used in place of GET and PUT:

Some_Routine:
  rtnAddr = __PARAM1                            ' save return address
  theValue = __RAM(rtnAddr)                     ' get value from address
  ...                                           ' do something with the value
  __RAM(rtnAddr) = newValue                     ' update value at passed address
  RETURN

Related instruction: PUT


GET / PUT Example

GET / PUT Example GET PUT

NOT COMPLETE


GOSUB

GOSUB ... RETURN Example

GOSUB Label ... RETURN { Value }

Function
Store the address of the next instruction after GOSUB, then go to the point in the program specified by Label; with the intention of returning to the stored address.

  • Label specifies the name of the subroutine to run.
  • Value is an optional value/variable to return

Quick Facts
 | SX18/20, SX28, SX48, SX52
Maximum Nested GOSUBs | 8

Explanation
GOSUB is a close relative of GOTO, in fact, its name means, "GO to a SUBroutine". When a program reaches a GOSUB, the program executes the code beginning at the specified Label. Unlike GOTO, GOSUB also stores the address of the instruction immediately following itself. When the program encounters the RETURN instruction, it interprets it to mean, "go to the instruction that follows the most recent GOSUB." In other words, a GOSUB makes the program do a similar operation as you do when you see a table or figure reference in this manual; 1) you remember where you are, 2) you go to the table or figure and read the information there, and 3) when you've reached the end of it, you "return" to the place you were reading originally.

GOSUB is mainly used to execute the same piece of code from multiple locations. If you have, for example, a block of three lines of code that need to be run from 10 different locations in your entire program you could simple copy and paste those three lines to each of those 10 locations. This would amount to a total of 30 lines of repetitive code (and extra space wasted in the program memory). A better solution is to place those three lines in a separate routine, complete with it's own label and followed by a RETURN instruction, then just use a GOSUB instruction at each of the 10 locations to access it. Since SX/B compiles instructions inline (no optimization) this technique can save a lot of program space.

Beginning with version 1.2, SX/B allows the programmer to declare subroutines (SUB directive) to simplify programming (GOSUB is in fact no longer required) and improve productivity by allowing the compiler to check the number of parameters passed to a subroutine. The following examples demonstrate the differences in code style.

Version 1.1 (This style is still valid but not recommended)

Get_Char:
  SERIN Sio, Baud, char                         ' wait for character
  RETURN

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

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  GOSUB Get_Char
  IF char <> "!" THEN Main                      ' wait for "!"

Version 1.2+

GETCHAR         SUB                             ' subroutine (no parameters)

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

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  char = GETCHAR                                ' no "GOSUB" required
  IF char <> "!" THEN Main                      ' wait for "!"

  END

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

GETCHAR:
  SERIN Sio, Baud, temp1                        ' wait for character
  RETURN temp1                                  ' return character to caller

Declared subroutines simplify SX/B programming by removing the necessity of the GOSUB keyword (which, in effect, allows the programmer to extend the language by creating new commands), it allows the compiler to validate the number of parameters being passed, and -- most valuable to the programmer -- it allows subroutine code to be placed anywhere in memory without concern of code page boundaries (now handled automatically).

Passing Parameters To/From a Subroutine
SX/B allows the programmer to pass up to four parameters to subroutines. The parameter may hold a value (bit or byte) or the address of a byte-variable (when prefaced with '@'). When used in subroutines, passed parameters must be saved before any SX/B instructions are called.

For example:

SENDCHAR        SUB     2                       ' subroutine with 2 parameters
TXBYTE          SUB     1                       ' subroutine with 1 parameter

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

Main:
  ' less convenient
  theChar = "*"                                 ' byte to send
  idx = 10                                      ' times to send
  TXBYTE
  theChar = 13
  idx = 1
  TXBYTE

  ' much more convenient
  SENDCHAR "*", 10                              ' **********
  SENDCHAR 13, 1                                ' <CR>
  PAUSE 1000
  GOTO Main

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

SENDCHAR:
  theChar = __PARAM1                            ' save character to send
  idx = __PARAM2                                ' times to send character

TXBYTE:
  DO WHILE idx > 0
    SEROUT Sio, Baud, theChar                   ' send the character
    DEC idx                                     ' update count, exit if 0
  LOOP
  RETURN

This subroutine (SENDCHAR) expects two parameters: the character to transmit (using SEROUT), and the number of times to send the character.

A subroutine can be constructed to modify any variable that is passed to it (by address using '@'). For example:

INVERTBITS      SUB     1                       ' subroutine with 1 parameter

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

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  myBits = $A5                                  ' myBits = %10100101
  INVERTBITS @myBits                            ' pass address of variable
  RB = myBits                                   ' RB = %01011010 ($5A)
  END

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

INVERTBITS:
  regAddr = __PARAM1                            ' save address
  GET rtnAddr, regVal                           ' get value from address
  regVal = ~regVal                              ' invert bits
  PUT rtnAddr, regVal                           ' update passed variable
  RETURN

An easier method, however, is to allow the subroutine to pass a value directly back to the caller. This update to the program above performs the same function, yet is easier to understand and prevents possible errors resulting is missing '@' headers.

INVERTBITS      SUB     1                       ' subroutine with 1 parameter

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

Start:
  TRIS_B = %00000000                            ' make RB pins outputs

Main:
  myBits = $A5                                  ' myBits = %10100101
  myBits = INVERTBITS myBits                    ' pass value, get one back
  RB = myBits                                   ' RB = %01011010 ($5A)
  END

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

INVERTBITS:
  regVal = __PARAM1                             ' get value from caller
  regVal = ~regVal                              ' invert bits
  RETURN regVal                                 ' return value to caller

Notice that this style eliminates the need for a variable that holds the address of the target variable and simplifies the subroutine code.

Related instruction: GOTO


GOSUB Example

GOSUB Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Demonstrates GOSUB with parameter passing across page boundaries. Note
' that the GOSUB keyword is no longer required when using version 1.2
' syntax (SUB definition).

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LEDs            VAR     RB
TRIS_LEDs       VAR     TRIS_B

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

rVal            VAR     Byte                    ' random number

temp1           VAR     Byte                    ' work vars
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

DELAY           SUB     1, 2                    ' base { x multiplier }
INVERTBITS      SUB     1                       ' register address

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_LEDs = %00000000                         ' make LEDs pins outputs
  rVal = $42                                    ' random seed

Main:
  LEDs = %00000000                              ' clear leds
  DELAY 250, 3                                  ' pause 0.75 secs
  RANDOM rVal                                   ' randomize
  LEDs = rVal                                   ' move to LEDs
  DELAY 250, 2                                  ' pause 0.5 secs
  LEDs = INVERTBITS LEDs                        ' invert the LEDs
  DELAY 250, 2
  GOTO Main

' -------------------------------------------------------------------------
' Subroutines Code
' -------------------------------------------------------------------------

' Use: DELAY base, { multiplier }
' -- pauses 'base' * (optional) 'multiplier' milliseconds

DELAY:
  temp1 = __PARAM1                              ' capture parameters
  IF __PARAMCNT = 1 THEN                        ' if no multiplier
    temp2 = 1                                   ' - set to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0
    IF temp2 > 0
      PAUSE temp1 * temp2                       ' do the pause
    ENDIF
  ENDIF
  RETURN

' Use: INVERTBITS @aVar
' -- inverts the bits of 'aVar'

INVERTBITS:
  temp1 = __PARAM1                              ' get current value
  temp1 = ~temp1                                ' invert the bits
  RETURN temp1                                  ' return inverted value


GOTO

GOTO Label

Function
Jump to the point in the program specified by Label.

  • Label is a program label that is followed by operational code (do not use GOTO with a DATA table label).

Explanation
The GOTO instruction forces the SX to jump to the line of code that immediately follows Label. A common use for GOTO is to create endless loops; programs that repeat a group of instructions over and over. For example:

Main:
  INC LEDs                                      ' update count
  PAUSE 100                                     ' delay 0.1 seconds
  GOTO Main                                     ' keep going

Related instructions: IF...THEN and GOSUB


GOTO Example

GOTO Example Syntax

NOT COMPLETE


HIGH

HIGH Example

HIGH Pin

Function
Make the specified Pin an output and high (1).

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).

Explanation
The HIGH instruction makes the specified Pin an output, and then sets its value to 1 (Vdd). For example:

  HIGH RA.3

does the same thing as:

  OUTPUT RA.3
  RA.3 = 1

Using the HIGH instruction is more convenient in this case.

Related instructions: LOW, OUTPUT, and TOGGLE


HIGH / LOW Example

HIGH / LOW Example HIGH LOW

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Simple LED blinker using HIGH and LOW.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0                    ' LED pin

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

OnDelay         CON     200                     ' time LED is on
OffDelay        CON     800                     ' time LED is off

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  HIGH LED                                      ' turn LED on
  PAUSE OnDelay                                 ' delay
  LOW LED                                       ' turn LED off
  PAUSE OffDelay                                ' delay
  GOTO Start                                    ' repeat forever


I2C Example

I2C Example I2CSTART I2CSTOP I2CSEND I2CRECV

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Writes a pseudo-random value to a 24LC16B EEPROM and then reads the
' value back. Run program in Debug mode to view output and input values.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

SDA             VAR     RA.0
SCL             VAR     RA.1

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

SlaveID         CON     $A0                 ' for 24LC16B

Ack             CON     0
Nak             CON     1

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

addrLo          VAR     Byte                ' address in 24LC16
addrHi          VAR     Byte
outVal          VAR     Byte                ' to 24LC16
inVal           VAR     Byte                ' from 24LC16

temp1           VAR     Byte                ' work vars
temp2           VAR     Byte
temp3           VAR     Byte
temp4           VAR     Byte

Watch_List:
  WATCH outVal, 8, UHEX
  WATCH inVal, 8, UHEX

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

MEMOUT          SUB     3                   ' write value to memory
MEMIN           SUB     2                   ' read value from memory

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  INPUT SDA                                 ' float I2C bus pins
  INPUT SCL

  addrHi = 0                                ' use just block 0

Main:
  FOR addrLo = 0 TO 255                     ' loop through low addresses
    RANDOM outVal                           ' recreate new value
    MEMOUT addrLo, addrHi, outVal           ' send to 24LC16
    PAUSE 50
    inVal = MEMIN addrLo, addrHi            ' get from 24LC16
    BREAK                                   ' allow WATCH window view
  NEXT

  END

' -------------------------------------------------------------------------
' Subroutines Code
' -------------------------------------------------------------------------

' Use: MEMOUT addrLo, addrHi, aVal
' -- writes 'aVal' to 24LC16 at location addrHi/addrLo

MEMOUT:
  temp1 = __PARAM1                          ' copy parameters
  temp2 = __PARAM2
  temp3 = __PARAM3

  I2CSTART SDA
  temp4 = temp2 & $03                       ' get block value
  temp4 = temp4 << 1
  temp4 = temp4 | SlaveID                   ' create control byte
  temp4.0 = 0                               ' set RW bit for write
  I2CSEND SDA, temp4                        ' send slave ID
  I2CSEND SDA, temp1                        ' send word address
  I2CSEND SDA, temp3                        ' send data byte
  I2CSTOP SDA                               ' finish
  RETURN

' Use: aVal = MEMIN addrLo, addrHi
' -- reads 'aVal' from 24LC16 at location addrHi/addrLo

MEMIN:
  temp1 = __PARAM1                          ' copy parameters
  temp2 = __PARAM2

  I2CSTART SDA
  temp4 = temp2 & $03                       ' get block value
  temp4 = temp4 << 1
  temp4 = temp4 | SlaveID                   ' create control byte
  temp4.0 = 0                               ' set RW bit for Write
  I2CSEND SDA, temp4                        ' send slave ID
  I2CSEND SDA, temp1                        ' send word address
  I2CSTART SDA                              ' restart for read
  temp4.0 = 1                               ' set RW bit for Read
  I2CSEND SDA, temp4                        ' resend slave ID
  I2CRECV SDA, temp4, Nak                   ' get one byte
  I2CSTOP SDA
  RETURN temp4


I2CRECV

I2CRECV Example

Syntax: I2CRECV Pin, ByteVar, AckVal

Function
Receives ByteVar from the I2C bus defined by Pin.

  • Pin defines the SDA pin of the I2C bus. Pin may any IO pin except RA.3 (RA.7 on the SX52), RB.7, RC.7, RD.6, or RE.6 (see below).
  • ByteVar is a byte variable that will hold the value returned by the slave device.
  • AckVal is a bit-value that will be sent to the slave after ByteVar has been received (Ack = 0, Nak = 1).

Quick Facts
 | SX18/20 | SX28 | SX48 | SX52
SDA pin | RA.0 - RA.2 RB.0 - RB.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6 | RA.0 - RA.6 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6
SCL pin | Next pin in same group as SDA assignment.
Transmission rate | Approximately 50 kBits/sec.
Special Notes | Both the SDA and SCL pins must have 4.7 kΩ pull-up resisters.

Explanation
The I2C protocol is a form of synchronous serial communication developed by Philips Semiconductor. It only requires two IO pins and both pins can be shared between multiple I2C devices. The I2CRECV instruction reads an eight-bit value from a previously addressed device on the I2C bus (SDA and SCL pins).

Note that the SCL pin is automatically assigned to the next higher pin in the same group as the SDA pin, so the SDA pin may not be assigned to RA.3 (RA.7 on the SX52), RB.7, RC.7, RD.7, or RE.7.

Related instructions: I2CSEND, I2CSTART, and I2CSTOP


I2CSEND

I2CSEND Example

Syntax: I2CSEND Pin, ByteVal {, AckVar}

Function
Sends ByteVal on the I2C bus defined by Pin.

  • Pin defines the SDA pin of the I2C bus. Pin may any IO pin except RA.3 (RA.7 on the SX52), RB.7, RC.7, RD.6, or RE.6 (see below).
  • ByteVal is a variable or constant (0 - 255) that will be transmitted on the I2C bus.
  • AckVar is an optional bit-variable that will hold the Ack/Nak status bit returned by the slave device.

Quick Facts
 | SX18/20 | SX28 | SX48 | SX52
SDA pin | RA.0 - RA.2 RB.0 - RB.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6 | RA.0 - RA.6 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6
SCL pin | Next pin in same group as SDA assignment.
Transmission rate | Approximately 50 kBits/sec.
Special Notes | Both the SDA and SCL pins must have 4.7 kΩ pull-up resisters.

Explanation
The I2C protocol is a form of synchronous serial communication developed by Philips Semiconductor. It only requires two IO pins and both pins can be shared between multiple I2C devices. The I2CSEND instruction transmits an eight-bit value to a previously addressed device on the I2C bus (SDA and SCL pins).

Note that the SCL pin is automatically assigned to the next higher pin in the same group as the SDA pin, so the SDA pin may not be assigned to RA.3 (RA.7 on the SX52), RB.7, RC.7, RD.7, or RE.7.

Related instructions: I2CRECV, I2CSTART, and I2CSTOP


I2CSTART

I2CSTART Example

Syntax: I2CSTART Pin

Function
Generates an I2C Start condition.

  • Pin defines the SDA pin of the I2C bus. Pin may any IO pin except RA.3 (RA.7 on the SX52), RB.7, RC.7, RD.6, or RE.6 (see below).

Quick Facts
 | SX18/20 | SX28 | SX48 | SX52
SDA pin | RA.0 - RA.2 RB.0 - RB.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6 | RA.0 - RA.6 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6
SCL pin | Next pin in same group as SDA assignment.
Special Notes | Both the SDA and SCL pins must have 4.7 kΩ pull-up resisters.

Explanation
The I2C protocol is a form of synchronous serial communication developed by Philips Semiconductor. It only requires two IO pins and both pins can be shared between multiple I2C devices. The I2CSTART instruction generates an I2C Start condition on the I2C bus (SDA and SCL pins); this condition is used to start (or restart) a transmission sequence.

Note that the SCL pin is automatically assigned to the next higher pin in the same group as the SDA pin, so the SDA pin may not be assigned to RA.3 (RA.6 on the SX52), RB.7, RC.7, RD.7, or RE.7.

Special Note
The I2CSTART instruction monitors the state of the SCL line and will wait for SCL to be high before returning; this could cause some systems to hang if the SCL line is shorted to Vss. To prevent this hang, the programmer can make the SCL line an input then test its state before calling I2CSTART.

Related instructions: I2CSTOP, I2CSEND, and I2CRECV


I2CSTOP

I2CSTOP Example

Syntax: I2CSTART Pin

Function
Generates an I2C Stop condition.

  • Pin defines the SDA pin of the I2C bus. Pin may any IO pin except RA.3 (RA.7 on the SX52), RB.7, RC.7, RD.6, or RE.6 (see below).

Quick Facts
 | SX18/20 | SX28 | SX48 | SX52
SDA pin | RA.0 - RA.2 RB.0 - RB.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 | RA.0 - RA.2 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6 | RA.0 - RA.6 RB.0 - RB.6 RC.0 - RC.6 RD.0 - RD.6 RE.0 - RE.6
SCL pin | Next pin in same group as SDA assignment.
Special Notes | Both the SDA and SCL pins must have 4.7 kΩ pull-up resisters.

Explanation
The I2C protocol is a form of synchronous serial communication developed by Philips Semiconductor. It only requires two IO pins and both pins can be shared between multiple I2C devices. The I2CSTOP instruction generates an I2C Stop condition on the I2C bus (SDA and SCL pins); this condition is used to terminate a transmission sequence.

Note that the SCL pin is automatically assigned to the next higher pin in the same group as the SDA pin, so the SDA pin may not be assigned to RA.3 (RA.6 on the SX52), RB.7, RC.7, RD.7, or RE.7.

Related instructions: I2CSTART, I2CSEND, and I2CRECV


IF-THEN

IF ... THEN

IF Condition [THEN | GOTO] [Label | EXIT]

Function
Evaluate Condition and, if it is true, jump to the point in the program designated by Label.

  • Condition is a simple statement, such as "x = 7" that can be evaluated as True or False.
  • Label specifies where to go in the event that Condition statement evaluates as True.

Explanation
IF...THEN is decision maker that affects program flow. It tests a Condition statement and, if that statement is True, goes to a point in the program specified by Label. The available comparison operators are:

Comparison Operator | Definition
= | Equal
<> | Not Equal
> | Greater Than
< | Less Than
>= | Greater Than or Equal To
<= | Less Than or Equal To

Comparisons are always written in the form: Variable Op Value.

  • Variable is a bit or byte variable.
  • Op is the comparison operator.
  • Value is a variable or constant for comparison.

Main:
  IF StartBtn = 1 THEN Main                     ' wait for input to go low

Check_Mode:
  IF ModePin = 0 GOTO ShowAMPM                  ' use HH:MM xM format if mode = 0

Related instructions: IF...THEN...ELSE, BRANCH, GOTO, and EXIT


IF-THEN-ELSE

IF ... THEN ... ELSE ... ENDIF

IF Condition THEN
statement(s)
{ ELSE
statement(s) }
ENDIF

Function
Evaluate Condition and, if it is true, run the code block that follows THEN, otherwise jump to the (optional) code block that follows ELSE. If no ELSE block is provided, the program will continue at the line that follows ENDIF.

  • Condition is a simple statement, such as "x = 7" that can be evaluated as True or False.
  • Statement is any valid SX/B program statement.

Explanation
IF...THEN...ELSE is a primary decision maker that allows one block of code or [optionally] another to run based on the result (True or False) of a condition. The available comparison operators are:

Comparison Operator | Definition
= | Equal
<> | Not Equal
> | Greater Than
< | Less Than
>= | Greater Than or Equal To
<= | Less Than or Equal To

Comparisons are always written in the form: Variable Op Value.

  • Variable is a bit or byte variable.
  • Op is the comparison operator.
  • Value is a variable or constant for comparison.

This simple example shows how IF...THEN...ELSE is used with a subroutine that can accept one or two parameters.

' Use: DELAY milliseconds {, multiplier}
' -- pause for milliseconds x (optional) multiplier

DELAY:
  temp1 = __PARAM1
  IF __PARAMCNT = 1 THEN                        ' if only base time
    temp2 = 1                                   ' set multiplier to 1
  ELSE
    temp2 = __PARAM2                            ' else use multiplier
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0
      PAUSE temp1 * temp2
    ENDIF
  ENDIF
  RETURN

Related instruction: IF...THEN


IF-THEN Example

IF-THEN Example Syntax

NOT COMPLETE


INC

INC ByteVar

Function
Increment value of ByteVar by one.

  • ByteVar is any byte variable.

Explanation
The INC instruction adds one to the specified byte variable. If the variable holds 255 before the INC instruction, it will roll over to 0 after. When incrmenting from 255 to 0 the Z flag gets set, otherise it is cleared.

Main:
  RB = 255                                      ' RB = %11111111, Z = 0
  INC RB                                        ' RB = %00000000, Z = 1
  INC RB                                        ' RB = %00000001, Z = 0

Related instruction: DEC


INC Example

INC Example Syntax

NOT COMPLETE


INPUT

INPUT Pin

Function
Make the specified Pin an input by writing a one (1) to the corresponding bit of the associated port TRIS register.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).

Explanation
There are several ways to make a pin an input. When an SX/B program is reset, all of the IO pins are made inputs. Instructions that rely on input pins, like PULSIN and SERIN, automatically change the specified pin to input mode. Writing 1s to particular bits of the port TRIS register makes the corresponding pins inputs. And then there's the INPUT instruction.

Start:
  INPUT RA.3

Hold:
  IF RA.3 = 1 THEN Hold                         ' stay until RA.3 = 0

What happens if your program writes to a port bit of a pin that is set up as an input? The value is stored in the port register, but has no effect on the outside world. If the pin is changed to output, the last value written to the corresponding port bit will appear on the pin.

Related instructions: OUTPUT and REVERSE


INTERRUPT

INTERRUPT ... RETURNINT Examples

Syntax: INTERRUPT {NOPRESERVE | NOCODE} Instruction(s) ... RETURNINT {Cycles}

Function
INTERRUPT allows the insertion a code block to handle an interrupt in an SX/B program. The interrupt code block is terminated with RETURNINT.

  • Cycles is an optional byte-variable or constant (0 - 255) that sets the number of RTCC instructions for a periodic interrupt.

Explanation
An interrupt handler allows the SX to perform "background" task, at regular intervals (using the internal RTCC rollover) or asynchronously (using the external RTCC input pin, or Port B inputs). The interrupt code must be located in Page 0 of your program, and before any other code -- this is a requirement of the SX microcontroller.

SX/B automatically saves internal program variables (__PARAMx) at the start of the ISR and restores them on exit of the ISR. This consumes ISR cycles (14 cycles on entry, 13 cycles on exit) and must be accounted for in time-critical ISR applications. If high-level instructions will not be used in the ISR, the NOPRESERVE option may be specified, eliminating the code that preserves and restores internal SX/B program variables. If the NOPRESERVE option is used, you must make sure that none of the __PARAMx variables are modified by the ISR (i.e., use high-level SX/B instructions). If the NOCODE option is specified then the interrupt routine must set FSR to zero to access variables in location $10 to $1F reliably.

Periodic Interrupts
The SX chip can be set to cause an interrupt upon rollover of the Real Time Clock Counter (RTCC). By configuring an interrupt on RTCC rollover, the SX chip can perform an operation at a predefined time interval in a deterministic fashion. This can be configured by setting the STACKX or OPTIONX fuse (in the DEVICE directive, and required by SX/B) and writing to the RTI, RTS and RTE bits of the Option register (OPTION). The RTCC rollover interrupt is disabled by default.

To configure the RTCC rollover interrupt:

  1. Set the STACKX or OPTIONX fuse in the DEVICE directive.
  2. Write to the RTI, RTS and RTE bits of the OPTION register to enable RTCC interrupts. For RTI, a high bit (1) disables RTCC rollover interrupts and a low bit (0) enables RTCC rollover interrupts. For RTS, a high bit (1) selects incrementing RTCC on internal clock cycle and a low bit (0) increments RTCC on the RTCC pin transitions. For RTE, a high bit (1) selects incrementing on low-to-high transition and a low bit (0) increments on a high-to-low transition.

An interrupt handler that uses the RTCC rollover to create a periodic interrupt might look as follows:

' -------------------------------------------------------------------------
  INTERRUPT
' -------------------------------------------------------------------------

ISR_Start:
  INC tix                                       ' update tix counter
  IF tix = 200 THEN                             ' check for 1 second
    tix = 0
    INC secs
    IF secs = 60 THEN
      secs = 0
      INC mins
      IF mins = 60 THEN
        mins = 0
        INC hrs
        IF hrs = MaxHr THEN
          hrs = 0
        ENDIF
      ENDIF
    ENDIF
  ENDIF

ISR_Exit:
  RETURNINT 156

This routine (ISR) maintains a real-time clock. The variable called tix is updated each time through the ISR and when it reaches 200 the seconds counter is updated. This indicates that the ISR is designed to run 200 times per second.

Even when using a 4 MHz oscillator, each instruction takes only 0.25 microseconds. By using the RTCC prescalar we can slow the RTCC timing to a more managable value and simplify the code. For the timer above, the RTCC prescalar ratio is set to 1:128 via the OPTION register (and clearing OPTION.6 enables the ISR):

  OPTION = $86                                  ' prescaler = 1:128

Note that the Cycles count is set to 156 -- this means that the ISR will run after 156 cycles of the internal RTCC. The final math for the ISR timing works out like this:

4 MHz (FREQ) ÷ 128 (prescalar) ÷ 200 (ISR rate) = 156.25 (Cycles)

Asynchronous Interrupts
Every I/O pin in port B can be set to cause an interrupt upon logic level transitions (rising edge or falling edge). By configuring interrupts on input pins, the SX chip can respond to signal changes in a quick and deterministic fashion. In addition, an interrupt of this sort will wake up the SX chip from a SLEEP state. This can be configured by writing to the Edge Selection register (WKED_B) and the Wake-Up Enable register (WKEN_B) and detected by monitoring the Pending register (WKPND_B) in the interrupt routine. The I/O pins have interrupts disabled and are set to detect falling edge transitions by default.

As with edge selection, the Pending register bits will never be cleared by the SX alone; the running program is responsible for doing so. This means if a desired edge is detected, the interrupt will occur and the flag indicating this will remain set until the program clears it. Additional transitions on that pin will not cause interrupts until the associated bit in the Pending register is cleared.

To configure the I/O pins for wake-up (interrupt) edge detection:

  1. Set I/O pin edge detection with WKED_B as desired.
  2. Use WKEN_B to enable the individual pins for wake-up interrupts. A high bit (1) disables interrupts and a low bit (0) enables interrupts.
  3. Set I/O pin directions as necessary.
  4. Clear the Pending register to enable new interrupts.

Special Notes
Interrupts should be avoided -- or at the very least disabled -- when using time-sensitive instructions such as SERIN, SEROUT, PULSIN, PULSOUT, etc. If an interrupt is triggered while a time-sensitive instruction is active the instruction is likely to fail, or return bad results.


INTERRUPT Examples

INTERRUPT Examples Syntax

This example shows how to create an RTCC rollover interrupt to create the modulation frequency for an infrared LED.

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' This program modules an IR LED using the interrupt handler to toggle the
' IR LED state every 13 microseconds.  When an object is detected, the
' alarm LED is illuminated.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

IrLed           VAR     RB.0                    ' IR LED control
Detect          VAR     RB.1                    ' detector input
Alarm           VAR     RB.2                    ' alarm LED output

' -------------------------------------------------------------------------
  INTERRUPT
' -------------------------------------------------------------------------

ISR_Start:
  IrLed = ~IrLed                                ' toggle IR LED
  RETURNINT 52                                  '   every 13 us @ 4 MHz

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  LOW IrLed                                     ' make output, off
  LOW Alarm                                     ' make output, off
  OPTION = $88                                  ' interrupt, no prescaler

Main:
  Alarm = ~Detect                               ' check detector
  PAUSE 50
  GOTO Main

This example shows how to create an RTCC rollover interrupt to create a "background" serial receiver that runs at from 1200 to 19.2K baud, N81, inverted mode.

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' This program demonstrates the construction of an ISR to receive serial
' data "in the background" using a 16-byte circular buffer.
'
' Note: Requires SX/B 1.2 or later

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Sin             VAR     RA.0                    ' serial in
Blinker         VAR     RB.0                    ' blinking LED
LEDs            VAR     RC                      ' eight LEDs (7-segs)
TRIS_LEDs       VAR     TRIS_C

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

B1200           CON     64                      ' 1200 Baud
B2400           CON     32                      ' 2400 Baud
B4800           CON     16                      ' 4800 Baud
B9600           CON     8                       ' 9600 Baud
B19K2           CON     4                       ' 19.2 kBaud (max @ 4 MHz)

BitTm           CON     B19K2                   ' samples per bit
BitTm15         CON     3*BitTm/2               ' 1.5 bits

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

rxCount         VAR     Byte                    ' bits to receive
rxTimer         VAR     Byte                    ' bit timer for ISR
rxByte          VAR     Byte                    ' serial byte
rxHead          VAR     Byte                    ' available slot
rxTail          VAR     Byte                    ' next byte to read
rxBuf           VAR     Byte(16)                ' circular buffer

regAddr         VAR     Byte                    ' register address
temp1           VAR     Byte                    ' parameter

' -------------------------------------------------------------------------
  INTERRUPT NOPRESERVE
' -------------------------------------------------------------------------

' ISR is setup to receive N81, inverted mode.

ISR_Start:
  ASM
    MOVB C, /Sin                                ' sample serial input
    TEST rxCount                                ' receiving now?
    JNZ RX_Bit                                  ' yes if rxCount > 0
    MOV W, #9                                   ' start + 8 bits
    SC                                          ' skip if no start bit
    MOV rxCount, W                              ' got start, load bit count
    MOV rxTimer, #BitTm15                       ' delay 1.5 bits

RX_Bit:
    DJNZ rxTimer, ISR_Exit                      ' update bit timer
    MOV rxTimer, #BitTm                         ' reload bit timer
    DEC rxCount                                 ' mark bit done
    SZ                                          ' if last bit, we're done
    RR rxByte                                   ' move bit into rxByte
    SZ                                          ' if not 0, get more bits
    JMP ISR_Exit

RX_Buffer:
    MOV FSR, #rxBuf                             ' get buffer address
    ADD FSR, rxHead                             ' point to head
    MOV IND, rxByte                             ' move rxByte to head
    INC rxHead                                  ' update head
    CLRB rxHead.4                               ' keep 0 - 15
  ENDASM

ISR_Exit:
  RETURNINT 52                                  ' 13 uS @ 4 MHz

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

GETBYTE         SUB     1

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_LEDs = %00000000                         ' make LED pins outputs
  OPTION = $88                                  ' interrupt, no prescaler

Main:
  IF rxHead <> rxTail THEN                      ' if buffer has data
    LEDs = GETBYTE                              ' get byte from buffer
  ENDIF
  TOGGLE Blinker                                ' blink LED
  PAUSE 50                                      ' small pause
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: aVar = GETBYTE
' -- if data is in buffer, the next byte is move to 'aVar'
' -- if called when buffer empty, code waits for character to arrive

GETBYTE:
  DO WHILE rxHead = rxTail
    ' wait while empty
  LOOP
  temp1 = rxBuf(rxTail)                       ' get first available
  INC rxTail                                  ' update tail position
  \ CLRB rxTail.4                             ' keep 0 - 15
  RETURN temp1

This example shows how to use a port B edge detection interrupt to determine which button was pressed first.

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' On reset the 7-segment LED is cleared to a dash and the program waits
' for a button press (RB.0 - RB.3) -- the "winner" (first pressed) will
' be displayed on the display until reset.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Buttons         VAR     RB                      ' button inputs
TRIS_Btns       VAR     TRIS_B
Display         VAR     RC                      ' 7-segment LED
TRIS_Disp       VAR     TRIS_C

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Dash            CON     %01000000               ' -
Dig1            CON     %00000110               ' 1
Dig2            CON     %01011011               ' 2
Dig3            CON     %01001111               ' 3
Dig4            CON     %01100110               ' 4
LtrE            CON     %01111001               ' E(rror)

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

winner          VAR     Byte                    ' button pressed first

' -------------------------------------------------------------------------
  INTERRUPT
' -------------------------------------------------------------------------

ISR_Start:
  WKPND_B = winner                              ' get winner

Ch1:                                            ' check channel
  IF winner <> %0001 THEN Ch2                   ' if not, try next
  Display = Dig1                                ' otherwise display
  GOTO ISR_Exit

Ch2:
  IF winner <> %0010 THEN Ch3
  Display = Dig2
  GOTO ISR_Exit

Ch3:
  IF winner <> %0100 THEN Ch4
  Display = Dig3
  GOTO ISR_Exit

Ch4:
  IF winner <> %1000 THEN Uh_Oh
  Display = Dig4
  GOTO ISR_Exit

Uh_Oh:
  Display = LtrE                                ' something went wrong

ISR_Exit:
  WKEN_B = %11111111                            ' no ISR until reset
  RETURNINT

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  Display = Dash                                ' indicate ready with dash
  TRIS_Disp = %00000000                         ' display port --> outputs
  WKPND_B = %00000000                           ' clear pending
  WKED_B = %11111111                            ' falling edge detect
  WKEN_B = %11110000                            ' use bits 0..3 for inputs
  END


KEYWORD

Syntax: KEYWORD parameters

Function
Short descriptive text.

  • Param_1 text
  • Param_2 text

Quick Facts

Explanation
Detailed descriptive text...

The following example illustrates this:

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4000000

LEDs            VAR     RC

PROGRAM Start

Start:
  LEDs = %00000000                              ' clear LEDs
  TRIS_C = %00000000                            ' RC pins are outputs

Main:
  PAUSE 100                                     ' 0.1 secs between counts
  INC LEDs
  GOTO Main
  END

Related instructions: THIS and THAT


ASM Example

ASM Example Syntax

Start:
  TRIS_LEDs = %00000000                         ' LED pins are outputs


LET

{LET} Variable = {Value} {Op} Value

Function
Assign a Value or result of an expression to Variable.

  • Variable is the target variable for the assignment.
  • Op is a unary (one value) or binary (two values) operator.
  • Value is a variable or constant value which affects Variable

Explanation
LET is an optional keyword an not typcially used. For example,

  LET idx = 25

... produces the same compiled output as:

  idx = 25

so using LET is of no advantage. Note that when assigning a bit variable the value of a byte variable, the bit variable will be set to zero if the byte variable is zero, otherwise it will be set to one.

  myByte = 0
  myBit = myByte                                ' myBit = 0
  myByte = 4
  myBit = myByte                                ' myBit = 1

Using Operators in Assignments
Note that SX/B supports only simple expressions, that is, just one operator per line of code. The following line will produce an error:

  idx = count / 2 + 1                           ' illegal in SX/B!

The error is corrected by splitting the operators across separate lines:

  idx = count / 2                               ' okay now
  idx = idx + 1

The tables below show available operators for SX/B assignments:

Unary Operator | Definition
- | Negate
~ | Bitwise inversion
NOT | Bitwise inversion

Binary Operator | Definition
+ | Addition
- | Subtraction
* | Multiplication
/ | Division
// | Modulus
MAX | Set Maximum
MIN | Set Minimum
& | Bitwise AND
AND | Bitwise AND
| | Bitwise OR
OR | Bitwise OR
^ | Bitwise Exclusive OR
XOR | Bitwise Exclusive OR
<< | Shift Left
SHL | Shift Left
>> | Shift Right
SHR | Shift Right

See the Operaters section for details.

Configuration Registers
When assigning values to SX configuration registers, the format is limited to:

{LET} Register = Value

When assigning values to the special registers WKPND_B and CMP_B a variable must be used and that variable will be exchanged with the SX register.

{LET} Register = ByteVar

  WKPND_B = wakeUp                              ' WKPND_B exchanged with wakeUp
  CMP_B = analog                                ' CMP_B exchanged with analog


LOOKDOWN

LOOKDOWN Target, Value0, {Value1, Value2, ...} ByteVar

Function
Compare Target value to a list of values and store the index number of the first value that matches into ByteVar. If no value in the list matches, ByteVar is left unaffected.

  • Target is a variable or constant (0 - 255) to be compared to the values in the list.
  • Values are variables or constants (0 - 255) to be compared to Target.
  • ByteVar is a variable that will be set to the index (0 - n) of the matching value in the Values list. If no matching value is found, ByteVar is left unaffected.

Explanation
LOOKDOWN works like the index in a book. In an index, you search for a topic and get the page number. LOOKDOWN searches for a target value in a list, and stores the index number of the first match in a variable. For example:

Do_Cmd:
  DO
    SERIN Sio, Baud, cmd                        ' wait for command input
    LOOKDOWN cmd, "F", "B", "S", cmd            ' compare against valid commands
  LOOP UNTIL cmd < 3                            ' wait until valid
  BRANCH cmd, Forward, Backward, Stop_Bot       ' execute valid command

Related instruction: LOOKUP


LOOKDOWN Example

LOOKDOWN Example Syntax

NOT COMPLETE


LOOKUP

LOOKUP Example

LOOKUP Index, Value0, {Value1, Value2, ...} ByteVar

Function
Find the value at location Index and store it in ByteVar. If Index exceeds the highest index value of the items in the list ByteVar is left unaffected.

  • Index is a variable indicating the list item to retrieve. The first Value is at Index 0.
  • Values are variables or constants.
  • ByteVar is a variable that will be set to the value at the Index location.

Explanation
LOOKUP retrieves an item from a list based on the item's position, Index, in the list. For example:

  idx = 3
  LOOKUP idx, $00, $01, $02, $04, $08, $10, $20, $40, $80, LEDs

In this example, the variable called LEDs will be set to $04 as this value appears at index position three in the values list.

Related instructions: LOOKDOWN and READ


LOOKUP Example

LOOKUP Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Uses LOOKUP to transfer a single digit value to a 7-segment LED.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LEDs            VAR     RB                      ' 7-segment display
TRIS_LEDs       VAR     TRIS_B

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

value           VAR     Byte                    ' digit to display
temp1           VAR     Byte                    ' parameter

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

PUTDIGIT        SUB     1

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_LEDs = %00000000                         ' make LEDs outputs

Main:
  FOR value = 0 TO 16                           ' demo values (last invalid)
    LEDs = PUTDIGIT value                       ' update the display
    PAUSE 1000                                  ' pause one second
  NEXT
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: destination = PUTDIGIT value
' -- converts number in 'value' to 7-segment digit pattern
'    and places it in 'destination'

PUTDIGIT:
  temp1 = __PARAM1                              ' copy value

  IF temp1 < $A THEN
    ' decimal
    LOOKUP temp1, $3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$67, temp1
  ELSE
    IF temp1 < $10 THEN
      ' hex
      temp1 = temp1 - 10                        ' adjust for LOOKUP
      LOOKUP temp1, $77,$7C,$39,$5E,$79,$71, temp1
    ELSE
      temp1 = %01000000                         ' display dash
    ENDIF
  ENDIF
  RETURN temp1


LOW

LOW Example

LOW Pin

Function
Make the specified Pin an output and low (0).

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).

Explanation
The LOW instruction makes the specified Pin an output, and then sets its value to 0 (Vss). For example:

  LOW RA.3

does the same thing as:

  OUTPUT RA.3
  RA.3 = 0

Using the LOW instruction is more convenient in this case.

Related instructions: HIGH, OUTPUT, and TOGGLE


OUTPUT

OUTPUT Pin

Function
Make the specified Pin an output by writing a zero (0) to the corresponding bit of the associated port TRIS register.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).

Explanation
There are several ways to make a pin an output. When an SX/B program is reset, all of the IO pins are made inputs. Instructions that rely on output pins, like PULSOUT and SEROUT, automatically change the specified pin to output mode. Writing 0s to particular bits of the port TRIS register makes the corresponding pins outputs. And then there's the OUTPUT instruction.

  OUTPUT RA.3
  RA.3 = 0

When your program changes a pin from input to output, whatever state happens to be in the corresponding bit of port TRIS register sets the initial state of the pin. To simultaneously make a pin an output and set its state use the HIGH and LOW instructions.

Related instructions: INPUT and REVERSE


OWRDBIT

Syntax: OWRDBIT Pin, BitVar

Function
Reads one bit from a 1-Wire bus.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • BitVar is a bit variable that will hold the 1-Wire Read Slot value.

Quick Facts
 | All SX Models
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.
 | 1-Wire commands require a FREQ setting of 4 MHz or higher.

Explanation
Some 1-Wire transactions require reading data from the device. While this is typically handled with OWRDBYTE, SX/B supports bit access with the OWRDBIT instruction. A 1-Wire read is accomplished by generating a brief (5 µS) low-pulse and sampling the DQ pin within 15 µS of the falling edge of the pulse. This is called a "Read Slot." The diagram and table below details the Read Slot sequence generated by the SX with OWRDBIT.

Note | Timing | Description
A | 5 µS | Initiate Read Slot (SX master)
B | 10 µS | Delay before sampling DQ
C | ~ 60 µS | Read Slot recovery

Related instructions: OWRESET, OWRDBYTE, OWWRBIT, and OWWRBYTE


OWRDBYTE

OWRDBYTE Example

Syntax: OWRDBYTE Pin, ByteVar

Function
Reads one byte (eight bits) from a 1-Wire device.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • ByteVar is any byte variable that will hold the 1-Wire read value.

Quick Facts
 | All SX Models
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.
 | 1-Wire commands require a FREQ setting of 4 MHz or higher.
Receive Rate | ~ 12 kBits/Sec (not including Reset)

Explanation
Some 1-Wire transactions require reading data from the device. A bit is read from the 1-Wire device byte generating a brief pulse on the DQ line, then reading the line withing 15 µS of the falling edge (see OWRDBIT for details). This is called a "Read Slot." The OWRDBYTE instruction generates eight 1-Wire Read Slot sequences and returns the value in ByteVar.

Related instructions: OWRESET, OWRDBIT, OWWRBIT, and OWWRBYTE


OWRESET

OWRESET Example

Syntax: OWRESET Pin {, ByteVar }

Function
Generates a 1-Wire reset sequence on Pin, returning (optional) status information in ByteVar.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • ByteVar is an optional byte variable that will hold the status of the 1-Wire connections (see below).

Quick Facts
 | All SX Models
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.
 | 1-Wire commands require a FREQ setting of 4 MHz or higher.
Status value | 0 = Bus shorted to Vss; 1 = Bad connection; 2 = Good connection; 3 = No device

Explanation
All transactions on the 1-Wire bus begin with an Initialziation sequece that consists of a Reset pulse generated by the master, followed by a Presences pulse generated by the 1-Wire slave. The OWRESET instruction generates the 1-Wire Reset pulse on the specified DQ Pin and, if ByteVar is specified, will monitor the bus and return status information to the program.

The diagram and table below details the Reset pulse generated by the SX with OWRESET and a typical Presence pulse generated by a 1-Wire slave, in response.

Note | Timing | Description
A | ~ 480 µS | 1-Wire Reset pulse (SX master)
B | ~ 15 µS | Delay before sampling for bus short
C | ~ 70 µS | Delay before sampling for Presence
D | ~ 60 - 240 µS | Presence pulse (1-Wire slave)
E | ~ 480 µS | Reset recovery

Related instructions: OWRDBIT, OWRDBYTE, OWWRBIT, and OWWRBYTE


OWWRBIT

Syntax: OWWRBIT Pin, BitVal

Function
Writes one bit to a 1-Wire bus.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • BitVal is a variable or constant value (0 to 1) that will be written to the 1-Wire bus.

Quick Facts
 | All SX Models
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.
 | 1-Wire commands require a FREQ setting of 4 MHz or higher.

Explanation
After reset, 1-Wire transactions require writing values to the bus. While this is typically handled with OWWRBYTE, SX/B supports bit access with the OWWRBIT instruction. A bit is written by generating a timed low pulse on the DQ line; this is called a "Write Slot." The diagrams and tables below details the Write Slot sequences generated by the SX with OWWRBIT.

WRITE 0

Note | Timing | Description
A | 60 µS | Write Slot 0 (SX master)
B | ~ 10 µS | Write Slot recovery

WRITE 1

Note | Timing | Description
A | 5 µS | Write Slot 1 (SX master)
B | ~ 65 µS | Write Slot recovery

Related instructions: OWRESET, OWRDBIT, OWRDBYTE, and OWWRBYTE


OWWRBYTE

OWWRBYTE Example

Syntax: OWWRBYTE Pin, ByteVal

Function
Writes one byte (eight bits) to the 1-Wire bus.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • ByteVal is a variable or constant value (0 - 255) that will be written to the 1-Wire bus.

Quick Facts
 | All SX Models
Special Notes | The DQ pin (specified by Pin) must have a 4.7 kΩ pull-up resister.
 | 1-Wire commands require a FREQ setting of 4 MHz or higher.
Transmission rate | ~ 12 kBits/Sec (not including Reset)

Explanation
After reset, 1-Wire transactions require writing values to the bus. A bit is written by generating a timed low pulse on the DQ line; this is called a "Write Slot" (see OWWRBIT for details). The OWWRBYTE instruction generates eight Write Slot sequences to put ByteVal on the 1-Wire bus.

Related instructions: OWRESET, OWRDBIT, OWRDBYTE, and OWWRBIT


PAUSE

PAUSE Example

Syntax: PAUSE Value1 {[, | *] Value2}

Function
Pause the program (do nothing) for a number of milliseconds.

  • Value1 is a variable (1 - 255) or constant (1 to 65535, or fractional value†) that affects the PAUSE duration.
  • Value2 is a variable (1 - 255) or constant (1 to 255) that affects the PAUSE duration.

† Note: A value up to 65535 is allowed when a single constant parameter is used.
† Note: Fractional values (0.01 to 65535.99) are allowed when a single constant parameter is used. SX clock speed will affect the accuracy of fractional timing.

Explanation
PAUSE delays the execution of the next program instruction for a number of milliseconds based on Value1 and Value2. For example:

Flash:
  LOW RC.0
  PAUSE 1000
  HIGH RC.0
  PAUSE 1000
  GOTO Flash

This code causes pin RC.0 to go low for 1000 milliseconds, then high for 1000 milliseconds. Note that a PAUSE duration of up to 65535 milliseconds is possible when a single constant parameter is used.

Some projects may require sub- or fractional-millisecond delays, and in some cases PAUSEUS may not be practical or desired. When using a single parameter, a fractional PAUSE value may be specified:

Flash:
  LOW RC.0
  PAUSE 12.5
  HIGH RC.0
  PAUSE 12.5
  GOTO Flash

PAUSE can take one or two values as parameters. When using two parameters, two forms are allowed. Here's an example of the first form:

  PAUSE 238, 2

Using this form, the PAUSE duration is Value1 + (Value2 * 256). In the example above the program will pause for 750 milliseconds. Note that this form is typically used with with variables, but will also work with constants up to 255.

The third form of PAUSE is demonstrated below:

  idx = 3
  PAUSE idx * 250

Using this form, the PAUSE duration is Value1 * Value2. In the example above the program will pause for 750 milliseconds. Note that this form is typically used with with variables, but will also work with constants up to 255.

Related instruction: PAUSEUS


PAUSE Example

PAUSE Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Variable-rate LED blinker.  Puts PAUSE into a subroutine for greatest
' flexibility and program space conservation.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

idx             VAR     Byte                    ' loop counter

temp1           VAR     Byte                    ' parameters
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

DELAY           SUB     1, 2                    ' base { x multiplier }

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  FOR idx = 1 TO 10                             ' loop 1 to 10
    HIGH LED                                    ' LED on
    DELAY 50, idx                               ' pause 50 to 500 ms
    LOW LED                                     ' LED off
    DELAY 50, idx                               ' pause 50 to 500 ms
  NEXT
  GOTO Start

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: DELAY base {, multiplier }
' -- pause for 'base' * (optional) 'multiplier' milliseconds

DELAY:
  temp1 = __PARAM1                              ' capture parameters
  IF __PARAMCNT = 1 THEN                        ' if no multiplier
    temp2 = 1                                   ' - set to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSE temp1 * temp2                       ' do the PAUSE
    ENDIF
  ENDIF
  RETURN


PAUSEUS

Syntax: PAUSEUS Value1 {[, | *] Value2}

Function
Pause the program (do nothing) for a number of microseconds.

  • Value1 is a variable (1 - 255) or constant (1 to 65535, or fractional value†) that affects the PAUSEUS duration.
  • Value2 is a variable (1 - 255) or constant (1 to 255) that affects the PAUSEUS duration.

† Note: A value up to 65535 is allowed when a single constant parameter is used.
† Note: Fractional values (0.01 to 65535.99) are allowed when a single constant parameter is used. SX clock speed will affect the accuracy of fractional timing.

Explanation
PAUSEUS delays the execution of the next program instruction for a number of microseconds based on Value1 and Value2. For example:

Tone:
  RC.0 = ~RC.0
  PAUSEUS 500
  IF RB.0 = 1 THEN Tone

This code toggles the state of RC.0 every 500 microseconds, creating a 1 kHz tone until pin RB.0 goes low. Note that a PAUSEUS duration of up to 65535 microseconds is possible when a single constant parameter is used.

Some projects may require sub- or fractional-microsecond delays. When using a single parameter, a fractional PAUSEUS value may be specified:

Tone440:
  DO
    RC.0 = ~RC.0
    PAUSEUS 1136.36
  LOOP

PAUSEUS can take one or two values as parameters. When using two parameters, two forms are allowed. Here's an example of the first form:

  PAUSEUS 238, 2

Using this form, the PAUSEUS duration is Value1 + (Value2 * 256). In the example above the program will pause for 750 microseconds. Note that this form is typically used with with variables, but will also work with constants up to 255.

The third form of PAUSEUS is demonstrated below:

  idx = 3
  PAUSEUS idx * 250

Using this form, the PAUSEUS duration is Value1 * Value2. In the example above the program will pause for 750 microseconds. Note that this form is typically used with with variables, but will also work with constants up to 255.

Related instruction: PAUSE


PAUSEUS Example

PAUSEUS Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Variable-rate LED blinker.  Puts PAUSEUS into a subroutine for greatest
' flexibility and program space conservation.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

idx             VAR     Byte                    ' loop counter

temp1           VAR     Byte                    ' parameters
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

DELAYUS         SUB     1, 2                    ' base { x multiplier }

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  FOR idx = 10 TO 100                           ' loop 10 to 100
    HIGH LED                                    ' LED on
    DELAYUS 200, idx                            ' pause 50 to 500 ms
    LOW LED                                     ' LED off
    DELAYUS 200, idx                            ' pause 50 to 500 ms
  NEXT
  GOTO Start

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: DELAYUS base {, multiplier }
' -- pause for 'base' * (optional) 'multiplier' milliseconds

DELAYUS:
  temp1 = __PARAM1                              ' capture parameters
  IF __PARAMCNT = 1 THEN                        ' if no multiplier
    temp2 = 1                                   ' - set to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSEUS temp1 * temp2                     ' do the PAUSE
    ENDIF
  ENDIF
  RETURN


PULSIN

PULSIN Pin, State, ByteVar {, Resolution}

Function
Measure the width of a pulse on Pin described by State in units of Resolution and store the result in ByteVar.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7). This pin will be set to input mode.
  • State is a constant (0 - 1) that specifies whether the pulse to be measured is low (0) or high (1). A low pulse begins with a 1-to-0 transition, and a high pulse begins with a 0-to-1 transition.
  • ByteVar is a variable in which the measured pulse duration will be stored. The unit of time for ByteVar is described in Resolution.
  • Resolution is an optional constant (1 - 255) that specifies the units for ByteVar, in increments of 10 microseconds (default value is 1 when not specified).

Quick Facts
Range of ByteVar | 0 (no pulse) to 255
Units in Resolution | 10 µs (0.01 ms)
Minimum pulse width | 10 µs
Maximum pulse width | 650.25 ms

Explanation
PULSIN is like a fast stopwatch that is triggered by a change in state (0 or 1) on the specified pin. The entire width of the specified pulse (high or low) is measured, in units shown above and stored in ByteVar.

Many analog properties (voltage, resistance, capacitance, frequency, duty cycle) can be measured in terms of pulse duration. This makes PULSIN a valuable form of analog-to-digital conversion.

PULSIN will wait for the desired pulse, for up to the maximum pulse width it can measure, shown in the table above. If it sees the desired pulse it measures the time until the end of the pulse and stores the result in ByteVar. If it never sees the start of the pulse, or the pulse is too long (greater than the Maximum Pulse Width shown above), PULSIN "times out" and store 0 in ByteVar. This operation keeps your program from locking-up should the desired pulse never occur.

  PULSIN RA.0, 1, pWidth                        ' measure 10 - 2550 us pulse

In the example above, pin RA.0 will be set to input mode, wait for a low-to-high transition, then measure the period that the pin stays high. Using the default Resolution of 10 microseconds, a pulse from 10 microseconds to 2.55 milliseconds in width can be measured.

Since PULSIN uses a byte variable for storage, the Resolution parameter can be used to allow the measurement of wider pulse widths. For the best accuracy, set Resolution to the smallest value that will allow the measurement of the greatest expected pulse width.

Get_Button:
  PULSIN RA.1, 0, btnIn, 100                    ' wait for (low) button press
  IF btnIn < 50 THEN Get_Button                 ' at least 50 ms?
  RETURN

The subroutine above will monitor the state of RA.1, waiting for it to go low and stay low for at least 50 milliseconds. This is a useful method of debouncing a button input.

Related instruction: PULSOUT


PULSIN Example

PULSIN Example Syntax

NOT COMPLETE


PULSOUT

PULSOUT Pin, Duration {, Resolution}

Function
Generate a pulse on Pin with a width of Duration * Resolution.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7). This pin will be set to output mode.
  • Duration is a variable or constant (1 - 255) that specifies the pulse width in Resolution units.
  • Resolution is an optional constant (1 - 255) that specifies the units for Duration, in increments of 10 microseconds (default value is 1 when not specified).

Quick Facts
Units in Resolution | 10 µs (0.01 ms)
Minimum pulse width | 10 µs
Maximum pulse width | 650.25 ms

Explanation
PULSOUT sets Pin to output mode, inverts the state of that pin; waits for the specified Duration x Resolution x 10 microseconds; then inverts the state of the pin again returning the bit to its original state.

The pulse width is the product of Duration and Resolution. In the following example, a pulse of 50 microseconds will be generated on RA.0

  PULSOUT RA.0, 5                               ' 50 µs pulse

The Resolution parameter gives the programmer a great deal of flexibility with PULSOUT. In the follow example, a stream of pulses will be created, each with a different pulse width:

Main:
  FOR idx = 1 TO 10
    PULSOUT RA.0, idx, 10                       ' pulses from 100 to 1000 µs
    PAUSE 1                                     ' delay 1 millisecond
  NEXT
  GOTO Main

By combining Duration and Resolution, pulses from 10 microseconds to 650.25 milliseconds can be generated.

Related instruction: PULSIN


PUT

PUT Location, Value {, Value, ... }

Function
Copy Value(s) into RAM, beginning at Location.

  • Location is the starting address in RAM for the PUT.
  • Value is a constant or variable.

Explanation
The PUT instruction provides a convenient method of moving multiple values into consecutive locations in RAM. For example,

  clock(0) = hrs                                ' copy hrs to clock(0)
  clock(1) = mins                               ' copy mins to clock(1)
  clock(2) = secs                               ' copy mins to clock(2)

Can be simplified to a single line of code:

  PUT clock(0), hrs, mins, secs

Note that array elements are internally represented by RAM addresses. To use PUT with consecutive bytes that are not part of an array, you must explicitly declare the address of the first variable using the @ symbol:

  PUT @hrs, 12, 34, 56                          ' hrs = 12, mins = 34, secs = 56

Using PUT With Address Parameters
When a variable is passed to a subroutine (declared with SUB) by address (using @), as in:

  Some_Routine @aValue                          ' pass address of 'aValue'

... PUT can be used to place a value into the address that was passed to the subroutine:

Some_Routine:
  rtnAddr = __PARAM1                            ' save return address
  GET rtnAddr, theValue                         ' get value from address
  ...                                           ' do something with the value
  PUT rtnAddr, newValue                         ' update value at passed address
  RETURN

This technique is useful for allowing a subroutine to modify a variable. Note that for single-parameter instances, the __RAM() system array may be used in place of GET and PUT:

Some_Routine:
  rtnAddr = __PARAM1                            ' save return address
  theValue = __RAM(rtnAddr)                     ' get value from address
  ...                                           ' do something with the value
  __RAM(rtnAddr) = newValue                     ' update value at passed address
  RETURN

Related instruction: GET


PWM

PWM Example

PWM Pin, Duty, Duration

Function
Convert a digital value to analog output via pulse-width modulation.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • Duty is a variable or constant (0 - 255) that specifies the analog output level (0 to 5V).
  • Duration is a variable or constant (0 - 255) that specifies the duration of the PWM output in milliseconds.

Quick Facts
Units in Duration | 1 ms
Average voltage equation | Average Voltage = (Duty ÷ 255) x 5 volts
Duration | 5 x R x C (suggested)
Notes | Pin is output while PWM active, then switched to input mode

Explanation
Pulse-width modulation (PWM) allows the SX (a purely digital device) to generate an analog voltage. The basic idea is this: If you make a pin output high, the voltage at that pin will be close to 5V. Output low is close to 0V. What if you switched the pin rapidly between high and low so that it was high half the time and low half the time? The average voltage over time would be halfway between 0 and 5V (2.5V). PWM emits a burst of 1s and 0s with a ratio that is proportional to the duty value you specify.

The proportion of 1s to 0s in PWM is called the duty cycle. The duty cycle controls the analog voltage in a very direct way; the higher the duty cycle the higher the voltage. In the case of the SX, the duty cycle can range from 0 to 255. Duty is literally the proportion of 1s to 0s output by the PWM instruction. To determine the proportional PWM output voltage, use this formula: (Duty ÷ 255) x 5V. For example, if Duty is 100, (100 ÷ 255) x 5V = 1.96V; PWM outputs a train of pulses to create (through an RC network) an average voltage of 1.96V.

In order to convert PWM into an analog voltage we have to filter out the pulses and store the average voltage. The resistor/capacitor combination shown below will do the job. The capacitor will hold the voltage set by PWM even after the instruction has finished. How long it will hold the voltage depends on how much current is drawn from it by external circuitry, and the internal leakage of the capacitor. In order to hold the voltage relatively steady, a program must periodically repeat the PWM instruction to give the capacitor a fresh charge.

Just as it takes time to discharge a capacitor, it also takes time to charge it in the first place. The PWM command lets you specify the charging time in terms of PWM duration. The timing for the units in Duration is one millisecond.

How do you determine how long to charge a capacitor? Use this rule-of-thumb formula: Charge Time = 5 x R x C. For instance, the circuit below uses a 10 kΩ (10 x 103 ohm) resistor and a 1 µF (1 x 10-6 uF) capacitor:

Charge time = 5 x 10 x 103 x 1 x 10-6 = 50 x 10-3 seconds, or 50 milliseconds.

  PWM RB.0, 128, 50                             ' charge to 2.5 volts, 50 ms

After outputting the PWM pulses, the SX leaves the pin in input mode (1 in the corresponding bit of the pin's TRIS register). In input mode, the pin's output driver is effectively disconnected. If it were not, the steady output state of the pin would change the voltage on the capacitor and undo the voltage setting established by PWM. Keep in mind that leakage currents of up to 1 µA can flow into or out of this "disconnected" pin. Over time, these small currents will cause the voltage on the capacitor to drift. The same applies for leakage current from an op-amp's input, as well as the capacitor's own internal leakage. Executing PWM occasionally will reset the capacitor voltage to the intended value.

PWM charges the capacitor; the load presented by your circuit discharges it. How long the charge lasts (and therefore how often your program should repeat the PWM instruction to refresh the charge) depends on how much current the circuit draws, and how stable the voltage must be. You may need to buffer PWM RC circuit output with a simple op-amp follower if your load or stability requirements are more than the passive circuit can handle.


PWM Example

PWM Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Uses PWM through an RC network to create an analog voltage.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

DAC             VAR     RB.0                    ' output to RC network

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

duty            VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  FOR duty = 0 TO 250 STEP 10                   ' 0 to ~4.9 volts
    PWM DAC, duty, 15                           ' charge RC to duty level
  NEXT
  GOTO Start


RANDOM

RANDOM ByteVar1 {, ByteVar2}

Function
Generate a pseudo-random number.

  • ByteVar1 is a variable whose bits will be scrambled to produce a random number. ByteVar1 acts as RANDOM's input and its result output. Each pass through RANDOM stores the next number, in the pseudo-random sequence, in ByteVar1.
  • ByteVar2 is an optional variable that, if provided, will receive a copy of ByteVar1 after RANDOM. This variable may be modified without affecting the seed value (ByteVar1) of the RANDOM function

Explanation
RANDOM generates pseudo-random numbers ranging from 0 to 255. They're called "pseudo-random" because they appear random, but are generated by a logic operation that uses the initial value in ByteVar1 to "tap" into a sequence of 255 essentially random numbers. If the same initial value, called the "seed", is always used, then the same sequence of numbers is generated. The following example demonstrates this:

Start:
  TRIS_B = %00000000                            ' make RB outputs (LEDs)

Main:
  result = 123                                  ' set initial "seed" value
  RANDOM result                                 ' generate random number
  RB = result                                   ' show the result on RB
  PAUSE 100
  GOTO Main

In this example, the same number would appear on RB over and over again. This is because the same seed value was used each time; specifically, the first line of the loop sets result to 123. The RANDOM command really needs a different seed value each time. Moving the "result =" line out of the loop will solve this problem, as in:

Start:
  TRIS_B = %00000000                            ' make RB outputs (LEDs)
  result = 123                                  ' set initial "seed" value

Main:
  RANDOM result                                 ' generate random number
  RB = result                                   ' show the result on RB
  PAUSE 100
  GOTO Main

Here, result is only initialized once, before the loop. Each time through the loop, the previous value of result, generated by RANDOM, is used as the next seed value. This generates a more desirable set of pseudo-random numbers.

In applications requiring more apparent randomness, it's necessary to "seed" RANDOM with a more random value every time. For instance, in the digital dice example program, RANDOM is executed continuously (using the previous resulting number as the next seed value) while the program waits for the user to press a button. Since the user can't control the timing of button presses very accurately, the results approach true randomness.


RANDOM Example

RANDOM Example Syntax

NOT COMPLETE


RCTIME

RCTIME Example

RCTIME Pin, State, ByteVar {, Resolution}

Function
Measure time while Pin remains in State; usually to measure the charge/discharge time of resistor/capacitor (RC) circuit.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • State is a constant (0 - 1) that specifies the desired state to measure. Once Pin is not in State, the command ends and stores the result in ByteVar.
  • ByteVar is a byte variable in which the time measurement will be stored. The unit of time for ByteVar is 2 microseconds multiplied by Resolution (if specified).
  • Resolution is an optional variable or constant (1 - 255) that specifies the units for ByteVar, in increments of 2 microseconds (default is 1 when not specified).

Explanation
RCTIME can be used to measure the charge or discharge time of a resistor/capacitor circuit. This allows you to measure 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, RCTIME can also serve as a fast, precise stopwatch for events of very short duration.

When RCTIME executes, it starts a counter. It stops this counter as soon as the specified pin is no longer in State (0 or 1). If pin is not in State when the instruction executes, RCTIME will return 0 in ByteVar. If pin remains in State longer than 255 timing cycles RCTIME returns 0.

The figure below shows suitable RC circuits for use with RCTIME. Circuit A is preferred, because the SX TTL logic threshold is approximately 1.4 volts. This means that the voltage seen by the pin will start at 5V then fall to 1.4V (a span of 3.6V) before RCTIME stops. With Circuit B, the voltage will start at 0V and rise to 1.4V (spanning only 1.4V) before RCTIME stops (this could be changed by setting the Pin threshold to CMOS). For the same combination of R and C, Circuit A will yield a higher count, and therefore more resolution than Circuit B.

(A) Use with State = 1 | (B) Use with State = 0

Here's a typical sequence of instructions for Circuit A, using a 0.1 µF capacitor and a 10 kΩ pot.

Start:
  TRIS_B = %00000000                            ' make LED pins outputs

Main:
  HIGH RA.0                                     ' charge the capacitor
  PAUSEUS 250                                   '   for 250 us
  RCTIME RA.0, 1, analog, 5                     ' measure in 10 us (2 x 5) units
  RB = analog
  PAUSE 100
  GOTO Main

Using RCTIME is very straightforward, except for one detail: For a given R and C, what value will RCTIME return? It's easy to figure, based on a value called the RC time constant, or tau (τ) for short. Tau represents the time required for a given RC combination to charge or discharge by 63 percent of the total change in voltage that they will undergo. More importantly, the value t is used in the generalized RC timing calculation. Tau's formula is just R multiplied by C:

τ = R x C

The general RC timing formula uses τ to tell us the time required for an RC circuit to change from one voltage to another:

time = -τ x ( ln(Vfinal / Vinitial) )

In this formula ln is the natural logarithm; it's a key on most scientific calculators. Let's do some math. Assume we're interested in a 10 kΩ resistor and 0.1 µF capacitor. Calculate τ:

τ = (10 x 103) x (0.1 x 10-6) = 1 x 10-3

The RC time constant is 1 x 10-3 or 1 millisecond. Now calculate the time required for this RC circuit to go from 5V to 1.4V (as in Circuit A):

Time = -1 x 10-3 x ( ln(5.0v ÷ 1.4v) ) = 1.273 x 10-3

Using SX/B the unit of time is 2 µs, that time (1.273 x 10-3) works out to about 635 units -- which exceeds the default resolution of RCTIME. What we can do is divide by 635 by 255 (byte value limit) to determine the smallest Resolution required to support the RC combination. In this case it works out to 2.49, so setting Resolution to 3 will allow us to measure the RC network with the greatest accuracy; in this case our measurement units will now be six microseconds (2 x 3). Note that setting Resolution too low will result in RCTIME returning zero.

Another handy rule of thumb can help you calculate how long to charge/discharge the capacitor before RCTIME. In the example above that's the purpose of the HIGH and PAUSE commands. A given RC charges or discharges 98 percent of the way in five time constants (5 x R x C). In Circuits A and B, the charge/discharge current passes through the 220 Ω series resistor and the capacitor. So if the capacitor were 0.1 µF, the minimum charge/discharge time should be:

Charge time = 5 x 220 x (0.1 x 10-6) = 110 x 10-6

So it takes only 110 µs for the capacitor to charge/discharge, meaning that the 250 microsecond charge/discharge time of the example is plenty.

A final note about the circuits above: You may be wondering why the 220 Ω resistor is necessary at all. Consider what would happen if resistor R was a potentiometer, and were adjusted to 0 Ω. When the I/O pin went high to discharge the capacitor, it would see a short direct to ground. The 220 Ω series resistor would limit the short circuit current to 5V ÷ 220 Ω = 23 mA and protect the SX IO pin from damage. (Actual current would be quite a bit less due to internal resistance of the pin's output driver, but you get the idea).


RCTIME Example

RCTIME Example RCTIME

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Reads a POT using RCTIME and converts to a decimal digit, 0 - 9.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

PotPin          VAR     RA.0                    ' IO pin for RCTIME
Display         VAR     RB                      ' 7-segment LED
TRIS_Disp       VAR     TRIS_B

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

analog          VAR     Byte                    ' pot value
theDigit        VAR     Byte

Watch_List:
  WATCH analog, 8, UDEC

' =========================================================================
  PROGRAM Start
' =========================================================================

SegMap:                                         ' segments maps
'       .gfedcba
  DATA  %00111111                               ' 0
  DATA  %00000110                               ' 1
  DATA  %01011011                               ' 2
  DATA  %01001111                               ' 3
  DATA  %01100110                               ' 4
  DATA  %01101101                               ' 5
  DATA  %01111101                               ' 6
  DATA  %00000111                               ' 7
  DATA  %01111111                               ' 8
  DATA  %01100111                               ' 9

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  Display = %00000000                           ' clear display
  TRIS_Disp = %00000000                         ' display port --> outputs

Main:
  HIGH PotPin                                   ' charge capacitor
  PAUSEUS 250                                   '   for 250 usecs
  RCTIME PotPin, 1, analog, 5                   ' read pot (10 us units)
  theDigit = analog / 12                        ' convert to 0 - 9
  READ SegMap + theDigit, Display               ' put digit into display
  PAUSE 100                                     ' wait 0.1 secs
  GOTO Main


READ

READ Example

READ Label {+ Offset}, ByteVar {, ByteVar, ...}

Function
Read one or more bytes from a table.

  • Label is a DATA table indentifier.
  • Offset is an optional variable indicating the starting point in the table for the READ operation.
  • ByteVar is any byte variable.

Explanation
The DATA directive can be used to create [read-only] tables for SX/B programs. The READ instruction is used to move one or more table values into the specified byte variable(s).

Pattern:                                        ' LED patterns
  DATA  %00000000
  DATA  %00011000
  DATA  %00111100
  DATA  %01111110
  DATA  %11111111

Start:
  TRIS_B = %00000000                            ' make RB outputs

Main:
  FOR idx = 0 TO 3
    READ Pattern + idx, RB                      ' move pattern to LEDs
    PAUSE 100
  NEXT idx
  FOR idx = 4 TO 1 STEP -1
    READ Pattern + idx, RB
    PAUSE 100
  NEXT idx
  GOTO Main                                     ' do it again

Related instructions: DATA and LOOKUP


READ Example

READ Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Uses READ to move values from a DATA table to a variable.  In this
' program, the table data holds segment patterns for a 7-segment LED.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LEDs		VAR	RB			' 7-segment display
TRIS_LEDs	VAR	TRIS_B

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

value		VAR	Byte			' value to display

regAddr		VAR	Byte			' register address
temp1		VAR	Byte			' parameter

' =========================================================================
  PROGRAM Start
' =========================================================================

SegMap:                                         ' segments maps
'        .gfedcba
  DATA 	%00111111                        	' 0
  DATA 	%00000110                          	' 1
  DATA 	%01011011                         	' 2
  DATA 	%01001111                           	' 3
  DATA 	%01100110                       	' 4
  DATA 	%01101101                         	' 5
  DATA 	%01111101                       	' 6
  DATA 	%00000111                       	' 7
  DATA 	%01111111                         	' 8
  DATA 	%01100111                       	' 9

  DATA 	%01110111                          	' A
  DATA 	%01111100                          	' b
  DATA 	%00111001                         	' C
  DATA 	%01011110                           	' d
  DATA 	%01111001                           	' E
  DATA 	%01110001                           	' F

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

PUTDIGIT	SUB	2

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_LEDs = %00000000				' make LEDs outputs

Main:
  FOR value = 0 TO 16				' demo values (last invalid)
    PUTDIGIT @LEDs, value 			' update the display
    PAUSE 1000					' pause one second
  NEXT
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: PUTDIGIT @destination, value
' -- converts number in 'value' to 7-segment digit pattern
'    and places it in 'destination'

PUTDIGIT:
  regAddr = __PARAM1                            ' copy destination
  temp1 = __PARAM2                              ' copy value

  IF temp1 <= $F THEN             		' check range
    READ SegMap + temp1, temp1               	' read table value
  ELSE
    temp1 = %01000000                       	' display dash
  ENDIF
  __RAM(regAddr) = temp1                     	' move pattern to output
  RETURN


RESETWDT

RESETWDT Example

RESETWDT

Function
Resets the SX Watchdog Timer.

Explanation
When the watchdog timer is enabled (through the DEVICE directive), the RESETWDT instruction must be used periodically to clear the timer in order prevent a device reset. If the program becomes stuck and RESETWDT instruction does not get called in time the watchdog timer will reset the SX.

An internal timer controls the watchdog timeout. By setting bit 3 (PSA) of the OPTION register, bits 2..0 (PS2..PS0) can be used to set the watchdog timeout period.

PS2 | PS1 | PS0 | Scale | Period
0 | 0 | 0 | 1:1 | 18 ms
0 | 0 | 1 | 1:2 | 37 ms
0 | 1 | 0 | 1:4 | 73 ms
0 | 1 | 1 | 1:8 | 146 ms
1 | 0 | 0 | 1:16 | 293 ms
1 | 0 | 1 | 1:32 | 585 ms
1 | 1 | 0 | 1:64 | 1.2 s
1 | 1 | 1 | 1:128 | 2.3 s

Related instructions: END and SLEEP


RESETWDT Example

RESETWDT Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Demonstrates the use of the RESETWDT instruction in SX/B.  When the
' RESETWDT instruction is removed (with comment), the LED will flash due
' to the SX being reset after the watchdog timer timeout.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX, WATCHDOG
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  OPTION = %11111110                            ' timeout = ~1.2 seconds
  LOW LED                                       ' LED off
  PAUSE 500                                     ' wait for LED on

Main:
  ' RESETWDT                                    ' prevent timeout
  HIGH LED                                      ' LED on
  GOTO Main


REVERSE

REVERSE Example

REVERSE Pin

Function
Reverse the data direction register (TRIS) bit of the specified Pin.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).

Explanation
REVERSE is convenient way to switch the I/O direction of a pin. If the pin is an input, REVERSE makes it an output; if it’s an output, REVERSE makes it an input.

Remember that "input" really has two meanings: (1) Setting a pin to input makes it possible to check the state (1 or 0) of external circuitry connected to that pin. The current state is in the corresponding bit of the associated port register. (2) Setting a pin to input also disconnects the output driver, possibly affecting circuitry being controlled by the pin.

  HIGH RA.3                                     ' RA.3 is output and high (1)
  PAUSE 100
  REVERSE RA.3                                  ' RA.3 is now an input

Related instructions: INPUT and OUTPUT


REVERSE Example

REVERSE Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Allows an LED to have one of two brighness levels by controlling port
' pin with REVERSE.  When the LED pin is an input (Hi-Z), the current
' passes through both resistors, causing the LED to be dim.  When the
' LED pin is an output low, the current only has to pass through one
' resistor, hence the LED is brighter.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  LED = 0                                       ' put low in output bit

Main:
  PAUSE 250                                     ' wait 1/4 second
  REVERSE LED                                   ' change brightness
  GOTO Main


SERIN

SERIN Example

SERIN Pin, BaudMode, ByteVar {, Timeout, ToLabel}

Function
Short descriptive text....

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • BaudMode is a string constant that specifies serial timing and configuration.
  • ByteVar is a variable in which the serial data byte is stored.
  • Timeout is an optional variable (1 - 255) or constant (1 - 65535) that tells SERIN how long to wait (in milliseconds) for incoming data. If data does not arrive in time, the program will jump to the address specified by ToLabel.
  • ToLabel 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.

Quick Facts
 | FREQ = 1 MHz | FREQ = 4 MHz | FREQ > 5 MHz
Maximum Baud Rate | 9600 | 19200 | > 38400
Baud Modes | T (true), N (inverted), OT (open, true), ON (open, inverted)
Units in Timeout | 1 millisecond

Explanation
Receive asynchronous serial byte at the selected baud rate and mode using no-parity, 8-data bits, and 1-stop bit. If Timeout is specified, jump to ToLabel if serial byte does not arrive within Timeout milliseconds.

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 SERIN and SEROUT commands are used to receive and send asynchronous serial data. See the SHIFTIN and SHIFTOUT command for information on the synchronous method.

The term asynchronous means "no clock." More specifically, "asynchronous serial communication" means data is transmitted and received without the use of a separate "clock" wire. Data can be sent using as little as two wires: one for data and one for ground.

This simple demo shows how to receive a single byte through RA.0 at 2400 baud, 8N1, inverted:

Main:
  SERIN RA.0, N2400, sData                      ' wait for byte
  LEDs = sData                                  ' put byte value on LEDs
  GOTO Main

Here, SERIN will wait for and receive a single byte of data through pin RA.0 and store it in the variable sData. If the SX were connected to a PC running a terminal program (set to the same baud rate) and the user pressed the "A" key on the keyboard, after the SERIN command executed, the variable sData would contain 65, the ASCII code for the letter "A".

When used without a Timeout parameter, SERIN block program operation until a byte arrives. Where this condition will have an adverse affect on program operation a Timeout parameter and label can be specified. In this update to the example above, the program will wait for two seconds (2000 milliseconds) for an incoming byte; if no byte arrives the program will be redirected to No_Char and the LEDs will be blanked.

Main:
  SERIN RA.0, N2400, sData, 2000, No_Char       ' wait for byte
  LEDs = sData                                  ' put byte value on LEDs
  GOTO Main

No_Char:
  LEDs = %00000000                              ' clear LEDs
  GOTO Main

Note: Interrupts will interfere with the proper operation of SERIN and should be disabled before the SERIN instruction is used.

Related instructions: SEROUT


SERIN Example

SERIN Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Waits for a command from a host controller and displays hex value or
' individual segments on a 7-segment LED display.
'
' Commands:
'   "!LEDH", value -- display hex digit value (0 .. F)
'   "!LEDS", value -- display individual segments

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Sio             VAR     RA.0                    ' pull-up via 4.7K

LEDs            VAR     RB                      ' 7-segment display
TRIS_LEDs       VAR     TRIS_B

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Baud            CON     "OT9600"

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

serByte         VAR     Byte                    ' serial IO byte

regAddr         VAR     Byte                    ' return address (subs)
temp1           VAR     Byte                    ' parameter

' =========================================================================
  PROGRAM Start
' =========================================================================

SegMap:                                         ' segments maps
'        .gfedcba
  DATA  %00111111                               ' 0
  DATA  %00000110                               ' 1
  DATA  %01011011                               ' 2
  DATA  %01001111                               ' 3
  DATA  %01100110                               ' 4
  DATA  %01101101                               ' 5
  DATA  %01111101                               ' 6
  DATA  %00000111                               ' 7
  DATA  %01111111                               ' 8
  DATA  %01100111                               ' 9

  DATA  %01110111                               ' A
  DATA  %01111100                               ' b
  DATA  %00111001                               ' C
  DATA  %01011110                               ' d
  DATA  %01111001                               ' E
  DATA  %01110001                               ' F

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

RXBYTE          SUB     1
PUTDIGIT        SUB     2

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  LEDs = %00000000                              ' clear display
  TRIS_Leds = %00000000                         ' make port pins outputs

Main:                                           ' wait for header
  serByte = RXBYTE
  IF serByte <> "!" THEN Main
  serByte = RXBYTE
  IF serByte <> "L" THEN Main
  serByte = RXBYTE
  IF serByte <> "E" THEN Main
  serByte = RXBYTE
  IF serByte <> "D" THEN Main

Check_Hex:
  serByte = RXBYTE                              ' get command
  IF serByte <> "H" THEN Check_Segments         ' hex display?
  serByte = RXBYTE                              ' get value
  LEDs = PUTDIGIT serByte
  GOTO Main

Check_Segments:
  IF serByte = "S" THEN                         ' segments display?
    LEDs = RXBYTE                               ' get segments
  ENDIF
  GOTO Main

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: rxInput = RXBYTE
' -- reads byte from serial input and places it in 'rxInput'

RXBYTE:
  SERIN Sio, Baud, temp1                        ' receive a byte
  RETURN temp1

' Use: destination = PUTDIGIT value
' -- converts number in 'value' to 7-segment digit pattern
'    and places it in 'destination'

PUTDIGIT:
  temp1 = __PARAM1                              ' copy value
  IF temp1 <= $F THEN                           ' check range
    READ SegMap + temp1, temp1                  ' read table value
  ELSE
    temp1 = %01000000                           ' display dash
  ENDIF
  RETURN temp1


SEROUT

SEROUT Example

SEROUT Pin, BaudMode, Value

Function
Transmit asynchronous serial byte (e.g., RS-232).

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • BaudMode is a string constant that specifies serial timing and configuration.
  • Value is a byte variable or constant (0 - 255) to be transmitted.

Quick Facts
 | FREQ = 1 MHz | FREQ = 4 MHz | FREQ > 5 MHz
Maximum Baud Rate | 9600 | 19200 | > 38400
Baud Modes | T (true), N (inverted), OT (open, true), ON (open, inverted)

Explanation
Transmit asynchronous serial byte at the selected baud rate and mode using no-parity, 8-data bits, and 1-stop bit .

  SEROUT RA.0, T9600, "A"

In the example above, the SX will transmit the letter "A" (decimal 65) to an external device at 9600 baud, in true mode on pin RA.0. Since SEROUT requires a substantial amount of assembly code a good way to save program space is by placing SEROUT in a subroutine.

For example:

TX_Char:
  temp1 = __PARAM1                              ' save byte to send
  temp2 = __PARAM2                              ' save number of repeats

  DO WHILE temp2 > 0
    SEROUT Sio, Baud, temp1                     ' send the byte
    DEC temp2                                   ' update count
  LOOP
  RETURN

Ths subroutine takes two parameters: the first is the byte to transmit and the second is the number of times to transmit that byte. By using the second parameter sending "**********" is as easy as (when the subroutine is declared with SUB):

  TX_Char "*", 10                               ' send "**********"

Note: Interrupts will interfere with the proper operation of SEROUT and should be disabled before the SEROUT instruction is used.

Related instructions: SERIN


SEROUT Example

SEROUT Example SEROUT

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Reads a potentiometer with RCTIME and sends the value to a SEETRON
' (www.seetron.com) serial LCD.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

PotPin          VAR     RA.0                    ' IO pin for RCTIME
Sout            VAR     RA.1                    ' output to SEETRON 2x16

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Baud            CON     "N9600"

LcdI            CON     $FE                     ' instruction
LcdCls          CON     $01                     ' clear the LCD
LcdHome         CON     $02                     ' move cursor home
LcdCrsrL        CON     $10                     ' move cursor left
LcdCrsrR        CON     $14                     ' move cursor right
LcdDispL        CON     $18                     ' shift chars left
LcdDispR        CON     $1C                     ' shift chars right
LcdDDRam        CON     $80                     ' Display Data RAM control
LcdCGRam        CON     $40                     ' Character Generator RAM
LcdLine1        CON     $80                     ' DDRAM address of line 1
LcdLine2        CON     $C0                     ' DDRAM address of line 2

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

analog          VAR     Byte                    ' pot value
char            VAR     Byte                    ' character to send
idx             VAR     Byte                    ' loop counter
line1           VAR     Byte(16)                ' line 1 buffer
line2           VAR     Byte(16)                ' line 2 buffer

temp1           VAR     Byte                    ' subroutine work vars
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine DECLARATIONS
' -------------------------------------------------------------------------

TXBYTE          SUB     1, 2                    ' transmit byte
DELAYUS         SUB     1, 2                    ' delay in microsecs
DELAY           SUB     1, 2                    ' delay in millsecs
Update_L1       SUB                             ' update line 1
Update_L2       SUB                             ' update line 2
Update_LCD      SUB                             ' update LCD

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  DELAY 250, 3                                  ' let LCD initialize
  TXBYTE LcdI                                   ' clear screen, home cursor
  TXBYTE LcdCls
  DELAY 1
  PUT line1, "POT:            "                 ' initialize LCD buffer
  PUT line2, "                "

Main:
  HIGH PotPin                                   ' charge capacitor
  DELAYUS 250                                   '   for 250 usecs
  RCTIME PotPin, 1, analog, 5                   ' read pot (10 us units)

Show_Pot:
  temp1 = analog / 100                          ' get 100s value
  temp2 = __REMAINDER                           ' save 10s and 1s
  temp1 = temp1 + "0"                           ' convert 100s to ASCII
  PUT line1(5), temp1                           ' move to LCD buffer
  temp1 = temp2 / 10                            ' get 10s value
  temp2 = __REMAINDER                           ' save 1s
  temp1 = temp1 + "0"                           ' convert 10s to ASCII
  PUT line1(6), temp1                           ' move to LCD buffer
  temp1 = temp2 + "0"                           ' convert 1s to ASCII
  PUT line1(7), temp1                           ' move to LCD buffer
  Update_L1                                     ' update LCD
  DELAY 100                                     ' wait 100 ms
  GOTO Main                                     ' do it over

' -------------------------------------------------------------------------
' Subroutines Code
' -------------------------------------------------------------------------

' Use: TXBYTE theByte {, repeats }
' -- first parameter is byte to transmit
' -- second (optional) parameter is number of times to send

TXBYTE:
  temp1 = __PARAM1                              ' char to send
  IF __PARAMCNT = 1 THEN                        ' if no repeats specified
    temp2 = 1                                   ' - set to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  DO WHILE temp2 > 0
    SEROUT Sout, Baud, temp1                    ' send the character
    DEC temp2
  LOOP
  RETURN

' Use: DELAYUS base {, multiplier }
' -- pause for 'base' * (optional) 'multiplier' microseconds

DELAYUS:
  temp1 = __PARAM1                              ' base delay
  IF __PARAMCNT = 1 THEN                        ' if no multiplier
    temp2 = 1                                   ' - set to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSEUS temp1 * temp2                     ' delay x * y us
    ENDIF
  ENDIF
  RETURN

' Use: DELAY base {, multiplier }
' -- pause for 'base' * (optional) 'multiplier' milliseconds

DELAY:
  temp1 = __PARAM1                              ' base delay
  IF __PARAMCNT = 1 THEN                        ' if no multiplier
    temp2 = 1                                   ' - set to 1
  ELSE
    temp2 = __PARAM2
  ENDIF
  IF temp1 > 0 THEN
    IF temp2 > 0 THEN
      PAUSE temp1 * temp2                       ' delay x * y ms
    ENDIF
  ENDIF
  RETURN

' Transfers line 1 buffer to LCD
' -- makes no change in LCD screen position

Update_L1:
  TXBYTE LcdI                                   ' move cursor to line 1, col 0
  TXBYTE LcdLine1
  DELAY 1
  FOR idx = 0 TO 15
    TXBYTE line1(idx)                           ' transfer buffer
  NEXT
  RETURN

' Transfers line 2 buffer to LCD
' -- makes no change in LCD screen position

Update_L2:
  TXBYTE LcdI                                   ' move cursor to line 2, col 0
  TXBYTE LcdLine2
  DELAY 1
  FOR idx = 0 TO 15
    TXBYTE line2(idx)                           ' transfer buffer
  NEXT
  RETURN

' Updates the LCD with both line buffers

Update_LCD:
  TXBYTE LcdI
  TXBYTE LcdHome
  DELAY 1
  Update_L1
  Update_L2
  RETURN


SHIFTIN

SHIFTIN Example

SHIFTIN DPin, CPin, ShiftMode, ByteVar {\Count}

Function
Shift data out to a synchronous serial device.

  • DPin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7). This pin will be set to input mode.
  • CPin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7). This pin will be set to output mode.
  • ShiftMode is one of four predefined symbols that tells SHIFTIN the order in which data bits are to be arranged and the relationship of clock pulses to valid data. See the table below for value and symbol definitions.
  • ByteVar is a variable which will hold the incoming data.
  • Count is an optional constant (1 - 8) specifying how many bits are to be input by SHIFTIN. If no Count parameter is given SHIFTIN defaults to eight bits.

Explanation
SHIFTIN and SHIFTOUT provide an easy method of connecting to synchronous serial devices. Synchronous serial differs from asynchronous serial (like SERIN and SEROUT) in that the timing of data bits (on a data line) is specified in relationship to clock pulses (on a clock line). 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 pass data bits along in a bucket brigade fashion to a single data output pin. Another bit is output each time the appropriate edge (rising or falling, depending on the device) appears on the clock line.

The SHIFTIN instruction first forces the clock pin (CPin) to output mode and the data pin (DPin) to input mode. Then, SHIFTIN either reads the data pin and generates a clock pulse (PRE mode) or generates a clock pulse then reads the data pin (POST mode). Clock pulses are generated by inverting the state of CPin, allowing the programmer to determine CPin behavior. SHIFTIN continues to generate clock pulses and read the data pin for as many data bits as are required.

Making SHIFTIN 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. Items to look for include: 1) which bit of the data arrives first; most significant bit (MSB) or least significant bit (LSB) and 2) is the first data bit ready before the first clock pulse (PRE) or before the second clock pulse (POST). The table below shows the values and symbols available for the ShiftMode parameter.

Symbol | Value | Meaning
MSBPRE | 0 | Data is MSB-first; sample bits before clock pulse
LSBPRE | 1 | Data is lsb-first; sample bits before clock pulse
MSBPOST | 2 | Data is MSB-first; sample bits after clock pulse
LSBPOST | 3 | Data is LSB-first; sample bits after clock pulse

SHIFTIN Timing

T0 - T1, T1 - T2, ... | ~ 6 µs
Transmission Rate | ~ 83 kBits/Sec

Here is a simple example:

  SHIFTIN RC.0, RC.1, MSBPRE, result

Here, the SHIFTIN instruction will read pin RC.0 (Dpin) and will generate a clock signal on RA.1 (Cpin). The data that arrives on the Dpin depends on the device connected to it. Let's say, for example, that a shift register is connected and has a value of $AF (%10101111) waiting to be sent. Additionally, let's assume that the shift register sends out the most significant bit first, and the first bit is on the Dpin before the first clock pulse (MSBPRE). The SHIFTIN instruction above will generate eight clock pulses and sample the Dpin eight times. Afterward, the result variable will contain the value $AF.

Some devices return more than eight bits. For example, the LTC1298 is a 12-bit ADC. To retrieve data from the LTC1298 would require two SHIFTIN calls to retrieve the 12-bit result.

  LOW CS
  SHIFTOUT Dio, Clk, LSBFIRST, config\4         ' send config bits
  SHIFTIN  Dio, Clk, MSBPOST, resultHi\4        ' get data (upper nibble)
  SHIFTIN  Dio, Clk, MSBPOST, resultLo\8        ' get data (lower byte)
  HIGH CS

Related instructions: SHIFTOUT


SHIFTIN Example

SHIFTIN Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Reads value from an ADC0831 and places that value on LEDs connected to
' port RB.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Dpin            VAR     RA.0                    ' shift data
Cpin            VAR     RA.1                    ' shift clock
CS              VAR     RA.2                    ' chip select

LEDs            VAR     RB
TRIS_LEDs       VAR     TRIS_B

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

temp1           VAR     Byte                    ' parameter

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

GETADC          SUB     1                       ' pass register address

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  TRIS_LEDs = %00000000                         ' make LED ports outputs
  HIGH CS                                       ' make CS output, no ADC
  LOW Cpin                                      ' make clock 0-1-0

Main:
  DO
    LEDs = GETADC                               ' move ADC value to LEDs
    PAUSE 100                                   ' wait 0.1 second
  LOOP

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

' Use: aVar = GETADC
' -- reads ADC0831 and places value into 'aVar'

GETADC:
  CS = 0                                        ' activate ADC0831
  SHIFTIN Dpin, Cpin, MSBPOST, temp1\1          ' start conversion
  SHIFTIN Dpin, Cpin, MSBPOST, temp1            ' shift in the data
  CS = 1                                        ' deactivate ADC0831
  RETURN temp1


SHIFTOUT

SHIFTOUT Example

SHIFTOUT DPin, CPin, ShiftMode, Value {\Count}

Function
Shift data out to a synchronous serial device.

  • DPin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7). This pin will be set to output mode.
  • CPin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7). This pin will be set to output mode.
  • ShiftMode is one of two predefined symbols that tells SHIFTOUT the order in which data bits are to be arranged. See the table below for value and symbol definitions.
  • Value is a variable or constant containing the data to be sent.
  • Count is an optional constant (1 - 8) specifying how many bits are to be output by SHIFTOUT. If no Count parameter is given SHIFTOUT defaults to eight bits. When the Count parameter is given, the SX transmits the rightmost number of bits specified, regardless of the ShiftMode.

Explanation
SHIFTIN and SHIFTOUT provide an easy method of connecting to synchronous serial devices. Synchronous serial differs from asynchronous serial (like SERIN and SEROUT) in that the timing of data bits (on a data line) is specified in relationship to clock pulses (on a clock line). 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 pass data bits along in a bucket brigade fashion to a single data output pin. Another bit is output each time the appropriate edge (rising or falling, depending on the device) appears on the clock line.

The SHIFTOUT instruction first sets the clock and data pins to switch to output mode. Then, SHIFTOUT sets the data pin to the next bit state to be output and generates a clock pulse by inverting the state of the clock pin. SHIFTOUT 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 SHIFTOUT 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). The table below shows the values and symbols available for the ShiftMode parameter.

Symbol | Value | Meaning
LSBFIRST | 0 | Data is shifted out LSB-first
MSBFIRST | 1 | Data is shifted out MSB-first

SHIFTOUT Timing

T0 - T1 | ~ 6 µs (allow pins to stabilize)
T1 - T2 | ~ 6 µs (allows reciever to capture bit)
X1 - X2, X2 - X3, ... | ~ 12 µs (bit-to-bit timing)
Transmission Rate | ~ 83 kBits/Sec

Here is a simple example:

  SHIFTOUT RC.0, RC.1, MSBFIRST, 250

Here, the SHIFTOUT instruction will write to RC.0 (the Dpin) and will generate a clock signal on RC.1 (the Cpin). The SHIFTOUT instruction will generate eight clock pulses while writing each bit (of the 8-bit value 250) onto the Dpin. In this case, it will start with the most significant bit first as indicated by the ShiftMode value of MSBFIRST.

By default, SHIFTOUT transmits eight bits, but you can set it to shift any number of bits from 1 to 8 with the Count parameter. For example:

  SHIFTOUT 0, 1, MSBFIRST, 250\4

Will output only the lowest (rightmost) four bits (%1010 in this case).

Related instruction: SHIFTIN


SHIFTOUT Example

SHIFTOUT Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Transfers a counter value to eight LEDs using a 74HC595 shift register.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Dpin            VAR     RA.0                    ' shift data
Cpin            VAR     RA.1                    ' shift clock
Latch           VAR     RA.2                    ' latch outputs

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

counter         VAR     Byte                    ' counter to display
temp1           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

PUT595          SUB     1                       ' pass value to write

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  FOR counter = 0 TO 255                        ' loop through all values
    PUT595 counter                              ' transfer counter to 595
    PAUSE 250                                   ' wait 1/4 seconds
  NEXT
  GOTO Start

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Use: PUT595 value
' -- moves 'value' to 74HC595

PUT595:
  temp1 = __PARAM1                              ' capture value
  SHIFTOUT Dpin, Cpin, MSBFIRST, temp1          ' send the bits
  PULSOUT Latch, 1                              ' transfer to outputs
  RETURN


SLEEP

SLEEP

Function
Ends program execution and puts the SX into power down (sleep) mode.

Explanation
SLEEP puts the SX into power down mode halting the execution any further instructions until it is reset, either externally (via MCLR\ pin), by a watchdog timer timeout, or (if configured) a valid transition on any of the Multi-Input Wakeup (MIWU) pins (RB pins).

Related instruction: END and RESETWDT


SLEEP Example

SLEEP Example Syntax

NOT COMPLETE


SOUND

SOUND Example

SOUND Pin, Note, Duration

Function
Generate square-wave tone for a specified duration.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).
  • Note is a variable/constant (0 - 127) specifying the frequency of the tone (see calculation below).
  • Duration is a variable/constant (1 - 255) specifying the amount of time to generate the tone. The unit of time for Duration is ~10 milliseconds.

Explanation
SOUND generates one of 255 square-wave frequencies on an IO pin. The output pin should be connected as shown in the circuits below for audio use.

The tones produced by SOUND can vary in frequency from 94.3 Hz (1) to 11,062 Hz (127). If you need to determine the frequency corresponding to a given Note value, or need to find the note value that will give you best approximation for a given frequency, use the equations below. Note values above 127 are handled as Note - 128, in other words, a Note value of 138 produces the same tone as 10.

Note | INT(127 - (((1 ÷ Frequency) - 0.0000812) ÷ 0.0000805))
Frequency (Hz) | 1 ÷ (0.0000812 + ((127 - Note) x 0.0000805))

When driving a Hi-Z speaker (> 40 Ω) or piezo element:

When connecting to an audio amplifier:

Related instruction: FREQOUT


SOUND Example

SOUND Example Syntax

40 Ω speaker or
peizo element

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' This program generates a constant tone 25 followed by an ascending tones.
' Both the tones are played for about 100 milliseconds.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

Spkr            VAR     RA.0                    ' piezo or 40-ohm speaker

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

tone            VAR     Byte                    ' tone to play

temp1           VAR     Byte                    ' for subroutine
temp2           VAR     Byte

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

PLAY            SUB     2                       ' pass note and timing

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  FOR tone = 1 TO 127
    PLAY 25, 10                                 ' play tone 25
    PLAY tone, 10                               ' play ascending tone
  NEXT
  END

' -------------------------------------------------------------------------
' Subroutines Code
' -------------------------------------------------------------------------

' Use: PLAY note, duration
' -- play 'note' for 'duration' units

PLAY:
  temp1 = __PARAM1                              ' save note
  temp2 = __PARAM2                              ' save duration
  SOUND Spkr, temp1, temp2
  RETURN


INC

SWAP

SWAP ByteVar

Function
Exchanges the upper and lower nibbles of ByteVar.

  • ByteVar is any byte variable (including an array element).

Explanation
The SWAP instruction exchanges the upper and lower nibbles of ByteVar.

Main:
  RB = $3F
  SWAP RB                                       ' RB now holds $F3


SWAP Example

SWAP Example Syntax

NOT COMPLETE


TOGGLE

TOGGLE Example

TOGGLE Pin

Function
Invert the state of the specified output Pin.

  • Pin is any SX IO pin (RA.0 .. RA.7, RB.0 .. RB.7, RC.0 .. RC.7, RD.0 .. RD.7, RE.0 .. RE.7).

Explanation
TOGGLE sets a pin to output mode and inverts the output state of the pin, changing 0 to 1 and 1 to 0.

In some situations TOGGLE may appear to have no effect on a pin's state. For example, suppose RA.3 is in input mode and pulled to +5V by a 10 kΩ resistor. Then the following code executes:

Main:
  INPUT RA.3                                    ' make RA.3 an input
  RA.3 = 0                                      ' set output driver to 0
  TOGGLE RA.3                                   ' toggle pin state
The state of RA.3 doesn't change; it's high (due to the pull-up resistor) before TOGGLE, and it’s high (due to the pin being output high) afterward. The point is that TOGGLE works on associated port register bit, which may not match the pin's state when the pin is initially an input. To guarantee that the state actually changes, regardless of the initial input or output mode, do this:

Main:
  INPUT RA.3                                    ' make RA.3 an input
  RA.3 = RA.3                                   ' get state at pin
  TOGGLE RA.3                                   ' toggle pin state

Related instructions: HIGH, LOW, and OUTPUT


TOGGLE Example

TOGGLE Example Syntax

' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Simple LED blinker using TOGGLE.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

LED             VAR     RB.0                    ' LED pin

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

BlinkDelay      CON     500                     ' blink rate

' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  LOW LED                                       ' start with LED off

Main:
  PAUSE BlinkDelay                              ' delay
  TOGGLE LED                                    ' toggle LED state
  GOTO Main                                     ' loop forever