基板から自作キーボードを作った！ with Pro Micro

# はじめに
こんにちは、自作キーボードをPCBから作ったので手順なども含めて紹介していきます(Pro Microは使ってます、次はマイコンボードから作りたい)。
[キーボードのGitHubリポジトリ](https://github.com/kakudo415/split-keyboard-promicro)

## 環境
- Windows 10 1809
- KiCAD 5.0.2 (本家からDLした、日本ミラーは古いので注意)
- Arduino IDE 1.8.8 (Windows Store 1.8.19.0)

## 使った物
- Pro Micro 5V 16MHz (互換品)
- Gateron 赤軸 (本家Cherry軸が高いため互換品)
- キーキャップ (よくわからない安いやつ、高さがちょっとバラバラ)
- Micro USBケーブル (そのへんにあったやつ、完全な充電用ケーブルだとうまくいかないので注意)

# つくる
後から考えたらもっと体系的に作れますが、自分がやった順番で書いていきます。
## 買う
まずは必要なものを買わないと始まらないのでとりあえず買ってみて考えることにしました。
TALP KEYBOARDやAliExpressとかを使いました。キーキャップとか意外とします。高校生には痛い出費。
## プレート作り
Cherry系のキースイッチは二通りの固定方法があり、使うスイッチが異なります。
PCBに固定する方法と、別にプレートを用意する方法(もちろんプレートを使うものもPCBに最終的にくっつく)です。
また、PCB固定用とプレート固定用では互換性は無いので注意してください(一応PCB固定用の突起を超過分折ればプレート固定用として使える)。
今回はよりしっかり固定できそうに思えたプレート固定を選択しました。
しかし意外とPCBの剛性が高いのでケースにPCBを固定するならPCB固定もありかもしれません。

基本的には `14mm x 14mm` の正方形の穴を `19mm` 間隔で格子状に配置しました。
今回はスイッチを固定する14mmの穴を少し変則的な形にしました(あとからスイッチを取り替えやすいと言われている形)が、よく考えたら一度できあがったキーボードのスイッチを交換することがなさそうなので、ただの正方形でよさそうです。

今回は作成に3Dプリントを選びました。
アクリル板やアルミ板を加工してもらっても良かったですが見積もりが高かったです。
材質のナイロンに不安があったのでスイッチの噛み合う部分以外を倍の厚みにして強度を増しました。

ぴったりはまってよかった。

## そして空中配線へ(断念)
PCBを作らない場合、プレートだけで後はエナメル線とはんだ付け技術を使ってもう完成させることができます。
しかし、結論が先に出ていますが空中配線(エナメル線などでそのままスイッチなどの電極間をつなぐこと)はうまくいかず断念しました。どこかのエナメルが剥がれていなくて接触不良とかかもしれませんが原因はわかっていません。

## PCBを作ろう
空中配線がうまくいかず長いこと放置していましたが、[この記事](https://github.com/ruiqimao/keyboard-pcb-guide)などに触発されてPCBを作ることにしました。
今回は無料で使えるKiCADを使います。使い方はいろいろ記事があるので調べてみてください。

回路などに関しては[ゆかりメモ](http://eucalyn.hatenadiary.jp/entry/original-keyboard-toc)や、[Romly](http://romly.com/archives/tag/build-my-own-keyboard)を参考にさせていただきました。ありがとうございます。

[Pro Micro & Fio V3 Hookup Guide](https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/all) に載っているArduinoのIOピンとして使えるピンをキーボードの行・列とに接続します。

[回路図(一枚で両用にするために両側にPro Microをつけるので２つあります)](https://github.com/kakudo415/split-keyboard-promicro/blob/master/schematic.pdf)

## PCB制作
どこのご家庭にもあるフライス盤などを使って制作することも可能でしょうが、僕の家はあいにく無いのでelecrowに委託します。
やり方は簡単で、ガーバーファイルと呼ばれるいくつかのファイルをzipで送るだけです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/271592/f9ca7844-8a94-07b8-1915-dcc2b631182f.png)
プロットを選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/271592/f3fb7954-d75e-a236-392f-64b4e5555116.png)
`Cu(電気が流れる所)` `SilkS(シルク = 文字など)` `Mask(はんだマスク？よく分かっていない)` `Edge.Cuts(基板の形)` 等のデータを出力すればいいと思います。
選択したら `製造ファイル出力` します。

更にドリルファイルを生成...をクリック
![image.png](https://qiita-image-store.s3.amazonaws.com/0/271592/8ae64a1f-013d-c4d1-a39a-643b252ce7ee.png)
`PTHとNPTH穴を一つのファイルにマージ` しておくとちょっと楽。
そして `ドリルファイルを生成` 。

できたらelecrowに合わせてファイル名&拡張子を変更します。

|元のファイル名|こう変更する|
|---|---|
|xxx.drl|xxx.TXT|
|xxx-B.Cu.gbr|xxx.GBL|
|xxx-B.Mask.gbr|xxx.GBS|
|xxx-B.SilkS.gbr|xxx.GBO|
|xxx-Edge.Cuts.gbr|xxx.GML|
|xxx-F.Cu.gbr|xxx.GTL|
|xxx-F.Mask.gbr|xxx.GTS|
|xxx-F.SilkS.gbr|xxx.GTO|

そしてまとめてzipで圧縮してelecrowにアップロードします。
[ELECROW PCB SERVICES](https://www.elecrow.com/pcb-manufacturing.html)
色が無料で選べるのが嬉しいですね！
あとは住所とか入力して支払い済ませると一週間とかで基板が届きます。
思ったより出来がいい。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">2/28に注文してもう届いた！<br>設計したものが形になるの感動だなぁ<br>Thank you! <a href="https://twitter.com/Elecrow1?ref_src=twsrc%5Etfw">@Elecrow1</a> <a href="https://t.co/cajJI4UnHv">pic.twitter.com/cajJI4UnHv</a></p>&mdash; Kakudo (@kakudo415) <a href="https://twitter.com/kakudo415/status/1103965987265642497?ref_src=twsrc%5Etfw">2019年3月8日</a></blockquote>

## 組み立てる
一番簡単。刺してはんだ付けするだけ。

## ファームウェア作り
Arduino IDEでコーディングしていく。

何よりの注意はPro Microを使う場合 **必ず周波数・電圧を確認すること** ミスるとスケッチを書き込めなくなりそもそもWindowsから `不明なUSB～` と認識されてしまい何もできなくなります。そうなってしまった場合はRESETピンとGNDを二回すばやく繋ぎリセットしたあと **8秒以内** に何らかのスケッチ(Blinkとかがコンパイル早くて良さそう)を書き込み直してください。

ファームウェアは列の電圧を順番に`LOW`にしていき(デフォルトを`HIGH`にする = アクティブローというらしい)行を順に読み取っていくものです。
内蔵の抵抗を利用する `INPUT_PULLUP` を利用して外部に抵抗を用意しなくていいようにしています。

```C++
void loop() {
  for (int i = 0; i < 6; i++) {
    digitalWrite(colPin[i], LOW);

    for (int j = 0; j < 4; j++) {
      currentState[i][j] = digitalRead(rowPin[j]);

      if (currentState[i][j] != beforeState[i][j]) {
        if (currentState[i][j] == LOW) {
          if (i == 5 && j == 3) {
            currentLayer = 1;
          }
          Keyboard.press(layers[currentLayer][j][i]);
        } else {
          Keyboard.release(layers[currentLayer][j][i]);
          if (i == 5 && j == 3) {
            currentLayer = 0;
          }
        }
      }

      beforeState[i][j] = currentState[i][j];
    }

    digitalWrite(colPin[i], HIGH);
  }
}
```

現在のコードはこんな感じ(たまに無限に "!" が入力されたりするのでバグってそう。暫定版ということで・・・)

これはレイヤーを実装しているので単純にキーを読み取る部分だけ抜き出すと

```C++
for (int i = 0; i < 6; i++) {
  digitalWrite(colPin[i], LOW);

  for (int j = 0; j < 4; j++) {
    currentState[i][j] = digitalRead(rowPin[j]);

    if (currentState[i][j] != beforeState[i][j]) {
      if (currentState[i][j] == LOW) {
        Keyboard.press(layers[j][i]);
      } else {
        Keyboard.release(layers[j][i]);
      }
    }

    beforeState[i][j] = currentState[i][j];
  }

  digitalWrite(colPin[i], HIGH);
}
```

要は、行→列の順に電気が流れる組み合わせを延々探すプログラム。
見つかったら`Keyboard.h`ライブラリを使って送信しています。

### うまくいかない場合
試しにPro Microのピンを物理的に繋いでキーが入力されるか試してみてください。

入力された場合、ファームウェアはおそらく正常なのでダイオードの向きが間違っている可能性が高いです。
ダイオード付け直すのはめんどくさいだろうと思うので、ファームウェアの行と列を入れ替えるといいです。

# 最後に
自作キーボード、お金はかかりますが間口が広く始めやすい趣味なのかなーと思いました。
一見ハードルが高そうに見えるプリント基板も実は委託サービスなどを利用することでぐっと身近になったのかなと思います。
あとプリント基板がしっかりしているのでケース無しで運用できるのがいいですねｗ(3Dプリント代が浮きます)
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">で き た <a href="https://t.co/kQAn68uU55">pic.twitter.com/kQAn68uU55</a></p>&mdash; Kakudo (@kakudo415) <a href="https://twitter.com/kakudo415/status/1104074992558329856?ref_src=twsrc%5Etfw">2019年3月8日</a></blockquote>
自作キーボードはいいぞ！