小学生の頃に半田付けしたくらいの自分が、自作キーボード作成のためのハード(TC74HC165AP)を実際に操作した

# 前書き

自作キーボード作成のために、入力された複数のスイッチのON/OFFを１つの入力で受ける必要がある。(74HC595でマトリクスのY軸を１ピンだけで実現しており、折角なのでX軸側も同じ仕組みを使いたかった)

# 目的

前回の調査に従い、SC(入力/シフト)、SL(入力保持)の動作を確認する。

# わかったこと

- 読み取るときはSLピンをLOWにし、読み取らないときはHIGHにしておく
- 出力(QH)ピンはHピンの内容が出力されるため、入力の全てを保持する場合は、LastInFastOutでデータを保持しないといけない。
- TC74HC595にあったSCLRピンがない(後述)
- シフトすると、SIの入力が先頭ビット列に入ってくる。TC74HC595のように、シグナルだけでは単純にビット列をぐるぐる回す事はできない。[^1]
SIが0だった場合…
SI=0 bit_array=10010101 QH=1　//初期状態
SI=0 bit_array=01001010 QH=0　//1bitシフト1回目
〜
SI=0 bit_array=00000010 QH=0　//1bitシフト6回目
SI=0 bit_array=00000001 QH=1　//1bitシフト7回目
SI=0 bit_array=00000000 QH=0　//2週目

- SIの入力だけは常に受け付ける。そのため、常時QHからSIに通電するように経路を立てておけば、ぐるぐるビット列は回せる事は可能
- ShiftIN関数はあまり使えないぽい

[^1]: よく考えたら、74HC165の入力は不定なのでグルグル回す必要なかった

# キーボード制作に向けて

なので、８ビット分のパラレル入力を獲得したい場合は、
SL(LOW)⇨入力ビット列準備⇨SL(HIGH)⇨CK⇨読み取り⇨CK⇨読み取り⇨CK⇨読み取り⇨CK⇨読み取り⇨CK⇨読み取り⇨CK⇨読み取り⇨CK⇨読み取り
とめんどくさい事をしなければいけないが、実は
[ShiftIn関数](https://www.arduino.cc/en/Reference/ShiftIn)というものがあるらしい。

byte incoming = shiftIn(dataPin, clockPin, bitOrder)

８ビットシフトインとのことなので、104キーボードを作りたいキーマトリクスを準備する場合は、ShiftInを二回実行する必要がありそう。

こちらが丁寧に説明されています。
<http://easylabo.com/2015/04/arduino/8339/>

## ShifIn関数を試した

手作りでビットを回すより、ShiftIn関数を利用したほうがいいのかなと思い、ShiftIn関数のリターンを確認した。

そもそも、MSBFIRSTとLSBFIRSTという言葉と、「まずclockPinがHIGHになり、dataPinから次のビットが読み込まれ、clockPinがLOWに戻ります。」という仕組みを正しく理解するため動作確認した。

前述を踏まえ、ビットの動きが分かりそうなソースを組んだ。（が、検証結果を編集の過程で紛失した…orz）
ソースの結果からわかった事は下記の通り。(事実ベースだが、この考察結果が正しいのか、かなり自信がない)

- リターンは、入力の状態の「1bitシフト後」が返ってくる
- MSBFIRST 右に１ビットシフトしたものを読み、「A~Hの入力順を反転したリターン」を返す
- LSBFIRST 右に１ビットシフトしたものをそのまま読み取ったリターンを返す
- リターン値はビット列のため、先頭ビットが０の場合、入力した桁数に対して足りなくなることがある。(リターンが「00000010」の場合、先頭の0が落ちる。Serial.printだと2が返ってくる)
- 8bitシフトしかしないので、65キー以上のキーを使用したい場合、ShiftIN関数を二回続けないといけない。(8×8の正方形キーマトリクスを単純に大きくした場合の事、入力の判定を８つ以内に抑えればこれでもいいかもしれない。)

#### こういうパターンならOKかも。

```lang:matrix
出力A　＋＋＋＋＋＋＋＋
出力B　＋＋＋＋＋＋＋＋
~
出力I　＋＋＋＋＋＋＋＋
出力J　＋＋＋＋＋＋＋＋
 入力　１２３４５６７８
```

結局、SLピンは制御しないといけないし、「1bitシフトしたもの」が出力になるので、キーマトリクスの入力捜査は向いてないのかもしれない。

```c:SHIFTIN確認ソース
  Serial.print("input=");
  Serial.println("10000000");
  setInput("10000000");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST));     
  setInput("10000000");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST),BIN);
  setInput("10000000");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST));    
  setInput("10000000");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST),BIN); 
  Serial.print("input=");
  Serial.println("00000001");  
  setInput("00000001");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST));   
  setInput("00000001");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST),BIN);   
  setInput("00000001");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST));   
  setInput("00000001");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST),BIN);   
  Serial.print("input=");
  Serial.println("00000010");
  setInput("00000010");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST));   
  setInput("00000010");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST),BIN);   
  setInput("00000010");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST));   
  setInput("00000010");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST),BIN);    
  Serial.print("input=");
  Serial.println("10100000");
  setInput("01010000");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST));   
  setInput("01010000");
  Serial.println(shiftIn(input,SCKPin,MSBFIRST),BIN);   
  setInput("010100000");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST));   
  setInput("010100000");
  Serial.println(shiftIn(input,SCKPin,LSBFIRST),BIN);
```


TC74HC165確認ソース

```lang:TC74HC165

int input=0;
int SLPin=4; 
int SCKPin=3;
int BitA=6;
int BitB=7;
int BitC=8;
int BitD=9;
int BitE=10;
int BitF=11;
int BitG=12;
int BitH=13;
String inputArray=("10001010");
String tmp="dummy";

void setup() {
  Serial.begin(9600);
  pinMode(BitA, OUTPUT);
  pinMode(BitB, OUTPUT);
  pinMode(BitC, OUTPUT);
  pinMode(BitD, OUTPUT);
  pinMode(BitE, OUTPUT);
  pinMode(BitF, OUTPUT);
  pinMode(BitG, OUTPUT);
  pinMode(BitH, OUTPUT);
  pinMode(input, INPUT);
  pinMode(SLPin, OUTPUT);
  pinMode(SCKPin, OUTPUT);
}

void loop() {
  delay(1000);

  Serial.print("input=");
  Serial.println(inputArray);
  setInput(inputArray);
  printOut("first");
  printOut("2nd");
  printOut("3rd");
  printOut("4th");
  printOut("5th");
  printOut("6th");
  printOut("7th");
  printOut("last");
  
  //while(1); //block repeat
}
//TC74HC165の出力
void printOut(String guide){
  String outPutData=""; 
  for(int i=0;i<8;i++){
     outPutData = String(outPutData + digitalRead(input));
     Serial.println(digitalRead(input));
     putSCK(); 
  }
  Serial.print(guide);
  Serial.print("=");
  Serial.print(outPutData);
  Serial.println(); 
  delay(1000); 

}

//SCK信号送出
void putSCK(){
  digitalWrite(SCKPin,LOW);
  digitalWrite(SCKPin,HIGH);
}

//インプット設定ピンの調整
//２回使うので別関数に切り出した
void setInput(String inputArray){
  //LOWはinputを有効にする
  digitalWrite(SLPin,LOW);
  //インプットの桁数だけ繰り返す
  for(int i=0;i<inputArray.length();i++){
    //インプットのi桁数が１のとき、インプット用ピンをHIGHにする
    //インプット用ピンは6から始まるので、i+6がインプット用ピン位置。
    tmp=inputArray[i];
    if(tmp.equals("1")){
       digitalWrite(i+6,HIGH); 
    }else{
       digitalWrite(i+6,LOW);
    }
  }
  //HIGHはinputを無効化する(LOWだったときを保持する)
  digitalWrite(SLPin,HIGH);
}
```