01

index - Daniel Bruns

03

weekly assignments

20

week 16 | interface and application programming

21

This week we had to program an application, which interfaces with an input and/or output device, we made.
I made this assignment in 2018 and used my - meanwhile - well known final project PCB to accomplish this assignment. One of the reasons to put a CP2104 USB-to-UART bridge on my board, was this assignment. I don't like those bulky FTDI cables. They're expensive (if it's not a clone...) and uncomfortable.

I never programmed a GUI, so this is my first time. I reviewed Neil's lecture and heard the word Processing. I remembered a long time ago, where really good friends of me - called machina eX where using Processing to program their theater performance.

At this point I decided to try it...

22

The RGB LED on my final project PCB was the appropriate output device to control. Not too hard and not too easy. It has 3 channels which can be controlled independently. To communicate from Processing to the PCB, I had to establish a serial connection. I already used the integrated Arduino Serial monitor in the Input devices, to show the counted encoder signals.

23

Preparing my PCB:

Preparing the skater dolly control PCB was not that complicated. I wrote a short program which listens the serial port for commands, to turn on the corresponding LED.

int led_r = 6;
int led_g = 9;
int led_b = 11;
char rgb;    // Variable to store submitted command

I initialized the LED pins and created the rgb variable to store the commands



void setup() {
  pinMode(15,OUTPUT);    // Set SysOn PIN as output
  digitalWrite(15,HIGH);    // Set SysOn HIGH to power PCB
  pinMode(led_r,OUTPUT);    // Set LED pins as output
  pinMode(led_g,OUTPUT);
  pinMode(led_b,OUTPUT);
  digitalWrite(led_r, HIGH);    // turn off LEDs on start up
  digitalWrite(led_g, HIGH);
  digitalWrite(led_b, HIGH);

  Serial.begin(9600);    // initialize serial connection with 9600 baud
}

The setup function does the usual "power on" start up process for my PCB, sets the LED pins as output and then as "HIGH", to turn them off. The last line will establish the serial connection with 9600 baud.



void loop() {
 if (Serial.available()) {    // check if data is available on the serial port
  rgb = Serial.read();    // read and store the data in the variable
 }
 if (rgb == '1') {
  digitalWrite(led_r, LOW);    // red LED on
 } else if (rgb == '2') {
  digitalWrite(led_g, LOW);    // green LED on
 } else if (rgb == '3') {
  digitalWrite(led_b, LOW);    // blue LED on
 } else if (rgb == '4') {
  digitalWrite(led_r, LOW);    // all 3 LEDs on
  digitalWrite(led_g, LOW);
  digitalWrite(led_b, LOW);
 } else if (rgb == '0') {
  digitalWrite(led_r, HIGH);    // turn all LEDs off
  digitalWrite(led_g, HIGH);
  digitalWrite(led_b, HIGH);
 }
 delay(10);
}

The loop function checks if there is any data on the serial port. If there is data, it stores the data in the 'rgb' variable. If the data corresponds to one of the 5 states, the RGB will be turned on accordingly to the sent data.


24

Programming the GUI with Processing:

As I never used Processing before, I needed little help. The best source for information is - in my humble opinion - the Processing Reference. You have to search a lot but everything is in it. My program might be a bit confusing and not that well written, but it works. :)

The first part is to initalize some variables...

import processing.serial.*;

Serial comPort;

int rectRX, rectRY, rectGX, rectGY, rectBX, rectBY, rectWX, rectWY;
int rectSize = 100;
color rectRColor, rectGColor, rectBColor, rectWColor;
color rectRHighlight, rectGHighlight, rectBHighlight, rectWHighlight;
boolean rectROver = false;
boolean rectGOver = false;
boolean rectBOver = false;
boolean rectWOver = false;



The setup sets the program window size, the COM port used to communicate with my board, the colors for different conditions (eg. highlighted while the mouse is over this area) and areas and the 'X' and 'Y' coordinates of the different buttons.

void setup() {
 size(500,200); // 500x200 pixel window
 String portName = Serial.list()[1]; // COMx -1 -> at the moment COM2
 comPort = new Serial(this, portName, 9600);

 rectMode(CENTER);
 rectRColor = color(125, 0, 0);
 rectRHighlight = color(255, 0, 0);
 rectGColor = color(0, 125, 0);
 rectGHighlight = color(0, 255, 0);
 rectBColor = color(0, 0, 125);
 rectBHighlight = color(0, 0, 255);
 rectWColor = color(125, 125, 125);
 rectWHighlight = color(255, 255, 255);
 rectRX = 100;
 rectRY = 100;
 rectGX = 200;
 rectGY = 100;
 rectBX = 300;
 rectBY = 100;
 rectWX = 400;
 rectWY = 100;
}



The 'draw' function draws the window content, the buttons, the text etc. . If any highlight function (from the update function below) is triggered through the mouse, the draw function changes the the color of the corresponding button.

void draw() {
 update(mouseX, mouseY);
 background(200, 200, 200);
 textSize(30);
 textAlign(CENTER, 35);
 fill(0);
 text("RGBW Selector", 250, 35);

 textSize(12);
 textAlign(CENTER, 180);
 fill(0);
 text("FabAcademy 2018 Interface and Application Programming / Daniel Bruns", 250 , 180);

 if (rectWOver) {
  fill(rectWHighlight);
 } else {
  fill(rectWColor);
 }
 stroke(255);
 rect(rectWX, rectWY, rectSize, rectSize);

 if (rectROver) {
  fill(rectRHighlight);
 } else {
  fill(rectRColor);
 }
 stroke(255);
 rect(rectRX, rectRY, rectSize, rectSize);

 if (rectGOver) {
  fill(rectGHighlight);
 } else {
  fill(rectGColor);
 }
 stroke(255);
 rect(rectGX, rectGY, rectSize, rectSize);

 if (rectBOver) {
  fill(rectBHighlight);
 } else {
  fill(rectBColor);
 }
 stroke(255);
 rect(rectBX, rectBY, rectSize, rectSize);
}



The 'update' function calls the 'overRect' function (see at the end) with the corresponding variables of each buttons. If a true is returned, the corresponding variable will be set to true. If nothing is true - the mouse is not above any button - the function will return false for all variables.

void update(int x, int y) {
 if (overRect(rectRX, rectRY, rectSize, rectSize) ) {
  rectROver = true;
  rectGOver = false;
  rectBOver = false;
  rectWOver = false;
 } else if ( overRect(rectGX, rectGY, rectSize, rectSize) ) {
  rectROver = false;
  rectGOver = true;
  rectBOver = false;
  rectWOver = false;
 } else if ( overRect(rectBX, rectBY, rectSize, rectSize) ) {
  rectROver = false;
  rectGOver = false;
  rectBOver = true;
  rectWOver = false;
 } else if ( overRect(rectWX, rectWY, rectSize, rectSize) ) {
  rectROver = false;
  rectGOver = false;
  rectBOver = false;
  rectWOver = true;
 } else {
  rectROver = rectGOver = rectBOver = rectWOver = false;
 }
}



The 'mousePressed' function will send the different values (1,2,3,4), according to the particular button, if it is pressed above one of the four buttons, on the set COM port. This will turn on the LED in different colors.

void mousePressed() {
 if (rectROver) {
  comPort.write('1');
 }
 if (rectGOver) {
  comPort.write('2');
 }
 if (rectBOver) {
  comPort.write('3');
 }
 if (rectWOver) {
  comPort.write('4');
 }
}



If the mouse button is 'released' after pressing, the program will send '0' on the set COM port, which tells the board to turn off all LEDs. To check if it works, the message will be displayed in the Processing serial monitor.

void mouseReleased() {
 comPort.write('0');
 println("0");
}



The 'overRect' function calculates, if the mouse is above any button with the corresponding variables (called by the 'update' function)and the given 'X' 'Y' position of the mouse. If yes, it returns 'true'.

boolean overRect(int x, int y, int width, int height) {
 if (mouseX >= x-width/2 && mouseX <= x+width/2 && mouseY >= y-height/2 && mouseY <= y+height/2) {
  return true;
 } else {
  return false;
 }
}



25

The result is nice. Not that fancy, but it works. I made a gif to show the highlight function.

GUI GIF



To best way to show the communication between my PCB and the Processing program is a video...



Download my Processing project as .pde

Download my PCB program as .ino

Creative Commons License
This work by Daniel Bruns is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.