12. Interface and application programming¶
Amsterdam, April 22, 2020
To do¶
Description | status |
---|---|
Group assignment: | done |
Document group assignment | done |
write an application that interfaces a user with an input &/or output device that you made | done |
write an application with Processing | done |
get it to work with the OLED monitor board | done |
Make a |
done |
See if you can make a keyboard simulation | done |
Make a bitmap and display it on the monitor | tried a couple of different things but I did not get it to work. |
Source files¶
Description | link |
---|---|
Monitor on/off Arduino IDE code for my board | Downloadable zip. |
Monitor on/off Processing DE code | Downloadable zip. |
Hello world + on/off Processing | Downloadable zip. |
Hello world + on/off Arduino | Downloadable zip. |
Keyboard in Processing | Downloadable zip. |
Typing multiple chars on Oled Arduino code | Downloadable zip. |
urls¶
Description | link |
---|---|
Index of this week’s topic | http://academy.cba.mit.edu/classes/interface_application_programming/index.html |
Global lecture video | https://vimeo.com/412495586 |
Global review video | https://vimeo.com/413242268 |
Group assignment documentation | https://fabacademy.org/2020/labs/waag/groupAssignments/week12.html |
Group assignment¶
A full description of the group assignment can be found on our communual page.
For the group assignment we had to ‘compare as many tool options as possible’. Here is what we compared:
Nathan: Phyton
Hyejin: Node red
Harm: block-based visual programming language
Tessel: Processing
I documented the use of Processing on the group page. On Tuesday morning we got together online and discussed how the different tools compare. What I learned is that there are many different approaches to programming. Hyejin used Node red which are blocks you can link together. But that does not mean it is easy. Because just as with Arduino IDE, if you want to combine different example codes it gets harder. Harm tried a lot of ‘easy’ block building platforms. But as soon as you want to use them to drive a device they aren’t easy any more. That is good to know. Nathan’s Python looked a lot like Processing and Arduino in terms of structure.
I learned that there are many different platforms and methods but what ever you choose, you’ll always will benefit from understanding the basic logic of coding. I also learned that from my individual assignment. Fiddling around with example code is fun up to a point. After that it’s wiser to spend some time understanding the logic and to start to think for yourself.
Individual assignment: write a user interface application¶
This weeks individual assignment is: ‘write an application that interfaces a user with an input &/or output device that you made’
Write an application with Processing¶
Henk advised the Processing coding software might be a good fit for me, so that is what I will try. Processing looks very much like the Arduino IDE. Or rather, Arduino looks like Processing. It was modelled after it.
To start up Processing, download it, cd into Processing directory /Downloads/processing-3.5.4/
and run ./processing
.
I started with a textual tutorial. The panel is called the Processing Development Environment (PDE).
Export application: exports all files in a single folder. The application folders are erased and re-created each time you use the Export Application command, so be sure to move the folder elsewhere if you do not want it to be erased with the next export. This is only valid for the same sketch. Different sketches export to different directories.
Right click on a reference to have it explained via a local webpage. Under Help > Reference
you can find the entire reference book which is also displayed as a local webpage.
Static sketch: series of functions that performs a task or creates an image without animation of interaction.
Interactive program: series of frames by adding setup()
and draw()
. These are build in functions that are called automatically.
Draw a line with the mouse
void setup() {
size(400, 400);
stroke(255);
background(192, 64, 0);
}
void draw() {
line(150, 25, mouseX, mouseY);
}
From the tutorial: ‘The setup()
block runs once, and the draw()
block runs repeatedly. As such, setup()
can be used for any initialization; in this case, setting the screen size, making the background orange, and setting the stroke color to white. The draw()
block is used to handle animation. The size()
function must always be the first line inside setup()
.’
Export as application: The Processing environment can bundle the sketch into an application with just one click. Select File > Export Application
to package your current sketch as an application.
This is cool: I export some example code as application. I cd into the directory ~/sketch_200423_mouse/application.linux64$
and run ./sketch_200423_mouse
and voila! the application runs on my computer. So I take the example code of drawing a line with the mouse, export it as application, and:
Processing includes Java runtime in the application folder, that means the files that are needed to run it are part of the app. It does make the files very large though, 256MB for just that simple script. You can export for Linux and Windows. MacOS is only possible from a Mac itself.
Connect Processing to OLED board¶
I then looked at a Sparkfun tutorial on connecting Processing to Arduino. I’ll try it out in the Arduino device first and then move on to my own board.
Processing and the Arduino IDE work well together
To find the serial port of Arduino I type dmesg
but no port is shown. Perhaps it works only for FTDI? I find the port number with:
ls /dev/tty*
.
The port can be either /dev/ttyUSB*
or /dev/ttyACM*
. It is /dev/ttyACM0
.
Talking from Arduino to Processing¶
For the Sparkfun tutorial I load a hello world
script on the Arduino. Important are the Serial
commands. These make it happen that Processing and the device communicate over the serial port.
void setup()
{
//initialize serial communications at a 9600 baud rate
Serial.begin(9600);
}
void loop()
{
//send 'Hello, world!' over the serial port
Serial.println("Hello, world!");
//wait 100 milliseconds so we don't drive ourselves crazy
delay(1000);
}
Then in Processing I use example code that should output the ‘Hello world’ the Arduino is producing in the console of Processing.
The first line is the library that takes care of a lot of the work for the serial communication.
Processing code
import processing.serial.*;
Serial myPort; // Create object from Serial class
String val; // Data received from the serial port
void setup() {
size(400, 400);
// I know that the first port in the serial list on my mac
// is Serial.list()[0].
// On Windows machines, this generally opens COM1.
// Linux: type: `ls /dev/tty*`. The port can be either `/dev/ttyUSB*` or `/dev/ttyACM*`
// 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
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
}
println(val); //print it out in the console
}
But I get an error saying serial port /dev/ttyACM0: Port busy
.
I have the Arduino serial monitor running. When I turn it off the Processing monitor is just gray.
The tutorial is in Processing v2 and I am running Processing v3. There is a warning at startup (of Processing) that v2 programs may not compatible with v3. I consider if this is the problem when I find something weird in one of my open terminals:
This is the terminal in which I run: ./processing
. I thought the serial output would be in the little console of Processing but the output is in the terminal. Another weird thing is that the terminal also says that the port is busy, but later starts to output ‘hello world’. Odd. Maybe there was something else as well.
Yes, I found it: if you run the serial monitor of the Arduino, Processing can’t connect to the port too. But if you close the Arduino serial monitor, Processing can access the port.
Hey! And now both the terminal and the Processing console are hello worlding me.
Talking from Processing to Arduino¶
The next step of the Sparkfun tutorial is to have Processing talk to Arduino.
I load example code in Processing: if you click with the mouse in the console a ‘1’ is outputted in the console.
Then the in the Arduino code it is defined that if the MCU receives a 1, it should put the LED pin HIGH. Now when you click a ‘1’ in the console the Arduino LED on pin 13 blinks. This is awesome!
Arduino IDE code
char val; // Data received from the serial port
int ledPin = 13; // Set the pin to digital I/O 13
void setup() {
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
if (Serial.available())
{ // If data is available to read,
val = Serial.read(); // read it and store it in val
}
if (val == '1')
{ // If 1 was received
digitalWrite(ledPin, HIGH); // turn the LED on
} else {
digitalWrite(ledPin, LOW); // otherwise turn it off
}
delay(10); // Wait 10 milliseconds for next reading
}
Processing code:
import processing.serial.*;
Serial myPort; //the Serial port object
String val;
// since we're doing serial handshaking,
// we need to check if we've heard from the microcontroller
boolean firstContact = false;
void setup() {
size(200, 200); //make our canvas 200 x 200 pixels big
// initialize your serial port and set the baud rate to 9600
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
}
void draw() {
//we can leave the draw method empty,
//because all our programming happens in the serialEvent (see below)
}
void serialEvent( Serial myPort) {
//put the incoming data into a String -
//the '\n' is our end delimiter indicating the end of a complete packet
val = myPort.readStringUntil('\n');
//make sure our data isn't empty before continuing
if (val != null) {
//trim whitespace and formatting characters (like carriage return)
val = trim(val);
println(val);
//look for our 'A' string to start the handshake
//if it's there, clear the buffer, and send a request for data
if (firstContact == false) {
if (val.equals("A")) {
myPort.clear();
firstContact = true;
myPort.write("A");
println("contact");
}
}
else { //if we've already established contact, keep getting and parsing data
println(val);
if (mousePressed == true)
{ //if we clicked in the window
myPort.write('1'); //send a 1
println("1");
}
// when you've parsed the data you have, ask for more:
myPort.write("A");
}
}
}
In the third part of the tutorial Arduino and Processing are talking to each other. The two previous examples are combined to have Processing receive ‘hello world!’ and the Arduino LED is toggled with the mouse. This works too.
Testing on my OLED board¶
Next I try the first ‘Hello world!’ example that works on the Arduino in my own board.
I set the Arduino IDE to the ATtiny3216.
I run python -m serial.tools.list_ports
to get the right port.
I upload the sketch but unsuccesful. AVRdude keeps trying. To stop the process: pkill avrdude
. Oops, clicked the Arduino IDE upload button, but must of course use pyupdi. See week11.
I run
/home/txl/.local/bin$ python3 pyupdi.py -d tiny3216 -c /dev/ttyUSB1 -b 57600 -f /tmp/arduino_build_263448/hello-world-processing.ino.hex -v
Programming succesfull.
I run the ‘hello world processing code’. I get error opening serial port, incorrect serial port.
Just to be sure I download a Processing application that helps you find your port. But I have the right port.
For it to work I have to change the portname in the Processing code:
myPort = new Serial(this, "/dev/ttyUSB0", 9600);
(The example code that worked with Arduino was: myPort = new Serial(this, portName, 9600);
)
Now my Oled board is outputting hello world:
Building interface for Arduino¶
I follow this Youtube tutorial. It builds a Sketch in Arduino and a Sketch in Processing. The result should be that pressing a button in the Processing Sketch lights up a LED in the Arduino. It uses the controlP5
library to make objects. The tutorial does not provide the code in a file, so I am typing along with the video. This actually helps a lot in understanding what each part does.
Processing outputted: "calibri light bold" is not available, so another font will be used. Use PFont.list() to show available fonts
‘
I place PFont.list();
in the code and right-click on it and selectFind in Reference
and a webpage opens that explains more about it. You can do this for all the commands.
The page explains you can only use fonts that are in tne data
folder. (Same goes for a picture you want to use. Place it in the data folder and you can call on it.)
This command will output all fonts available:
String[] fontList = PFont.list();
printArray(fontList);
Based on the output I changed to Ubuntu mono font. And then removed the code from the sketch.
Also handy: printArray(Serial.list());
prints all available serial ports.
And it works, when I press the RED button the LED of the Arduino lights up.
Arduino Sketch
void setup() {
pinMode(13, OUTPUT); // set pin as output
Serial.begin(9600); // start serial communication 09600bps
}
void loop() {
if(Serial.available()){ //id data is available to read
char val = Serial.read();
if(val == 'r'){ // if r received
digitalWrite(13, HIGH); // turn on led
}
}
}
Processing Sketch
import controlP5.*; //import control library
import processing.serial.*;
Serial port;
ControlP5 cp5; //create controlP5 object
PFont font;
void setup(){
size(300, 400); //window size
printArray(Serial.list()); // prints all available serial ports
port = new Serial(this, "/dev/ttyACM0", 9600); // The port Arduino is connected to
cp5 = new ControlP5(this);
font = createFont("Ubuntu Mono", 20);
cp5.addButton("red") // add button to window
.setPosition(100, 50) // x and y coordinates upper left
.setSize(100, 80) // width, height
.setFont(font)
;
cp5 = new ControlP5(this);
cp5.addButton("yellow") // add button to window
.setPosition(100, 150) // x and y coordinates upper left
.setSize(100, 80) // width, height
.setFont(font) // set font
;
}
void draw() { //same as loop in Arduino
background(150, 0 ,150); //background color
//title for window
text("LED CONTROL", 80, 30); //text + coordinate
textFont(font);
}
// Adding functions to button. Each button sends a particular (char) character
//over the serial port.
void red (){ // the first button is named red
port.write('r'); // In the Arduino sketch we wrote 'if(val == 'r') '
}
I export the Processing Sketch as application File > export application
. Cd into the directory where the app is stored. Run: ./sketch_name
and I have a stand alone application controlling the Arduino.
Arduino graphics library https://www.arduino.cc/en/Reference/ArduinoGraphics https://processing.org/tutorials/
Tiny4kOLED library & interfacing¶
First I load a Tiny4kOLED example sketch from Studio Pieters, on my AT3216 board, to see if it works:
cd to ~/.local/bin
and run: python3 pyupdi.py -d tiny3216 -c /dev/ttyUSB0 -b 57600 -f /tmp/arduino_build_645272/studio-pieters.ino.hex -v
Tiny4kOLED does not work.
Adafruit does:
python3 pyupdi.py -d tiny3216 -c /dev/ttyUSB0 -b 57600 -f /tmp/arduino_build_342796/I2C-example-Ada.ino.hex -v
Even though Adafruit works, I do want to run the I2C scanner to make sure I have the right address (see week11). So I load the I2C scanner on my board:
python3 pyupdi.py -d tiny3216 -c /dev/ttyUSB0 -b 57600 -f /tmp/arduino_build_926314/IcCscanner.ino.hex -v
Then start the Python serial monitor: python -m serial.tools.miniterm /dev/ttyUSB0 9600
It outputs garble. Change the baudrate to 9600 on a hunch. Output: Scanning... No I2C devices found
.
I go back to the tutorial from week11 and realize I haven’t connected my monitor to the board. And that is what the scanner is scanning for. So now I get the address: 0x3c
.
I use an example code from the Tiny4kOLED that simply displays a bit map image on the screen. It works on my board. (I think the previous try of installing the Tiny4kOLED did not work because in that example file the wire.h
library was not imported in the code.)
The original code is: (abbreviated-comments removed for brevity)
// Code is from https://www.studiopieters.nl/attiny85-oled-i2c/
#include <Wire.h>
#include <Tiny4kOLED.h>
#include "SolomonSystech.h"
void setup() {
oled.begin();
oled.clear();
oled.bitmap(6, 0, 6 + 37, 4, solomon_systech_logo_bitmap);
oled.bitmap(54, 0, 54 + 69, 4, solomon_systech_text_bitmap);
// Now that the display is all setup, turn on the display
oled.on();
}
void loop() {
// This example only shows a static image on the display.
// The microcontroller could be turned off now.
}
I adjusted the code to include the code for calling on the serial port that I learned in the tutorial described above. The program displays the bitmap image. Then use the Processing code from the same tutorial. When you press the ‘red’ button in Processing the screen is cleared.
#include <Wire.h>
#include <Tiny4kOLED.h>
#include "SolomonSystech.h"
// ============================================================================
void setup() {
oled.begin();
oled.clear();
oled.bitmap(6, 0, 6 + 37, 4, solomon_systech_logo_bitmap);
oled.bitmap(54, 0, 54 + 69, 4, solomon_systech_text_bitmap);
oled.on();
Serial.begin(9600); // start serial communication 09600bps
}
void loop() {
// This example only shows a static image on the display.
// The microcontroller could be turned off now.
if(Serial.available()){ //id data is available to read
char val = Serial.read();
if(val == 'r'){ // if r received
oled.clear(); // clear the screen
}
}
}
- I get the monitor to turn of with the Processing application. But I can not get it to turn on again. I look in the SSD1306 datasheet and find some interesting things:
- ‘I2C-bus data signal SDA (SDAOUT/D2 for output and SDAIN/D1 for input) and I2C-bus clock signal SCL (D0). Both the data and clock signals must be connected to pull-up resistors. RES# is used for the initialization of device.’
I was wondering how people know they have to put resistors in their schematic. I indeed placed to resistors at SCL and SDA in my board, but did that because I saw others do it. Now I read in the datasheet, that SDA and SCL must have pull-up resistors. So that is how you find out. - Perhaps the following means that if you pull the pin is HIGH the data written to the monitor will be displayed on the monitor:
- ‘Command Decoder This module determines whether the input data is interpreted as data or command. Data is interpreted based upon the input of the D/C# pin. If D/C# pin is HIGH, D[7:0] is interpreted as display data written to Graphic Display Data RAM (GDDRAM). If it is LOW, the input at D[7:0] is interpreted as a command. Then data input will be decoded and written to the corresponding command register.’
- Yes the GDDRAM holds the data that is to be displayed on the monitor.
- ‘The GDDRAM is a bit mapped static RAM holding the bit pattern to be displayed’
I find the on/off function in the datasheet:
‘These commands set the display to one of the two states: oAEh : Display OFF oAFh : Display ON’.
But I have no idea how to translate that to code that can be read by Arduino. Instead I test another library: SSD1206ASCII. For this library I found the on/off command somewhere online:
if(val == 'r'){ // if r received
oled.ssd1306WriteCmd(SSD1306_DISPLAYON);
}
if(val == 'y'){ // if y received
oled.ssd1306WriteCmd(SSD1306_DISPLAYOFF);
}
This works on Arduino but not on my own board. Perhaps this library is not compatible with my board. But by comparing the libraries I realize that what they each do in their own way is defining the OLED monitor. In the Tiny4k library the monitor is defined as oled
. This is not defined in the code so that is probably done by the library. The ASCII libary defines the monitor in the coding space above void setup
: SSD1306AsciiAvrI2c oled;
I also realize there is no universal on/off command (other then the one in the datasheet) but that this varies per library. I search for Tiny4kOled commands which I find on this Github page.
oled.on();
is the command for on
it states and I guess correctly, that oled.off();
. This must be added to void setup
. After that you can use the command in the void loop
.
Then it works on my board:
The final code for arduino is:
/*
* Tiny4kOLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x32 displays
*
* Based on ssd1306xled, re-written and extended by Stephen Denne
* from 2017-04-25 at https://github.com/datacute/Tiny4kOLED
*
*/
// To use the Wire library:
#include <Wire.h>
#include <Tiny4kOLED.h>
#include "SolomonSystech.h"
// ============================================================================
void setup() {
// put your setup code here, to run once:
oled.begin();
// Two rotations are supported,
// The begin() method sets the rotation to 1.
//oled.setRotation(0);
oled.clear();
oled.on(); // turn display on
oled.off(); // turn display off
oled.bitmap(6, 0, 6 + 37, 4, solomon_systech_logo_bitmap);
oled.bitmap(54, 0, 54 + 69, 4, solomon_systech_text_bitmap);
// Now that the display is all setup, turn on the display
oled.on();
Serial.begin(9600); // start serial communication 09600bps
}
void loop() {
// This example only shows a static image on the display.
// The microcontroller could be turned off now.
if(Serial.available()){ //id data is available to read
char val = Serial.read();
if(val == 'r'){ // if r received
oled.on(); // turn screen on
}
if(val == 'y'){ // if y received
oled.off(); // turn screen off
}
}
}
The final code for Processing is:
import controlP5.*; //import control library
import processing.serial.*; // import serial library
Serial port;
ControlP5 cp5; //create controlP5 object
PFont font;
void setup(){
size(300, 400); //window size
printArray(Serial.list()); // prints all available serial ports
port = new Serial(this, "/dev/ttyUSB0", 9600); // The port Arduino is connected to
cp5 = new ControlP5(this);
font = createFont("Ubuntu Mono", 20);
cp5.addButton("on") // add button to window
.setPosition(100, 50) // x and y coordinates upper left
.setSize(100, 80) // width, height
.setFont(font)
;
cp5 = new ControlP5(this);
cp5.addButton("off") // add button to window
.setPosition(100, 150) // x and y coordinates upper left
.setSize(100, 80) // width, height
.setFont(font) // set font
;
}
void draw() { //same as loop in Arduino
background(150, 0 ,150); //background color
//title for window
text("Screen on / off", 80, 30); //text + coordinate
textFont(font);
}
// Adding functions to button. Each button sends a particular (char) character
//over the serial port.
void on(){ // the first button is named 'on'
port.write('r'); // In the Arduino sketch we wrote 'if(val == 'r')'
}
void off(){
port.write('y');
}
Exporting application¶
I export the Processing code as application file > export application
. Cd into the directory and run ./>filename>
. At first there is an error because the app isn’t listening on the right port. That means the port is hardcoded into the app. That is not very good. There are probably ways to make the app choose the correct port itself. But for now I set the right port in the code and re-export the application. Now I can turn the monitor on and off from an stand-alone application.
Making my own bitmap¶
So far, I have only used bitmaps from the examples. I tried making my own bitmap and display it on the monitor. But I did not succeed. Here is a tutorial on creating bitmaps. They use the the online image2cpp converter but I did not get a working bitmap out of it. I also tried just exporting an image as .bmp in Gimp. There are formats for which that works in Gimp: just save the file and add the extension of the format you want. For instance, when you have an .PNG you can just save it as .JPG and it will be a working .JPG file. But that does not work for .bmp. I did not put a lot of time in this task because it is not crucial to the assignment.
making my own interface¶
Using the handy library for Processing I’m going to make a nicer interface. Here is a getting started page and here the reference overview. In the first lines you call the handy library and also the handy renderer:
import org.gicentre.handy.*;
HandyRenderer h;
Under Help > Reference
and Help > Libraries reference
I open the reference page for Processing in general and for the Handy library in particular. This way I don’t have to look up everything I want to do on the internet.
I’ll make an interface and keep comments of what I do in the code. I won’t be double posting it in this general documentation.
I use computerhope.com to find the codes for the hex colors. And also encycolorpedia
Took a while to figure out how to change colors. This example on the prcessing forum made it clear
.setColorBackground(color(0, 0, 255)) //top of slider color r,g,b
.setColorForeground(color(0, 255, 0)) //botom of slider color r,g,b
.setColorValue(color(255, 255, 255)) //vall color r,g,b
.setColorActive(color(255, 0, 0)) //mouse over color
I tried for a while with the Handy library. It looks nice but you seem to only be able to make hand-drawn-like shapes. They look nice but for an entire interface it is a bit much. Here is the code:
import org.gicentre.handy.*; // import the handy library for hand-drawn-like sketching
HandyRenderer h; // calls on the handy renderer that does the heavy lifting.
void setup() // initialize the application
{
size (600,400); // size of the panel of the app
h = new HandyRenderer(this); // defining 'h' as the call-up for handy objects within
// the panel
}
void draw() // Here animated/interactive code takes place.
{
background(#B2C248); // setting background color of panel with hex.
h.setBackgroundColour(color(#82CAFF));
h.setFillGap(0);
h.setFillWeight(0);
h. rect (175,50,50,100); // call-up rectangle to make. First numbers are
//position, second numbers are size.
noLoop(); // without this, the shape will jitter as if it's lines are redrawn
}
And then I went on using the ControlP5
library for making an interface.
The idea is to make a keyboard that outputs what you write on the monitor. I do not know if I will succeed in doing that. The first step is to replicate the on/off button I made earlier. This works.
Here is the code. I removed most of the buttons from the program because the code is the same for each and it makes the program very long
// processing keyboard interface
import controlP5.*; //import control library
import processing.serial.*; // importing serial communication library
Serial port;
ControlP5 cp5; // define to create controlP5 object
PFont font; // set font
void setup() /// initialize
{
size(600, 400); // panel size
printArray(Serial.list()); // prints all available serial ports
port = new Serial(this, "/dev/ttyUSB1", 9600); // The port device is connected to
cp5 = new ControlP5(this);
font = createFont("Montserrat Medium", 20); // define font
cp5.addButton("dummy1") // dark rectangle to give button an outline
.setPosition(99, 84) // x and y coordinates
.setSize(152, 72) // width, height
.setFont(font) // call on font
.setColorBackground(color(#002952)) // color rectangle
;
cp5.addButton("dummy2") // dark rectangle to give button an outline
.setPosition(349, 84) // x and y coordinates upper left
.setSize(152, 72) // width, height
.setFont(font)
.setColorBackground(color(#821c17)) // rectangle
;
cp5.addButton("on") // add button 'on' to panel
.setPosition(100, 85) // x and y coordinates upper left
.setSize(150, 70) // width, height
.setFont(font)
.setColorBackground(color(#567d46)) // color button
.setColorForeground(color(#6b9c58)) // color mouse-over
;
cp5.addButton("off") // add button 'off' to panel
.setPosition(350, 85)
.setSize(150, 70)
.setFont(font)
.setColorBackground(color(#952f2a))
.setColorForeground(color(#cb2c24))
;
cp5.addButton("Q") // add button 'Q' to panel
.setPosition(50, 185) // x and y coordinates upper left
.setSize(40, 40) // width, height
.setFont(font)
.setColorBackground(color(#223546))
.setColorForeground(color(#5480ac))
;
// This goes on for all the buttons on the screen.
// Removed for brevity.
}
void draw() // starting loop
{
background(#b5c5d9); // background color of panel
fill(#000B34); // color of background text in the panel (text outline)
text("post-colla networking", 110, 45); //text + coordinates
textFont(font, 30); // calling font, setting font size
fill(#ffffff); // color of main text in panel
text("post-colla networking", 112, 47); //Slightly different coordinates
textFont(font, 30);
fill(#000B34); // falling 'p' in text in the panel
text("p", 260, 49);
textFont(font, 30);
fill(#ffffff); // Text again in black to create illusion of text outline
text("p", 262, 51);
textFont(font, 30);
// removed code for falling 's' and 'e' for brevity.
}
void on() // first button is named on
{
port.write('1'); // In the Arduino sketch we wrote 'if(val == 'r')'
}
void off(){
port.write('0');
}
Next I am going to try to display letters typed in the Processing application on the monitor. The device must listen to the serial port. If it receives data it should output it on the monitor.
There are a lot of examples of printing to an OLED monitor and examples of printing to the serial monitor. I am going to combine the codes to print data received on the serial port to the OLED.
Here are some helpfull sources about OLED monitors and/or serial communication:
Lengthy tutorial with many things you can do with OLED. Uses the Adafruit library.
A tutorial on serial communication. Using three examples the basics of serial comms are being explained.
Here is the Arduino reference guide for serial communication.
An Arduino forum thread on debugging non-working OLED+serial.
Making use of these sources I combine two programs. One program from the Arduino reference guide. This program listens to the serial port and if it receives data it outputs something to the serial monitor. The other program is the one I used before from studio Pieters. Originally it printed a bitmap on the monitor. Then I adjusted it to the ‘on/off program’. Now I adjusted it again:
//helloworld_receiving_arduino
#include <Wire.h>
#include <Tiny4kOLED.h>
int incomingByte = 0; // for incoming serial data
void setup() {
oled.begin(); // Send the initialization sequence to the oled.
//This leaves the display turned off
oled.clear(); // Clear the memory before turning on the display
oled.on(); // Turn on the display
oled.switchRenderFrame(); // Switch the half of RAM that we are writing to,
//to be the half that is non currently displayed
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
oled.clear(); // Clear the non-displayed half of the memory to all black
// (The previous clear only cleared the other half of RAM)
oled.setFont(FONT8X16); // The characters in the 8x16 font are 8 pixels wide and 16 pixels tall
oled.setCursor(12, 0); // Position the cursor. X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
oled.print(F("Hello World!")); // Write the text to oled RAM (which is not currently being displayed)
// Wrap strings in F() to save RAM!
if (Serial.available() > 0) // reply only when you receive data:
{
incomingByte = Serial.read(); // read the incoming byte:
oled.print("I received: "); // say what you got:
oled.println(incomingByte, DEC); // print what you got
}
oled.switchFrame(); // Swap which half of RAM is being written to, and which half is being displayed
delay(3000);
}
What you can see in the picture is that monitor displays:’I received’ and then prints numbers. After 3000 ms the screen clears. This is because the Arduino receives data on half of its RAM and prints what is in the other half of it’s RAM. The oled.switchFrame();
line switches to the other half of RAM after the delay(3000);
.
You can also see that the ‘I’ of ‘I received’ is on the top line. I also have to look into having it displayed on the right lines. This can be done with the something like start cursor
Next up:
- test if it works with my Processing interface.
- print letters instead of numbers.
- get it to work on my OLED board.
- get on/off switch to work too.
- get text to start on the right line.
-
test if it works with my Processing interface.
It works with both the ‘on/off’ and the ‘keyboard’ interfaces I made. -
print letters instead of numbers.
I use the tutorial on serial communication again. Interesing: ‘At 9600 baud about 960 characters arrive per second which means there is a gap of just over 1 millisecond between characters.’
I try several ways of combining serial port listening code and OLED monitor code. But I don’t get it to work. Aa I trial and error my way across many example codes I pick up snippets of information. Like how different libraries use different commands. And that they aren’t called commands but structures and values and functions and classes. It matters a lot where you place the curly bracket and sometimes I would reason something should go in void setup but it turns out to be a loop function and vice versa.
Rather then randomly trying to combine existing codes, I should take a step back and look into some overviews. Understand the logic better so I have a more clear idea of what I am doing.
Presently, it’s 11.00 a.m. on the Wednesday and local review starts in an hour. So I take a short cut, abandon the tiny4kOLED library and switch to Adafruit’s much larger but also much better documented library.
The first code I try works on the Arduino and works on my board. When I pair it with my Processing interface it works too. Processing, by the way, doesn’t seem to mind anything. It always works with whatever port or device you appoint it to. Nice that.
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET -1 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 display(OLED_RESET);
char inChar;
String string;
void setup() {
pinMode(13, OUTPUT);
// initialize with the I2C addr 0x3C / mit I2C-Adresse 0x3c initialisieren
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
Serial.begin(115200);
string.reserve(200);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(0.5);
display.setTextColor(INVERSE);
}
void loop()
{
if (Serial.available()) {
display.clearDisplay();
inChar = Serial.read();
string+=inChar;
display.setCursor(0,0);
display.print(string);
display.display();
if( inChar == '\r'){
Serial.println("End");
delay(1000);
string="";
}
}
display.display();
}
The example code on Arduino worked. But you could write 4 lines and then you’d have to reboot. The screen would not clear after the four lines. Perhaps adding oled.switchFrame();
might help but that is a function (structure?, class?) from the Tiny4k library so I’d have to find its equivalent and I am running out of time.
When I load the code on my own board and connect it to the Python serial monitor, it behaves different. When I press Enter
, the screen clears.
I can’t try that on my Processing interface yet, because I have not added an enter key. Plus, Enter probably works different than just sending a character.
Also, I have not yet finished the keyboard on my interface. So no hello world
this time.
Allright, here is my hastily wrapped up final result.
Global lecture¶
Write an application that interfaces a user with an input and/or output device that you made.
Processor: Like arduino. But there is limit to complexity.
LabView, etc. visual coding aids. But there is limit to complexity. 1
Bash: coding on terminal, scripts for automating.
Python & Javascript
Pyserial: Python talks to device via pyserial.
FTDI: transmit + receive line
MQTT: talking to multiple devices. IoT.
Sockets: talk to the internet.
ncurses: text based user interface.
Tkinter: Python binding.
Forms HTML
canvasimage.html > drawing images in the browser.