Skip to content

14. Interface and Application Programming

Hero Shot


This week’s Assignment

Group assignment:

  • Compare as many tool options as possible.
  • Document your work on the group work page and reflect on your individual page what you learned.

Individual assignment:

  • Write an application for the embedded board that you made. that interfaces a user with an input and/or output device(s)

Learning outcomes:

  • Implement a User Interface (UI) using programming and explore protocols to communicate with a microcontroller board that you designed and made.

Group Assignment

This week’s group work page is here


Individual Assignment

Processing

I made color select screen by Processing. The color was first selected by Red, Green, or Blue button.
Then, it could be changed with slide potentiometers. The color was select by pushing button and potentiometer and then also changed the background color.

First try

First aim was a screen with 3 button(red, green, blue). When you touch one of the button, the background color is changed as the button color.

I wrote the code using the example “button” at Processing as a reference.

Note

In the example code, I didn’t understand about the equation below,

sqrt(sq(disX) + sq(disY)) < diameter/2

I asked chatGPT about it.

(1) First Mistake
When I wrote a code on the Processing, the screen was appeared only background color and no circle was there. I asked chatGPT checking my code, and it told the order of description of circle and background should be opposite.

After switching the order, all circles were seen on the screen.

(2) Second Mistake
Then the circles are seen on the screen but the color didn’t change even pushing the button. I asked again about the solution to chatGPT.

first wrong part -> no break in each case sentence

switch (currentButton){
 case 0: currentColor = baseColor;    
 case 1: currentColor = RedOn;    
 case 2: currentColor = GreenOn;    
 case 3: currentColor = BlueOn;    
 default: currentColor = baseColor;    
}
-> After changing
switch (currentButton){
 case 0: currentColor = baseColor;  
         break;  
 case 1: currentColor = RedOn;    
         break; 
 case 2: currentColor = GreenOn; 
         break;    
 case 3: currentColor = BlueOn; 
         break;    
 default: currentColor = baseColor; 
         break;   
}
Though I changed the code above, it didnt still work what I wanted to. I wanted to create a code that only changes the color of the background to the chosen color when the button is pushed. So I asked GPT about
I want to create a code that only changes the color of the background 
to the chosen color when the button is pushed.
Then GPT answered
I see!
So you want to make the specification ‘The color doesn't change just 
by hovering the mouse, but the background color only changes 
when the button is clicked’.

In that case, in 
✅ draw() you just draw the background color according to the current currentButton.
In ✅ mousePressed(), determine ‘which button is pressed’ from the mouse position 
and update the currentButton only then.
I changed the code GPT advised and it could work as I wanted to.

Second Try

Then I’d like to put slide potentiometers at each colors as color would be changed with potentiometer too. I put slide potentiometer as used another example code from the internet(address is at link).
At first, I found to add ControlP5 for put the potentiometer.

Then I added library at first,

import controlP5.*;
in the code. I also asked to chatGPT how to put the slider and showed the code below.
import controlP5.*;

ControlP5 cp5;
float sliderValue = 100;

void setup() {
  size(600, 400);
  cp5 = new ControlP5(this);

  cp5.addSlider("sliderValue")
     .setPosition(100, 100)
     .setSize(300, 20)
     .setRange(0, 255)
     .setValue(sliderValue);
}

void draw() {
  background(sliderValue);  // スライダー値で背景の明るさを変える

  fill(0);
  text("Slider Value: " + sliderValue, 100, 150);
}
I changed the sliders for R,G,B from reference code above.

Then I asked chatGPT to “How can I reflect the slider values in the background?”
Then chatGPT answered the code.

void draw() {
  currentColor = color(sliderR, sliderG, sliderB);  // スライダー値で背景色を作る
  background(currentColor);

  // Drawing by button
  fill(baseColor);
  ellipse(BaseX, BaseY, circleSize, circleSize);

  fill(RedOff);
  ellipse(RedX, RedY, circleSize, circleSize);

  fill(GreenOff);
  ellipse(GreenX, GreenY, circleSize, circleSize);

  fill(BlueOff);
  ellipse(BlueX, BlueY, circleSize, circleSize);

  // スライダーの値を表示(デバッグ用)
  fill(0);
  textSize(16);
  text("R: " + sliderR, 50, height - 60);
  text("G: " + sliderG, 50, height - 40);
  text("B: " + sliderB, 50, height - 20);
}

Serial Connect with Xiao C3

Next, I tried to put the neo pixel light which was changed to the selected color at processing.

For communicating Processing and Arduino, I asked to GPT as follows;

I want this code to reflect the colour of the led using serial communication, 
can you tell me the code for SERIAL?
To send LED colours via serial communication from Processing, simply combine 
the slider values (R, G, B) into a string and send it to the serial port.

For example, if you want to control LEDs by receiving values in the form R, G, B on the Arduino side, 
you can write the following serial transmission code on the Processing side.
Showed the example code of
Processing Side
At setup():
String portName = "COM7";  // ←あなたの環境に合わせて
myPort = new Serial(this, portName, 9600);

At draw():
if (myPort != null) {
  String sendString = int(sliderR) + "," + int(sliderG) + "," + int(sliderB) + "\n";
  myPort.write(sendString);
}
And Arduino Side
void loop() {
  if (Serial.available()) {
    String input = Serial.readStringUntil('\n');
    int comma1 = input.indexOf(',');
    int comma2 = input.lastIndexOf(',');

    if (comma1 > 0 && comma2 > comma1) {
      int r = input.substring(0, comma1).toInt();
      int g = input.substring(comma1 + 1, comma2).toInt();
      int b = input.substring(comma2 + 1).toInt();

      // ここで r, g, b をLEDに反映
    }
  }
}

Connect with Neo Pixel

It was first time to light the neo pixel, I checked the internet about it. Adafruit_NeoPixel.h was needed for lighten the neo pixel. So I added this library and made a code by the help of internet and chatGPT. Code is below.(Neo Pixel)


Connect with RGB LED

After I could light on the Neopixel, I’d like to light with RGB LED too. I learnt using ledcAttach() for changing the LED color more smoothly.

Note

PWM (Pulse Width Modulation) (from chatGPT)
it’s a way to control the average power delivered to a device (like an LED or motor) by rapidly turning a signal ON and OFF.
Key concepts
Duty cycle → How much of the time the signal is ON.
0% → always off
50% → on half the time
100% → always on
Frequency → How fast you switch between ON and OFF.
Even at high frequencies, devices like LEDs or motors will smooth out the flicker, so you see it as dimmer or slower, not as fast blinking.

I wrote the neo pixel code using internet page as a reference. Code is below(RGB LED)

Research

I’ve searched a lot about “Processing” this week. It was totally new language for me, but it seemed similar with arduino. I listed several links that I searched. I also check and learnt about neo pixel. I learnt Neo pixel has a library from my classmate and checked it.

What I’ve learnt this week

I’ve learnt several new languages, Processing, P5.js and Three.js. I tried to make a code with Processing. The codes in Arduino seem possible to create something that could be used as a reference.

Code Example

Processing Side

/**
 * Button. 
 * 
 * Click on one of the colored shapes in the 
 * center of the image to change the color of 
 * the background. 
 */
import processing.serial.*; 
import controlP5.*;

Serial myPort; 
ControlP5 cp5;

//From instructor
String myString = null; //3. create a variable to receive the string from MCU
int nl = 10;            //4. create a variable to represent the carriage return (end of message)
float myVal;            //5. create a variable to hold a float number

int RedX, RedY;    //Position of circle red button
int GreenX, GreenY;  // Position of circle Green button
int BlueX, BlueY;  // Position of circle blue button
int BaseX, BaseY;  // Position of circle blue button

color   baseColor, currentColor,Blackout;
color   RedOff, RedOn;
color   GreenOff, GreenOn;
color   BlueOff, BlueOn;

int     currentButton = 0;
int     circleSize = 85;   // Diameter of circle
int     currentX = 0;
int     currentY = 0;

int sliderR;
int sliderG;
int sliderB;
//from chatGPT
   int lastR = -1;
   int lastG = -1;
   int lastB = -1;
//from chatGPT   
boolean RedOver = false;
boolean GreenOver = false;
boolean BlueOver = false;
boolean BaseOver = true;

void setup() {
  size(640, 360);            // Board size

  RedOff = color(150,0,0);
  RedOn = color(255,0,0);
  GreenOff = color(0, 150, 0);
  GreenOn = color(0,255,0);  
  BlueOff = color(0, 0, 150);
  BlueOn = color(0,0,255);  

   RedX = width/4;
   RedY = height/4+circleSize/4;
   GreenX = width/4*2;
   GreenY = height/4+circleSize/4;
   BlueX = (width/4)*3;
   BlueY = height/4+circleSize/4;
   BaseX = width-circleSize;
   BaseY = height-circleSize;

   baseColor = color(102);
   currentColor = baseColor;
   currentButton = -1;
   Blackout = color(0);
   ellipseMode(CENTER);

  cp5 = new ControlP5(this);

  cp5.addSlider("sliderR")
     .setPosition(width/4-circleSize,height/2)
     .setSize(150,20)
     .setRange(0,255)
     .setValue(127)
     ;

  cp5.addSlider("sliderG")
     .setPosition(width/4*2-circleSize,height/2)
     .setSize(150,20)
     .setRange(0,255)
     .setValue(127)
     ;

  cp5.addSlider("sliderB")
     .setPosition((width/4)*3-circleSize,height/2)
     .setSize(150,20)
     .setRange(0,255)
     .setValue(127)
     ;

//     String portName = "/dev/cu.usbmodem2101";        //6. specify the COM port number where the MCU is connected
     String portName = "/dev/cu.usbmodem101";        //6. specify the COM port number where the MCU is connected
     myPort = new Serial(this,portName,9600);         //7. initialize the Serial object

}


void draw(){

//     update(mouseX, mouseY);
   // select color
   // Advised from chatGPT
   currentColor = color(sliderR, sliderG, sliderB);
   background(currentColor);

   fill(Blackout);
   ellipse(BaseX, BaseY, circleSize, circleSize);

   fill(RedOff);
   ellipse(RedX, RedY, circleSize, circleSize);

   fill(GreenOff);
   ellipse(GreenX, GreenY, circleSize, circleSize);

   fill(BlueOff);
   ellipse(BlueX, BlueY, circleSize, circleSize);

   // Advised from chatgpt -slider
   fill(0);
   textSize(16);
   text("R: " + sliderR, 50, height - 60);
   text("G: " + sliderG, 50, height - 40);
   text("B: " + sliderB, 50, height - 20);

   /*    
   if (myPort != null) {
      String sendString = int(sliderR) + "," + int(sliderG) + "," + int(sliderB) + "\n";
      myPort.write(sendString);
      println(sendString);
    }
*/
    // chatGPT
    if (myPort != null) {
        int r = int(sliderR);
        int g = int(sliderG);
        int b = int(sliderB);
        if (r != lastR || g != lastG || b != lastB) {
            String sendString = r + "," + g + "," + b + "\n";
            myPort.write(sendString);
            println(sendString);
            lastR = r;
            lastG = g;
            lastB = b;
        }
    }
}

//void update(int x, int y) {
void update(){
  if ( overCircle(BaseX, BaseY, circleSize)){      //Base
    currentButton = 0;
  }else if ( overCircle(RedX, RedY, circleSize) ) {    //Red
    currentButton = 1;
  } else if ( overCircle(GreenX, GreenY, circleSize) ) { //Green
    currentButton = 2;
  } else if ( overCircle(BlueX, BlueY, circleSize) ) {   //Blue
    currentButton = 3;
  } else {
    currentButton = -1;
  }
}


boolean overCircle(int x, int y, int diameter) {
  float disX = x - mouseX;
  float disY = y - mouseY;
  if (sqrt(sq(disX) + sq(disY)) < diameter/2 ) {
    return true;
  } else {
    return false;
  }
}

void mousePressed() {
 if (overCircle(BaseX, BaseY, circleSize)) {
    currentButton = 0;
    // Advised from chatGPT
    cp5.getController("sliderR").setValue(0);
    cp5.getController("sliderG").setValue(0);
    cp5.getController("sliderB").setValue(0);
  } else if (overCircle(RedX, RedY, circleSize)) {
    currentButton = 1;
    // Advised from chatGPT    
    cp5.getController("sliderR").setValue(255);
    cp5.getController("sliderG").setValue(0);
    cp5.getController("sliderB").setValue(0);
  } else if (overCircle(GreenX, GreenY, circleSize)) {
    currentButton = 2;
    // Advised from chatGPT
    cp5.getController("sliderR").setValue(0);
    cp5.getController("sliderG").setValue(255);
    cp5.getController("sliderB").setValue(0);
  } else if (overCircle(BlueX, BlueY, circleSize)) {
    currentButton = 3;
    // Advised from chatGPT
    cp5.getController("sliderR").setValue(0);
    cp5.getController("sliderG").setValue(0);
    cp5.getController("sliderB").setValue(255);
  }
}

Arduino Side
(1) Neo Pixel

#include <Adafruit_NeoPixel.h>

#define Neopin  D0
#define NUMPIXELS  8   // ネオピクセルの数(必要に応じて変更)

int r = 0;
int g = 0;
int b = 0;

Adafruit_NeoPixel pixels(NUMPIXELS, Neopin, NEO_GRB + NEO_KHZ800);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pixels.begin();  // 初期化
  pixels.show();   // すべてのLEDをオフに
}

void loop() {
  // from chatGPT
  if (Serial.available()) {
    String input = Serial.readStringUntil('\n');
    int comma1 = input.indexOf(',');
    int comma2 = input.lastIndexOf(',');

    if (comma1 > 0 && comma2 > comma1) {
      r = input.substring(0, comma1).toInt();
      g = input.substring(comma1 + 1, comma2).toInt();
      b = input.substring(comma2 + 1).toInt();

      // ここで r, g, b をLEDに反映
      for (int i = 0; i < NUMPIXELS; i++) {
          pixels.setPixelColor(i, pixels.Color(r, g, b)); // R, G, B
      }
      pixels.show();
 //     delay(500);
    }
  }
  // from chatGPT
}

(2) RGB LED

#define RED_PIN   D0  // GPIOピン番号に合わせて変更
#define GREEN_PIN D1
#define BLUE_PIN  D2

// Brightness correction (chatGPT)
// float redFactor = 0.45;
float redFactor = 1.0;
float greenFactor = 1.0         ;
float blueFactor = 1.0;

int r = 0, g = 0, b = 0;

void setup() {
  Serial.begin(9600);

  ledcAttach(RED_PIN, 5000, 8);
  ledcAttach(GREEN_PIN, 5000, 8);
  ledcAttach(BLUE_PIN, 5000, 8);

  // ledcSetup(0, 5000, 8); // channel 0, freq 5kHz, resolution 8bit
  // ledcAttachPin(RED_PIN, 0);
  // ledcSetup(1, 5000, 8);
  // ledcAttachPin(GREEN_PIN, 1);
  // ledcSetup(2, 5000, 8);
  // ledcAttachPin(BLUE_PIN, 2);
}

void loop() {
  if (Serial.available()) {
    String input = Serial.readStringUntil('\n');
    int comma1 = input.indexOf(',');
    int comma2 = input.lastIndexOf(',');

    if (comma1 > 0 && comma2 > comma1) {
      r = input.substring(0, comma1).toInt();
      g = input.substring(comma1 + 1, comma2).toInt();
      b = input.substring(comma2 + 1).toInt();

     // Correction to 0~255
      int correctedR = constrain(r * redFactor, 0, 255);
      int correctedG = constrain(g * greenFactor, 0, 255);
      int correctedB = constrain(b * blueFactor, 0, 255);

      // 共通カソード用(値そのまま)
      // analogWrite(RED_PIN, r);
      // analogWrite(GREEN_PIN, g);
      // analogWrite(BLUE_PIN, b);

      //Write PWM values using ledcWrite (from chatGPT)
      ledcWrite(RED_PIN, correctedR);  // channel 0 → RED
      ledcWrite(GREEN_PIN, correctedG);  // channel 1 → GREEN
      ledcWrite(BLUE_PIN, correctedB);  // channel 2 → BLUE

      // 共通アノード用(反転値)
      // analogWrite(RED_PIN, 255 - r);
      // analogWrite(GREEN_PIN, 255 - g);
      // analogWrite(BLUE_PIN, 255 - b);
    }
  }
}