Software/Library for Arduino

From ZaberWiki
Jump to navigation Jump to search

This page is dedicated to Zaber's official libraries for the Arduino IDE, and details how to get up and running with your own Arduino code in a matter of minutes.

Please note: This documentation is for older versions of the libraries (before version 1.2.0) and is no longer being updated. The up-to-date documentation can be found in the following locations:

Downloading Zaber's Libraries for Arduino

  1. Download and install the Arduino IDE.
  2. Open the Arduino IDE, and navigate to Sketch -> Include Library -> Manage Libraries...
  3. Within the window that opens, search within the Filter your search... box for "Zaber".
  4. Click on each library that shows up, then click the Install button.

Arduino Library Manager

Getting Started

Plug in the Arduino board to your computer using the provided USB cable and mount the recommended RS232 shield on top of the Arduino. To connect the Zaber device to the RS232 shield, you will first need to convert the female DSUB9 into a Male DSUB9 using a null M/M adapter. If you are using a T- or A- series Zaber device, you will also need the T-DSUB9 adapter. If you are using an X-series device, you will need the X-SDC cable. When uploading to the Arduino, ensure the RS232 converter is OFF (switch located on the top).

When you are ready to begin programming, download the Arduino Integrated Development Environment (IDE). The following example will home a device in the ASCII protocol with 115200 baud rate. Copy and paste into the Arduino IDE, save and upload (the right-pointing arrow at the top of the screen).

/* Getting started with Arduino and Zaber devices - ASCII */

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);

    /* Issue a home command to device 1 */
    za.send(1, "home");

    /* Always read the reply to a command even if not checking for errors. */
    /* This helps avoid serial port receive buffer overruns and message corruption. */
    za.receive();

    /* Wait for the move command to finish moving. */
    za.pollUntilIdle();

    /* Additional commands can now be issued */
}

void loop() {

}

The following is an example for a device in Binary with baud rate 9600. Copy, and paste the following code into the Arduino IDE, save and upload (the right-pointing arrow at the top of the screen).

/* Getting started with Arduino and Zaber devices - Binary */

#include <ZaberBinary.h>

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);

    /* Issue a home command to device 1 */
    zb.send(1, 1, 0);
    zb.pollUntilIdle();

    /* Additional commands can now be issued */
}

void loop() {

}

Click the upload button (the right-pointing arrow at the top of the screen), and watch your device move to the home position.

In-Depth Beginner's Guide

Connecting Your Zaber Device to an Arduino Board

Arduino boards are like tiny computers, but they can only run one program at once. This makes them cheap and useful tools for prototyping, testing, or in this case, interacting with motors.

Zaber devices communicate to Arduino boards via serial communications. This means that a RS232 serial communications port and cable is necessary to connect the Arduino to a Zaber device. Zaber recommends the RS232 shield, made by DFRobot. If you're interested in using multiple serial ports, see the Advanced Guide section below.

In total, to complete this beginner's guide you will need:

  • A Zaber device
  • An Arduino board
  • A USB cable to plug the Arduino into your PC (this should come with an Arduino)
  • An RS232 shield for the Arduino
  • An RS232 cable to connect the Zaber device and the RS232 shield
  • DSUB9 male to male converter

Writing Code - The Arduino IDE

Arduino programs are compiled and uploaded to an Arduino board using the Arduino IDE, available here for download. Once the Arduino IDE is installed and open on your computer, you should be presented with a screen similar to as follows:

ArduinoIDE.png

This is where all C++ code is written and compiled for Arduino boards. Code that is present in the setup() function will be run once, when the Arduino initially boots the program. Code that is present in the loop() function is called repeatedly, so long as the Arduino board has power and the program has not halted execution.


Simple ASCII Homing Example

This example is intended to familiarize one with Zaber's libraries for Arduino, and goes into detail regarding initialization and command-issuing. If you'd like, you can follow along with this guide to learn about how the program is written; alternatively, you can navigate within the Arduino IDE to File -> Examples -> Zaber ASCII, and click on the Basic_Homing example to load the completed code into the Arduino IDE.

For now, let's write a simple program: When the Arduino turns on, we'll send the attached Zaber device back to its home position. As this command only needs to be issued once and not repeatedly, we can utilize the setup() function in this case, leaving the loop() function empty.

Initializing Zaber's Libraries for Arduino

First, import the appropriate library, which will be either ZaberAscii or ZaberBinary, depending on which protocol your device is set to use. If your device is in binary mode and you would prefer to switch to ASCII, Zaber Console provides easy accessibility to changing your device's mode of operation under its Options tab. For the sake of this example, we will assume that the device is in ASCII mode, and thus we import ZaberAscii at the very top of our file.

Common Questions and Confusions

What is a library?
A library is a set of functions contained inside a class. Importing the library allows us to utilize its functions for our own program.
#include <ZaberAscii.h>

Creating an Instance

Now, we need to initialize an instance of the ZaberAscii class. When doing so, a Serial class must be passed through to the constructor. A Serial class controls communications to the Zaber device through serial ports on an Arduino board. For all Arduino boards, the basic Serial class is available, as all Arduino boards possess at least one serial port. However, if your Arduino board has more than one serial port, the classes Serial1, Serial2, Serial3 are additionally available, allowing simultaneous control with non-Zaber devices, or debug-printing.

We'll define the instance of the ZaberAscii class as a global variable named za, and pass in the standard Serial class.

#include <ZaberAscii.h>

ZaberAscii za(Serial);

Common Questions and Confusions

What is an instance and why do I need one?
Our instance za is a specific variation of our ZaberAscii class, created using the Serial class as a parameter. Creating an instance lets us utilize all of the functions in the ZaberAscii class, but subject to our specifically-created version.
What is a constructor?
A constructor is a method that is called when we want to create an instance. The parameters passed into the constructor are what create the instance. In our case, we construct za with Serial as a parameter to the constructor.
What does initialization mean?
Initialization is used to describe the act of creating an instance of a class and passing in the appropriate values as parameters to the constructor.
What is a global variable?
A global variable is one that can be accessed anywhere in the program - it has the highest scope, declared at the top of a file in order to allow all nested functions access to it.

Setting the Baudrate

Now that an instance has been initialized, it is important to set and match the baudrate to the device. Zaber X-series devices, by default, use a baudrate of 115200. Let's initialize the Serial class with this baudrate in the setup() function, to be called at startup:

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}

Issuing a Command to the Zaber Device

With all of the serial communications setup out of the way, we can now send commands to the device. Commands are sent to a ZaberAscii instance with the send(int deviceNumber, String command, int data) function. The parameters of this function are as follows:

  • The int deviceNumber can be found by looking in Zaber Console, but is by default 1 for any device. Additionally, issuing a command with deviceNumber = 0 will send the command to all devices.
  • The various String command values available can be found by looking at the Zaber ASCII Protocol Manual. For this example, we'll use the "home" command.
  • Finally, if a command string requires data to be sent (for example, the distance for the device to move), the data can be passed through the int data parameter. Note that this parameter is optional, and if a command string does not require additional data to be sent, it can be ignored.

Let's issue the home command to our device number 1 using the predefined home command string, right after setting the baudrate. This command does not require any data to be passed through.

/* Issue a home command to device 1 */
za.send(1, "home");

In most cases, when you send a command to a device, you should read its reply - even if you don't use the reply for anything. If you do not read the reply, it will wait in the Arduino's serial port receive buffer until you do try to read a reply. If you don't read every reply, you can end up reading the reply to a previous command by accident, or the receive buffer can overflow causing you to read corrupted replies. The receive() function will read one reply. In this example we ignore the reply by not assigning the function's return value to a variable:

/* Always read the reply even if not checking it for errors. */
za.receive();

Your code should now look as follows:

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);

    /* Issue a home command to device 1 */
    za.send(1, "home");

    /* Always read the reply even if not checking it for errors. */
    za.receive();
}

void loop() {

}

Compiling and Running the Program On Your Arduino Board

You are now ready to run the program. Plug in your Arduino board via the USB connector to your PC, and set the following options:

  • Under "Tools", check that the correct port is selected (you should see your Arduino board name by the port number in brackets)
  • Under "Tools", set "Board" to the appropriate board that you have (this should be the same as the board name you saw in brackets when selecting a port)

Now, click the upload button (the right-facing arrow next to the checkmark button at the top of the IDE) to compile and upload the program to your Arduino board. The program should run as soon as it has been uploaded, and send the Zaber device to its home position.


Simple Binary Homing Example

The binary protocol library for Arduino is similar to the ASCII library for Arduino. If you'd like, you can follow along with this guide to learn about how the program is written; alternatively, you can navigate within the Arduino IDE to File -> Examples -> Zaber Binary, and click on the Basic_Homing example to load the completed code into the Arduino IDE.

Sending a command in the binary protocol is done with the send function, as follows:

ZaberBinary::send(byte device, byte commandNumber, long data)
  • The byte device is the device number upon which to send the command.
  • The byte commandNumber is the command number to send to the device. Rather than using strings such as "get pos" or "move rel" in the ASCII protocol, the binary protocol defines commands as numbers. A full list of available commands and their corresponding command numbers is available in the Zaber Binary Protocol Manual. Zaber's binary library for Arduino contains several example command number constants, which can be accessed using (for example,
    ZaberBinary::Command::HOME
    
    ZaberBinary::Command::MOVE_REL
    
    among others.
  • Lastly, the long data functions the same way as the command data sent in the ASCII protocol. This is the data to be sent alongside with the message. For example, if the desired message to send is to move relative 100 units, one would send 100 as the data passed into the send function.

Keep in mind that Zaber binary devices typically use a baudrate of 9600. Using this information, we can form a simple binary homing example similar to the previous one in the ASCII protocol.

As with the ASCII protocol, it is a good practice to read the devices' replies to every command, to avoid clogging the serial port receive buffer with irrelevant data. The binary protocol can be a little trickier to work with because the replies to move commands do not come until the physical movement ends. Also, using the manual move knob on the device can generate messages from the device to your software at any time.

#include <ZaberBinary.h>

ZaberBinary zb(Serial);

void setup() {

    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);

    /* Issue a home command to device 1 */
    zb.send(1, ZaberBinary::Command::HOME);

    /* Read the reply even if not checking it for errors. */
    zb.receive();
}

void loop() {

}

To run the program, see Compiling and Running the Program On Your Arduino Board.


Intermediate ASCII Example

If you'd like, you can follow along with this guide to learn about how the program is written; alternatively, you can navigate within the Arduino IDE to File -> Examples -> Zaber ASCII, and click on the Intermediate_LED example to load the completed code into the Arduino IDE.

Perhaps you are working overnight, and you only want to monitor devices that are not currently at their home position. The devices that are at their home position are not currently in use, but are still receiving power, and you'd like a way to differentiate them from the devices that are receiving power but not in their home positions. Using our Arduino knowledge, we can write a fairly simple script to fix this problem.

We'll start our program as before, creating an instance of the Zaber Ascii class, and initializing the baudrate to 115200 in the setup() function:

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}

void loop() {

}

Next, we'll query for the device's position in the loop function. This function runs continuously until the Arduino loses power or the program halts. This way, by checking if the device's position is 0, we can turn the device's LED lights on or off. First, send the request for the position of the device.

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}

void loop() {
    /* Issue a get position command to the device */
    za.send(1, "get pos");
}

Next, we'll want to receive and analyze the response. This can be done using the receive function, which returns a reply struct. A response from the Zaber ASCII library takes the form of a struct reply, with the following objects inside:

  • String fullResponse: The entire unparsed response String
  • bool isReply: Evaluates to true if the response is a reply
  • int deviceNumber: Evaluates to the device number that the command response is in relation to
  • int axisNumber: Evaluates to the axis number that the command response is in relation to
  • bool isRejected: Returns true if the command was rejected by the device
  • bool isBusy: Returns true if the device was busy and could not receive the command
  • bool hasWarning: Returns true if the command presented a warning from the device
  • String warningFlags: A string containing the warning flags if a warning was issued
  • String responseDataString: The data attached to the response in a String variable
  • long int responseData: The data attached to the response in a Integer variable

For now, store the reply from the device into a local variable.

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}

void loop() {
    /* Issue a get position command to the device */
    za.send(1, "get pos");

    /* Create a variable to store the device response inside */
    ZaberAscii::reply posResponse = za.receive();
}

We only want the data from the response, as it contains the device's position from our issued "get pos" command. This will be in the long int responseData variable of the reply struct. Thus, we use an if statement on the variable to check whether it is 0, or any other value.

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}

void loop() {
    /* Issue a get position command to the device */
    za.send(1, "get pos");

    /* Create a variable to store the device response inside */
    ZaberAscii::reply posResponse = za.receive();

    /* Check if the device is currently at the home position */
    if(posResponse.responseData == 0)
    {

    }
    else
    {

    }
}

Finally, we can issue a command to turn the LED lights off if the device is in the home position. If the device is not at the home position (inside the else{}), we want to continue to monitor the device, and thus turn the LED lights on.

#include <ZaberAscii.h>

ZaberAscii za(Serial);

void setup() {
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}

void loop() {
    /* Issue a get position command to the device */
    za.send(1, "get pos");

    /* Create a variable to store the device response inside */ 
    ZaberAscii::reply posResponse = za.receive();

    if(posResponse.responseData == 0)
    {
        /* Set the device's LED lights to OFF if it is at home */
        za.send(1, "set system.led.enable", 0);
    }
    else 
    {
        /* Set the device's LED lights to ON */
        za.send(1, "set system.led.enable", 1);
    }

    /* Always read the reply, even if not using it. */
    /* Since each of the if/else blocks above only sends one */
    /* command, we can read either reply outside the blocks, here. */
    za.receive();
}

You can now upload this program to your Arduino, and you'll notice that any device that is at the home position will have its power LED lights and communication LED lights turned off. If you move the device away from the home position (using one of the knobs) you'll see the LED lights turn back on, ready to be monitored.


Intermediate Binary Example

If you'd like, you can follow along with this guide to learn about how the program is written; alternatively, you can navigate within the Arduino IDE to File -> Examples -> Zaber Binary, and click on the Intermediate_SoftMaxPosition example to load the completed code into the Arduino IDE.

Instead of the above example, consider the following situation: You'd like to set a soft maximum limit to the device's position, without using the built-in max position variables. You'd also like the device to be sent to its home position if it ever reaches the soft max position limit. We can implement this in Arduino as follows:

Begin by importing the Zaber Binary class as before, creating an instance, and setting the baudrate. We'll also define the position at which our soft max position lies: in this case we chose 60,000.

#include <ZaberBinary.h>

int SOFT_MAX = 6000;

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);
}

void loop() {

}

Next, we'll query for the device's position in the loop() function, as this function runs continuously until the Arduino loses power or the program halts.

#include <ZaberBinary.h>

int SOFT_MAX = 6000;

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);
}

void loop() {
    /* Issue a get position command to device 1 (this number may need to be modified) */
    zb.send(1, ZaberBinary::Command::GET_POS, 0);
}

Next, we call the receive() function in order to read the response from the get pos command.

#include <ZaberBinary.h>

int SOFT_MAX = 6000;

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);
}

void loop() {
    /* Issue a get position command to device 1 (this number may need to be modified) */
    zb.send(1, ZaberBinary::Command::GET_POS, 0);

    /* Receive the command from the device */
    ZaberBinary::reply posResponse = zb.receive();
}

We've now successfully constructed our program to receive a command's response. A good measure of stability is to ensure that the response is in fact a response to the get pos command, and not another command that may have been issued.

A struct reply in the binary protocol is in the form of:

  • int deviceNumber: Evaluates to the device number that the response is in relation to
  • int commandNumber: Evaluates to the command number that theresponse is in relation to
  • unsigned long responseData: The data attached to the response
  • bool isError: Returns true if the command resulted in an error when issued to the device

Thus we can now access the response's int commandNumber field to verify that the response we have received is from our "get pos" command.

#include <ZaberBinary.h>

int SOFT_MAX = 6000;

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);
}

void loop() {
    /* Issue a get position command to device 1 (this number may need to be modified) */
    zb.send(1, ZaberBinary::Command::GET_POS, 0);

    /* Receive the command from the device */
    ZaberBinary::reply posResponse = zb.receive();

    /* Check that the response is from the GET POS command */
    if(posResponse.commandNumber == ZaberBinary::Command::GET_POS)
    {

    }
}

Now that we've ensured that posResponse contains a reply to the get pos command, we can access its response data and act upon the value. We'll perform a simple check to see if the responseData (position) has exceeded the soft maximum limit, and if so, send the device home.

#include <ZaberBinary.h>

int SOFT_MAX = 6000;

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);
}

void loop() {
    /* Issue a get position command to device 1 (this number may need to be modified) */
    zb.send(3, ZaberBinary::Command::GET_POS, 0);
    ZaberBinary::reply posResponse = zb.receive();

    /* Check that the response is from the GET POS command */
    if(posResponse.commandNumber == ZaberBinary::Command::GET_POS)
    {
        /* If the position returned is greater than SOFT_MAX, we'll send the device home */
        if(posResponse.responseData > SOFT_MAX)
        {
            /* Issue a home command to the device */
            zb.send(3, ZaberBinary::Command::HOME, 0);
        }
    }
}

At this point in time, you may think that the program will run as intended with what we've written so far. However, if the device's position were to be much larger than the SOFT_MAX, the home command may be issued multiple times as void loop() is called repeatedly. This could cause issues for our program, causing the home command to be issued again. Fortunately, this can easily be worked around.

In this case, we'll use the function pollUntilIdle(byte device) to command the device to block all requests until it is idle (not moving).

#include <ZaberBinary.h>

int SOFT_MAX = 6000;

ZaberBinary zb(Serial);

void setup() {
    /* Initialize baudrate to 9600, typical for Zaber binary devices */
    Serial.begin(9600);
}

void loop() {
    /* Issue a get position command to device 1 (this number may need to be modified) */
    zb.send(1, ZaberBinary::Command::GET_POS, 0);
    ZaberBinary::reply posResponse = zb.receive();

    /* Check that the response is from the GET POS command */
    if(posResponse.commandNumber == ZaberBinary::Command::GET_POS)
    {
        /* If the position returned is greater than SOFT_MAX, we'll send the device home */
        if(posResponse.responseData > SOFT_MAX)
        {
            /* Issue a home command to the device */
            zb.send(1, ZaberBinary::Command::HOME, 0);

            /* Block requests on the device until it is idle */
            /* Note this also consumes the reply to the home command when it arrives. */
            zb.pollUntilIdle(1);
        }
    }
}

Your code should look similar to the above. You can now load this program onto your Arduino, and play around with the Zaber device knob until you notice the stage move back to the home position after you pass the soft maximum limit.

My Program Isn't Working!

The program won't upload to the Arduino board
Ensure the RS232 board is turned off. If your RS232 shield does not have a an on/off switch, simply remove it when uploading to the Arduino.
The device isn't recognizing my commands or seems to be moving/reacting randomly
* Make sure that you are using the correct protocol and baudrate. By default, X-series devices are in ASCII, 115200 baudrate, and T- and A-series devices are in Binary 9600 baudrate (except the A-MCB2). You can check the protocol and baudrate in Zaber Console, and switch between the two protocols using the options tab. Zaber Console provides easy accessibility to changing your device's protocol under its Options tab. Also confirm you are sending the correct commands. In binary protocol, commands are identified as integers, and the full list of commands can be found here. In ASCII protocol, commands are identified as strings, such as "get pos" - the full list of commands for the ASCII protocol can be found here.
* Make sure you are reading every response returned by each device. In most cases Zaber devices send one response for each command they receive, and treating them this way is usually sufficient for basic use. There are exceptions, covered in the protocol manuals mentioned above; ASCII devices can be configured to send alerts when certain conditions are met, binary devices may generate move tracking messages spontaneously, and binary devices can be configured to not reply to certain command types.
The device is making high-pitched beeping noises whenever it moves
Contact Zaber support at contact@zaber.com to ensure that your device was configured correctly.
These fixes didn't work for me and my program still won't run
Contact Zaber support at contact@zaber.com, detailing your Arduino board type, Zaber device model, RS232 shield connector, and the Arduino code that refuses to run.

Additional Example Programs

This section contains additional example programs that utilize various other parts of Zaber's libraries for Arduino, as well as other Arduino libraries (eg: buttons, LCD displays).

Continuously Printing the Device's Position to an LCD Screen (ASCII)

This example utilizes the official LiquidCrystal Arduino library, and thus no installation of any additional libraries is necessary.

#include <ZaberAscii.h>
#include <LiquidCrystal.h>

/* 
    Initialize an instance of the LCD class, passing in the appropriate pins:

        LCD(rs, enable, d4, d5, d6, d7)

    These pin numbers can be found by checking the appropriate LCD manufacturer page for your screen    
*/
LiquidCrystal LCD(8, 9, 4, 5, 6, 7);

/* 
    Define microstep size for conversion into millimeter displacement
    To see the microstep size (default resolution) for the device, go to the product overview page:

                https://www.zaber.com/products/

    Find your device and click on the "Series Specs" tab. The microstep size (default resolution) will be shown in
    the list of product specs either in the "Group Specifications" section or the "Comparison" section
*/
float MM_RESOLUTION = 0.000049609375;

ZaberAscii za(Serial);

void setup()
{
    /* Initialize the LCD screen of size 16x2 */
    LCD.begin(16, 2);
   
    /* Initialize baudrate to 115200, typical for Zaber ASCII devices */
    Serial.begin(115200);
}
 
void loop()
{
    /* Set the LCD cursor to the top row */
    LCD.setCursor(0, 0);
    
    /* Issue a get position command to the device, storing the response */
    za.send(1, "get pos");

    /* Create a variable to store the device response inside */
    ZaberAscii::reply posResponse = za.receive();

    /* Convert the position response data to a readable format, and print it to the LCD screen */
    LCD.print("Position: " + mm(posResponse.responseData));
}

/* Translates the given microstep size into displacement in millimeters */
String mm(double dataValue)
{
    double mmValue;
    mmValue = (dataValue * MM_RESOLUTION);
    return String(mmValue);
}

Advanced Guide - Using Additional Serial Ports

Setting up an additional serial port can be done if your Arduino board has more than one transmit (TX) and receive (RX) pins. An extra serial port could be used to print solely to a specific serial port, and the serial port could be plugged into a PC with a terminal open to view the debug print statements. Unfortunately, the additional TX and RX pins on an Arduino are of a voltage that we can't use. If you have a breadboard, some ceramic capacitors, an RS232 port, and a MAX232 chip, you can construct an RS232 level converter from the schematic and breadboard shown below. Click "expand" to view the schematic and breadboard images.

RS232 level converter breadboard RS232 level converter schematic

Images were created through Fritzing.org

Documentation

Documentation for all of Zaber's libraries for Arduino can be found in their specified ZaberAscii.h and ZaberBinary.h files. On a Windows PC, the location of these files should be: Documents\Arduino\libraries\ZaberAscii and Documents\Arduino\libraries\ZaberBinary.