はじめてのMKR ZERO (8) 透過OLEDディスプレイ②
前回、MKRZEROのSPIバスにSpartFunのTransparent Graphical OLED Breakoutボードをつないで、デモ・スケッチを動かしました。しかし、print()が使えず、文字が表示できません。そこで、センサなどの測定結果を表示するために、7セグメントの数字だけでも出せるようにします。
●文字をline()関数で描画する
7セグメントLEDは、七つのエレメントとドットで構成されています。
多くは上記のような名前がついているのでこれに合わせます。line()関数の引数は、始点座標x、始点座標y、終点座標x、終点座標y、線の太さ、色です。このディスプレイは色に0x01を指定すると光り、0では光らなくなります。
#define a {offsetX = 0; offsetY = 0; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7,start_offsetY,2,(color_t)&color);}
#define b {offsetX = 6; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define c {offsetX = 3; offsetY = 14; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define d {offsetX =-6; offsetY = 15; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7 ,start_offsetY,2,(color_t)&color);}
#define e {offsetX =-8; offsetY = 14; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define f {offsetX =-6; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define g {offsetX =-2; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7,start_offsetY,2,(color_t)&color);}
#define dot {offsetX = 6;offsetY = 15; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX,start_offsetY+1,2,(color_t)&color);}
数字を、これらのエレメントを合成して作ります。0~9をマクロのS0~S9で表します。
#define S0 a;b;c;d;e;f;
#define S1 b;c;
#define S2 a;b;g;e;d;
#define S3 a;b;c;d;g;
#define S4 b;c;f;g;
#define S5 a;c;d;f;g;
#define S6 a;c;d;e;f;g;
#define S7 a;b;c;
#define S8 a;b;c;d;e;f;g;
#define S9 a;b;c;d;f;g;
Arduinoのスタイル・ガイドでは、#defineは使わないほうがよいと書かれています。上記のマクロは、数字の0をS0と書くだけで、コンパイラが、そこにコードを埋め込みます。したがって、フラッシュ・メモリ領域を大量に消費します。MKRZEROは十分なメモリが搭載されているので、大丈夫だと思います。
これらのマクロを使って、任意の座標指定、任意の数字を表示する関数segments()を作成します。引数は、表示する数字、座標x、座標y、ドットの有無です。ディスプレイは左上隅が(0,0)の原点です。
void segments(byte numbers, int x, int y, bool F){
start_X = x; start_Y = y;
offsetX = 0; offsetY = 0;
start_offsetX = start_X + offsetX ; start_offsetY = start_Y + offsetY;
if (F == true) dot;
if (numbers==0) {S0;}
else if (numbers==1) {S1;}
else if (numbers==2) {S2;}
else if (numbers==3) {S3;}
else if (numbers==4) {S4;}
else if (numbers==5) {S5;}
else if (numbers==6) {S6;}
else if (numbers==7) {S7;}
else if (numbers==8) {S8;}
else if (numbers==9) {S9;}
}
例えば、
int testData=9876543;
の整数データを表示するスケッチです。文字の個数を算出し、左から順番に数字を取り出しながら表示します。1文字を表示したら、17ドット右にずらし、文字がなくなるまで表示を続けます。
x座標は10、y座標は35の位置に表示しました。
for (byte n=0; n < String(testData).length(); n++ ) {
byte i = String((String(testData).charAt(n))).toInt() ;
segments(i,10+17*n,35,0);
}
全体のスケッチです。
// By: Owen Lyke SparkFun Electronics Date: February 26, 2019
#include "HyperDisplay_UG2856KLBAG01.h" // Your library can be installed here: http://librarymanager/All#SparkFun_Transparent_Graphical_OLED
// The rest of the Layer Cake: http://librarymanager/All#SparkFun_HyperDisplay_SSD1309
// http://librarymanager/All#SparkFun_HyperDisplay
#define SPI_PORT SPI // Used if USE_SPI == 1
#define CS_PIN 7 // Used only if USE_SPI == 1
#define DC_PIN 6 // Used only if USE_SPI == 1
UG2856KLBAG01_SPI myTOLED; // Declare a SPI-based Transparent OLED object called myTOLED
uint8_t color = 0x01;
uint8_t noColor = 0x00;
#define a {offsetX = 0; offsetY = 0; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7,start_offsetY,2,(color_t)&color);}
#define b {offsetX = 6; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define c {offsetX = 3; offsetY = 14; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define d {offsetX =-6; offsetY = 15; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7 ,start_offsetY,2,(color_t)&color);}
#define e {offsetX =-8; offsetY = 14; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define f {offsetX =-6; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define g {offsetX =-2; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7,start_offsetY,2,(color_t)&color);}
#define dot {offsetX = 6;offsetY = 15; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX,start_offsetY+1,2,(color_t)&color);}
#define S0 a;b;c;d;e;f;
#define S1 b;c;
#define S2 a;b;g;e;d;
#define S3 a;b;c;d;g;
#define S4 b;c;f;g;
#define S5 a;c;d;f;g;
#define S6 a;c;d;e;f;g;
#define S7 a;b;c;
#define S8 a;b;c;d;e;f;g;
#define S9 a;b;c;d;f;g;
int start_X; int start_Y;
int offsetX; int offsetY;
int start_offsetX; int start_offsetY;
void setup() {
Serial.begin(9600);
Serial.println("\n Start");
SPI_PORT.begin();
myTOLED.begin(CS_PIN, DC_PIN, SPI_PORT); // Begin for SPI requires that you provide the CS and DC pin numbers
myTOLED.clearDisplay();
}
void segments(byte numbers, int x, int y, bool F){
start_X = x; start_Y = y;
offsetX = 0; offsetY = 0;
start_offsetX = start_X + offsetX ; start_offsetY = start_Y + offsetY;
if (F == true) dot;
if (numbers==0) {S0;}
else if (numbers==1) {S1;}
else if (numbers==2) {S2;}
else if (numbers==3) {S3;}
else if (numbers==4) {S4;}
else if (numbers==5) {S5;}
else if (numbers==6) {S6;}
else if (numbers==7) {S7;}
else if (numbers==8) {S8;}
else if (numbers==9) {S9;}
}
int testData=9876543; // integer, max 7 segments
void loop() {
myTOLED.clearDisplay();
for (byte n=0; n < String(testData).length(); n++ ) {
byte i = String((String(testData).charAt(n))).toInt() ;
segments(i,10+17*n,35,0);
}
delay(2000);
}
●距離センサと組み合わせる
第6回の「はじめてのMKR ZERO (6) 距離センサVL53L1X」のプログラムを一緒にし、testDataの代わりに読み出した距離を表示するように変更しました。表示している1667は、机の上から天井までの距離(単位mm)です。
// By: Owen Lyke SparkFun Electronics Date: February 26, 2019
#include "HyperDisplay_UG2856KLBAG01.h" // Your library can be installed here: http://librarymanager/All#SparkFun_Transparent_Graphical_OLED
// The rest of the Layer Cake: http://librarymanager/All#SparkFun_HyperDisplay_SSD1309
// http://librarymanager/All#SparkFun_HyperDisplay
#define SPI_PORT SPI
#define CS_PIN 7
#define DC_PIN 6
UG2856KLBAG01_SPI myTOLED; // Declare a SPI-based Transparent OLED object called myTOLED
#include <Wire.h>
#include <VL53L1X.h>
VL53L1X sensor;
uint8_t color = 0x01;
uint8_t noColor = 0x00;
#define a {offsetX = 0; offsetY = 0; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7,start_offsetY,2,(color_t)&color);}
#define b {offsetX = 6; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define c {offsetX = 3; offsetY = 14; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define d {offsetX =-6; offsetY = 15; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7 ,start_offsetY,2,(color_t)&color);}
#define e {offsetX =-8; offsetY = 14; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define f {offsetX =-6; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+3,start_offsetY-6,2,(color_t)&color);}
#define g {offsetX =-2; offsetY = 7; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX+7,start_offsetY,2,(color_t)&color);}
#define dot {offsetX = 6;offsetY = 15; start_offsetX =start_X + offsetX ; start_offsetY = start_Y + offsetY ;myTOLED.line(start_offsetX,start_offsetY,start_offsetX,start_offsetY+1,2,(color_t)&color);}
#define S0 a;b;c;d;e;f;
#define S1 b;c;
#define S2 a;b;g;e;d;
#define S3 a;b;c;d;g;
#define S4 b;c;f;g;
#define S5 a;c;d;f;g;
#define S6 a;c;d;e;f;g;
#define S7 a;b;c;
#define S8 a;b;c;d;e;f;g;
#define S9 a;b;c;d;f;g;
int start_X; int start_Y;
int offsetX; int offsetY;
int start_offsetX; int start_offsetY;
void setup() {
Serial.begin(9600);
Serial.println("\n Start");
SPI_PORT.begin();
myTOLED.begin(CS_PIN, DC_PIN, SPI_PORT); // Begin for SPI requires that you provide the CS and DC pin numbers
myTOLED.clearDisplay();
Wire.begin();
Wire.setClock(400000); // use 400 kHz I2C
sensor.setTimeout(500);
if (!sensor.init())
{
Serial.println("Failed to detect and initialize sensor!");
while (1);
}
sensor.setDistanceMode(VL53L1X::Long);
sensor.setMeasurementTimingBudget(50000);
Serial.println("\n VL53L1X Start");
sensor.startContinuous(50);
}
void segments(byte numbers, int x, int y, bool F){
start_X = x; start_Y = y;
offsetX = 0; offsetY = 0;
start_offsetX = start_X + offsetX ; start_offsetY = start_Y + offsetY;
if (F == true) dot;
if (numbers==0) {S0;}
else if (numbers==1) {S1;}
else if (numbers==2) {S2;}
else if (numbers==3) {S3;}
else if (numbers==4) {S4;}
else if (numbers==5) {S5;}
else if (numbers==6) {S6;}
else if (numbers==7) {S7;}
else if (numbers==8) {S8;}
else if (numbers==9) {S9;}
}
void loop() {
sensor.startContinuous(50);
int distanceL = sensor.read();
Serial.println(distanceL);
if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
myTOLED.clearDisplay();
for (byte n=0; n < String(distanceL).length(); n++ ) {
byte i = String((String(distanceL).charAt(n))).toInt() ;
segments(i,10+17*n,35,0);
}
}