Monday, 1 February 2016

Arduino - Debugging via Serial

The ability to debug code is indispensable. This can be quite tricky when working with microcontrollers as they do not have in-built displays, used to observe intermediate results, nor built-in input devices, for data controllability. When programming on a computer we can use print statements to trace issues. We can also input expected and unexpected data to see how the system operates under different scenarios.

The Serial Interface


Debugging in Arduino is done through the serial interface. It communicates on pin0(RX) and pin1(TX) or, more conveniently, via USB. A serial interface is much slower than a parallel one as it sends 1 bit at a time but requires only 2 pins, making it a very popular choice for debugging in the microcontroller world where pins are precious.

For 2 ends to communicate, they require a protocol which is understood by both. The Arduino's serial interface uses the Universal Asynchronous Receiver/Transmitter (UART) protocol. Most microcontrollers these days have hardware support for UART. We won't go into detail about its inner workings, but the following is some useful terminology:
  • Bit Duration (T) - The time each bit is transmitted for; measured in seconds
  • Baud Rate (f) - Number of transmissions per second; the frequency; measured in bits per second
  • Baud Rate/Bit Duration relationship
    • T = 1/f : Bit duration and frequent are inversely proportional to each other
    • Example: if F = 9600 baud, then T is ~104 microseconds
    • Transmission rate is always less than Baud rate due to overhead caused by the start bit(s), stop bit(s) and parity bit(s) which are required by the UART protocol to operate

The Serial Monitor


To access the power of debugging on the Arduino, connect it to the computer and, from the IDE, go to Tools -> Serial Monitor. You should be presented with something similar to the following:



The Serial Monitor is minimalistic. It contains a text field to send data to the device, a message box to display the data received, and a few settings such as the Baud rate. The latter has to match the rate we set in the sketch. Since UART is asynchronous, and hence does not require a clock, the rate has to be predetermined and set to match on both ends. We now jump to the Arduino part and see how the Serial interface can be used to control the Arduino.

The Serial Library


The Serial library permits us programmatically send and receive messages from the Serial monitor. Let's take a look at some of the functions it has to offer:
  • Serial.begin (speed [, config]) - Initialises serial communication
    • speed - Baud rate; must match the Baud rate set in the Serial Monitor
    • config - An optional parameter which configures the data, parity and stop bits. Below are some examples
      • SERIAL_8N1 - 8 data bits; no parity; 1 stop bit (Default configuration)
      • SERIAL_6N2 - 6 data bits; no parity; 2 stop bits
    • Examples - Serial.begin(9600), Serial.begin(9600, SERIAL_8N1)
  • Serial.print (value [, format]) - Prints ASCII text to the Serial Monitor; returns # of chars written
    • value - The value to be sent
    • format - Specifies number base (BIN/OCT/DEC/HEX) or decimal places (0, 1, 2, ...); Optional parameter
    • Examples
      • Serial.print ("Test") - Returns: Test
      • Serial.print (321) - Returns: 321
      • Serial.print (321, BIN) - Returns: 101000001
      • Serial.print (321.123, 2) - Returns: 321.12
  • Serial.println (value [, format]) - Same as print() but adds '\r\n' at the end

Let's use these newly learnt functions to create a circuit which displays ON on the Serial Monitor when a push-button is pressed and OFF otherwise. Set up the schematic used in the previous post.

And upload the following code:

void setup() {
    Serial.begin(9600);
    pinMode(10, INPUT);
}

void loop() {
    if ( digitalRead(10) == HIGH )
        Serial.println ("ON");
    else
        Serial.println ("OFF");
}


The sketch initialises the serial interface with 9600 baud, sets pin10 in INPUT mode and constantly reads it's voltage level. If HIGH, i.e. the push-button is pressed, the Serial Monitor displays ON, else OFF. Make sure the baud rate matches the one set in the IDE. After uploading, the result should look something like this:




Writing to the serial interface is as easy:
  • Serial.available() - Returns number of bytes waiting in the buffer to be read
    • Example - int bufBytes = Serial.available()
  • Serial.read() - Reads a single byte from incoming serial data; returns -1 if no data available
    • Example - int bufByte = Serial.read()
  • Serial.readString() - Reads bytes from serial buffer to string
    • Example - String bufString = Serial.readString()
  • Serial.readBytes (buffer, length) - Reads bytes from serial buffer to buffer; returns # of chars written
    • buffer - The destination buffer; Can be char[] or byte[]
    • length - Number of bytes to read
    • Example - char buf[10]; int bytesRead = Serial.readBytes(buf, 10)
As an example of reading bytes from serial we'll build a Serial-controlled LED: when a 1 is sent to the Arduino, an LED lights, until we send a 0. Wire the following circuit which we've used in the previous post:

Upload the following sketch:

void setup() {
    Serial.begin(9600);
    pinMode(9, OUTPUT);
}

void loop() {

    if ( Serial.available() ){    
        int inputDigit = Serial.read();
        
        if ( inputDigit == 49 )
            digitalWrite(9, HIGH);
        else if ( inputDigit == 48 )
            digitalWrite(9, LOW); 
    }
}

The Arduino will constantly poll for available data to be read from the serial buffer and if there is, it will read a single byte. If the ASCII value of the byte read is 49, which translates to 1, it sends current down pin9, if the ASCII value is 48, i.e. a 0, it will stop sending. Successful implementation will look like this:



No comments:

Post a Comment