Blog2Viewer

以前、Movable Typeで運用していたブログの内容を表示させるために作成したページです。
カラーレーザープリンタ購入
s_160728c5カラー・レーザ・プリンタを使おうと、久しぶりに電源を入れると、しばらくしてエラーが出る。それまでならテスト印刷とかできる。ファンとか壊れたのだろうか。引っ越しのせい? 修理しようにも、凄く重いし、安い機種なのでどう考えても新しく買うほうが安いので、購入を検討。

価格.comでカラーレーザープリンタの売れ筋を調べると,NECのPR-L5600c 9,780円とかPR-L5750C 17,800円とかが目に付く。安い。前のプリンタはPR-L5750Cで、まだ余っているトナーもあるので魅力的。しかし、調べていくと発売日が2008年12月と古い。PR-L5600Cも2011年、5年前の機種だ。だから安いのかも。

新しくて安い機種を探し、Brother HL03170CDWが目に付く、2013年発売で18,604円。Brotherのプリンタの印象は悪くないので、これに決定。amazonに発注。翌日届いた。

あまり、たくさん印刷するつもりはないのだけれど、どれくらい持つかな?1回目のトナー交換は覚悟しておこう。
HSES-LCD24に文字を表示するプログラム(1)
s_160802a7HSES-LCD24は面白い、ということを伝えていきたいと思う。そのために、HSES-LCD24の簡単なプログラムを紹介します。
機能がありすぎて、どんなプログラムにするか悩みますが、基本的な機能でかつ応用が利く、WiFi経由で文字や図形をLCDに表示するプログラムを作っていくことにしました。




まずは、単体で、LCDに文字を表示するプログラム。使用するライブラリはAdafruit_GFXとAdafruit_ILI9341。インストールされていなければ、インストールしてください。(->Adafruit_ILI9341のインストール)

スケッチ(プログラム)は簡単で以下のようになります。


#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 15
#define TFT_CS 2
#define TFT_RST -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

void setup() {
 tft.begin();
 tft.setRotation(3);
 tft.setTextSize(5);
 tft.fillScreen(ILI9341_BLACK);
 tft.setTextColor(ILI9341_GREEN);
 tft.setCursor(50,80);
 tft.print("Hello ");
 tft.setCursor(100, 140);
 tft.setTextSize(4);
 tft.setTextColor(ILI9341_YELLOW);
 tft.print("ILI9341");
}

void loop() {
}


実行すると下の写真のように表示されます。

s_160802a7

Adafruit_ILI9341で使えるメソッド(関数)のリストはWikiにまとめました。Adafruit_ILI9341クラスはAdafruit_GFXクラスを継承していますので、そのメソッドも使えますし、さらにPrintクラスも継承していますのでSerialクラスで使用できるprintやprintlnメソッドも使えます。使えるメソッドをwikiに抜き出してみました。

tft.setRotation()で描画の方向を設定できます。引数の値と表示の関係を調べるため、次のスケッチを動かしてみました。


#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 15
#define TFT_CS 2
#define TFT_RST -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

void setup() {
 int i;
 
 tft.begin();
 tft.fillScreen(ILI9341_BLACK);
 tft.setTextSize(3);
 
 for(i=0;i<4;i++){
   tft.setRotation(i);
   tft.setCursor(10,10);
   tft.print("rotation=");
   tft.print(i);
 }
}

void loop() {
}


実行すると次のようになります。

s_160802a2

tft.setTextSize()で文字の大きさを整数倍に大きくできます。 これもテストプログラムを作ってみました。


#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#define TFT_DC 15
#define TFT_CS 2
#define TFT_RST -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

void setup() {
 int i,j;
 tft.begin();
 tft.setRotation(3);
 tft.setTextSize(5);
 tft.fillScreen(ILI9341_BLACK);
 
 tft.setCursor(30,10);
 for(i=0;i<=6;i++){
   tft.setTextSize(i);
   tft.setCursor(10, tft.getCursorY()+3);
   tft.print("Size=");
   tft.println(i);
 }
}

void loop() {
}


実行すると、次の写真のようになりました。 size=0と1に違いはありません。

s_160802a5

setTextSize以外にsetFontで大きなフォントを設定する方法もあります。
WiiU ゲームパッド修理
s_160723a4splatoonをやっていて、ゲームパットの左スティックの調子が悪くなってきた。前進しようとしても微速前進になってしまう。グリグリとしてやると復活したりする。splatoonやってれば、普通にそうなるらしい。WiiUの購入は昨年12月で十分保証期間内なので無償修理は可能だと思うが、1週間以上splatoonができないのは嫌なので、WiiU 修理セット ゲームパッド 修理交換用 部品 スティック コントロール基板左右+接続ケーブルセット (Lスティック・Rスティック・接続ケーブル2本)& 修理専用Y字ドライバーセットを購入し、修理。



修理は、動画を見ながら、慎重に行う。自分のゲームパッドが接続ケーブルが必要なタイプかどうかわからなかったが、念のためケーブル付きを選んだところ、必要なタイプだった。よかった。無事、修理は完了。スティックの調子も復活した。

[gallery link="file" ids="10658,10659"]

HSES-LCD24に文字を表示させるプログラム(2)
LCDに文字を表示させることはできたので、次はWiFi経由での操作方法を調べる。スケッチの例を調べるとESP8266WebServer/HelloServerが良さそうだ。72行の簡単なプログラムで、必要な機能がうまく説明されている。





#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char* ssid = "........";
const char* password = "........";

ESP8266WebServer server(80);

const int led = 13;

void handleRoot() {
 digitalWrite(led, 1);
 server.send(200, "text/plain", "hello from esp8266!");
 digitalWrite(led, 0);
}

void handleNotFound(){
 digitalWrite(led, 1);
 String message = "File Not Found\n\n";
 message += "URI: ";
 message += server.uri();
 message += "\nMethod: ";
 message += (server.method() == HTTP_GET)?"GET":"POST";
 message += "\nArguments: ";
 message += server.args();
 message += "\n";
 for (uint8_t i=0; i<server.args(); i++){
   message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
 }
 server.send(404, "text/plain", message);
 digitalWrite(led, 0);
}

void setup(void){
 pinMode(led, OUTPUT);
 digitalWrite(led, 0);
 Serial.begin(115200);
 WiFi.begin(ssid, password);
 Serial.println("");

 // Wait for connection
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
 }
 Serial.println("");
 Serial.print("Connected to ");
 Serial.println(ssid);
 Serial.print("IP address: ");
 Serial.println(WiFi.localIP());

 if (MDNS.begin("esp8266")) {
   Serial.println("MDNS responder started");
 }

 server.on("/", handleRoot);

 server.on("/inline", [](){
   server.send(200, "text/plain", "this works as well");
 });

 server.onNotFound(handleNotFound);

 server.begin();
 Serial.println("HTTP server started");
}

void loop(void){
 server.handleClient();
}




WiFiの設定をするだけで、すぐ動いた。プログラムではIO13にLEDが接続されているものとして操作しているが、HSES-LCD24の場合IO13はMOSIに接続されているので操作されても特に問題は無い。LCDには何も表示されないので、写真は載せない。

シリアルモニターを開くと、次のように表示される。

sc160805a0

ブラウザで http://192.168.0.104にアクセスしてみると、次のように表示された。

sc160805a1

http://192.168.0.104/inline にアクセスすると、こうなった。

sc160805a2

存在しないパスにパラメータ付きでアクセスしてみる。
http://192.168.0.104/foo?bar=4&x=zだと,こうなった。

sc160805a3

これで、パラメータへのアクセス方法もわかった。ネットワーク経由でLCDへの文字表示、できそうだ。
HSES-LCD24に文字を表示させるプログラム(3)
160810a6現在、梱包上の問題でスイッチサイエンスでのHSES-LCD24の販売が停止されています。対策の目途は立っていますので、お盆明けぐらいには再開できると思います。

さて、HSES-LCD24に文字を表示させるプログラムですが、前回紹介したサンプルプログラムESP8266WebServer/HelloServerをベースに簡単に作ってみました。ソースは、この記事の最後に置いておきます。



拡張性を考え、/printというパスに、文字表示のハンドラを設定しました。パラメータで表示にひつような情報を渡します。現在有効なパラメータを以下に示します。

[cpp]
text: // 表示する文字列
clear: // 画面クリアの有無、 1:全クリア、 2: x0,y0,x1,y1で指定した領域のみクリア
size: // 文字サイズ 
rotation: // 描画座標の向き、デフォルト3
x,y: // 文字描画の位置
color: // 文字描画色、 #rrggbb または white, black, red, green, blueなど
bg: // クリアに使用する背景色
x0,y0,x1,y1: // 部分クリアの領域指定
[/cpp]

動作確認はブラウザで行えます。プログラムを書き込み、WiFiと接続できると、表示は次のようになります。


160810a1

HSES-LCD24に割り当てられたIPアドレスが 192.168.0.104だったとして、ブラウザで

http://192.168.0.104/print?clear=1&size=3&text=Hello

にアクセスすると、次の写真のように表示されます。


160810a3

与えるパラメータの値を変えることで、表示をコントロールできます。

PC側のプログラムから表示を行うこともできます。
下のプログラムはPython3のプログラムで、1秒ごとに時刻を表示させています。

[python]
import urllib.request
import time
from datetime import datetime

ip_addr = '192.168.0.104'
url_date = "http://%s/print?clear=1&color=%%238080ff&x=21&y=80&size=3&text=%s"
url_time = 'http://%s/print?x=10&y=120&color=green&size=6&text=%s'

while(1):
s = datetime.now().strftime("%Y/%m/%d(%a)")
req = urllib.request.Request(url_date % (ip_addr,s));
the_page = urllib.request.urlopen(req).read()

s = datetime.now().strftime("%H:%M:%S")
req = urllib.request.Request(url_time % (ip_addr,s));
the_page = urllib.request.urlopen(req).read()
time.sleep(1)
[/python]

時刻を表示させる前に画面クリアをしていますので、多少ちらついて見えます。この辺は今後改良していきたいところです。

最後に、HSES-LCD24側のプログラムを以下に掲載します。

[cpp title="HSES_LCD24のプログラム"]
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#define TFT_DC 15
#define TFT_CS 2
#define TFT_RST -1

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

const char* ssid = "ssid-name"; // 接続するWiFiのssidを設定
const char* password = "password"; // 接続するWiFiのパスワードを設定

ESP8266WebServer server(80);

typedef const struct {
const char *name;
uint16_t value;
} color_name_t;

color_name_t color_names[] = {
{"BLACK", ILI9341_BLACK},
{"LIGHTGREY", ILI9341_LIGHTGREY},
{"DARKGREY", ILI9341_DARKGREY},
{"BLUE", ILI9341_BLUE},
{"GREEN", ILI9341_GREEN},
{"RED", ILI9341_RED},
{"YELLOW", ILI9341_YELLOW},
{"WHITE", ILI9341_WHITE},
{"PINK", ILI9341_PINK},
{NULL, 0},
};

struct {
int16_t x0;
int16_t y0;
int16_t x1;
int16_t y1;
uint16_t bg_color;
} lcd_cont = { 0, 0, 320, 240, ILI9341_BLACK};

void handleRoot() {
server.send(200, "text/plain", "NetLCD server");
}

static boolean getHex(const char *s, int *pVal)
{
int i,vv=0;

for(i=0; i<2; i++){
int v;
if(!isxdigit(s[i]))
return false;
if(s[i] > 'f') return false;
else if(s[i] >= 'a') v = s[i] - 'a' + 10;
else if(s[i] > 'F') return false;
else if(s[i] >= 'A') v = s[i] - 'A' + 10;
else if(s[i] > '9') return false;
else if(s[i] >= '0') v = s[i] - '0';
else return false;
vv = vv * 16 + v;
}
*pVal = vv;
return true;
}

static boolean getColor( const char *str, uint16_t *pColor)
{
if(*str == '#'){
int r,g,b;
if(getHex(str+1, &r) && getHex(str+3, &g) && getHex(str+5, &b)) {
*pColor = tft.color565(r,g,b);
return true;
}
Serial.print("Bad color:\"");
Serial.print(str);
Serial.println("\" found.");
return false;
}
else {
color_name_t *p;
for(p=color_names; p->name; p++){
if(stricmp(str, p->name)==0){
*pColor = p->value;
return true;
}
}

Serial.print("Undefned color name:\"");
Serial.print(str);
Serial.println("\" found.");
return false;
}
}

void handlePrint() {
for(int i=0; i<server.args(); i++){
String name = server.argName(i);
String value = server.arg(i);
if(name == "text")
tft.print(value.c_str());
else if(name == "clear") {
if(value == "1"){
tft.fillScreen(lcd_cont.bg_color);
tft.setCursor(0,16);
}
else if(value == "2"){
tft.fillRect(lcd_cont.x0, lcd_cont.y0, lcd_cont.x1, lcd_cont.y1,
lcd_cont.bg_color);
}
}
else if(name == "size")
tft.setTextSize(value.toInt());
else if(name == "rotation")
tft.setRotation(value.toInt());
else if(name == "x")
tft.setCursor( value.toInt(), tft.getCursorY());
else if(name == "y")
tft.setCursor( tft.getCursorX(), value.toInt());
else if(name == "color") {
uint16_t color;
if(getColor(value.c_str(), &color))
tft.setTextColor(color);
}
else if(name == "bg") {
getColor(value.c_str(), &lcd_cont.bg_color );
}
else if(name == "x0")
lcd_cont.x0 = value.toInt();
else if(name == "y0")
lcd_cont.y0 = value.toInt();
else if(name == "x1")
lcd_cont.x1 = value.toInt();
else if(name == "y1")
lcd_cont.y1 = value.toInt();
else {
Serial.print("param:");
Serial.print(name.c_str());
Serial.print(" not defined.");
Serial.println();
}
}
server.send(200, "text/plain", "Ok");
}

void handleNotFound(){
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}

void setup(void){
Serial.begin(115200);
tft.begin();
tft.setTextSize(2);
tft.setRotation(3);
tft.fillScreen(ILI9341_BLACK);

tft.setCursor(2, 16);
tft.println("Initialize");

WiFi.begin(ssid, password);
Serial.println("");
tft.print("connecting");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
tft.print(".");
}
Serial.println();
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

tft.println();
tft.print("connected to ");
tft.setTextColor(ILI9341_GREEN);
tft.println(WiFi.localIP());
tft.setTextColor(ILI9341_WHITE);

server.on("/", handleRoot);
server.on("/print", handlePrint);
server.onNotFound(handleNotFound);

server.begin();
Serial.println("HTTP server started");
tft.println("start");
}

void loop(void){
server.handleClient();
}
[/cpp]

今後、このプログラムに、もう少し機能を追加していく予定です。
HSES-LCD24に文字を表示させる(4) 画像表示とNetLCD公開
HSES-LCD24の販売再開しました。あとNetLCDというプログラムをgithubで公開しました。URLはhttps://github.com/h-nari/NetLCD。中身は今回の記事のプログラムです。

160819a3今回は画像を表示させる機能を追加させたのだが、プログラムの公開方法に悩み、githubで公開することにし、プログラムを整理し、ドキュメントなども書いてたら、時間がかかってしまった。

HSES-LCD24のディスプレーは320x240画素で、1画素16bitなので1画面で 320x240x2byte = 153,600byte必要になる。これだとパラメータで渡すのは無理そうだ、そもそも153kbyteも空容量がESP8266にありそうにない。

WebServerのファイルアップロード機能が使えるのではないかと考え、探すと、サンプルプログラムがあった。SDWebServer.inoだ。これの93行あたりにあるhandleFileUpload()という関数に必要な情報が詰まっている



[cpp]
void handleFileUpload(){
if(server.uri() != "/edit") return;
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
} else if(upload.status == UPLOAD_FILE_WRITE){
if(uploadFile) uploadFile.write(upload.buf, upload.currentSize);
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize);
} else if(upload.status == UPLOAD_FILE_END){
if(uploadFile) uploadFile.close();
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
}
}
[/cpp]

これらの機能を利用して、画像表示機能を追加、その他の機能も整理してプログラムをgithubに公開した。ある程度、汎用性があるプログラムだと思うのでNetLCDと名付けた。リンクはNetLCD。

ESP8266-Ardonoのスケッチにあわせて、Pythonのライブラリも公開している。特に画像は、PIL(Pillow)ライブラリのImageオブジェクトを描画するインターフェースを作ったので、それを使うのが便利。 PIL側で図形や文字を描画して表示することもできる。これだと日本語も表示可能だ。

PC側でサンプルプログラム drawTest.pyを動作させ、HSES-LCD24に表示させた動画を以下に貼る。






splatoon その後の後

一時はA+まで上がったウデマエも、すぐに落ち、今はA-あたりをウロウロしている。今は、ウデマエを上げることを目標にせず、毎晩少しづつ楽しんでいる。A-でも、十分相手は強いし楽しい。

動画は、先日できた気持ちの良い試合。編集のミスで、なんか動画が小さくなってしまった。この辺も慣れて行きたい。
ESP8266 Arduinoでmake
Arduinoのスケッチをmakeコマンドでコンパイルしたいという欲求は昔からあり、sudar/Arduino-Makefileなどというものがあるのも知っているのだが、ちょっと調べて


  • Linux前提っぽい
  • Makefileにincludeさせて使うものらしい
  • Arduino非純正CPU (ESP8266とか)に対応しているか不明


というような感じなので、手を出さずにいた。

HSES-LCD24で日本語の表示をさせようと検討すると、やっぱり fontxファイルをバイナリーのままコードに埋め込みたくなった。Arduino-IDEでコンパイルさせていると、埋め込み先のsectionがわからない。ということでgcc等のコマンドが見えるmakeコマンドでのコンパイルに挑戦してみることにした。


まずは esp8266 arduino makefileで検索し、thunderace/Esp8266-Arduino-Makefile: Makefile to build arduino code for ESP8266 under linux (tested on debian X64)を発見。この中の esp8266Arduino.mkをコピーし、サンプルのMakefileを書いてみる。コンパイルするスケッチは、HelloWorld.ino. cygwin上でmakeコマンドを実行するとエラーがいっぱい。まず、パスの指定をMakefile側に追加、今度はライブラリーのインクルードパスの自動生成に失敗しているようなので、これもMakefile側で追加、 esp8266Arduino.mkは1か所だけコメントアウトして、コンパイルとプログラムが書き込めるようになった。めでたしめでたし。

出来上がったMakefileは、こんな感じ



使用しているコンパイラ等のツールが非cygwinなので、cygwinのパスと非cygwinのパスが混じっているのが気持ち悪い、が我慢する。LinuxやMacでやれば楽なんだろうな。 Windowsでbashが使えるようになれば楽になるかしら?って、メーカー提供のSDKがbash対応しなければいけないわけだから望みは薄い。

修正した esp8266Arduino.mkはこちら. コンパイルしたスケッチ HelloWorld.inoはこれ。Arduino-IDEでもコンパイルできるままなのも良い。

makeコマンドだから、当然更新があったファイルしかコンパイルしないので、2回目以降のコンパイルはArduino-IDEよりはるかに速い。コンパイルエラーもわかりやすい。Arduinoである程度規模以上のプログラムを開発する必要がある人にはお勧めします。

さぁ、次は日本語表示。できるかな?