Gooseのアイコン画像
Goose 2022年09月20日作成 (2022年09月20日更新)
製作品 製作品 閲覧数 1277
Goose 2022年09月20日作成 (2022年09月20日更新) 製作品 製作品 閲覧数 1277

SPRESENSE で Small BI

SPRESENSE で Small BI

2022年 SPRESENSE™ 活用コンテスト作品です。

作品概要

Numbers4 の当選番号に出現する数字を年別にグラフ表示します。
データは、事前に別途収集&集計したものをSDカードに書き込んでいます。

使い方

D04 ボタン:前年データを表示
D05 ボタン:翌年データを表示
D06 ボタン:グラフの色変更(18色逆送り)
D07 ボタン:グラフの色変更(18色順送り)

デモ動画

ここに動画が表示されます

部品

部品名 説明
Spresense メインボード(※提供品) キャプションを入力できます
Spresense 拡張ボード キャプションを入力できます
Mic&LCD KIT for SPRESENSE(※LCDのみ使用) キャプションを入力できます
SDカード キャプションを入力できます

設計図(組み立て方法)

※公式マニュアルより抜粋
キャプションを入力できます
キャプションを入力できます
キャプションを入力できます

ソースコード

#include <Arduino.h> // SDカード #include <SDHCI.h> #include <File.h> SDClass SD; /**< SDClass object */ File myFile; /**< File object */ const String csvFile = "num4.csv"; // TFT液晶 #include <SPI.h> #include <Adafruit_GFX.h> #include <Adafruit_ILI9341.h> #define TFT_DC 9 #define TFT_CS -1 #define TFT_RST 8 Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI, TFT_DC, TFT_CS, TFT_RST); // LED const int buttonPinYearMinus = 04; // 年変更(前年)Pin const int buttonPinYearPlus = 05; // 年変更(翌年)Pin const int buttonPinColorMinus = 06; // 色変更(降順)Pin const int buttonPinColorPlus = 07; // 色変更(昇順)Pin int buttonStateYearMinus; // 年変更(前年)ON/OFF int buttonStateYearPlus; // 年変更(翌年)ON/OFF int buttonStateColorMinus; // 色変更(降順)ON/OFF int buttonStateColorPlus; // 色変更(昇順)ON/OFF // グラフ(データ取得) char num4_data[30]; // 文字列格納用 String num4_array[30][10][3]; // データ格納用3次元配列(年,数字,出現数) String num4_work; // データ編集用ワーク String num4_work_substring; // データ編集用ワーク int len; // データ編集用ワーク int j; // データ編集用添字 // グラフ(データ描画) int num4_work_num[10]; // データ格納用配列(出現数) int i; // データ編集用文字切り出し用添字 int ai; // データ編集用配列用添字(年) int aj; // データ編集用配列用添字(数字) int ak; // データ編集用配列用添字(出現数) int yyyy = 2022; // データ表示用変数(取得年) int yyyy_min = 0; // データ表示用変数(取得年)最小値 int yyyy_max; // データ表示用変数(取得年)最大値 uint16_t bar_color[18] = // 棒グラフの色 { ILI9341_NAVY // 0 ,ILI9341_DARKGREEN // 1 ,ILI9341_DARKCYAN // 2 ,ILI9341_MAROON // 3 ,ILI9341_PURPLE // 4 ,ILI9341_OLIVE // 5 ,ILI9341_LIGHTGREY // 6 ,ILI9341_DARKGREY // 7 ,ILI9341_BLUE // 8 ,ILI9341_GREEN // 9 ,ILI9341_CYAN // 10 ,ILI9341_RED // 11 ,ILI9341_MAGENTA // 12 ,ILI9341_YELLOW // 13 ,ILI9341_WHITE // 14 ,ILI9341_ORANGE // 15 ,ILI9341_GREENYELLOW // 16 ,ILI9341_PINK // 17 }; int bar_color_pos = 8; // 棒グラフのデフォルト色数字 const uint16_t color_background = ILI9341_BLACK; // 画面の背景色 const uint16_t color_title = ILI9341_WHITE; // タイトルの文字色 const uint16_t color_line = ILI9341_DARKCYAN; // 線の色 const uint16_t color_xAxis_label = ILI9341_WHITE; // X軸ラベルの文字色 const uint16_t color_data_label = ILI9341_WHITE; // データラベルの文字色 uint16_t color_bar; // 棒グラフの色 //////////////////////////////////////////////////////// // 初期処理 //////////////////////////////////////////////////////// void setup() { // シリアル通信準備 Serial.begin(115200); while (!Serial) { ; /* wait for serial port to connect. Needed for native USB port only */ } // SDカード準備 Serial.println("Insert SD card."); while (!SD.begin()) { ; /* wait until SD card is mounted. */ } // TFT液晶準備 tft.begin(40000000); // タクトスイッチ Pinモード初期化 pinMode(buttonPinYearMinus , INPUT_PULLUP); // 年変更(前年)Pin pinMode(buttonPinYearPlus , INPUT_PULLUP); // 年変更(翌年)Pin pinMode(buttonPinColorMinus , INPUT_PULLUP); // 色変更(降順)Pin pinMode(buttonPinColorPlus , INPUT_PULLUP); // 色変更(昇順)Pin // LED Pinモード初期化 pinMode(LED0, OUTPUT); // 年変更(前年)Pin pinMode(LED1, OUTPUT); // 年変更(翌年)Pin pinMode(LED2, OUTPUT); // 年変更(降順)Pin pinMode(LED3, OUTPUT); // 年変更(昇順)Pin // SDカードよりデータ読み込み myFile = SD.open(csvFile); Serial.print("Open CSV FileName = "); Serial.println(csvFile); if (myFile) { // カウンタ初期化 i = 0; ai = 0; // データ編集用配列用添字(年) aj = 0; // データ編集用配列用添字(数字) ak = 0; // データ編集用配列用添字(出現数) while (myFile.available()) { num4_data[i] = myFile.read(); if (num4_data[i] == ',' || num4_data[i] == '\n') { // カンマか改行がくるまで読み込む // 年、数字、出現数の値を切り出し num4_work = num4_data; len = num4_work.length(); num4_work_substring = ""; num4_work_substring = num4_work.substring(0,len-1); // 年、数字、出現数の値を3次元配列に格納 if (ak<3) { num4_array[ai][aj][ak] = num4_work_substring; if (yyyy_min==0) { yyyy_min = num4_work_substring.toInt(); // データ編集用配列用添字(年)最小値 } if (ak==0) { yyyy_max = num4_work_substring.toInt(); // データ編集用配列用添字(年)最大値 } ak++; if (ak==3) { ak = 0; aj++; if (aj==10) { aj = 0; ai++; } } } // 変数のクリア for( j = 0; j < 30; j++ ){num4_data[j]='\0';} i = 0; } else { i++; } } myFile.close(); } else { // CSVファイルが存在しなかった時はエラー Serial.print("CSV File Open Error."); } // オープニング画面表示後にグラフ表示 openingScreen(); delay(300); bar(yyyy,bar_color_pos); } //////////////////////////////////////////////////////// // ループ処理 //////////////////////////////////////////////////////// void loop(void) { delay(100); //////////////////////////////////////////////////////// // 1つ目のボタン押下(前年を表示:最小はCSVファイル内最小年) //////////////////////////////////////////////////////// buttonStateYearMinus = digitalRead(buttonPinYearMinus); if (buttonStateYearMinus == LOW) { digitalWrite(LED0, HIGH); // LED01点灯 yyyy--; // 表示年をマイナス // if (yyyy < 1994) {yyyy = 1994;} if (yyyy < yyyy_min) {yyyy = yyyy_min;} bar(yyyy,bar_color_pos); // グラフ再表示 } else { digitalWrite(LED0, LOW); // LED01消灯 } //////////////////////////////////////////////////////// // 2つ目のボタン押下(翌年を表示:最大はCSVファイル内最大年) //////////////////////////////////////////////////////// buttonStateYearPlus = digitalRead(buttonPinYearPlus); if (buttonStateYearPlus == LOW) { digitalWrite(LED1, HIGH); // LED02点灯 yyyy++; // 表示年をプラス if (yyyy > yyyy_max) {yyyy = yyyy_max;} bar(yyyy,bar_color_pos); // グラフ再表示 } else { digitalWrite(LED1, LOW); // LED02消灯 } //////////////////////////////////////////////////////// // 3つ目のボタン押下(棒グラフの色を降順に変更) //////////////////////////////////////////////////////// buttonStateColorMinus = digitalRead(buttonPinColorMinus); if (buttonStateColorMinus == LOW) { digitalWrite(LED2, HIGH); // LED03点灯 bar_color_pos--; if (bar_color_pos < 0) {bar_color_pos = 17;} // 最小値を超えたらループ bar(yyyy,bar_color_pos); // グラフ再表示 } else { digitalWrite(LED2, LOW); // LED03消灯 } //////////////////////////////////////////////////////// // 4つ目のボタン押下(棒グラフの色を昇順に変更) //////////////////////////////////////////////////////// buttonStateColorPlus = digitalRead(buttonPinColorPlus); if (buttonStateColorPlus == LOW) { digitalWrite(LED3, HIGH); // LED04点灯 bar_color_pos++; if (bar_color_pos > 17) {bar_color_pos = 0;} // 最大値を超えたらループ bar(yyyy,bar_color_pos); // グラフ再表示 } else { digitalWrite(LED3, LOW); // LED04消灯 } } //////////////////////////////////////////////////////// // グラフ表示(引数:年) //////////////////////////////////////////////////////// unsigned bar(int p_yyyy,int p_color_pos) { //////////////////////////////////////////////////////// // 描画準備 //////////////////////////////////////////////////////// // 引数で指定された年のデータ(出現数)を配列に格納 for( ai = 0; ai < 30; ai++ ){ if (num4_array[ai][0][0]==String(p_yyyy)){ for( aj = 0; aj < 10; aj++ ){ num4_work_num[aj] = num4_array[ai][aj][2].toInt(); // 出現数 } } } // 引数で指定された色でグラフの色をセット color_bar = bar_color[p_color_pos]; // 画面の大きさを取得 tft.setRotation(3); // 画面の回転 int h = tft.width(); // 画面の縦幅(Y軸) int w = tft.height(); // 画面の横幅(X軸) // 描画用各種変数定義 int iy0 = 20; // 0地点調整値(Y軸) int ix0 = 30; // 0地点調整値(X軸) int ky0 = w-iy0; // 0地点(Y軸) int kx0 = h-ix0; // 0地点(X軸) int label_tx = 0; // Bar ラベル X軸起点 int label_ty = w-15; // Bar ラベル Y軸起点 int xxx1 = kx0; // Bar 棒グラフ X軸起点 int yyy1 = ky0; // Bar 棒グラフ Y軸起点 int bar_height; // Bar 棒グラフ 高さ int bar_width = -20; // Bar 棒グラフ 幅 int adjust_xAxis_label = 5; // X軸ラベル位置調整 int adjust_data_label = -15; // データラベル位置調整 int adjust_bar_pos_x = -30; // 棒グラフ開始横位置調整 int data_number; // 表示データ 出現数字(0~9) int data_value; // 表示データ 出現数 //////////////////////////////////////////////////////// // 描画 //////////////////////////////////////////////////////// // 画面の初期化 tft.fillScreen(color_background); // 画面の背景色 tft.setRotation(3); // 画面の回転 // タイトルの表示 tft.setTextColor(color_title); // 文字色 tft.setCursor(h/2-80,15); // 文字位置 tft.setTextSize(2); // 文字の大きさ tft.print("Number of "); // タイトル文字(固定文字) tft.println(p_yyyy); // タイトル文字(可変文字) // X軸Y軸線の表示 tft.drawLine(iy0,0,iy0,w,color_line); // Y軸の描画 tft.drawLine(0,w-iy0,h,w-iy0,color_line); // X軸の描画 // 棒グラフの描画 xxx1=kx0; for(data_number=0; data_number<10; data_number++) { // 棒グラフの描画 tft.setRotation(0); data_value=num4_work_num[data_number]; bar_height = data_value * -1; tft.fillRect(yyy1, xxx1, bar_height, bar_width, color_bar); // X軸ラベル描画 tft.setRotation(3); tft.setTextSize(2); label_tx+=30; tft.setCursor(label_tx + adjust_xAxis_label, label_ty); tft.println(data_number); // データラベル描画 tft.setCursor(label_tx, label_ty + bar_height + adjust_data_label); tft.setTextSize(1); tft.println(data_value); delay(25); // 棒グラフ開始横位置調整 xxx1+=adjust_bar_pos_x; } return; } //////////////////////////////////////////////////////// // オープニング画面表示 //////////////////////////////////////////////////////// unsigned openingScreen() { // 画面の大きさを取得 tft.setRotation(0); // 画面の回転 int ow = tft.width(); // 画面の縦幅 int oh = tft.height(); // 画面の横幅 // 線描画の表示 tft.fillScreen(color_background); int oyy1 = 0; int oxx1 = ow; int oyy2 = 0; int oxx2 = ow; for(oyy1=oh; oyy1>0; oyy1-=8) { oxx2-=16; delay(50); tft.drawLine(oxx1, oyy1, oxx2, oyy2, color_line); }; // タイトルの表示 tft.setTextSize(2); tft.setRotation(3); tft.setCursor(5,50); tft.print("Number "); delay(500); tft.print("of "); delay(500); tft.print("Numbers4 "); delay(500); tft.print("by "); delay(500); tft.print("Year"); delay(500); tft.setRotation(0); delay(1000); return; }

参考にしたもの

参考 補足
SPRESENSEではじめるローパワーエッジAI(※懸賞当選品) キャプションを入力できます
3.12. SDHCI ライブラリ https://developer.sony.com/ja/develop/spresense/developer-tools/get-started-using-arduino-ide/developer-guide#sdhci_library
3.6. File ライブラリ https://developer.sony.com/ja/develop/spresense/developer-tools/get-started-using-arduino-ide/developer-guide#file_library
Spresense 5. LCDにグラフィックを表示する【ソニー公式】 https://www.youtube.com/watch?v=3a2VrQBmCiU
Arduino 日本語リファレンス http://www.musashinodenpa.com/arduino/ref/

感想

始めは SPRESENSE の使い方を覚えるために
『SPRESENSEではじめるローパワーエッジAI 』を読み進めながらハンズオンで学習をしました。

その後、GNSS で遊んでみましたが、なかなか上手くいきませんでした。
10機以上の衛星は捕捉できたものの、結局、緯度経度の取得はできないまま断念。
再チャレンジしたいと思います。

その後、本作品作りに入りました。
全て Arduino IDE のサンプルスケッチをベースにソースコードを書きました。
しかし、カスタマイズに想像以上に時間がかかってしまいました。
SDカードの使い方で1日、TFT液晶の使い方で2日、調整で1日。
台風でどこにも出かけられなかったので丁度良かったかも。

TFT液晶が最初表示されていたのに、ある時から表示されなくなってしまいました。
原因は、拡張ボードのジャンパーピンを 3.3V に変更していなかっただけだったのですが、
これに全然気づけなかった…。
どうして最初表示されていたのかは未だに謎ですが、
これが下手に影響してハード故障を疑ってしまい、
TFT液晶と拡張ボードを追加購入してしまいましたが当然解決せず。
数日と数千円を無駄にしてしまいました。
ここからの教訓としては「マニュアルを良く読む」です。
これ大事…

ログインしてコメントを投稿する