Labs
Lab - Intro to Serial Communication
ASCII vs Binary. What are you sending?
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
Flow Control: Call & Response (Handshaking)
Established a handshaking protocol to read values only when sending data.
Lab - P5.js Serialport Library (Input & Output)
Connected to the information being sent out from the Arduino.
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);
}
// 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);
}
}