2021年4月中旬にスイッチサイエンス様でFLINT Control Panel 28 shieldをお買い上げいただきました方へ
概要
FLINT Control Panel 28 shieldは、20×4のLCDと28個のボタンを、I2C接続のみで制御できるArduinoシールドです。このシールドに必要な制御は2ピンで済みますので、Arduinoの外部接続ピンが節約できます。
機械の制御パネルや、テストの信号発生用の治具コントローラなどに最適です。
このシールドの特徴
- このシールドには、ATmega328Pが搭載されていて、このマイコンでLCDとボタンの入力の制御を行っています。I2Cスレーブとして動き、Master側のArduinoと通信します。
- Arduino用のライブラリを用意しました。複雑なI2Cの通信を考える事なく、プログラミングが可能です。
- キートップは、ラベルが入れられる透明キャップが付いたタイプですので、キーの表示を自由にカスタマイズが可能です。
- Arduino互換ピンのマイコンボードであれば、シールドとして使用できます(このシールドは5Vのみ対応です)。ただし、I2Cの通信部分を書く必要があります。
- Arduinoのシールド用のピンの全てがArduino peripheralとして引き出されているので、外付け部品を接続する事ができます。
- Arduinoへの接続するシールド用のピンヘッダは、ロングピン(9mm)を採用。
- このマイコン自体のファームウェアもArduinoでのプログラミングが可能なため、ユーザー側で改造もできます。(FTDI Basicが必要です)
- INT PINがあります。これを使うとプログラム側で常にボタンの状況を監視する必要はありません。INT PINは、シールド側のD2/D3/D7に変更できますので、ボードによって違う割り込みピンに対応する事ができます。
- 本体サイズ W140×H150×D20(単位:mm)
使用例
本体の説明
I2C SELECT
INT PINを接続するピンを設定します。INT PINを使用しない場合は、ジャンパーピンを外します。D2/D3/D7以外をINT PINとして使用したい場合は、Arduino peripheralと、NCの左側のピンの裏まで線はんだづけすると便利です。INT PINの出力は、普段LOWで、ボタンを押した時に、1/1000秒 HIGHになります。
LCDボリューム
LCDの表示の濃さを変えるボリュームです。ちょうど良いところに調整しましょう。
ファームウェア書き換え用
FTDI Basic
FTDI Basic接続する端子です。ピンヘッダを半田付けしてください。ArduinoIDEを使用し、シールドのATmega328Pを書き換えをする時に使用します。
ICSP
ICSPを接続する端子です。AVRライターを使用し、シールドのATmega328Pを書き換えする時に使用します。
Arduino UNOでのプログラミング方法
このシールドにArduinoを差す
ピンが正確に刺されているように確認してください。ずれて刺されていると動作しません。
ライブラリをインストール
ライブラリは、ArduinoIDE1.8.2で動作確認されています。ここからライブラリをダウンロードします。
ArduinoIDEの「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール」から、ダウンロードしたファイルを開きます。
プログラムを書く
サンプルプログラムです。押されている一つのキーを読み込み、LCDに表示します。
#include <ControlPanel28.h>
#define I2C_ADDRESS 0x1E
ControlPanel cp(I2C_ADDRESS);
void setup() {
delay(1500);
cp.clear();
cp.setCursor(0,0);
cp.print("FLINT CP 28");
}
void loop() {
int KeyNo = 0;
KeyNo = cp.keyOne();
cp.setCursor(0,2);
char s1[3];
sprintf(s1, "%d", KeyNo);
cp.print(s1);
cp.print(" ");
}
1行目、ライブラリをインクルードします。
2行目、I2Cのアドレスを定義しています。このシールドのデフォルトのアドレスは、0x1Eです。
4行目、クラスを宣言しています。この時に、I2Cのアドレスを宣言します。
7行目、1.5秒間のディレイを入れています。シールドに装着されている、ATmega328Pが起動するまで待ちます。これを入れないと、setup()内のArduinoからシールドに対しての通信(I2C通信)が実行されない事があります。
8行目、LCDをクリアしています。
9行目、LCDのカーソルを0,0に。
10行目、LCDに文字列を出力します。
14行目、押されているボタンの番号を取得します。何も押されていないと0を返します。
17行目、数字を文字列に変換します。
18行目、ボタン番号をLCDへ出力します。
プログラミングのヒント
LCDへの出力は、LiquidCrystalとほぼ一緒ですので、迷う事はないと思います。
キーの入力に関しては、用途に応じていくつかの方法が用意されています。
ただ単純に、一つのキーが押されているかどうかを判断するのには、keyOne()で良いのですが、プログラムのloop(){}内ではループするので、何度もキーが押されている事になり、何度も実行する事になります。一度だけ実行すればいい時には、INT PINを使用し一度だけ実行するようにプログラミングするか、keyOrder()を使う事をお勧めします。
複数ボタンを押している事を認識したい場合、たとえば、あるキーを押しながら(Shiftキーのような使い方)、任意のキーを押したかどうか判断したい場合は、keyOrder()でキーを監視し、Shiftキーにあたるキーが押された時には無視をし、他のキーを押した時に、keyHear(num)で、Shiftキーにあたるキーが押されているかを確認して、動作を分岐するようなアルゴリズムが考えられます。
関数
このライブラリで提供している関数は以下の通りです。
clear()
LCDの画面をクリアし、カーソルを左上の角に移動させます。
home()
LCDのカーソルを左上の角へ移動します。続くテキストはその位置から表示されます。画面をクリアしたいときは、clear()を使用します。
setCursor(col, row)
LCDのカーソルの位置を指定します。続くテキストは、その位置から表示されます。
引数
col: 桁 (0が左端)
row: 行 (0が1行目)
write(data)
LCDに文字をLCDに表示します。
引数
data: 表示したい文字
print(data)
LCDにテキストを表示します。
構文
lcd.print(data)
lcd.print(data, BASE)
引数
cd: LiquidCrystal型の変数
data: 表示したいデータ (char, byte, int, long, stringの各型)
BASE (オプション): 数値を表示する際の基数。OCT、DEC、HEX
サンプルプログラム
#include <ControlPanel28.h>
#define I2C_ADDRESS 0x1E
ControlPanel cp(I2C_ADDRESS);
void setup() {
delay(1500);
cp.clear();
cp.setCursor(0,0);
cp.print("FLINT CP 28");
}
void loop() {
int KeyNo = 0;
KeyNo = cp.keyOne();
cp.setCursor(0,2);
cp.print(KeyNo,DEC);
cp.print(" ");
}
cursor()
LCDのカーソルを表示します。カーソルはアンダーラインで、その位置に次の文字が表示されます。
noCursor()
LCDのカーソルを隠します。
blink()
LCDのカーソルを点滅させます。結果は使っているディスプレイに依存します。
noBlink()
LCDのカーソルの点滅を停止します。
display()
LCDでnoDisplay()で消したディスプレイを元に戻します。表示されていた文字やカーソルもリストアされます。
noDisplay()
LCDを消します。表示中の文字は保持されます。
scrollDisplayLeft()
LCDで表示中の文字とカーソルを1文字分左へずらします。
scrollDisplayRight()
LCDで表示中の文字とカーソルを1文字分右へずらします。
autoscroll()
LCDで自動スクロール機能を有効にします。自動スクロールが有効のとき、新たな文字を出力すると、表示位置に元からある文字が押し出されます。デフォルトでは左から右へ押し出されます。右から左へ設定することもできます。
noAutoscroll()
LCDで自動スクロール機能を無効にします。
leftToRight()
LCDでテキスト表示の向きを左から右に指定します(デフォルト)。一連の文字は、右へ向かって伸びていきます。
rightToLeft()
LCDでテキスト表示の向きを右から左に指定します。一連の文字は、左へ向かって伸びていきます。
createChar(num, data)
LCDでカスタムキャラクタ(絵文字)を作成します。最大8文字まで登録可能です。キャラクタの形は8バイトの配列で表現され、各バイトが1行に対応します。各バイトの下位5ビットがピクセルパターンを表します。作成したキャラクタを表示するときは、そのキャラクタ番号とwrite()を組み合わせます。
引数
num: 作成するキャラクタの番号(1 to 7)
data: ピクセルデータの配列
サンプルプログラム
#include <ControlPanel28.h>
#define I2C_ADDRESS 0x1E
ControlPanel cp(I2C_ADDRESS);
void setup() {
delay(1500);
cp.clear();
byte smiley[8] = {
B00000,
B10001,
B00000,
B00000,
B10001,
B01110,
B00000,
};
cp.createChar(1,smiley);
cp.setCursor(1,1);
cp.write(1);
}
void loop() {
}
keyOne()
押されているキーの番号を返します。値は、0~28です。0が返された時は、どのキーも押されていません。2個同時押しされている場合は、先に押したキーの値しか返されません。
戻り値
byte値。0~28。
keyAll()
キーの全てのステータスを得ます。この関数を実行して、KeyStatusAllプロパティの配列を参照します。この関数からの戻り値はありません。
SW1のステータスは、KeyStatusAll[1] に booleanの値で、trueなら押されている、falseなら押されていない、という意味になります。
引数
なし
サンプルプログラム
ボタンのステータスをすべて、シリアル通信で返します。シリアルモニタで確認できます。
#include <ControlPanel28.h>
#define I2C_ADDRESS 0x1E
ControlPanel cp(I2C_ADDRESS);
void setup() {
delay(1500);
Serial.begin(9600);
Serial.println("------start Arduino Master------");
cp.clear();
}
void loop() {
cp.keyAll();
for(int i = 1;i <= 28 ; i++ ){
boolean ks = cp.keyStatusAll[i];
Serial.print(i);
Serial.print("=");
Serial.print(ks);
Serial.print(" ");
}
Serial.println("");
delay(500);
}
keyHear(num)
指定したキーが押されているか、検査します。
引数
num:1~28
戻り値
結果をbooleanで返されます。
True : 引数で指定したキーが押されています。
False : 引数で指定したキーが押されていません。
keyOrder()
キーを押された順番に、キー番号を返します。1キーずづ返されます。シールドには、この関数が実行されるまでに押されたキー番号をキャッシュする機能があります。9個までキャッシュされます。0が返されたとき、押されたキーはありません。
戻り値
byte値。0~28。
サンプルプログラム
#include <ControlPanel28.h>
#define I2C_ADDRESS 0x1E
ControlPanel cp(I2C_ADDRESS);
void setup() {
delay(1500);
cp.clear();
cp.print("start--");
cp.setCursor(0,1);
}
void loop() {
int KeyNo = 0;
KeyNo = cp.keyOrder();
if(KeyNo != 0){
cp.print(KeyNo,DEC);
cp.print(" ");
switch(KeyNo){
case 2:
cp.clear();
break;
case 28:
cp.demo();
break;
}
}
}
keyOrderClear()
keyOrder()のキャッシュを削除します。
demo()
押されているキーを表示する、デモモードになります。一度、このモードになると、PANEL RESETを押すまでこのモードから抜けません。ライブラリのバージョンや、ファームウェアのバージョンも確認できます。
プロパティ
errorCode
I2Cの通信状態のステータスを返します。
値
送信結果 (byte)
0: 成功
1: 送ろうとしたデータが送信バッファのサイズを超えた
2: スレーブ・アドレスを送信し、NACKを受信した
3: データ・バイトを送信し、NACKを受信した
4: その他のエラー
サンプルプログラム
#include <ControlPanel28.h>
#define I2C_ADDRESS 0x1E
ControlPanel cp(I2C_ADDRESS);
void setup() {
delay(1500);
cp.clear();
cp.print("start--");
cp.setCursor(0,2);
}
void loop() {
int KeyNo = 0;
KeyNo = cp.keyOrder();
if(KeyNo != 0){
cp.print(KeyNo,DEC);
cp.print(" ");
}
switch(cp.errorCode){
case 0:
Serial.println("OK");
break;
case 1:
Serial.println("Buffre overflow");
break;
case 2:
Serial.println("NACK to the slave address");
break;
case 3:
Serial.println("NACK to the data byte");
break;
case 4:
Serial.println("Unknown");
break;
}
delay(1000);
}
keyStatusAll
キーが押されているかどうか、配列の形で入っています。関数のkeyAll()を実行してからこのプロパティを参照してください。
値
boolean型。
boolean ks = cp.keyStatusAll[28];
true : キーが押された状態です。false : キーが押されていない状態です。
フロントパネルの設計例
シールドのファームウェアを書き換える
このシールドは、ATmega328P/16MHzが乗っており、LCDとキーの制御を行っています。I2CのSlaveデバイスとして、Master側のArduinoと通信する機能も担っています。
このシールドのATmega328Pは、ArduinoIDEでプログラミングされています。基板上のFTDI Basicにピンヘッダを半田付けし、FT232RL搭載小型USB-シリアルアダプタ 5Vなどを使ってプログラミングします。
また、ICSPも付いていますので、AVRライタを使用する事もできます。
FAQ
Q.Arduinoの対応機種は?
A.Aruduino UNO R2とR3で開発しています。Aruduino MEGA R3/Aruduino Leonardoでも動くと報告を頂いています。
Q.Arduino Leonardoで動きません。
A.INT PINがD2に刺さっていると、I2C通信ができません。
Q.LCDのバックライトをプログラム的に消すことはできますか?
A.回路的にそうなっていませんので、出来ません。ハードウェア的にバックライトを消すには、R3の抵抗を取るとバックライトが消えます。