フォト
2025年3月
            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          
無料ブログはココログ

« 2017年8月 | トップページ | 2017年10月 »

2017年9月の8件の記事

2017年9月25日 (月)

注文していたスイッチが到着

キーボード作成のために注文していた、未到着スイッチが到着しました。

Dscn7071

ボタン部がシリコン製のスイッチは、タッチ感抜群で、タクトスイッチがゴミのように思えます。
連打を要するゲーム機の作成にはこのスイッチがおすすめです。

一方、2ピン省スペース角形スイッチ、タッチ感は通常のタクトスイッチを同じですが、
面積を取らず、これはこれで使い勝手良好です。

キーボード製作(完成版)はシリコン製のスイッチを利用、
試作では前回到着した激安タクトスイッチ利用で作業を進めていきます^^

2017年9月20日 (水)

グラフィック描画まわりの実装に苦戦

ここ数日、手がけている豊四季Tiny BASIC for ArduinoのOLED(SSD1309)利用
グラフィックスクロール処理の実装ではまっていました。

画面の向き(縦横の変更)を変えることが出来て、各画面の向きに応じて
画面の任意矩形領域の上下左右1ドット単位スクロールを行うというコマンドの実装です。

いきなりコーディングしていたのですが、上手く動かず。
それで、机上で図やなりやらを書いて、変換式を求めて再度実装すると
期待通りの動きが出来ました。

やはり、コーディング => 実行 => 修正の繰り返しの試行錯誤で「何となく動いた」ではなく
ちぇんとロジックと方式を検討してからコードを書かないとだめですね。効率的にも..

Dscn7032

具体的な数値の変換例から、抽象的な数式を求めて一般化しました。

とりあえず、GSCROLLコマンドが実装出来ました。


デモ動画では全画面スクロールですが、画面上の任意の矩形領域のスクロールも可能です。
あまり用途の無いコマンドですが、まあいいでしょう^^

OLEDだと、スクロールしても残像もなくっ切り表示ですね。
手持ちのモノラルグラフィック液晶はもう、使いたくなくなります。


動画の動作確認のプログラムはつぎのような感じです。

10 'GSCROLL TEST
20 FOR R=0 TO 3
30 SCREEN 1,R
40 FOR D=0 TO 3
50 GOSUB "@DISP"
60 FOR I=1 TO 8
70 GSCROLL 0,0,GW-1,GH-1,D
80 WAIT 200
90 NEXT I
100 NEXT D
110 NEXT R
120 SCREEN 1
130 END
140 "@DISP"
150 CLS:GPRINT 10,10,"GSCROLL"
160 GPRINT 0,0,"A"
170 GPRINT GW-7,0,"B"
180 GPRINT 0,GH-9,"C"
190 GPRINT GW-7,GH-9,"D"
200 RETURN

2017年9月15日 (金)

豊四季 Tiny BASIC でOLEDとグラフィック液晶の対応

現在取り組んでいる豊四季 Tiny BASIC for Arduino STM32、
OLEDディスプレイとグラフィック液晶対応を行っています。

そこそこ、動作するようになってきました。

Dscn7017

OLED (SH1106コントローラ I2C接続)ディスプレイ利用のデモ

TFTグラフィック液晶(ILI9341コントローラ SPI接続)パネル利用のデモ


表示系は、NTSC、ターミナルコンソール、グラフィック液晶、OLEDと複数対応するために
プログラム的には基本クラスを設けて、派生する形で各表示器対応の実装をしています。

ただし、クラス設計が今一だったため、実装が進むにつれて、
非常に分かりにくいプログラムになってしまいました。

思うがままに、機能追加していった割には、良く動いているなぁ



注文していた激安タクトスイッチが到着

Aliexpressで注文していたタクトスイッチが到着しました。
9/6に注文して、9/15に到着。最近配達が早くなった感じです。

Dscn7026


Dscn7028

2ピンタイプはブレッドボード上での利用に良さそうです。
送料込みで 4ピンタイプが100個 $0.79、2ピンタイプが100個 $1.57。

国内で買うと1個10円するのでかなりお得です。

2017年9月14日 (木)

Windowsストア版 Arduino IDEは自動アップデートされる

Windowsストア版 Arduino IDEを起動したら、いつの間にか 1.8.4にアップデートされていました。
常に最新版を利用したい場合には、Windowsストア版の方が良さそうです。


01

2017年9月12日 (火)

SH1106コントローラ使用OLED用ライブラリの作成

以前購入した 次の1.3インチのOLEDモジュール(I2C版とSPI版)、

I2Cインタフェース版
1.3" OLED module white color 128X64 1.3 inch OLED Display Module 1.3" I2C Communicate

02

SPIインタフェース版
1.3" OLED module white color 128X64 1.3 inch OLED Display Module 1.3"  SPI Communicate
03

SH1106というコントローラーが乗っているのですが、Arduino STM32用のライブラリがありません。
そこで、公開されている次のAdafruitベースのライブラリを参考にして作成しました。
(正確には移植ですね^^)

https://github.com/wonho-maker/Adafruit_SH1106
ttps://github.com/rogerclarkmelbourne/Arduino_STM32/tree/master/STM32F1/libraries/Adafruit_SSD1306


SH1106というコントローラーはほぼSSD1306コマンド等はにており、
wonho-makerさんが作成公開しているArduino用のSH1106利用ライブラリの参考にして
Arduino STM32版 SSD1306利用ライブラリを修正しました。
(wonho-makerさんに感謝!)

SSD1306ではSPIのクロック速度が10MHzくらいまでしか出せなかったのですが、
SH1106ではBlue Pillボードで出せる最高速度の36MHzでも動作しました。

作成したライブラリは下記にて公開しました。
https://github.com/Tamakichi/Adafruit_SH1106_STM32


サンプルスケッチを動かした様子
左がSPI版、右がI2C版です。

01

SSD1306とほぼ同じ動作ですが、スクロール機能は未対応です。

2017年9月10日 (日)

ベットに寝ているタマちゃん

ベットに寝ているタマちゃん。う~ん、デカい! 居られると寝れません。

Dscn6999

動物病院でも、「デカいなぁ、洋猫の血が混ざってるね」と言われています。

デカいだけあって怪力の持ち主。完全に閉まっているアルミサッシ窓を自力で開けて
ベランダに出ます。私が開けてもちょっと重く感じるのですが..

怪力により猫用爪研ぎ段ボールは、短時間でボロボロになり要交換。
幸いなことに、家の壁や備品での爪研ぎは全く行いませんが、やられたら被害は甚大!


2017年9月 4日 (月)

キーボードの作成 その2

前回の続きです。

64キーを次のような感じに割り付けました。
64キーだと足りないため、Fnキーを押すことで、ファンクションキー等の水色キーが
入力できます。

01

押したボタン入力は、PS/2キーボード I/Fの信号に変換します。
とりあえず、IchigoJamにて利用出来ることを確認しました。

Dscn6955

PS/2 キーボードのエミュレーションは ps2devライブラリを利用しました。
・PS2 mouse interface for Arduino
  http://playground.arduino.cc/ComponentLib/Ps2mouse

スケッチは次のような感じです。
Fnキーの処理とキーの長押し時のリピート処理がちょっと面倒でした。

(2017/9/6 スケッチを修正しました)

#include <Arduino.h>
#include <ps2dev.h>

#define KB_CLK      9  // PS/2 CLK  IchigoJamのKBD1に接続
#define KB_DATA     10 // PS/2 DATA IchigoJamのKBD2に接続

#define SOUT_PIN   2 // シリアルアウト
#define CLK_PIN    3 // クロック
#define LATCH_PIN  4 // ラッチ
#define SCN1_PIN   5 // ライン1
#define SCN2_PIN   6 // ライン2
#define SCN3_PIN   7 // ライン3
#define SCN4_PIN   8 // ライン4

#define KEY_NUM 64 // キー数
// キーリピートの定義
#define REPEATTIME      5   // キーを押し続けて、REP_INTERVALxREPEATTIMEmsec後にリピート開始
#define EMPTY           0   // リピート管理テーブルが空状態
#define MAXKEYENTRY     64  // リピート管理テーブルサイズ
#define REP_INTERVAL    10  // リピート間隔 100msec

PS2dev keyboard(KB_CLK, KB_DATA); // PS/2デバイス

// スキャンコードテーブル
const uint8_t scan_table[][4] =  {
 {  0x76,0x00  ,  0x05,0x00  ,  },  // 0 ESC
 {  0x16,0x00  ,  0x06,0x00  ,  },  // 1 1
 {  0x1E,0x00  ,  0x04,0x00  ,  },  // 2 2
 {  0x26,0x00  ,  0x0C,0x00  ,  },  // 3 3
 {  0x25,0x00  ,  0x03,0x00  ,  },  // 4 4
 {  0x2E,0x00  ,  0x0B,0x00  ,  },  // 5 5
 {  0x36,0x00  ,  0x83,0x00  ,  },  // 6 6
 {  0x3D,0x00  ,  0x0A,0x00  ,  },  // 7 7
 {  0x3E,0x00  ,  0x01,0x00  ,  },  // 8 8
 {  0x46,0x00  ,  0x09,0x00  ,  },  // 9 9
 {  0x45,0x00  ,  0x78,0x00  ,  },  // 10 0
 {  0x4E,0x00  ,  0x07,0x00  ,  },  // 11 -
 {  0x55,0x00  ,  0x00,0x00  ,  },  // 12 ^
 {  0x6A,0x00  ,  0x00,0x00  ,  },  // 13 ¥
 {  0xE0,0x6C  ,  0xE0,0x70  ,  },  // 14 Home
 {  0x66,0x00  ,  0xE0,0x71  ,  },  // 15 BS
 {  0x29,0x00  ,  0x0D,0x00  ,  },  // 16 Space
 {  0x15,0x00  ,  0x6C,0x00  ,  },  // 17 q
 {  0x1D,0x00  ,  0x75,0x00  ,  },  // 18 w
 {  0x24,0x00  ,  0x7D,0x00  ,  },  // 19 e
 {  0x2D,0x00  ,  0x7B,0x00  ,  },  // 20 r
 {  0x2C,0x00  ,  0xE0,0x4A  ,  },  // 21 t
 {  0x35,0x00  ,  0x00,0x00  ,  },  // 22 y
 {  0x3C,0x00  ,  0x00,0x00  ,  },  // 23 u
 {  0x43,0x00  ,  0x00,0x00  ,  },  // 24 i
 {  0x44,0x00  ,  0x00,0x00  ,  },  // 25 o
 {  0x4D,0x00  ,  0x00,0x00  ,  },  // 26 p
 {  0x54,0x00  ,  0x00,0x00  ,  },  // 27 @
 {  0x5B,0x00  ,  0x00,0x00  ,  },  // 28 [
 {  0x00,0x00  ,  0x00,0x00  ,  },  // 29 Fn
 {  0xE0,0x69  ,  0x00,0x00  ,  },  // 30 End
 {  0x59,0x00  ,  0x00,0x00  ,  },  // 31 RghtShift
 {  0x12,0x00  ,  0x58,0x00  ,  },  // 32 LeftShift
 {  0x1C,0x00  ,  0x6B,0x00  ,  },  // 33 a
 {  0x1B,0x00  ,  0x73,0x00  ,  },  // 34 s
 {  0x23,0x00  ,  0x74,0x00  ,  },  // 35 d
 {  0x2B,0x00  ,  0x79,0x00  ,  },  // 36 f
 {  0x34,0x00  ,  0x7C,0x00  ,  },  // 37 g
 {  0x33,0x00  ,  0x00,0x00  ,  },  // 38 h
 {  0x3B,0x00  ,  0x00,0x00  ,  },  // 39 j
 {  0x42,0x00  ,  0x00,0x00  ,  },  // 40 k
 {  0x4B,0x00  ,  0x00,0x00  ,  },  // 41 l
 {  0x4C,0x00  ,  0x00,0x00  ,  },  // 42 ;
 {  0x52,0x00  ,  0x00,0x00  ,  },  // 43 :
 {  0x5D,0x00  ,  0x00,0x00  ,  },  // 44 ]
 {  0xE0,0x71  ,  0x00,0x00  ,  },  // 45 PageUp
 {  0xE0,0x75  ,  0x00,0x00  ,  },  // 46 ↑
 {  0xE0,0x7A  ,  0x00,0x00  ,  },  // 47 PageDown
 {  0x14,0x00  ,  0x13,0x00  ,  },  // 48 LeftCtrl
 {  0x1A,0x00  ,  0x69,0x00  ,  },  // 49 z
 {  0x22,0x00  ,  0x72,0x00  ,  },  // 50 x
 {  0x21,0x00  ,  0x7A,0x00  ,  },  // 51 c
 {  0x2A,0x00  ,  0x70,0x00  ,  },  // 52 v
 {  0x32,0x00  ,  0x71,0x00  ,  },  // 53 b
 {  0x31,0x00  ,  0x00,0x00  ,  },  // 54 n
 {  0x3A,0x00  ,  0x00,0x00  ,  },  // 55 m
 {  0x41,0x00  ,  0x00,0x00  ,  },  // 56 ,
 {  0x49,0x00  ,  0x00,0x00  ,  },  // 57 .
 {  0x4A,0x00  ,  0x00,0x00  ,  },  // 58 /
 {  0x51,0x00  ,  0x00,0x00  ,  },  // 59 ¥
 {  0x5A,0x00  ,  0x00,0x00  ,  },  // 60 Enter
 {  0xE0,0x6B  ,  0xE0,0x2F  ,  },  // 61 ←
 {  0xE0,0x72  ,  0xE0,0x1F  ,  },  // 62 ↓
 {  0xE0,0x74  ,  0x11,0x00  ,  },  // 63 →
};            

uint8_t lines[] = { SCN1_PIN, SCN2_PIN, SCN3_PIN, SCN4_PIN }; 
uint16_t scn[4];        // キーボード状態
uint16_t prev_scn[4];   // 前回のキーボード状態
uint8_t enabled =0;               // PS/2 ホスト送信可能状態
uint8_t keyentry[MAXKEYENTRY];    // リピート管理テーブル
uint8_t repeatWait[MAXKEYENTRY];  // リピート開始待ち管理テーブル

// PS/2 ホストにack送信
void ack() {
  while(keyboard.write(0xFA));
}

// PS/2 ホストから送信されるコマンドの処理
int keyboardcommand(int command) {
  unsigned char val;
  uint32_t tm;
  switch (command) {
  case 0xFF:  ack();// Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。
    //keyboard.write(0xAA);
    break;
  case 0xFE: // 再送要求
    ack();
    break;
  case 0xF6: // 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //キースキャンを開始する
    //FM
    enabled = 1;
    ack();
    break;
  case 0xF3: //set typematic rate/delay : 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xF2: //get device id : 
    ack();
    keyboard.write(0xAB);
    keyboard.write(0x83);
    break;
  case 0xF0: //set scan code set
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xEE: //echo :キーボードが接続されている場合、キーボードはパソコンへ応答(ECHO Responce)を返す。
    //ack();
    keyboard.write(0xEE);
    break;
  case 0xED: //set/reset LEDs :キーボードのLEDの点灯/消灯要求。これに続くオプションバイトでLEDを指定する。 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  }
}

//
// PS/2 makeコード送信
// 引数 index    : キーライン   0 ~ 3
//      no       : ライン内番号 0 ~ 15
//      flgFnKey : Fnキーの状態 0 or 1
//
void sendKeyMake(uint8_t index, uint8_t no, uint8_t flgFnkey) {
  uint8_t code1,code2;
  
  // キーコードの取得
  if (flgFnkey) {
    code1 = scan_table[index*16+no][2];
    code2 = scan_table[index*16+no][3];
  } else {
    code1 = scan_table[index*16+no][0];
    code2 = scan_table[index*16+no][1];
  }

  // PS/2キーの発行
  if (code2 == 0) {
    keyboard.write(code1);
  } else {
    keyboard.write(code1);
    keyboard.write(code2);    
  }
}

//
// PS/2 breakコード送信
// 引数 index    : キーライン   0 ~ 3
//      no       : ライン内番号 0 ~ 15
//      flgFnKey : Fnキーの状態 0 or 1
//
void sendKeyBreak(uint8_t index, uint8_t no, uint8_t flgFnkey) {
  uint8_t code1,code2;

  // キーコードの取得
  if (flgFnkey) {
    code1 = scan_table[index*16+no][2];
    code2 = scan_table[index*16+no][3];
  } else {
    code1 = scan_table[index*16+no][0];
    code2 = scan_table[index*16+no][1];
  }

  // PS/2キーの発行
  if (code2 == 0) {
    keyboard.write(0xF0);
    keyboard.write(code1);
  } else {
    keyboard.write(code1);
    keyboard.write(0xF0);
    keyboard.write(code2);    
  }
}

// リピート処理(タイマー割り込み処理から呼ばれる)
void sendRepeat() {
  uint8_t index,no,flgFnKey;
  uint8_t key;
  
  for (uint8_t i=0; i < MAXKEYENTRY; i++) {
    if (keyentry[i] != EMPTY) {
      if (repeatWait[i] == 0) {
        key = keyentry[i]; 
        flgFnKey = key & 0x80 ? 1:0;
        no = key % 16;
        index = (key & 0x7F)/16;      
        sendKeyMake(index,no,flgFnKey);
    } else {
        repeatWait[i]--;          
      }
    }
  }
}

// キーボード状態の取得
void getKeyCode() {
  uint16_t clm = 0x0001;  
  memset(scn, 0, 8);
  for (uint8_t i=0; i < 16; i++) {
    digitalWrite(LATCH_PIN, LOW);
    shiftOut(SOUT_PIN, CLK_PIN, LSBFIRST, ~clm & 0xff );
    shiftOut(SOUT_PIN, CLK_PIN, LSBFIRST, ~(clm>>8) & 0xff ); 
    digitalWrite(LATCH_PIN, HIGH);     
    for (uint8_t j=0; j <4; j++) {
        scn[j]<<=1;
        scn[j] |= digitalRead(lines[j]);
     }
     clm<<=1;  
  }
}

// スキャンコードの送信
void sendScanCode() {
  uint8_t scn_bit;      // 現在の状態
  uint8_t prev_scn_bit; // 前回の状態
  uint8_t flgFnKey;     // Fnキーの状態
  uint8_t prevflgFnKey; // Fnキーの状態

  // Fnキーのチェック
  flgFnKey = scn[1]&(0x8000>>13) ? 0:1; 
  prevflgFnKey = prev_scn[1]&(0x8000>>13) ? 0:1; 
  
  for (uint8_t i=0; i < 4; i++) {
    for (uint8_t j=0; j < 16; j++) {     
      scn_bit = scn[i]&(0x8000>>j) ? 0:1;
      prev_scn_bit = prev_scn[i]&(0x8000>>j) ? 0:1;

      // Fnキーの場合
      if (i==1 && j==13) {
        continue;
      }

      // 前回から状態が変化しているキーの処理 
      if (scn_bit != prev_scn_bit) {
        if (scn_bit) {
          // キーが押された
          sendKeyMake(i, j, flgFnKey);
          if ( !(i == 2 && j == 0) &&  !(i == 1 && j == 15)) {
            addKey(i, j, flgFnKey);
          }       
        } else {
          // キーが離された
          sendKeyBreak(i, j, flgFnKey);
          if ( !(i == 2 && j == 0) && !(i == 1 && j == 15)) {
            delKey(i, j, flgFnKey);
          }
        }
      } else {
        if (scn_bit && flgFnKey != prevflgFnKey){
          // キーを押している状態でFnキーが切り替わった
          sendKeyBreak(i, j, prevflgFnKey);
          if ( !(i == 2 && j == 0) && !(i == 1 && j == 15)) {
            delKey(i, j, prevflgFnKey);
            sendKeyMake(i, j, flgFnKey);
            addKey(i, j, flgFnKey);
          }
        }
      }
    }
  }
}

// リピート管理テーブルのクリア
void claerKeyEntry() {
 for (uint8_t i=0; i <MAXKEYENTRY; i++)
    keyentry[i] = EMPTY;
}

// リピート管理テーブルにキーを追加
void addKey(uint8_t index, uint8_t no, uint8_t flgFnkey) {
 uint8_t key = index*16+no | (flgFnkey ? 0x80:0);
 for (uint8_t i=0; i <MAXKEYENTRY; i++) {
  if (keyentry[i] == EMPTY) {
    keyentry[i] = key;  
    repeatWait[i] = REPEATTIME;
    break;
  }
 }
}

// リピート管理テーブルからキーを削除
void delKey(uint8_t index, uint8_t no, uint8_t flgFnkey) {
 uint8_t key = index*16+no | (flgFnkey ? 0x80:0);
 for (uint8_t i=0; i <MAXKEYENTRY; i++) {
  if (keyentry[i] == key) {
    keyentry[i] = EMPTY;
    //break;
  }
 }  
}

void setup() {
  Serial.begin(115200);
  pinMode(SOUT_PIN,  OUTPUT);
  pinMode(CLK_PIN,   OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);  
  pinMode(SCN1_PIN,  INPUT_PULLUP);  
  pinMode(SCN2_PIN,  INPUT_PULLUP);  
  pinMode(SCN3_PIN,  INPUT_PULLUP);  
  pinMode(SCN4_PIN,  INPUT_PULLUP); 

  while(keyboard.write(0xAA)!=0);  
  while(keyboard.write(0x00)!=0);
  
  claerKeyEntry();
  memset(scn, 0xff, 8);
  Serial.println(F("Start."));
}

void loop() {
  static uint32_t tm = 0;
  unsigned char c;  // ホストからの送信データ
  if( (digitalRead(KB_CLK)==LOW) || (digitalRead(KB_DATA) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  } 

  for (uint8_t i=0; i <4; i++)  prev_scn[i] = scn[i];    
  getKeyCode();
  sendScanCode();

  //キーリピート処理
  if (millis() >= tm+100) {
    sendRepeat();
    tm = millis();
  }
}

一点、問題が発覚。
なぜか、同じライン(横一列)の同時入力が出来ません。
シフトキーとの同時押しが出来ないのはちょっと問題です。
ハードウェア的には可能なはずなのですが.. ソフト的な問題?
原因調査中です。

2017/09/05 追記
スイッチを2つにて単純化して検証。
結線して確認しました(左側の回路図)。

K1のボタンを押すとLEDが点灯しますが、K2を同時に押すとVCC→K2→K1→GNDの経路で、

電流が流れてしまいショートしてしまいます。
これはちょっとまずいですね。

右の回路のようにダイオードを入れて対応するしかなさそうです。
このタクトスイッチモジュール、そのまま使うには問題ありですね。
安いですが、あまりお手軽に利用出来ないようです。

回路図

配線もちょっとめんどくさくなりますね。

全体をダイオードを追加する回路図に修正しましました。

01_3

端子を基板に乗せられるものに変更し、実装し直しました。

Dscn6964

再度、IchigoJamに接続して動作確認

Dscn6968

同時押しも出来るようになりました。

Dscn6967

このサイズのキーボード、意外と使い心地良さそうです。
現時点ではArduinoを使っていますが、Atmega328マイコンに置き換えて、
基板実装すれば、小型化は出来ると思います。

キーの刻印を何としたいですね。方法をちょっと考えてみます。

2017/09/09追記

結局、タクトスイッチを基板に並べ5行、12列の60キーで実装することにしました。
キーの刻印は、基板にシールを貼る形にします。

手持ちのタクトスイッチでは足りないため、手ごろな製品をAliexpressにて見つけて発注しました。

100個 $0.79の激安タクトスイッチ 試作に使うにはこれで良いでしょう

07

2ピンタイプのタクトスイッチ 100個 $1.57 はんだ付け楽になるが強度不足になるかも

05

2ピンタイプで通常の1/2幅 100個 $1.50 空いたスーペースにキーの刻印表記出来そう

06

ボタン部分の素材がシリコン 100個 $4.90 (多く買うと割引) 押し心地がよさそう

08

キーが5行×12列の場合、キーの状態をスキャンする端子は17本となります。
これとは別に、PS/2 IF に2本、シリアル通信 2本が必要で合計で21本が必要。

ATmega328をArduinoとして利用する場合、最大22本をデジタル入出力で利用出来ます。
そうすると、シフトレジスタ無しで直接制御も出来そうですね。
結線もさらに簡略化出来ると思います。
1本余るので状況に応じて、1列または1行分キーの追加も出来ます。






« 2017年8月 | トップページ | 2017年10月 »