Programming an Interface

In honor of Thanksgiving break, how to make almost anything presented its students with the task of programming an interface device. Something that could nominally be undertaking remotely. With a wealth of information available online, but a limitted capacity to test or debug a circuit remotely, a fair amount of time was spent trying to guess as to how the circuit would behave.

On recommendation from peers, I started with processing, a simple graphical interface designed to be visually and functionally similar to the arduino environment. A wealth of tutorials existed online, and the means for establishing a serial connection seemed reasonably straightforward (though again impossible to test remotely).

The preliminary code pulled from a tutorial for connecting to serial is shown below:

  import processing.serial.*;

Serial myPort;
String val;

// I know that the first port in the serial list on my mac
// is Serial.list()[0].
// On Windows machines, this generally opens COM1.
// Open whatever port is the one you're using.
String portName = Serial.list()[0]; //change the 0 to a 1 or 2 etc. to match your port

void setup()
{
  size (500,400);
  myPort = new Serial(this, portName, 9600); 
}
void draw()
{
  if ( myPort.available() > 0) 
  {  // If data is available,
  val = myPort.readStringUntil('\n');         // read it and store it in val
  } 
  background(163);
  stroke(255);
  fill(0);
  rect(100,100,300,50);
  
  stroke(255);
  fill(255);
  rect(100,100,(val/350)*300,50);
  
println(val); //print it out in the console
}

The hope was to use the bottom of that code as a means to create a rudimentary thermometer. The colour picking feature wasn't working, so it was going to be black and white for a first draft. A gray background was created, with a white-bordered black rectangle inside. A second rectangle, this time white with a white border, was set up to overlay the first rectangle (by being placed later in the code). The height of this rectange was set to the same as the black rectangle, but the width was controled to be a proportional function of the black rectangle, with the value of the thermister being divided by the total temperature range, and then multiplied by the width of the black rectangle. This of course neglects the fact that in the above code "val" is a "string" rather than an "int", which means I would not be able to do mathematical operations with it.

In implementation, this second rectangle would repetitively overlay the first, and change width with the varying input data from the thermistor.

At this point, programming issues of the input device from last week are preventing me from testing the code on this device. As the assignment is to create a serial connection with that device, this will have to await further debugging that could not be completed previously due to the break.

In the interest of demonstrating some degree of serial connectivity, I used a packaged Arduino that I had, and attempted to run some sample code created by Tom Igoe (below for reference). As this was largely a matter of cutting and pasting, it allowed me to start debugging quickly.

  /*
  Serial Call and Response
 Language: Wiring/Arduino

 This program sends an ASCII A (byte of value 65) on startup
 and repeats that until it gets some data in.
 Then it waits for a byte in the serial port, and
 sends three sensor values whenever it gets a byte in.

 Thanks to Greg Shakar and Scott Fitzgerald for the improvements

   The circuit:
 * potentiometers attached to analog inputs 0 and 1
 * pushbutton attached to digital I/O 2

 Created 26 Sept. 2005
 by Tom Igoe
 modified 24 April 2012
 by Tom Igoe and Scott Fitzgerald

 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/SerialCallResponse

 */

int firstSensor = 0;    // first analog sensor
int secondSensor = 0;   // second analog sensor
int thirdSensor = 0;    // digital sensor
int inByte = 0;         // incoming serial byte

void setup() {
  // start serial port at 9600 bps:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  pinMode(2, INPUT);   // digital sensor is on digital pin 2
  establishContact();  // send a byte to establish contact until receiver responds
}

void loop() {
  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    // read first analog input, divide by 4 to make the range 0-255:
    firstSensor = analogRead(A0) / 4;
    // delay 10ms to let the ADC recover:
    delay(10);
    // read second analog input, divide by 4 to make the range 0-255:
    secondSensor = analogRead(1) / 4;
    // read  switch, map it to 0 or 255L
    thirdSensor = map(digitalRead(2), 0, 1, 0, 255);
    // send sensor values:
    Serial.write(firstSensor);
    Serial.write(secondSensor);
    Serial.write(thirdSensor);
  }
}

void establishContact() {
  while (Serial.available() <= 0) {
    Serial.print('A');   // send a capital A
    delay(300);
  }
}

/*
Processing sketch to run with this example:

// This example code is in the public domain.

import processing.serial.*;

int bgcolor;                 // Background color
int fgcolor;                 // Fill color
Serial myPort;                       // The serial port
int[] serialInArray = new int[3];    // Where we'll put what we receive
int serialCount = 0;                 // A count of how many bytes we receive
int xpos, ypos;                  // Starting position of the ball
boolean firstContact = false;        // Whether we've heard from the microcontroller

void setup() {
  size(256, 256);  // Stage size
  noStroke();      // No border on the next thing drawn

  // Set the starting position of the ball (middle of the stage)
  xpos = width/2;
  ypos = height/2;

  // Print a list of the serial ports for debugging purposes
  // if using Processing 2.1 or later, use Serial.printArray()
  println(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
}

void draw() {
  background(bgcolor);
  fill(fgcolor);
  // Draw the shape
  ellipse(xpos, ypos, 20, 20);
}

void serialEvent(Serial myPort) {
  // read a byte from the serial port:
  int inByte = myPort.read();
  // if this is the first byte received, and it's an A,
  // clear the serial buffer and note that you've
  // had first contact from the microcontroller.
  // Otherwise, add the incoming byte to the array:
  if (firstContact == false) {
    if (inByte == 'A') {
      myPort.clear();          // clear the serial port buffer
      firstContact = true;     // you've had first contact from the microcontroller
      myPort.write('A');       // ask for more
    }
  }
  else {
    // Add the latest byte from the serial port to array:
    serialInArray[serialCount] = inByte;
    serialCount++;

    // If we have 3 bytes:
    if (serialCount > 2 ) {
      xpos = serialInArray[0];
      ypos = serialInArray[1];
      fgcolor = serialInArray[2];

      // print the values (for debugging purposes only):
      println(xpos + "\t" + ypos + "\t" + fgcolor);

      // Send a capital A to request new sensor readings:
      myPort.write('A');
      // Reset serialCount:
      serialCount = 0;
    }
  }
}
*/

First things first was a good sign, I was able to write to the arduino. This suggests that I had resolved some of my toolchain issues from earlier. From Arduino, I was able to see that I was plugged into USB port designation /dev/ttyS1. I adjusted Igoe's code to call this port, but ran into issues on the processing side with the error message:

  Error opening serial Port /dev/ttyS1: Incorrect serial port

To debug this, I switched from my Ubuntu Virtual box to Windows, where I installed Processing and Arduino. Here too I found an error, but it was due to the fact that the indexing of ports apparently counts in order of use. Even though I was using COM4, as COM4 was the only port currently receiving data, I was supposed to refrence this as serial port 0. When this was corrected, serial data began to flow from the arduino to the computer, and an animation of a circled flickerd to life onscreen.

Admittedly, this was a problem. The way the code is written, nothing should be happeing until a button is pressed. To remedy this, I added a 39kohm pulldown resistor between the button input and ground. This drove the input to zero when the button was released, but provided enough resistance that a button press would drive the pin high.

Taking the newfound knowledge that connection could be acheived, I returned to the Ubuntu virtual box, and examined the error message more closesly. I noteced that though the port in Arduino was being identified as /dev/ttyUSB1, the port in processing (when called by the line: String portName = Serial.list()[1];) was /dev/ttyS1. I therefore removed the line listing all the ports, and replaced it with a designated string "/dev/ttyUSB1". This was succssful, and I was able to emulate the window that I had seen in the Windows OS.