google-site-verification: google3bd66dd162ef54c7.html

キャラクタ液晶とスイッチでパラメーター設定する関数 (Arduino)

 日の出日の入り時刻を計算で求めることが出来たので、ソーラータイマースイッチを作っているところです。ソーラータイマースイッチとは、日の出日の入り時刻に連動して動作するタイマーです。このタイマーは、例えば日の入り時刻の10分前にON、などと動作条件を細かく設定出来ると使い勝手が良くなります。

 このようなパラメーター設定を、Arduinoを使い、キャラクタ液晶と限られた数のスイッチだけで行うのは結構面倒なプログラムを書かないといけません。

 今回、ソーラータイマー用に液晶画面を使って数値を入力する関数を作りましたが、これ、けっこう汎用的に使えそうです。ということで、自分用のメモも兼ねてデモプログラムとして公開します。

▼プログラムを動かすための回路
回路図
 液晶はI2Cの16文字、2行(AQM1602)。スイッチは dec.(-)、inc.(+)、Enterの三つを使います。

◆液晶とボタン3つで値を設定するデモプログラム
/* キャラクタ液晶と押しボタンを使って数値を入力するデモ
* 液晶:AQM1602A
* 2017/7/13 ラジオペンチ http://radiopench.blog96.fc2.com/
*/

#include <I2CLiquidCrystal.h> // N. MitsunagaさんのI2C液晶ライブラリ http://n.mtng.org/ele/arduino/i2c.html

I2CLiquidCrystal lcd(30, true); // コントラスト(0-63),液晶電源(true=5V, false=3.3V)

int DecB = 8; // - (Dec) ボタンのピン指定
int IncB = 9; // +(Inc)ボタンのピン指定
int EntB = 10; // Enterボタンのピン指定

int Data1 = 0; // テスト用データー
int Data2 = 6;
void setup() {
pinMode(IncB, INPUT_PULLUP); // + (Increment)ボタン
pinMode(EntB, INPUT_PULLUP); // Enterボタン
pinMode(DecB, INPUT_PULLUP); // - (Decrement)ボタン
lcd.begin(16, 2); // 16文字2行のI2C液晶を使用
}

void loop() {
lcd.clear();lcd.print("Input sNN +-20"); // 2桁の正負の値の入力(符号付き表示)
lcd.setCursor(0, 1); lcd.print("Data1 sNN");
Data1 = lcdInput(Data1, 8, 1, -20, 20); // Data1を±20の範囲で入力(値は上下限で飽和)
lcd.clear();
lcd.print("Data1 = "); lcd.print(Data1); // 確認のために表示
delay(2000);

lcd.clear();lcd.print("Input NN 1-12"); // 2桁の整数入力(符号無し表示)
lcd.setCursor(0, 1); lcd.print("month NN");
Data2 = lcdInput(Data2, 7, 1, 1, 12); // Data2を1~12の範囲で入力(値はサーキュレート)
lcd.clear();
lcd.print("month = "); lcd.print(Data2); // 確認のために表示
delay(2000);
}

int lcdInput(int d, int x, int y, int minV, int maxV) { // 液晶表示と値の入力関数
// +-ボタンで値を変更、Enterボタンで確定
// d=初期値、x, y=液晶座標、 minV,maxV=下限上限、戻り値=入力決定値
// 下限値(minV)が負なら符号付き表示(sNN) 正なら符号無し表示(NN)を行う
// minVが正なら値をサーキュレート、minVが負なら値は上下限でストップ

lcdDisp(d, x, y, minV); // 値を表示
while (digitalRead(EntB) == LOW) { // もしEntBが押されていたら離されるまで待つ
delay(30);
}
while (digitalRead(EntB) == HIGH) { // EntBが押されていなければ以下の処理を繰り返す
if (digitalRead(IncB) == LOW) { // +ボタンが押されていたら
delay(30);
d++; // dをインクリメント
if (d > maxV ) { // 上限を超えていたら
if (minV < 0) { // minVがマイナスの場合は
d = maxV; // 上限で抑える
} else { // そうでなければ
d = minV; // 値を下限に変更(サーキュレート)
}
}
lcdDisp(d, x, y, minV); // 指定フォーマットで表示
while (digitalRead(IncB) == LOW) { // +ボタンが離されるまで待つ
}
delay(30);
}

if (digitalRead(DecB) == LOW) { // -ボタンが押されていたら
delay(30);
d--; // dをデクリメント
if (d < minV ) { // 下限を下回っていたら
if ( minV < 0) { // minVがマイナスの場合は
d = minV; // 下限で抑える
} else { // そうでなければ
d = maxV; // 値を上限に変更(サーキュレート)
}
}
lcdDisp(d, x, y, minV); // 指定フォーマットで表示
while (digitalRead(DecB) == LOW) { // -ボタンが離されるまで待つ
}
delay(30);
}
}
delay(30);
lcd.noCursor(); // 入力が終わったのでカーソルを消す
return d;
}

void lcdDisp(int d, int x, int y, int minV) { // 指定位置に2桁の値を表示する関数
// minVが正ならNN形式、負ならsNN形式
if (minV < 0) { // 負の値がある場合
lcd.setCursor(x - 2, y); // 2文字左にカーソルを移動して
if (d >= 0) { // 値が正なら
lcd.print("+"); // +を表示
} else { // それ以外(つまり負)なら
lcd.print("-"); // -を表示
d = abs(d);
}
}
lcd.setCursor(x - 1, y); // 1文字左から
if (d < 10) { // 値が10以下なら
lcd.print("0"); // 0を埋めて
}
lcd.print(d); // 値を表示
lcd.setCursor(x, y); // 1桁目にカーソル移動
lcd.cursor(); // カーソル表示
}

 このプログラムは2桁の数値の入力を行うデモになっています。カーソル(アンダーバー)が出ている位置の値(2桁)を変更します。値は inc. (+)ボタンで増加、dec. (-)ボタンで減少し、Enter ボタンで入力決定して次の処理へ進みます。

▼デモプログラムの表示
液晶の表示

 lcdInput( )関数を適当な引数を付けて呼び出すと、設定した値が関数の戻り値として帰ってきます。細かい動作はコメントに書いておいたので、興味のある方はご覧ください。なお、このプログラムは順番にゴリゴリと書いただけで、たぶん誰が描いても同じようなものになると思います。ということで、勝手に改変して使って頂いてかまいません。

◆参考
 現在作りかけのソーラータイマースイッチに使う関数のテスト用のスケッチは以下の通りです。これは上の関数を中心に、もう少し複雑な機能を入れたものです(同じ回路図で動きます)。なお、まだテスト中なのでおかしな所があるかも知れませんが、何かの参考になれば幸いです。
 ソーラータイマースイッチ設定機能テストプログラム、20170713SolarTimerSetTest.txt (拡張子をinoに要変更)

ArduinoでI2Cキャラクタ液晶を使う(その3) 最終動作確認

 ArduinoからI2Cインターフェイスのキャラクタ液晶を使う話の最終回です。前回の記事で選んだI2Cキャラクタ液晶表示ライブラリの I2CLiquidCrystal (N. Mitsunagaさん) を使って実際に表示を行ってみます。なお、このライブラリにはいろいろなサンプルが入っているのでデモプログラムには事欠かないのですが、私が特に気にしている lcd.setCursor と lcd.print について自作のテストプログラムを動かしてみます。と言っても以前作ったものをちょっと手直ししただけのものです。

 プログラム自体の説明は後回しにして、表示結果は以下の写真の通りです。なお、接続回路図は、以前の記事に掲載したものと同じです。また、ライブラリのバージョンは I2CLiquidCrystal-1.5.zip を使いました。

▼実行結果
Arduino UNOの電源電圧
 CPUチップの温度と電源電圧を連続表示します。うまくいっているようです。

 なお、CPU温度の測定精度はかなり怪しくて大きなオフセットを伴っています。つまりこの表示の絶対精度はあてになりません。但し、分解能は高くて 0.1度あるので、CPUを指で触ると温度がどんどん上がることが判ります。

▼プログラム
/* CPU温度センサーと電源電圧の読み出し、表示デモ
初版 2014/7/19
改版 2017/06/11 I2C液晶用に修正 ラジオペンチ
http://radiopench.blog96.fc2.com/
*/
#include <I2CLiquidCrystal.h> // http://n.mtng.org/ele/arduino/i2c.html
#include <Wire.h>

I2CLiquidCrystal lcd(20, true); // コントラスト(0-63),液晶電源(true=5V, false=3.3V)

void setup() {
pinMode(13, OUTPUT);
lcd.begin(16, 2);
lcd.print("Starting...");
delay(1000);
Serial.begin(9600);
}

void loop() {
float temp, Vcc;
digitalWrite(13, HIGH);
temp = cpuTemp(); // CPU温度測定
Vcc = cpuVcc(); // 電源電圧測定
digitalWrite(13, LOW);

Serial.print("Temp= "); // シリアルに温度を出力
Serial.print(temp,1);
Serial.print(", Vcc= "); // シリアルにVccを出力
Serial.println(Vcc,2);

lcd.setCursor(0, 0); // 液晶に表示
lcd.print("Temp= ");
lcd.print(temp,1); // 温度、小数点以下1桁表示
lcd.print("c "); // 単位表示と後ろのゴミ消し
lcd.setCursor(0, 1);
lcd.print("Vcc = "); // Vcc
lcd.print(Vcc,2);
lcd.print("V "); // 単位表示と後ろのゴミ消し

delay(500);
}

// 流用する場合は以下を全てコピーする

float cpuTemp(){ // CPU温度測定関数
long sum=0;
adcSetup(0xC8); // Vref=1.1V, input=ch8
for(int n=0; n < 100; n++){
sum = sum + adc(); // adcの値を読んで積分
}
return (sum * 1.1/102.4)- 342.5; // 温度を計算して戻り値にする。-342.5は要調整
}

float cpuVcc(){ // 電源電圧(AVCC)測定関数
long sum=0;
adcSetup(0x4E); // Vref=AVcc, input=internal1.1V
for(int n=0; n < 10; n++){
sum = sum + adc(); // adcの値を読んで積分
}
return (1.1 * 10240.0)/ sum; // 電圧を計算して戻り値にする
}

void adcSetup(byte data){ // ADコンバーターの設定
ADMUX = data; // ADC Multiplexer Select Reg.
ADCSRA |= ( 1 << ADEN); // ADC イネーブル
ADCSRA |= 0x07; // AD変換クロック CK/128
delay(10); // 安定するまで待つ
}

unsigned int adc(){ // ADCの値を読む
unsigned int dL, dH;
ADCSRA |= ( 1 << ADSC); // AD変換開始
while(ADCSRA & ( 1 << ADSC) ){ // 変換完了待ち
}
dL = ADCL; // LSB側読み出し
dH = ADCH; // MSB側
return dL | (dH << 8); // 10ビットに合成した値を返す
}
 このプログラムはかなり前に書いた「外付け部品無しでArduinoの電源電圧を測定する」という記事に掲載したもので、インクルードするライブラリを入れ替えて、初期化の設定を修正しただけです。動作としては、CPUの電源電圧と温度を連続表示します。43行以降が測定ルーチンですが、このプログラムはCPUのレジスタを設定するだけで動いています。つまり外部の配線は何もしなくていいので、今回のように、ちょっとした動作確認をしたい時に使うと便利です。

 33行で温度を小数点以下1桁、37行で電圧を小数点以下2桁表示するように指定しています。こういうふうに表示フォーマットを指定出来るとプログラム作りが楽になります。

◆まとめ
 ということでうまく表示が出来るようになったので、I2Cインターフェイスのキャラクタ液晶を動かすライブラリの話は終わりです。I2Cインターフェースは少ないピン数で表示が出来るので便利になるはずです。

 あと、この後はこの液晶を使って日の出日の入りタイマーを作る予定です。そちらは進展があったら記事にする予定です。

ArduinoでI2Cキャラクタ液晶を使う(その2) ライブラリの選定

 ArduinoからI2Cインターフェイスのキャラクタ液晶を使う話の続きです。前回の記事で基本的な接続は確認出来たので、今回はライブラリを使って動かしてみます。実は、以前ライブラリの使用を試みたことがあるのですが、うまくいかなくて途中で断念しました。ライブラリを使わなくてもプログラムで頑張れば表示は出来ますが、いつもそんな面倒なことはやってられません。

▼回路図
AQM1602XA-RN-GBWとArduinoの接続図
 テストの前提条件は上の回路図で動くことです(I2Cバスは変換基板上でプルアップされています)。つまり、Arduino UNO に秋月の I2C 接続キャラクタ液晶(AQM1602XA-RN-GBW)を接続して動かすことが目標です。たぶんこれ、現時点で一番多い使い方だと思います。なお、この回路では液晶の電源電圧とI2Cバスの信号レベルは共に5Vです。後の記事に出てきますが、この電圧の条件をクリア出来ないライブラリがいくつかありました。

▼テストの様子
動作確認中
 I2Cバスの信号を見ながらテストしました。

 ネットを検索してArduino で使えそうな I2C液晶のライブラリを探して、Arduino IDEに登録しました。ライブラリを登録すると、下の図のようにスケッチ例が出るようになるので、これを動かしてみれば正常に動くかどうか簡単に調べることが出来ます。なお、登録したライブラリが使えなかった場合は単にそのファイルを消すだけで済むはずで、後遺症は残らないと思います(たぶん)。

▼ライブラリに登録した様子
サンプルプログラム

 上を拡大したのが下の画面です。

▼今回登録したI2C液晶表示ライブラリ
登録したライブラリ
 今回は赤枠内の5種類のライブラリを登録しました。

 以下、この画面に出ている順にテスト結果をレポートしていきます。

1.I2CLiquidCrystal Noriaki Mitsunaga さん
 いきなりこの記事の結論が出てしまいました、このライブラリが一番具合がいいです。私はこれを使うことにしました。このライブラリからは、lcd.setCursorとか、lcd.print などパラレル液晶でおなじみのコマンドが使えます。それに何の修正も不要です。これこそ私が求めていたライブラリです。

 少しだけ説明を加えたいと思います。 このライブラリは初期化ルーチンでいろいろなメーカーのLCDが選べるようになっています。今回私が探していたのは上の回路図に書いたように秋月で売られているLCD用のライブラリですが、それはこのライブラリのデフォルトで指定されている Straberry Linux の定義がそのまま使えました。昔はストリナで売ってたけど今では秋月でも取り扱うようになったということなんでしょう。

 もう少し細かく説明すると、下記ルーチンで

// initialize the library
// uncomment next line if you are using a LCD from Straberry Linux
I2CLiquidCrystal lcd(20, (bool)true);
// | +--- set true if the power suply is 5V, false if it is 3.3V
// +-------- contrast (0-63)
 I2CLiquidCrystal lcd(20, (bool)true); となっているものを I2CLiquidCrystal lcd(20, (bool)false); とすれば電源電圧3.3V用の設定(Voltage Boosterが動く)となりますが、今回は5Vで使うのでこのままで大丈夫です。このあたりは作者の方のWebに詳しい説明があるのでそちらを見た方が判り易いです。

 なお、電源電圧指定の引数に論理値のキャスト(bool)が入っていますが、これは省略して下記のように書いてもかまわないと思います。 true という変数名は論理変数の真を表す予約語なのでキャストで明記する必要は無いと思うのですが、何か深い理由があるのかも知れません。
I2CLiquidCrystal lcd(20, true); 

2.LiquidCrystal_I2C fdebrabander さん@gitHub
 これ、gitHubに登録されていたものです。試してみたのですが全く動きませんでした。プログラムを見るとI2Cアドレスが0x27となっているので、全く別の液晶用のライブラリのようです。なお、gitHub内の説明資料やプログラムの中も見たのですが液晶の型格が特定出来るような情報はありませんでした。名前だけで判断してはダメということですね。

3.skI2CLCDlib きむ茶工房さん
 きむ茶工房さんのwebには参考になる情報がいっぱいあって、いつもお世話になっています。このライブラリは液晶モジュールの電圧設定がデフォルトでは3Vになっているのでこれを下記のように修正して5Vに変更する必要があります。なおこのあたりは作者のWebに詳しく書かれています。
     // ICON OFF,コントラスト(0-63),VDD=3.3Vで使う
// LCD.Init(LCD_NOT_ICON,32,LCD_VDD3V) ;
LCD.Init(LCD_NOT_ICON,32,LCD_VDD5V) ;
 これでライブラリとしては正常に動くようになります。ただ残念なことに、文字表示の関数としてLCD.putc( )と LCD.puts( )くらいしか用意されていないようで、肝心のlcd.print( ) がありません。これではArduinoの文化で育った私は困ってしまいます(すみません)。たぶんPIC使いの方なら大丈夫なんでしょう。

 あと、きむ茶工房さんのサイトにこのキャラクタ液晶の昇圧回路について繰り返し注意が書かれています。これは私も気にしていた点で、同じ見解が書かれていたので安心しました。

 それと、ライブラリの名前が skI2CLCDlib となっていて、先頭にsk という文字が入っているのは私の好きな作法です。このあたりの話は記事の後ろの方でもう一度触れたいと思います。

4.ST7032 オレ工房さん
 このライブラリはとても良く出来ていて必要な関数は全て揃っています。もちろん lcd.print もあります。スケッチ例もたくさん揃っていて親切な作りになっています。

 ただとても残念なことに 昇圧回路が常にONになっていてライブラリからOFFにすることが出来ません。つまり液晶の電源電圧が3.3Vの場合しか使えません。Arduino UNOには3.3V電源を供給するピンがあるので、ここから液晶に電源を供給すればとりあえず動くとは思います。でも信号のレベルが合わないので I2Cバスのノイズマージンが確保出来ません。そんなことでこういう使い方はお勧め出来ません。

 ということで私の結論は、このライブラリは使えない、ということになります。 あと、ライブラリの名称がドライバチップの名前のまま(ST7032)になっているのは、私としてはちょっと気になる点です。

5.wI2cLcdACN1602 エレキジャック、nakaoさん
 これ動きませんでした。よく見ると液晶のPNがACM1602となっていますが今回の液晶はAQM1602です。おまけにドライバのチップはST7066ということで全然別の製品用でした。これくらいは事前にちゃんと理解してから探せよ→自分。ということなんですが、すみません私が悪いです。

◆まとめ
 Arduinoで動かすI2Cキャラクタ液晶のライブラリは検索すれば簡単に見つかるだろう、と思っていたのですが。実際には簡単ではありませんでした。事実、今回は5種類試してそのまま使えたのは一つだけ(1.項の I2CLiquidCrystal)でした。昔、知識も無い状態で適当にネットで拾ったライブラリを入れてうまく動かなかったのはある意味当然の結果でした。

 あと、今頃気付いたのですが、パラレルインターフェイスの液晶を使う場合のライブラリはいつも LiquidCrystal.h を使いますが、このライブラリの完成度が素晴らしいので、他のライブラリを探す必要が全く無かったということなんですね。

◆ライブラリの名について
 この記事の中でちょっと触れていますが、ライブラリの名前について以前から気になっていることがあります。それは、ライブラリの名前は後で改良版を作る人のことを考えて付けて欲しい、ということです。

 デバイスの名前と同じライブラリがよく作られています(ex:デバイス名がABC123ならライブラリ名もABC123.h) 。でもそういうど真ん中の名前を使われると、後で改良版を作る人はライブラリ名をどうするか困ってしまいます。(改変版を作る場合、オリジナルの作者の方の権利を侵さない注意は当然必要です。)

 もちろん最初の作者の方が、ずっとそのライブラリをメンテナンスしていただけるなら、ど真ん中の名前を使っていただいてかまいません。でも現実を見ていると、ArduinoIDEのバージョンアップなどに伴い、そのままでは動かなくなってしまったライブラリがいくつかあります。こうなってしまうと、ど真ん中にゴミが放置されているようなもので、すごく邪魔です。

 ライブラリの名前はもちろん判り易くないといけません。でもそれをそのまま使うのでは無く、ちょっと自分のイニシャルを追加して傷を付ける、というスタイルが良いのではないかと個人的には思います。今回の記事で取り上げたものでは、3.項と5.項のライブラリがそうなっていると思います。

 このくだりはちょっと余計だったかも知れません、また異論もあるでしょう。そもそもライブラリを一つも公開していない人間が偉そうなこと言うんじゃないよ、というお叱りを受けそうです。ただ、ずっと気になっていたので、この機会に文章にしてみました。
カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード