Labs | Asynchronous Serial Communication

Labs | Asynchronous Serial Communication

Labs

Lab - Intro to Serial Communication

ASCII vs Binary. What are you sending?

image
Getting the output as specified in the lab.
Getting the output as specified in the lab.
Output ranges from 0 to 1023
Output ranges from 0 to 1023
Output ranges from 0 to 255
Output ranges from 0 to 255

Formatting Multiple Serial Data: Punctuation

Reading multiple values from my rotary encoder and the push button.

Note: I had to modify the blue pin's location to be on the ground for the switch work as intended

image

Flow Control: Call & Response (Handshaking)

Established a handshaking protocol to read values only when sending data.

image

Lab - P5.js Serialport Library (Input & Output)

Connected to the information being sent out from the Arduino.

image

P5 Sketch - Connecting the Rotary Encoder with the

For this rotary encoder I didn't use the handshake protocol. If the button is pressed then rotating makes the square move. Otherwise it changes the size of the square. Link to P5 Sketch

// Arduino Rotary Encoder Code
#define CLK 14
#define DT 15
#define SW 16

int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;

void setup() {
  
  // Set encoder pins as inputs
  pinMode(CLK,INPUT);
  pinMode(DT,INPUT);
  pinMode(SW, INPUT_PULLUP);

  // Setup Serial Monitor
  Serial.begin(9600);

  // Read the initial state of CLK
  lastStateCLK = digitalRead(CLK);
}

void loop() {
  // Read the current state of CLK
  currentStateCLK = digitalRead(CLK);

  // If last and current state of CLK are different, then pulse occurred
  // React to only 1 state change to avoid double count
  if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){

    // If the DT state is different than the CLK state then
    // the encoder is rotating CCW so decrement
    if (digitalRead(DT) != currentStateCLK) {
      counter--;
      currentDir ="CW";
    } else {
      // Encoder is rotating CW so increment
      counter++;
      currentDir ="CCW";
    }

    // Write the data    
    Serial.print(currentDir);
    Serial.print(",");
    Serial.print(counter);
    Serial.print(",");
    Serial.print(digitalRead(2)); // Read btn status
    Serial.println();
  }

  // Remember last CLK state
  lastStateCLK = currentStateCLK;

  // Read the button state
  int btnState = digitalRead(SW);

  //If we detect LOW signal, button is pressed
  if (btnState == LOW) {
    //if 50ms have passed since last LOW pulse, it means that the
    //button has been pressed, released and pressed again
    if (millis() - lastButtonPress > 50) {
//      Serial.println("Button pressed!");
    }

    // Remember last button press event
    lastButtonPress = millis();
  }

  // Put in a slight delay to help debounce the reading
  delay(1);
}
image
// P5.js code

let serial;
let counter = 10;
let rotaryDirection = "CW";
let buttonPressed = false;
let circleSize = 10;
let angle = 0;
let inData = '';
let btn = false;
let portName = '/dev/tty.usbmodem14401';

function setup() {
  createCanvas(400, 400);
  serial = new p5.SerialPort();
  serial.on('list', printList);
  serial.on('connected', serverConnected);
  serial.on('open', portOpen);
  serial.on('data', serialEvent);
  serial.on('error', serialError);
  serial.on('close', portClose);
  serial.list(); // list the serial ports
  serial.open(portName, {
    baudRate: 9600
  });

  rectMode(CENTER);
  
  // Request data every 300 miliseconds
  setInterval(() => {
    serial.write(byte("\n"));
  }, 300);
}

function draw() {
  let c = radians((angle * 10) % 360) ;
  background(245);
  text(`${angle}, ${btn}, ${buttonPressed}, ${circleSize}`, 10, 20);
  
  push()
  translate(width / 2, height / 2);
  rotate(c);
  rect(0, 0, circleSize, circleSize);
  pop()
}

function keyPressed() {
  serial.write(byte("\n"));
}


// Get the list of ports:
function printList(portList) {
  portList.forEach((port, i) => {
    console.log(i + port);
  })
}

function serverConnected() {
  serial.clear();
  console.log('connected to server.');
}

function portOpen() {
  console.log('the serial port opened.')
}

function serialEvent() {
  inData = serial.readLine();
  [rotaryDirection, cnt, btn] = inData.split(",")
  console.log([rotaryDirection, cnt, btn])

  if (rotaryDirection === "") {
    return
  }

  // Handle btn
  if (btn === "1") {
    buttonPressed = true;
  } else {
    buttonPressed = false;
  }
    
  if (!buttonPressed) {
    if (rotaryDirection === "CW") {
      angle++;
    } else {
      angle--;
    }
  } else {
    if (rotaryDirection === "CW") {
      circleSize = circleSize + 5
    } else {
      circleSize = circleSize - 5;
    }
  }

}

function serialError(err) {
  console.log('Something went wrong with the serial port. ' + err);
}

function portClose() {
  console.log('The serial port closed.');
}

P5 Sketch that follows the handshake protocol

I've combined the remaining two labs to read and write data and following the handshake code from earlier.

P5 keeps requesting data at an interval of 300ms at which point the hardware provides it. Otherwise there's no information provided.

let serial;
let counter = 10;
let circleSize = 10;
let inData = '';
let portName = '/dev/tty.usbmodem14401';
let clk, dt, sw, btn;

// Code to detect behavior of encoder
let currentStateCLK;
let lastStateCLK;
let currentDir = "CW";
let lastButtonPress = 0;
let isButtonPressed = false;

function setup() {
  createCanvas(400, 400);
  serial = new p5.SerialPort();
  serial.on('list', printList);
  serial.on('connected', serverConnected);
  serial.on('open', portOpen);
  serial.on('data', serialEvent);
  serial.on('error', serialError);
  serial.on('close', portClose);
  serial.list(); // list the serial ports
  serial.open(portName, {
    baudRate: 9600
  });

  // Request data every 300 miliseconds
  setInterval(() => {
    serial.write(byte("\n"));
  }, 300);
}

function draw() {
  background(245);
  text(inData, 10, 20);
  text(`clk ${clk} | sw ${sw} | dt ${dt} | btn ${btn}`, 10, 60);
  text(`Counter: ${counter} | Direction ${currentDir} | Button Pressed ${isButtonPressed}`, 10, 40);
  text(`currentState: ${currentStateCLK} | Direction ${lastStateCLK} | Button Pressed ${isButtonPressed}`, 10, 90);
  // ellipse()
}

function keyPressed() {
  serial.write(byte("\n"));
}


// Get the list of ports:
function printList(portList) {
  portList.forEach((port, i) => {
    console.log(i + port);
  })
}

function serverConnected() {
  serial.clear();
  console.log('connected to server.');
}

function portOpen() {
  console.log('the serial port opened.')
}

function serialEvent() {
  inData = serial.readLine();
  [clk, dt, sw, btn] = inData.split(",").map(i => Number(i))
  
  currentStateCLK = clk;
  lastStateCLK = clk;

  // Handle btn 
  if (btn === 0) { 
    isButtonPressed = false;
  } else {
    isButtonPressed = true;
  }
  
  // Handle rotary encoder
  // - If last and current state are different, then the pulse
  //   occurred. React to only 1 state change to avoid double count
  if (currentStateCLK != lastStateCLK && currentStateCLK == 1) {
    if (dt != currentStateCLK) {
      counter--;
      currentDir = "CCW";
    } else {
      counter++;
      currentDir = "CW"
    }
  }

  //If we detect LOW signal, button is pressed
  if (sw > 511) {
    //if 50ms have passed since last LOW pulse, it means that the
    //button has been pressed, released and pressed again
    if (millis() - lastButtonPress > 50) {
      isButtonPressed = true;
    } else {
      isButtonPressed = false;
    }

    // Remember last button press event
    lastButtonPress = millis();
  }
}

function serialError(err) {
  console.log('Something went wrong with the serial port. ' + err);
}

function portClose() {
  console.log('The serial port closed.');
}

Arduino Sketch for Sending Rotary Encoder & Push Button Data

#include <Encoder.h>

// Rotary Encoder Inputs
#define CLK A0
#define DT A1
#define SW A2
#define PUSHBTN 2

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

   // Set encoder pins as inputs
   pinMode(CLK,INPUT);
   pinMode(DT,INPUT);
   pinMode(SW, INPUT_PULLUP);

   while (Serial.available() <= 0) {
     Serial.println("hello"); // send a starting message
     delay(300);              // wait 1/3 second
   }
}

long oldPosition  = -999;
int sensorValue;

void loop() {
   if (Serial.available()) {
      // read the incoming byte:
      int inByte = Serial.read();
      
      // read the sensor: CLK
      sensorValue = analogRead(CLK);
      // print the results:
      Serial.print(sensorValue);
      Serial.print(",");
 
      // read the sensor: DT
      sensorValue = analogRead(DT);
      // print the results:
      Serial.print(sensorValue);
      Serial.print(",");

      // read the sensor: DT
      sensorValue = analogRead(DT);
      // print the results:
      Serial.print(sensorValue);
      Serial.print(",");
 
      // read the sensor:
      sensorValue = digitalRead(PUSHBTN);
      // print the results:
      Serial.println(sensorValue);
   }
}