前回の投稿から、ずいぶん時間が経ってしまいましたが、久しぶりに再開します。今回は、#256ボード上に搭載されているシフトレジスタHC595のアクセス方法や、Arduinoの入力ポートに接続されたタクト・スイッチの読み出しなどについて説明します。
●シフトレジスタHC595について
HC595はシリアル信号をパラレル信号に変換する、シフトレジスタと呼ばれる一種の一時記憶デバイスです(レジスタとは一時記憶素子のこと)。1本のデータ信号とクロック信号により、1デバイスあたり、8ビットのパラレル信号に変換することができます。
クロックが入力されるごとに、シフトレジスタのQAビットの内容がQBビットに、QBビットの内容がQCにというふうに、それぞれ上位ビットに同時に移動し、最下位のQAビットには、SI入力の状態が設定されます。これを8回繰り返すと、一番初めのSI信号の状態がQHに、8番目のSI信号の状態がQAビットに設定された状態、つまり、8個のシリアル信号が、8ビットのパラレル信号に変換されたことになります。
元々QHビットにあったデータは消失しますが、このデータをさらに別のシフトレジスタの入力として、同じクロック信号でシフトさせることで、パラレル・ビットの幅を拡張することができます。
通常はシフトしている途中のデータが順次QA~QHに出力され、出力状態が定まりませんが、このHC595にはシフトレジスタの後段にラッチ(パラレルのレジスタ)がついていますので、8回のシフトが完了した時点で、確定したデータのみを出力することができます。そのラッチを制御するのにRCK信号が用意されています。
マイコンのプログラムで汎用ポートを利用してICを制御する場合、ハードウェアの動作速度に対して、マイコン動作が十分に遅いので、信号の安定待ち(セットアップ時間確保)などためにディレイを入れる必要はあまりありません。今回もクロック信号SCKなどのパルス生成の際にも余計な待ち処理は不要で、プログラムもシンプルになります。
HC595で8ビットのデータを出力する手順を簡単に説明すると次のようになります。
(1) SI信号に出力すべきデータの最上位ビットの状態を設定
(2) SCK信号にパルスを印加→これにより、1ビットシフト
(3) 出力データの値を1ビット左(上位側)にシフト
(4) (1)~(3)の処理を8回繰り返す
(5) 最後にRCK信号にパルスを印加して、出力を確定
実際のコード(1バイト出力関数)は次のようになります(該当部分のみ抜粋)。
// HC595制御信号が接続されている、Arduinoのディジタル・ポートの倫理番号(#256用)
#define SR_LAT 12
#define SR_DAT 6
#define SR_CLK 7// ビット操作マクロ
#define SR_DAT_1 digitalWrite(SR_DAT, HIGH)
#define SR_DAT_0 digitalWrite(SR_DAT, LOW)
#define SR_LAT_H digitalWrite(SR_LAT, HIGH)
#define SR_LAT_L digitalWrite(SR_LAT, LOW)
#define SR_CLK_H digitalWrite(SR_CLK, HIGH)
#define SR_CLK_L digitalWrite(SR_CLK, LOW)byte SRBuf; // 出力値保存用バッファ変数
// 1バイト出力関数
void SetSR(byte val) {
byte i;SRBuf = val; // バッファ変数へ出力値を保持
for(i = 0; i < 8; i++) { // 8回繰り返し
if((val & 0x80) != 0) {
SR_DAT_1; // HC595のSI信号を"H"レベルに設定
} else {
SR_DAT_0; // HC595のSI信号を"L"レベルに設定
}
val <<= 1; // 出力データの次のビットを最上位ビットに移動// シフトパルス
SR_CLK_H; // HC595のSCK信号を"H"レベルに設定
SR_CLK_L; // HC595のSCK信号を"L"レベルに設定
} // for文の終わり// ラッチパルス
SR_LAT_H; // HC595のRCK信号を"H"レベルに設定
SR_LAT_L; // HC595のRCK信号を"L"レベルに設定
}
SR_XXX_1またはSR_XXX_Hは該当する出力ポートを"H"レベルに設定するマクロ、SR_XXX_0またはSR_XXX_Lは"L"レベルに設定するマクロです。これらのポートはあらかじめ出力に設定しておく必要があります。
digitalWrite()は1ビットの出力ポートの状態を"H"または"L"レベルに設定するためのArduinoの標準ライブラリ関数です。
SRBufは出力した値を保持する1バイトの変数で、シフトレジスタの出力値をビット演算したいときに、現在の出力値を取得するために使用します。
8回シフト・パルスを加えたのち、RCKパルスで出力を確定しています。
#256基板では、HC595のQA~QDの四つの出力にLEDが接続されているため、出力データの下位4ビットの該当ビットを"1"に設定すると対応するLEDが点灯します。また、QFはLCDのバックライトのON/OFF、QGはリレーON/OFF信号になっています。
●スイッチ状態の読出し
四つのスイッチがダイオードを通してArduinoのD4~D7(スイッチ・センス時は入力に設定)に接続されています。この4本の信号は、I/Oポート数を節約するため、LCDのデータ線と共用しています。
スイッチはイネーブル信号(D13)により電気的に切り離し可能で、LCDにデータを書き込むときは、スイッチはディセーブルにしておきます。スイッチの状態を読み出す時だけイネーブルにしてスイッチ状態を読み出したのち、再びディセーブルにしてLCD用にデータ線を解放しておきます。
イネーブル状態のとき、スイッチを押すと対応信号がGNDに接続され、対応する入力ポートが"L"レベルになります。
イネーブル信号を"H"レベルに設定するとトランジスタが導通して、スイッチの一端がGNDに接続されます。逆にこの信号を"L"レベルに設定すると、トランジスタが遮断してスイッチの一端はフロート状態となり、スイッチは電気的にD4~D7ポートから切り離されます。
スイッチ周辺の回路図(抜粋)を次に示します。
// スイッチ・イネーブル、ディセーブル切替マクロ(D13)
#define KEY_ENA digitalWrite(13, HIGH)
#define KEY_DIS digitalWrite(13, LOW)// スイッチが接続されている、Arduinoのディジタルポートの倫理番号(#256用)
#define KEY_D0 4
#define KEY_D1 5
#define KEY_D2 6
#define KEY_D3 7// キーセンス関数
unsigned char KeySense(void) {
unsigned char dat;// スイッチ用ディジタル・ポートを入力に設定
pinMode(KEY_D0, INPUT);
pinMode(KEY_D1, INPUT);
pinMode(KEY_D2, INPUT);
pinMode(KEY_D3, INPUT);KEY_ENA; // スイッチをイネーブル
dat = PIND >> 4; // スイッチ状態を読み出す(下位詰め)
KEY_DIS; // スイッチを切り離す// ディジタル・ポートを出力に戻しておく(LCD制御のため)
pinMode(KEY_D0, OUTPUT);
pinMode(KEY_D1, OUTPUT);
pinMode(KEY_D2, OUTPUT);
pinMode(KEY_D3, OUTPUT);return dat; // 読み出した4ビットのスイッチ状態を返す
}
●LCDアクセス
LCDはAruduino標準ライブラリのLiquidCrystal()関数を利用します。前述のように、4ビットのデータ信号はスイッチ用の入力ポートと兼用になっていますが、スイッチを使い終わった後にすぐディセーブルにするようにしておけば、LCDのアクセスに関しては、このことを意識する必要はありません。
コード例は連載(3)の「LiquidCrystal(LCD;液晶表示器)」の項を参照してください。
