- 最終更新日
- 記事公開日
スカウターを再現!透明ディスプレイでドラゴンボールの世界が現実になるかも?
ドラゴンボールの中で、相手の戦闘力を測定するために使用される『スカウター』
初期のフリーザやベジータといった敵キャラがよく付けてたハイテク装置ですね。
今回はこのスカウターを透明ディスプレイで再現してみました。
透明ディスプレイは超最新技術というわけではなく、存在自体はあったのですが、値段が高かったり透明度が低かったりと、まだまだ実用的ではありませんでした。
ところが最近になって、ようやく私のような一般人でも入手可能となり、値段も手頃なところまで落ち着いてきたので、今回購入してみました。
この記事で紹介している内容は、透明ディスプレイの応用編です。
基本的な使い方を知りたい方は、まずは下記の記事をご覧ください↓
使用部品
- 透明ディスプレイ - AliExpress
- KKHMF Pro Mini(3.3V・8M) Arduino用 - Amazon
- 3V以上のバッテリーまたは乾電池 (Panasonic EVOLTA)
- スライドスイッチ
配線図
バッテリーの消費量を抑えるために、電源をON・OFFするためのスライドスイッチを取り付けてます。
Arduino本体に搭載してあるリセットボタンを押すことで、計測をスタートしています。
電源はスペースの関係で「3.7V・300mAh リチウムポリマーバッテリー」使用しました。
もし乾電池で動かす際は「Panasonic EVOLTA」の使用がオススメです。
百円均一で購入できる乾電池では必要な量の電流を流すことができないので、正常に画面が表示されなかったり、途中でアニメーションが止まってしまいます。
プログラム
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8); // SW SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
// power set
int power_num = 0;
char power_cnt = 0;
int power_arr[6]; // 100000 - 999999
char power_arr_length;
char power_num_size = 12;
char power_x,power_y;
char power_end_flag = 0;
// circle set
char circle_size = 14;
// triange set
char triangle_cnt = 0;
char triangle_flash = 1; // 1:ON , -1:OFF
char triangle_end_flag = 0;
// line set(diagonal)
char diagonal_line_x = 0;
char diagonal_line_y = 0;
char diagonal_line_end_flag = 0;
// line set(straight)
char straight_line_x = 0;
char straight_line_end_flag = 0;
// message set
int message_y[] = {34,44,54};
String message_body[] = {"completed!","unidentified","No data..."};
int message_flag[] = {0,0,0};
char message_arr_length;
char message_font_size = 5;
char message_hiddenbox_size = 12;
char message_cnt = 0;
char message_no = 0;
char message_end_flag = 0;
// setup
void setup(void) {
//Serial.begin(9600);
//Serial.println("");
// pixel on
u8g.setColorIndex(1);
// random power number generator
randomSeed(analogRead(0));
long power_rand = random(100000, 999999);
String power_str = String(power_rand);
power_arr_length = power_str.length();
// power number position ( MAX: 128*64 )
power_x = power_num_size * power_arr_length;
power_y = 20;
// power arr set
String power_val;
for(char i=0; i<power_arr_length; i++) {
// round set
if (i>1) {
power_val = "0";
} else {
power_val = power_str.charAt(i);
}
power_arr[i] = power_val.toInt();
}
// message arr
message_arr_length = sizeof(message_y) / sizeof(int);
}
void loop(void) {
u8g.firstPage();
do {
// all end (dispay clear)
if (message_end_flag) {
u8g.setColorIndex(0);
u8g.drawBox(0, 0, 128, 64);
}
else {
// circle draw
u8g.drawCircle(100,32,circle_size);
u8g.drawCircle(100,32,circle_size + 3);
// triangle flash
if (triangle_flash == 1) {
u8g.setColorIndex(1);
} else {
u8g.setColorIndex(0);
}
// triangle draw
u8g.drawTriangle(97,5, 103,5, 100,11);
u8g.drawTriangle(100,55, 103,61, 97,61);
u8g.drawTriangle(128,29, 123,32, 128,36);
u8g.drawTriangle(77,32, 72,29, 72,36);
u8g.setColorIndex(1);
// diagonal_line draw
if (triangle_end_flag) {
u8g.drawLine(82, 28, 82 - diagonal_line_x, 28 - diagonal_line_y);
}
// straight_line draw
if (diagonal_line_end_flag) {
u8g.drawLine(76, 22, 76 - straight_line_x, 22);
}
// power number draw
if (straight_line_end_flag) {
// draw position
for (char i=0; i<power_arr_length -1; i++) {
if(power_x <= power_arr_length * power_num_size - ((i + 1) * power_num_size)) {
u8g.setPrintPos(power_arr_length * power_num_size - ((i) * power_num_size + power_num_size), power_y);
u8g.setFont(u8g_font_profont22);
u8g.print(power_arr[power_arr_length - (i + 1)]);
}
}
// last number draw
if(power_x < power_num_size) {
u8g.setPrintPos(power_num_size - power_num_size, power_y);
u8g.setFont(u8g_font_profont22);
u8g.print(power_arr[0]);
power_end_flag = 1;
}
// shaffuru number draw (animation)
else {
u8g.setPrintPos(power_x - power_num_size, power_y);
u8g.setFont(u8g_font_profont22);
u8g.print(power_num);
}
}
// message draw
if (power_end_flag) {
for (char i=0; i<message_arr_length; i++) {
if (message_flag[i] == 1 or message_no == i ) {
u8g.setFont(u8g_font_profont10);
u8g.setPrintPos(0, message_y[i]);
u8g.print(message_body[i]);
// hiddenbox draw
if (message_no == i) {
u8g.setColorIndex(0);
if (message_cnt <= message_hiddenbox_size) {
u8g.drawBox(message_font_size * message_cnt, message_y[i] - 8, message_font_size * (message_hiddenbox_size - message_cnt), 10);
}
else {
message_cnt = -1;
message_flag[message_no] = 1;
message_no++;
}
u8g.setColorIndex(1);
}
}
}
}
}
} while ( u8g.nextPage() );
// triangle flash motion set
if (!triangle_end_flag) {
// waiting for line_motion to start
if (triangle_cnt == 0) {
delay(2000);
}
// triangle_cnt = odd only
if (triangle_cnt > 11) {
triangle_end_flag = 1;
delay(500);
} else {
triangle_flash = triangle_flash * -1;
triangle_cnt++;
}
}
// diagonal line motion set
else if (!diagonal_line_end_flag) {
if(diagonal_line_x < 6) {
diagonal_line_x = diagonal_line_x + 1;
diagonal_line_y = diagonal_line_y + 1;
} else {
diagonal_line_end_flag = 1;
}
}
// straight line motion set
else if (!straight_line_end_flag) {
if(straight_line_x < 16) {
straight_line_x++;
} else {
straight_line_end_flag = 1;
}
}
// power number motion set
else if (!power_end_flag) {
straight_line_x++;
// num animation continue
if(power_num >= 9) {
power_num = 0;
power_cnt++;
// num animation time set
if(power_cnt >= 1) {
power_x = power_x - power_num_size;
power_cnt = 0;
// last
if(power_x < 0) {
power_x = power_num_size * power_arr_length;
}
}
} else {
power_num++;
}
}
// message motion set
else {
if(message_cnt <= message_hiddenbox_size) {
if(message_cnt == 0) {
delay(1000);
}
message_cnt++;
} else {
if(message_no == message_arr_length) {
message_end_flag = 1;
}
}
}
}
コード解説
このプログラムは、大きく分けて7つの項目で構成されています。
- 二重の円を描く
- 上下左右の四方向に三角マークを表示する
- 三角マークを点滅させる
- 斜めに伸びるラインを描く
- 横に伸びるラインを描く
- 数字アニメーションを表示する
- タイプライター風にメッセージを表示する
簡単な処理に見えるかもしれませんが、意外と大変です。
常に画面がクリアされるので、毎回クリアされる前の画面を再描画してから、アニメーションをスタートさせなくてはいけません。
また描画を開始するタイミングを制御するために、各項目ごとに終了フラグを撒き散らしています。
結果、メモリ消費が激しいコードになってしまいました。
特に難しい処理は行っていませんが、アニメーションの一部分だけ特殊なところがあるので、解説しておきます。
三角マークを点滅させる方法
三角マーク「u8g.setColorIndex(1)」「u8g.setColorIndex(0)」を交互に繰り返すことで点滅を表現しています。
setColorIndexは、ドットのONとOFFの切り替えを行うコマンドです。
塗るときは「1」、消すときは「0」という使い方をします。
「triangle_flash」というフラグを用いて、読み込み毎にON・OFFを切り替えています。
// triangle flash
if (triangle_flash == 1) {
u8g.setColorIndex(1);
} else {
u8g.setColorIndex(0);
}
~
triangle_flash = triangle_flash * -1;
タイプライター風に文章を表示する方法
カウントを用いて一文字ずつ表示する方法が一般的かもしれませんが、あまりにもコード量が多くなってしまいます。
そこで、最初に文字の上に黒いボックスを被せておいて、一文字分ずつ黒いボックスを小さくする手法を採用しました。