Blog2Viewer

以前、Movable Typeで運用していたブログの内容を表示させるために作成したページです。
パーツケース整理
161102a0パーツケースの中身は、適宜、必要なものに入れ替えているのだが、入れ替えすぎて順番がめちゃくちゃ。探すのに時間がかかるようになったので、ラベルをエクセルで作り直し、順序も探し易いように入れ替えた。

昔と比べると、ネジ、スペーサが増えている。これは、在庫が増えたというよりも、探し回ることが多いので、パーツケースに領域を確保して探し易くしたということ。

今後も状況に応じて、パーツケースの中身はどんどん入れ替えていきたい。部品の在庫は最小限にしたい。
ILI9341のスクロール機能
fig161103a2ILI9341には,画面をスクロールさせる機能がある。VerticalScrollDifinition(33h)コマンドで、上下の非スクロールエリアの幅を設定(リセット時は0)。VerticalScrollStartAddress(37h)コマンドでスタート位置を設定すれば、Vertical Scroll Areaの表示を自由にスクロール(回転?)表示できる。




このことは以前から知っていたので、いずれHublisoft_ILI9341ライブラリでサポートし、HSES-LCD24で使おうと考えていた。今、HSES-LCDのデモ用にRss表示プログラムを作成している。RSSの表示に、このスクロール機能を使って、大きな文字で下図のような表示をするべく作業していた。

fig161103a1

ところが、いろいろ試していくうち、そんな変な表示をするより、普通にテキストの改行時にスクロールさせた方が、見栄えも良いし、汎用性もあることに気が付いた。

fig161103a3
というわけで、Humblesoft_ILI9341ライブラリにVerticalScrollArea機能を実装、公開した。

使い方を説明する。Humblesoft_ILI9341クラスにpublicなメンバーとしてtfa,vsa,bfaを追加した。これらは、それぞれ Top Fixed Area, Vertical Scroll Area, Bottom Fixed Area  に対応するAdafruit_GFXクラスのサブクラスで、Humblesoft_ILI9341クラス同様に描画できる。fontxの設定を行えば、漢字の描画も可能。

それぞれの領域の高さはsetVerticalScrollAreaメソッドで行う。設定しなければ全領域がvsaとなる。print/println/printfメソッドで文字描画後、カーソル位置が下限を超えた場合、vsa領域のみスクロールされる。

サンプルプログラムは、Humblesoft_ILI9341/vsaSample.inoにある。

[cpp]
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include "Fontx.h"
#include "FontxGfx.h"
#include "Humblesoft_ILI9341.h"

IMPORT_BIN("fontx/ILGH16XB.FNT", font_h);
IMPORT_BIN("fontx/ILGZ16XB.FNT", font_z);
extern uint8_t font_h[], font_z[];

Humblesoft_ILI9341 tft = Humblesoft_ILI9341();

void setup()
{
Serial.begin(115200);
delay(100);
Serial.println("\n\nReset:");

tft.begin();
tft.setVerticalScrollArea(20,20);

tft.tfa.fillScreen(ILI9341_RED);
tft.vsa.fillScreen(ILI9341_BLACK);
tft.bfa.fillScreen(ILI9341_BLUE);
tft.tfa.setTextSize(2);
tft.tfa.print("TFA");
tft.vsa.setTextColor(ILI9341_WHITE);
tft.vsa.setFontx(font_h, font_z);
tft.vsa.print("VSA - Vertical Scroll Area\n");
tft.bfa.print("BFA");
}

void loop()
{
static int i=1;
tft.vsa.printf("%d行目\n",i++);
delay(1000);
}
[/cpp]

使用上の注意がいくつかある。このスクロール機能は、setRotation(0)の時しか、まともに動かない。tftに対する描画はスクロールのことを考慮していないので、 vsaでスクロールが発生した後は、変になるはず。getTextBoundsの処理がちょっと間違っている気がする。

あと、従来 Humblesoft_ILI9341に入っていたfontx関連機能をFontxとFontxGfxライブラリに分離したので、これらのライブラリもインクルードしてやる必要がある。 これは、作業を進めるうち、いろんなクラスにFontx描画機能を組み込まなければいけなくなり、そのたびに同じ処理が重複するのがいやになり、Adafruit_GFXを継承したクラスに対するFontx描画機能のHelperクラスとしてFontxGfxクラスを作成、Adafruit_GFX非依存部分をFontxクラスとして作成した。
RSS表示プログラム
161107a2HSES-LCD24用にRSS表示プログラムを作成し、GitHubで公開した。

RSS表示プログラムは、ニュース/Webサイト、Blog等の更新情報であるRSSを表示させるプログラムで、ニュース等のタイトルだけ、表示させ続ける電光掲示板でみかけるやつである。PCでは普通の機能だが、ネットワーク接続された表示装置にとっては、その機能をうまくアピールできる有難いプログラムである。

HSES-LCD24用にRSS表示プログラムを作るにあたって、日本語表示機能やスクロール表示機能は作成済みなので、残る必要な機能はRSSのパーザぐらいである。これも昔C言語作成したSAXっぽいプログラムがあったので、C++に書き直し、PC上でデバッグ&テストを済ませたのち、ESP8266/Arduinoに組み込んだ。なおRSSはサイト毎に読み込み、20Kbyte程度のバッファに蓄えたのち、1記事あたり5秒づつ表示させている。

最後に、時刻の表示機能も欲しくなり、自作する必要があるのかと調べたら、簡単に使えるntp同期の時計がESP8266-Arduinoに組み込まれていることがわかり、使用した。これについては、また、別記事で紹介したい。

161107a6m

RSSも表示できるHSES-LCD24はスイッチサイエンスにて絶賛発売中です。
esp8266/ArduinoのRTC
f161108a1ESP-WROOM-02等で使用するesp8266/Arduinoでは、サンプロプログラムにNTPClienttが含まれていることもあり、現在の時刻を取得するRTC(Real Time Clock)は自分で作成するものだと思い込んでいた。

時刻を取得するたびにntpパケットを飛ばすのもどうかと思うので、ntpパケットは適当な間隔で飛ばして、millis()関数とのオフセットでも管理することになるのかな。ntpサーバ1つだけだと嫌だな、とか色々考えているうち、偶然 esp8266/Arduinoの中にtime.cというファイルを発見。configTime()関数で、サーバーやタイムゾーン等を設定してやれば、time()関数でUNIX時間を取得できそう。



中身は、sntp.cの各関数を呼び出しているらしい...って、sntp組み込まれてる。 time()関数を呼び出すと,そのまま sntp_get_current_timestamp()関数が呼び出されるのだが、そのたびにntpパケット投げられるといやだなと sntp_get_current_timestamp()のソースプログラムを見ると、realtime_stampという変数の値を返すだけだ。sntp.cのソースを眺めると、デフォルトでは1時間に1回パケットを投げるみたい。

最後に気になったのがtime.hにconfigTime()の宣言が無いこと。それじゃ使えないじゃんと思ったがArduino.hにあった。

で、以下のサンプルプログラムを試すと、無事動作した。



動作させると、シリアルモニターに以下のように出力された。

sc161108a1

最初の1回目はntpでの同期が間に合っていないが、2回目以降は同期している。
ということで、esp8266/ArduinoではRTCをお手軽に使用できる。

以上の説明では、esp8266/ArduinoのgitHub上のソースにリンクを張っているが、これは最新版で、多くの人が使っているstable版とは若干違う。わたしもstable版を使用していて、プログラムのコンパイル・動作はstable版で行っている。
cygwin上でArduinoOTA動作
161114a1ArduinoOTAというのは、OTA(Over The Air)無線経由でArduinoでコンパイルしたプログラムをターゲットに書き込む機能らしい。存在は、前から知っていたが、ROM容量を倍使うとか読んだことがあって、そうなると日本語フォントを使用するプログラムでは容量的に非常に苦しい。ということで、手を出さなかったのだが、今、作業しているプログラムは日本語無しでも行けそうなので、組み込んでみることにした。



公式のドキュメント(?)はここにある。サンプルプログラムを見ながら、OTA機能を組み込み、COMポート経由で書き込む。

さて、日ごろ私は、esp8266 のプログラム開発を cygwin + emacs +make で行っている。makefileはplerup/makeEspArduinoを使用している。以前は、別の物を使用していたが、macbook Airで開発を試みた時、こちらでうまくいったので、それ以来 cygwinでも使用している。ただ、プログラムの書き込みはArduino IDEを使用している。make uploadでも書き込みは可能なのだが、シリアルモニターを開け閉めしなければいけないのが面倒で、その手間が無いのでArduino IDEを使用している。 makeからは、 make ota とすると pythonスクリプトespota.pyが呼び出され、書き込みが行われるのだが、やってみるとうまくいかない。通信が途中で途切れているようだ。

espota.pyの使い方を調べてデバッグオプション(-d)を付けてみたり、ArduinoOTP.cppの中をいじってみたりしているうち、段々動作がわかってきた。 espota.pyでTCPポートをlisten開始後、UDPパケットでポート番号等をArduinoOTP側に知らせ、ArduinoOTPがTCPポートにアクセスするところで繋がらないことが判明。WireSharkまでインストールし、動作を確認しているうち、思いついたというか思い出した。Firewallのせい? 試しにFireWallを一時停止すると、OTPでの書き込みができた。

その後、-Pオプションでespota.pyのポートを固定し、firewallの設定で、そのポートを通過させることで、いつでもOTAが使えるようになった。

makeからotaでプログラムを書き込めると快適だ。makeはコンパイル・リンクの中間ファイルを残し、最小限のコンパイル・リンクしか行わないので、通常コンパイルはすぐ終わる。そのあとの書き込みも高速に終了するようになったので、プログラム修正から動作確認までが凄く早くなった。Arduino IDEだとuploadボタンを押すと毎回全部コンパイル・リンクするから書き込みが速くなっても全体としては大して早くならない。ついでにコンパイルエラーが凄く醜い。cygwin+emacsなら next-errorコマンド一発である。ということで emacs + make環境をお勧めします。

SPI3台使いは、ちょっと大変
d161117a2HSES-LCD24ではESP8266(ESP-WROOM-02)のSPIに3つのデバイスが接続されている。TFT LCDとTouchscreenとSDカードスロットの3つだ。1つづつの動作確認は済んでいるのだが、今回初めて3つのデバイスを同時に動作させるプログラムを作ろうとしてトラブった。

各デバイスのライブラリーは、いろいろ提供されている。、SPI接続のライブラリーは基本的にSPIに複数のデバイスが接続されていることをあまり考慮していないので、使用の際には注意が必要だ。

まず、SPIデバイスのCS信号に接続されている端子は、初期化時にHighを出力されるようにされるが、そのまま初期化処理を続行されてしまうので、デバイスの初期化処理(biginメソッド?)を順次呼び出すと、他のデバイスのCS信号が未初期化、INPUTモードでハイインピーダンス状態でSCLK/MOSI/MISOに信号が出てくることになりMISO信号の衝突がありえる。よって、全部のCS信号を自分でHigh出力状態にしてやる必要がある。



bk161117次に、定番!超軽量マイコン用ファイル・システムFatFs (TECH I シリーズ) を読み直してわかったのだが、SDカードは起動時SPIモードで動いていない。起動時はネイティブ・モードで、そこにコマンドを入力しSPIモードに遷移する。SDカードはSPIモードになるまでCS信号がHighでも反応してしまうので、他のSPIデバイスを初期化する前、一番最初に初期化する必要がある。あと、SPIモードでもCSをHighにした後、1byte分クロックをSCLKに送ってやらないとMISOを解放しないらしい。

というような、対応をしてみたが、まだうまくいかない。各デバイスのCS信号をオシロスコープで観測。TFT LCDの使用時、SDカードのCS信号(IO0)がバンバン変化する。調査の結果、Adafruit_ILI9341ライブラリのバグだった。gitHubでは4月にpull requestが出されて修正方法も議論されているように見えるのだが、修正されていない。

自分で以下の修正を行った。
[cpp]
$ git diff -U Adafruit_ILI9341.cpp
diff --git a/Adafruit_ILI9341.cpp b/Adafruit_ILI9341.cpp
index e1b571b..6a15d11 100644
--- a/Adafruit_ILI9341.cpp
+++ b/Adafruit_ILI9341.cpp
@@ -73,7 +73,8 @@ Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) : Adafruit_
_dc = dc;
_rst = rst;
hwSPI = true;
- _mosi = _sclk = 0;
+ _mosi = -1;
+ _sclk = -1;
}
[/cpp]

これでプログラム開発を進められる。

ota(Over the Air, WiFi経由のプログラム書き込み)は、とても便利。たまに自分のプログラムのバグで例外を引き起こし、Arduino IDEで書き込まなければならなくなるが、プログラム更新の速さはたまらない。スクロール表示機能も便利でデバッグに活用したくなる。
arduino用にsscanf関数のサブセットを作成
d161118a1C/C++のプログラムで簡単な文字列解釈が必要になった時、sscanf()で処理しているのだが、esp8266 arduino環境だと使えない。コンパイルは通るがリンク時にエラーとなる。仕方がないので strtol()関数などで凌いでいたのだが、浮動小数点の解釈をする必要があり、StringのtoFloatの説明を見ているうち、段々腹が立ってきて、sscanf()のサブセットを作ることを思いついた。

toFloat()で許せないのは、数字として解釈できなかった場合0を返すだけで、元の文字列を見ないと数字だったのかどうかわからないこと。解釈できたかどうかをbool値で返し、値は引数に変数のポインタを渡して返すべきだと思う。



sscanfで日ごろ使うのは%d,%x,%f程度。そういう仕様で作ってみたら70行ぐらいだった。こんなことなら、もっと早く作っておけばよかった。githubで公開したので、間違いなどあれば指摘してもらうと嬉しいかもしれない。

avrlibcにはsscanfがあるようなのでArduinoでもAVRだと使えるのかもしれない。

toFloat()の文句を書いているうち、sscanfでも "123!"のように数字の後に余分な文字がある場合を上手く識別できないのが気になって来た。フォーマット文字列で"%d%c"とかやって、後続の空白文字以外の文字がないことを判定してやれば良いのかもしれないが、余分な変数と引数が必要になる。正規表現みたいに文字列の最後にマッチする奴があれば綺麗に判定できるのにと思いnscanfに、その機能もつけてみた。%+何かの文字でマッチさせたいところだが、nscanfにはformat/scanf attributeを付けているのでgccに警告される。空白文字はフォーマット文字列中で無視されるので、フォームフィード(\f)でマッチさせることにした。以下のように使用できる。

[c]
int i;
if(nscanf(buf,"%d\f",&i) != 2)
fprintf(stderr,"Bad integer strng:%s\n",buf);
[/c]

今後、使っていって、気が向いたら機能拡張しよう。
温度計プログラム完成
HSES-LCD24のサンプルプログラムとして温度計が完成、githubに公開した。まずは、画面を見て貰おう。

161124a1i
画面には、日付、時刻、温度センサーから取得した4つの温度と、その平均値、温度変化のグラフが表示されている。グラフには当日のデータに加えて、前日のデータもグレイで表示されている。



温度センサー



161124b5温度センサーはHSTS-ATD7410で、ESP-WROOM-02搭載の近日発売予定のモジュールとともにGROVE-WRAPPERで1.8mの棒に固定されており、この棒を立てて設置する。

このような温度センサーを使っているのには理由がある。もっとも大きな理由は、室温といっても足元の温度と天井近くの温度では全然違うだろうということ。適当なところに置かれた温度計の表示を見ても納得できない。いろんなところの温度を同時に見たい。次に、HSES-LCD24自体にもI2CコネクタがありI2Cの温度センサーを接続可能なのだが、ESP-WROOM-02自体が発熱する。ほんのり温かくなる程度だが、これが計測温度に影響すると嫌なので、温度センサーを近くに置けない。 使ってみてわかったが、ディスプレイは小さいこともあって、ちょいちょい動かす。よく見えるように位置を変えたりする。この時、センサーがつながっていないので、気にせず動かせるのは利点だと思う。

システム構成



センサーの計測値をWiFiで飛ばし、ネット接続の小型ディスプレーに表示するのであれば、通常は、常時稼働のサーバを介するシステム構成とすると思う。私も当初は、そう考えていたが、それでは、サーバを持っていない人に勧め辛い。そこで、HSES-LCD24自体をサーバにできないか検討した。 WebServerはサンプルプログラムも提供されているし問題なく動く。SDカードも使用可能ということで、性能面はわからないが、不可能ではなさそうだ。実際に作り始めるとSPI上の3つのデバイスを使用することになり大変なことも色々あったが、なんとかできた。

[gallery link="file" size="medium" columns="2" ids="10886,10887"]

出来上がってみると、なかなか良い。受信した温度データは1データ1行のcsv形式のテキストファイルで、1日毎のファイルに書き込んでいる。このデータは、SDカードを抜いてPCで読み出すこともできるが、esp8266で動作するWebServerからも読み出すことができる。これがあればサーバーが無くても常時データを記録することができるので、他にも活用できる状況がありそうな気がする。但し、注意が必要なの点がある。SDカードにファイルを書き込んでいる途中に電源断やリセットをしてしまうと、SDカードのファイルシステムが破壊される可能性がある。プログラムの開発中、なんどもSDカードのフォーマットをやり直す必要があった。リセットでも壊れる可能性があるので、Arduino SDKでのプログラム書き込み、シリアルモニタの開け閉めにも注意が必要となる。OTAでの書き込みは、プログラム内部でタイミングが取れているので問題ない。この問題に対応するため、shutdownと称しSDカードへの書き込みをブロックするモードを用意、タッチスクリーンからの操作で呼び出せるようにした。

今後



まずは、再来週のOMMFでの展示用に準備を進めたい。ネットワーク接続はどうなるかとか、いろいろ心配。 他のデモプログラムと統合し、切り替えて表示する、というようなことも可能だと思うが、そこまで準備する時間は無いような気がする。

未完成な機能、グラフの拡大表示や日付選択なども、いづれ作りたい。あと、外気温をOpenWeatherMapやDark Skyあたりから取ってきて一緒に表示する、というアイデアもある。これにはJSONパーザを作らなければならない。

この温度計は、もともと自分が欲しくてHSES-LCD24を作った面もあるので、自分使い用のガジェットとして、もっと完成度を上げていきたい。そうなると、温度データはSDカードではなく、サーバのデータベースに保存するのが自然、そうすればパソコンでも温度変化のグラフを見れるようになる。

あと、今回のプログラム開発ではOTAを使用し、プログラム書き込みがとても速く大変便利だった。OTAはROM容量を2倍使用するので、Fontxを使用するプログラムはをROM容量的に使えない。今回の開発でSDカードに慣れたので、漢字FontをSDカードに置いて使用できる漢字表示機能を作りたい。これならOTAが使用できるはずだ。

発売予定のESP-WROOM-02搭載新モジュール



161124h0発売予定のESP-WROOM-02搭載新モジュールは GROVE-WRAPPERで固定できることが特徴。あと、0.96インチSPI接続 128x64dot OLEDモジュール接続可能。GROVE-I2Cコネクタ付き。OLED付きと無しの2種類、GROBE-WRAPPERの入手が国内では難しいようなのでGROVE-WRAPPER1個付きで発売予定。温度センサーHSTS-ATD7410もGROVE-WRAPPER付属の物を発売したい。