LEDドライバ TM1630 を使ってみる (3) キー読み取り

秋月電子通商で購入した「7 セグメント用 LED ドライバー IC TM1630 IC TM1630」、LED 表示がうまくいきましたので、今回はキースキャン読み取りの動作を確認してみたいと思います。

キースキャン読み取りを含めた回路図

回路図です。
前回の LED 表示回路に、押しボタンスイッチを追加しています。表示まわりに変更はありません。

まずスイッチの取り付けですが、マトリクス用にスイッチングダイオードを追加しています。これがないと、複数のボタンを同時に押したときに、SEG ピンがショートしてしまい、LED 表示が狂ってしまいます。
前回、SEG ピンの出力波形の説明でも書きましたが、キースキャン読み取りモードでは、SEG ピンから定期的にパルスを出して K2 ピンで検出し、そのタイミングによってどのキーが押されたかを判断しています。したがって、SEG から K2 へ向けてダイオードを配置します。

DIO ピンは、読み取りモードではデータ出力としても働きます。データシートには、出力はオープンドレインなのでプルアップ抵抗をつけろ、と書かれています。
でも実測してみると、書き込みモード (入力) でも読み取りモード (出力) でも、DIO ピンには 5V 出ているんですよね。10KΩ の抵抗で GND に引っ張り込むと電圧が 2V に下がるんで、内部プルアップしているんじゃないかと。
そんなわけで、プルアップ抵抗はつけませんでした。もちろん、問題なく動作しています。

CLK 、STB は Arduino からの入力ですので、プルアップする必要はありません。もっとも、これらのピンも内部プルアップされてるようで、常に 5V が出ています。
100pF コンデンサは部品箱に、ないので (^_^;) つけてません。

キースキャン読み取りのスケッチ

前回の LED 表示のスケッチに、キースキャン読み取りの機能をプラスしました。

  1. // LED Driver TM1630 v.1.2a 2021.03.01 by meyon
  2. #include <MsTimer2.h>
  3. #define DISPLAY_MODE 0x00
  4. #define WRITE_REG_AUTO_ADDR 0x40
  5. #define WRITE_REG_FIXED_ADDR 0x44
  6. #define READ_KEY_SCAN 0x42
  7. #define SET_DISPLAY_ADDR 0xC0
  8. #define DISPLAY_OFF 0x80
  9. #define DISPLAY_ON 0x88 | 0x84
  10. #define STB_ENABLE LOW
  11. #define STB_DISABLE HIGH
  12. #define DOT_POSITION -1

キースキャンを時間割り込みするために MsTimer2 をインクルードしています。

データシートのフローチャートにあるように、表示処理のあとに続けてキースキャンをやってもいいと思います。目的にあわせて、より良い方法で。

  1. const int dioPin = 5;
  2. const int clkPin = 6;
  3. const int stbPin = 7;
  4. const int numberOfDigits = DISPLAY_MODE & 1 ? 5 : 4;
  5. int gridData[numberOfDigits] = {0};
  6. byte buttonState = 0;
  7. const int digit[] = {
  8.   0b01111110, // 0
  9.   0b00001100, // 1
  10.   0b10110110, // 2
  11.   0b10011110, // 3
  12.   0b11001100, // 4
  13.   0b11011010, // 5
  14.   0b11111010, // 6
  15.   0b01001110, // 7
  16.   0b11111110, // 8
  17.   0b11011110, // 9
  18.   0b00000000, // 10:blank
  19.   0b00100000, // 11:dot
  20. };
  21. const int blank = 10;
  22. const int dot = 11;

buttonState という変数を追加しています。ここに各ボタンの状態を格納します。

  1. void displayNumbers(int n) {
  2.   noInterrupts();
  3.   
  4.   for (int i = 0; i < numberOfDigits; i++) {
  5.     int exponentialInDecimal = pow(10, i) + 0.5;
  6.     bool zeroSuppression = (0 != i) && (DOT_POSITION < i) && (exponentialInDecimal > n);
  7.     gridData[i] = zeroSuppression ? blank : n / exponentialInDecimal % 10 ;
  8.   }
  9.   digitalWrite(stbPin, STB_ENABLE);
  10.   shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_MODE);
  11.   digitalWrite(stbPin, STB_DISABLE);
  12.   digitalWrite(stbPin, STB_ENABLE);
  13.   shiftOut(dioPin, clkPin, LSBFIRST, WRITE_REG_AUTO_ADDR);
  14.   digitalWrite(stbPin, STB_DISABLE);
  15.   digitalWrite(stbPin,STB_ENABLE);
  16.   shiftOut(dioPin, clkPin, LSBFIRST, SET_DISPLAY_ADDR | 0x00);
  17.   for (int i = 0; i < numberOfDigits; i++) {
  18.     shiftOut(dioPin, clkPin, LSBFIRST, digit[gridData[i]]);
  19.     shiftOut(dioPin, clkPin, LSBFIRST, DOT_POSITION == i ? digit[dot] : 0);
  20.   }
  21.   digitalWrite(stbPin, STB_DISABLE);
  22.   digitalWrite(stbPin, STB_ENABLE);
  23.   shiftOut(dioPin, clkPin, LSBFIRST, DISPLAY_ON);
  24.   digitalWrite(stbPin, STB_DISABLE);
  25.   interrupts();
  26. }

LED 表示の部分です。この処理中には割り込みを行わないようにしています。それ以外は、変更ありません。

  1. void keyboardScan() {
  2.   static byte scanData[4] = {0};
  3.   digitalWrite(stbPin, STB_ENABLE);
  4.   shiftOut(dioPin, clkPin, LSBFIRST, READ_KEY_SCAN);
  5.   
  6.   pinMode(dioPin, INPUT);
  7.   for (int i = 0; i < 4; i++) {
  8.     scanData[i] = shiftIn(dioPin, clkPin, LSBFIRST);
  9.   }
  10.   pinMode(dioPin, OUTPUT);
  11.   digitalWrite(stbPin, STB_DISABLE);
  12.   buttonState = 0;
  13.   for (int i = 0; i < 8; i++) {
  14.     buttonState |= (scanData[i / 2] >> ((i % 2) ? 4 : 1) & 1) << i;
  15.   }
  16. }

今回追加したキースキャン読み取りの部分。

まず、STB を有効にして、読み取りモードのコマンドを送ります。

次に Arduino 側の DIO (D5) ピンのモードを INPUT に変更し、shiftIn() で 4byte 受け取ります。
コマンドからデータの出力までの間に 1μs 待つようにデータシートには書かれていますが、ピンモードを変更したりしてる間にそんな時間は過ぎちゃいます。気にする必要はありません。

データを受け取ったらピンモードを OUTPUT に戻し、STB を無効にして終了です。

87~89 行目は、受け取ったデータを buttonState にビット列として格納しています。
KS1 ってキーは存在しませんがあるものとして、キーのデータは BYTE1~BYTE4 の B1 、B4 ビットにあります。それをひとつずつとりだしていきます。

KS1 = (BYTE1 >> 1) & 1 
KS2 = (BYTE1 >> 4) & 1
KS3 = (BYTE2 >> 1) & 1
  :
KS8 = (BYTE4 >> 4) & 1 

で、これらを buttonState にビット列として並べます。

buttonState = (BYTE1 >> 1) & 1
buttonState |= ((BYTE1 >> 4) & 1) << 1
buttonState |= ((BYTE2 >> 1) & 1) << 2
  :
buttonState |= ((BYTE4 >> 4) & 1) << 7

これが 89 行目のわけわからん部分です。

したがって、buttonState は LSB から KS1 、KS2 、KS3 … KS8 の 8 ビットのデータで、オン時 1 、オフ時 0 となります。KS1 は存在しませんから、常に 0 です。

この処理は、単にデータが 1byte に並んでいたら扱いやすいかなと思って作っただけなので、目的によってお好きなように。

  1. void setup() {
  2.   pinMode(dioPin, OUTPUT);
  3.   pinMode(clkPin, OUTPUT);
  4.   pinMode(stbPin, OUTPUT);
  5.   MsTimer2::set(1, keyboardScan);
  6.   MsTimer2::start();
  7. }

割り込み用の MsTimer2 の初期設定をしています。

  1. void loop() {
  2.   switch (buttonState) {
  3.     case 0x02:
  4.       displayNumbers(1);
  5.       break;
  6.     case 0x04:
  7.       displayNumbers(2);
  8.       break;
  9.     case 0x08:
  10.       displayNumbers(3);
  11.       break;
  12.     case 0x10:
  13.       displayNumbers(4);
  14.       break;
  15.     case 0x20:
  16.       displayNumbers(5);
  17.       break;
  18.     case 0x40:
  19.       displayNumbers(6);
  20.       break;
  21.     case 0x80:
  22.       displayNumbers(7);
  23.       break;
  24.     default:
  25.       displayNumbers(0);
  26.   }
  27. }

押したボタンに応じた数を表示させる確認用のスケッチです。
ボタンの状態を読み込めれば、あとはもうどうにでもしてください。

ブレッドボード

ブレッドボードです。

TM1630 による LED 表示 / キースキャン回路

下にタクトスイッチを 7 個つないでいます。タクトスイッチはそれぞれダイオードを介して K2 ピンへつながります。
オシロスコープは、「8888」を表示しているときの SEG2 / KS2 ピンの波形です。これはセグメント a につながっていて 4 桁とも点灯していますから、4 個のパルスが繰り返し出ています。

キーの読み取り方法

キースキャンでどのようにキーを読み取っているのか、波形をみることでわかってきました。

波形 1 SEG2 / KS2 の出力

波形 1 は SEG2 / KS2 の出力です。

幅 0.5ms のパルスが 4 個ずつ並んでいますが、これがセグメントをオンにする信号です。間に 0.5ms の LOW の期間がありますが、その期間の 2 回に 1 回、幅の小さなパルスが出ているのがわかります。これが、キースキャン用の信号です。

SEG2 / KS2 では、0.5ms の期間の初めのほうで出力されています。

波形 2 SEG5 / KS5 の出力

波形 2 は SEG5 / KS5 の出力です。

同様にセグメントの信号が 4 個ずつ並んでいて、間に 0.5ms の LOW の期間があります。そこにキースキャン用の細いパルスが出ています。

SEG5 / KS5 では、キースキャン用の信号は、0.5ms の期間の中央付近で出力されます。

波形 3 SEG8 / KS8 の出力

波形 3 は SEG8 / KS8 の出力で、キースキャン用信号は、0.5ms の期間の最後のほうで出力されています。

このように時間差を持った信号を出力することで、どのキーが押されているかを判別しているようです。

ちなみに、K2 ピンに 5V を放り込むと、BYTE1~4 のすべてのビットが立ちます。なにか裏技に使えるかも (^_^;)

とゆーわけで。
LED 表示を 4 桁の数値表示させてみましたけど、固定アドレスを使って 4 桁を独立して制御することも可能です。時計のように時分を 2 桁ずつわけて表示することも簡単にできそう。
ボタンは、たとえば LED の輝度調整とかオンオフとかもできますねぇ。ボタン入力だけでもいいわけで、7 個のボタン入力を 3 線でできるのは、Arduino のピン節約に大いに役立ちます。
今回は動作確認の実験だけでしたが、いろいろ使えそうな気がしています。

タイトルとURLをコピーしました