Understanding Variables and Symbols in PICAXE BASIC

The General Purpose Variables

Every processor in the PICAXE family of microcontrollers has a certain number of general purpose variables(or registers) to store data temporarily while the program is running. The basic unit of storage is the byte. (Quick computer science refresher: 8 bits = 1 byte and 2 bytes = 1 word.) The first generation, and the A, M, and X series chips have 14 general purpose byte registers, the X1 series chips have 28 registers, and the X2 have a luxurious 56 registers. The byte variables are named b0, b1, b2 etc. These variables can be assigned values and used directly in equations and statements. In the following code snippet it should be fairly intuitive that b2 is 6 and b3 is 8:

  b0 = 2
  b1 = 4

  b2 = b0 + b1
  b3 = b0 * b1

In this next example, after setting the variable b0 to 250, that variable is used in the PAUSE statement to cause the program to delay 250 milliseconds:

  b0 = 250
  pause b0

A byte variable can store an integer number from 0 to 255. It cannot store a negative number or a fraction.

In addition to byte variables, PICAXE offers bit variables and word variables. Bit variables are named bit0, bit1, etc. They store and refer to a single binary digit of 1 or 0. There are 16 bit variables available on first generation, and the A, M, and X series chips, and 32 bit variables on the X1 and X2 chips. Bit variables are frequently used to store and retrieve states for inputs and outputs, but they can be effectively used anytime that information can be represented in a binary mode of 1/0 or true/false.

Word variables are named w0, w1 etc. They store 2 bytes of data allowing for integer numbers between 0 and 65535.

The bit, byte, and word variables all exist in the same memory space and overlap one another - bit0 to bit7 are within b0, while b0 and b1 make up w0. This relationship will be more clear in the chart below which maps the variables of the PICAXE 08M.

Notice in this chart that the registers are sketched from right to left. PICAXE stores data in what is known as a "little endian" fashion which means that the lowest numbered registers hold the least significant digits. The least significant digits of a number are to the right while the most significant digits are to the left: in the number 16, "1" is the most significant digit while "6" is the least significant.

There is nothing to prevent these overlapping variables from overwriting one another so care must be taken programmatically to ensure that the assignment of variables works as intended. Consider this code snippet:

  b0 = 56
  bit2 = 1

The value of b0 is initially set equal to decimal 56 which is binary 00111000. As bit2 is the third bit of b0, when bit2 is set equal to 1 the value of b0 becomes binary 00111100 which equals decimal 60.

Likewise, in the following code snippet when w2 is set to a value after first setting b5 to a value, the value of b5 will be set to the top byte of w2 and the original value effectively lost:

  b5 = 16
  w2 = 429

Of course when properly understood the overlapping nature of the variables can be used to good advantage. For example, the serial memory chips that are frequently used in projects require that data be sent one byte at a time. To use these memory devices to store and retrieve word variables, it is necessary to break word variables into their constituent bytes to store them, and then correctly reconstruct the bytes into words when retrieving the data. In the following example, two bytes of data are read from an external eeprom as b6 and b7, and then transmitted to the serial terminal as w3:

  readi2c (b6,b7)
  sertxd (#w3)

Using Symbols to Help Manage Variables

The SYMBOL command in PICAXE can be used to assign alias names to variables. Once the symbol is assigned, it can be used throughout the program as you would use the variable. The following example assigns the symbol "temperature" to the variable b0 and then uses that symbol in the place of b0 when storing an analog reading from ADC 1:

  symbol temperature = b0
  readadc 1, temperature

Symbols can be any combination of letters, numbers and the underscore character. They cannot begin with a number and they cannot be a PICAXE statement, command or other reserved keyword such as "pause," "sound," or "timer." Symbols have no effect on program length so they can and should be used liberally. Within reason, it is good practice to make symbols as descriptive as possible of the data they represent.

Symbols are typically assigned near the top of the program prior to the execution of any code.

In addition to making code more readable, symbols are a powerful tool in managing variables. By assigning all variables to symbols at the beginning of a program, it becomes easy to see which variables are in use. If it is necessary or desirable to change a variable, it is much easier and less error prone to simply change the symbol assignment than it would be to change all instances of the variable throughout a program.

The Programming Editor will allow multiple symbols to be assigned variables. Although misunderstanding this capability can lead to errors, when properly understood, the use of multiple aliases can be a powerful tool. In an earlier example, a word variable was broken into its constituent bytes for use in an external memory chip. In the following example, symbols will be used to make a similar code snippet more readable - and more manageable:

  symbol range = w0
    symbol range_low_byte = b0
    symbol range_high_byte = b1


  readi2c (range_low_byte, range_high_byte)
  sertxd (#range)

In microcontroller environment like PICAXE in which resources such as variables are at a premium. There are times when a variable will store a value to be used briefly in the execution of loop or subroutine and once the operation is complete that value is no longer needed. The variable is then free to be reused in another routine. Many higher level computer programming languages will allow a variable to be designated as local or global - this designation is known as the variable's scope. Global variables store values that persist throughout the entire program, while the scope of the local variable is restricted to the subroutine or module in which it was created. Through careful management of variables and their aliases a similar effect can be achieved in PICAXE BASIC which can be a powerful helper in maximizing variable space. It is a good idea to group variables which are available for reuse together. For example on a 20X2 with 56 byte variables, b0-b40 might be used for global variables and b41-b55 for local variables. Also helpful is to adopt a naming convention which makes it clear which aliases are local variables - for example to include _loc at the end of all local symbols.

Virtual Variables

As a general rule, if a value is contained in storage RAM or EEPROM memory, that value must be moved into a variable before it can be used in calculations. However, the X1 and X2 parts do have additional RAM memory that can be accessed via virtual variables and used in equations.

Scratchpad RAM is available on X1 and X2 parts. PICAXE-28X1, 40X1 and 20X2 have 128 scratchpad bytes (0-127) and PICAXE-28X2 and 40X2 have 1024 scratchpad bytes (0-1023). This memory is directly accessed by the GET and PUT commands. In direct addressing the commands reference a byte location and either a variable or constant value to store or retrieve. Executing put 27,b1 places the value of b1 in location 27 (the 28th byte) of the scratchpad while executing get 27,b1 places the value in location 27 into the b1 variable. When using direct addressing, a value in the scratchpad must first be moved into a variable using the GET command before it can be used in a command or equation. However, the PICAXE compiler allows a form of indirect addressing using what is called a virtual variable @ptr that can be used directly in commands and equations. To use the virtual variable the pointer - ptr - is set to a register address and then @ptr contains the value stored at that address. In the following example, the pointer is set to 0, the value 15 is stored at that location, and then the virtual variable (i.e. the number 15) is output to the terminal.

  ptr = 0
  @ptr = 15
  sertxd (@ptr)

The real value of the virtual variable can be more readily seen when a sequence of bytes is to be retrieved from the scratchpad. In addition to the @ptr variable, PICAXE BASIC includes @ptrinc (post increment) and @ptrdec (post decrement) variables which will cause the pointer to be automatically incremented or decremented by one after the read/write of the value @ptr. In other words using @ptrinc is the equivalent of reading the value and then executing ptr = ptr + 1. In the following example ten consecutive readings are taken from a sensor on ADC 1 and then those readings are transmitted to the terminal:

   ptr = 0                ; set the pointer to 0
   for b0 = 1 to 10      
    readadc 1, @ptrinc    ; store the value and increment the pointer

   ptr = 0                ; reset the pointer to 0
   for b0 = 1 to 10
    sertxd (#@ptrinc)     ; transmit the value and increment the pointer

On the X2 parts only, there is an additional variable bptr that is used for accessing general purpose RAM. On these chips there are up to 256 general purpose variables (128 on the 20X2) which include the 56 known as b0 to b55. The entire general variable space, including b0 to b55, can be written to and read from using the PEEK and POKE commands which work in an identical fashion to the GET and PUT commands used for accessing the scratchpad - peek 60, b1 places the value stored at location 60 into the variable b1, while poke 60, b1 writes the value stored in b1 to the RAM location 60. The @bptr variable, as well as the @bptrinc and @bptrdec function identically to the @ptr described for the scratchpad - the bptr byte pointer is set to a RAM location and the value of @bptr is the value stored in the location indicated. Do note that when using @bptr the byte pointer values 0-55 will also refer to the variables b0-b55 so once again care must be taken programmatically to ensure that the assignment of variables works as intended.

Other Articles You Might Find Enjoyable

PICAXE USB to Serial Conversion

Introduction to the PICAXE Microcontroller

Adding Memory with i2c EEPROMs

Guide to PICAXE Selection

Robot Obstacle Detection and Avoidance with the Devantech SRF05 Ultrasonic Range Finder

Setting Up A Differential Drive For Your PICAXE Project

Basic PICAXE Servo Interfacing

Things to Do Here

All PICAXE Articles