喫茶blanc

何か作ったり、何か食べたり

#answer40 の組み立てについて

answer40では、ビルドガイドに当たる記述を見なくても組み立てられるように基板上に部品リスト/マウント位置を印刷しています。 このキットは表面実装の部品を使用しているため、ある程度知識や経験のある方の購入/組み立てを想定しています。後日大半の部品を実装済みの基板もごく少数ですが頒布予定ですので、細かい部品のはんだ付けにあまり自信のない方は今しばらくお待ちください。 部品の対応などがわからなくなった際は、以下に先日組み立てた際のビルドログを記しますので、こちらをご覧ください。また、ビルドログ中の写真にあるベリリウム銅ソケットはキットに含まれませんのでご注意ください。

qmk_firmwareのビルド環境を構築していない場合は、まず先に環境構築からお願いします。 2019年5月4日現在対応ファームウェアは私のフォーク先"answer40"ブランチにございます。

github.com

回路図についても以下に用意がございます。

github.com

USBコネクタ(J1)を取り付けます

https://pbs.twimg.com/media/D5F1Gf2UEAAdU1G.jpg

テスターなどを用いて導通確認をします

https://pbs.twimg.com/media/D5F1ZenUwAIzWkX.jpg

リセットスイッチ(SW45)を取り付けます

https://pbs.twimg.com/media/D5F1hmsUYAAQPqv.jpg

水晶発振器(Y1)を取り付けます

https://pbs.twimg.com/media/D5F3WRDUIAAnG76.jpg

向きに注意して、U1を取り付けます

https://pbs.twimg.com/media/D5F674tVUAEWm0O.jpg

https://pbs.twimg.com/media/D5F674vUcAoRUUu.jpg

https://pbs.twimg.com/media/D5F674sUUAIqEop.jpg

https://pbs.twimg.com/media/D5F674sUcAEnldK.jpg

ショットキーバリアダイオード(D45)を取り付けます

  • 以降ダイオードの向きは白枠にパッケージの帯が来るように合わせます

https://pbs.twimg.com/media/D5F7p4qUEAABoz2.jpg

基板のパーツリストとマウント位置、チップ部品のシールを確認しながら残りの部品を取り付けます

  • 黄色のシールはコンデンサ(C)、白のシールは抵抗(R)にそれぞれ対応しています

https://pbs.twimg.com/media/D5F9T5KU0AMQvYg.jpg

https://pbs.twimg.com/media/D5F9T5KUYAEztmf.jpg

https://pbs.twimg.com/media/D5F9T5LUwAAOAxp.jpg

https://pbs.twimg.com/media/D5F9T5KU4AEhNNf.jpg

  • 基板表面のSK6812MINI(D46,D47)はレンズ脇の切り欠きが右下に来るように合わせます

https://pbs.twimg.com/media/D5GDTpiUwAIyzsF.jpg

https://pbs.twimg.com/media/D5GDTphUYAEbXIj.jpg

キースイッチ実装の前に動作確認をします

  • USBハブなどを介してPCと接続し、lsusbやSystem ImformationなどでATmega32u4 DFU bootloaderなどと見えることを確認します

f:id:keyaki-namiki:20190504005709p:plain

  • qmk_firmware配下/answer40ブランチ内でmake answer40:default:dfuを実行し、リセットスイッチを押すことで書き込むことができます

  • LEDを実装した場合、この段階で熱による破損、動作不良などがないことを確認します

動作確認が済んだ後、キースイッチの配置/レイアウトを決めます

  • 下の画像のようなレイアウトを選ぶことができます
    • Backspace部の1U+1U/2U/1.75U
    • スラッシュ、右シフト部の2.75U/1U+1.75U/1.75U+1U
    • スペースバー部の6.25U/2.75U+1.25U+2.25U

f:id:keyaki-namiki:20190409195616j:plain

レイアウトを決めたら、スタビライザーを取り付けます

https://pbs.twimg.com/media/D5GQ-kUUIAA_6P_.jpg

キースイッチを取り付けて、完成です!

https://pbs.twimg.com/media/D5GWL4SUYAEfaze.jpg

#answer40 について

何枚かの基板を発注してきた私も、一体型キーボードとして動作する基板を作りたい気持ちになったので、作ってみました。このエントリは先日のツイートをひとまとめにしたものになります。詳しくはまた後日書くかもしれませんし、書かないかもしれません。

f:id:keyaki-namiki:20190409195100j:plain answer40は最大44キーを扱うことができる40%一体型自作キーボードです。 使用するキーキャップセットによってBを中心におよそ左右対称のレイアウトで使うことができます。

f:id:keyaki-namiki:20190409195616j:plain ゆかりキーボードファクトリーさんなどで手に入るtai-hao製のキーキャップセットをきれいに使うことができるほか、Shiftキーの多く含まれるキーキャップセットではスペースバーを3つに分割することができ、レイヤーを駆使したキーマップを大変便利に使うことができます。

f:id:keyaki-namiki:20190409195750j:plain この基板には試験的にジョグダイアルなどと呼ばれるレバースイッチ“TMHU28”用のフットプリントを追加しています。 プログラム側での対応がまだ済んでいないほか、最終的な配線は手で行う必要がありますが、左右カーソルキーやShift+スクロールホイールを割り当てることでさらに便利に使うことができるのではないかと考えております。

f:id:keyaki-namiki:20190409195910j:plain キースイッチを除くほぼすべての部品が表面実装になっているため、若干(?)のはんだ付けスキルは必要になるかと思います。 現在製作中の第2版ではPCBAできるようなデザインにする予定です。

github.com

自キと私とu16(universal16)

この記事は『自作キーボード #3 Advent Calendar 2018』11日目に寄せたものです。
進捗が渋いため 怪文書 ポエムでお茶濁しさせてください...ごめんなさい......
昨日の記事はENDO Katsuhiro(@ka2hiro)さんの『小斧(MiniAxe)ノススメ』です。

adventar.org

小斧(MiniAxe)ノススメ – かぎざら屋


前置き)

昨年の冬コミ辺りからキーボードを自作する人をよく見かけるようになり「わたしもなにかやってみたいなぁ」と思って半年と少し。2018のMaker Faire Tokyoで自作キーボードの人たちが多く出展すると聞き、足を運びました。

当時HHKBを使っていた私は、ゆかりさん(https://twitter.com/eucalyn_)が設計したMint60という、いわゆる60%キーボードを左右で分けたデザインのものを求めて東京ビックサイトへと出掛けていきました。

eucalyn.shop

前回MFTに出掛けたのは2年前で、その時の倍ほどの広さの会場に少し迷いながらウロウロとしていると、遊舎工房さんのブースを見つけます。ゆかり屋さんでのMint60の販売開始まで時間があったため、キースイッチテスターを触りにお邪魔しました。

そこで見かけたのがHelix Picoで、こちらも事前情報として『"ピコピコ"と音がなりコンパクトでとても可愛らしい自作キーボードキット』と聞いていました。家を出た時点でのお買い物リストには上がっていなかったのですが、どういうわけか東京ビックサイトを出たとき鞄の中に入っていました🤔

HelixPico キーボードキット | 遊舎工房

ゆかり屋さんでの販売が開始される頃には、ブースに長い列ができていました。

そこでMint60キーボードキットと一緒に買ったのが『ねこでも作れる!オリジナルキーボード』(通称"ねこつく")という本で、左右分割のキーボードをケースの3Dモデリングの方法まで触れられています。

eucalyn.booth.pm

(ここまでが前置き


ねこつく内ではブレッドボードを用いた実験などが紹介されていますが、手元に大量に余ったキースイッチを使ってなにかしたいなと、また、基板に直接スイッチを乗せるようにして、手作業でアクリル板に四角く穴を開けるケース加工の必要ないものにしたいなと思った私は、かねてから気になっていた基板発注をしてみようと思いました。

Kicadを初めて触る私にはkimio_kosakaさんの『KiCad 5.0入門実習テキスト「KiCad Basics for 5.0」』がとてもわかりやすく、参考になりました。

kosakalab.booth.pm

部品のフットプリントを配置して、線を繋いで。1つ目(厳密には2つ目ですが)のデザインはこのような、planck_thkの部品を取り除いたようなものになりました。

f:id:keyaki-namiki:20181210223053p:plain

ですが、このデザインの外形サイズを見積もり画面に入力すると、10枚で$57.01、5枚でも$42程度と少し勇気のいる価格になりました。そこで、Twitterで見かけたFusionPCBの「$1で基板3枚を手に入れよう!」という企画の100mm x 100mm に収まるサイズで作り直しします。

そしてできたのが、universal16でした。

f:id:keyaki-namiki:20181211001228j:plain

これは全く別の基板ですが、ユニバーサル基板にすることでこんな風に後から自分で配線できるため、いろいろなMCU/コントローラーや秋月電子さんのDIP化基板で2.54mmピッチに揃えてある電子部品をキーボード(キーパッド(?))に乗せて実験できて良さそうだなと思っています。

universal16についてはこちらにある他、多く発注した分をお譲りしていますのでこちらもご確認ください。

booth.pm

1枚目の基板を発注/受け取ってみて、見えてきた改善点をもとに2枚目(2種類目)を発注してと、作って見えてくる点が多くとても面白い経験でした。(2種類目が届いてまたやりたいことができました💪

またそれとは別に、plus4として20キーを配置できる基板を発注して、事実上の40キー キーボードとしてなにか作ることができそうだなと思っています(本当はここをまとめたかった)。

f:id:keyaki-namiki:20181211000425j:plain

写真の、Mbedを使ったものはまた別の記事にすることとして、今日はこの辺りで締めさせていただきます。

無理矢理まとめるなら、「軽い気持ちで基板を発注してみましょう」という感じでしょうか。。。


この記事は、Corne-Cherry + Gateron Silent Black + Bigbang Ortholinear Kit で書きました。

12日目はanekosさん『寒いので目玉もキーボードも光らせる』です。

adventar.org

anekos.hatenablog.com

Moge Micro

それは、朝日の昇る少し前の話であった。

なんとはなしにキーキャップを外していたところ、universal16が僅かに傾いた。私はそれに気づかず、軽く力をかけてしまった。

ガリッ』

キーキャップと机が立てた音と思って手に取ると、なにか"シガラミ"から解き放たれたような軽い感覚があった。

universal16は、時代の先をゆく『BLE Micro Pro』を搭載してはいない。

置き去りにされた"しっぽ"を横目に、私は悟った。

そう、これが世に言う『Moge Micro』であると。

さようなら、わたしのぷろまいこ。

短い間だったね。


対策をしっかりしてMoge Microを未然に防ぎましょう

以下はMC 英 (@hdbx) | Twitterさんの記事。

qiita.com

#universal16 v0.2をqmk_firmwareで使う(その2) ソフトウェアの用意

keyaki-namiki.booth.pm


このエントリは以下の'続き'になります。配線にあたっての注意点などをお探しの場合はこちらをご覧ください

keyaki-namiki.hatenablog.jp


Note

universal16を使ってqmk_firmwareで新しいキーボードを作成する手順をご紹介します。私自身、qmk_firmwareでキーボードを作成する一連の操作は初めてのものであり、手順に誤りや不足がある可能性があります。この手順のコピペだけでなく公式のDocumentなどを読みながらの操作をおすすめします。当記事についてお気づきの点がありましたら、Twitter(@keyaki_namiki)までお知らせいただけると幸いです。

また、これ以降Git/GitHubの知識が必要になる箇所が多々あります。知らない単語やコマンドはコピペして実行するのではなく、適宜検索するなどしてどういう意味なのか、何をするコマンドなのかを確認するようにしてください。

Gitがインストールされていない場合はapt install gitpacman -S gitbrew install gitなどでインストールできる場合があります。詳しくは、[ git インストール ]などで検索してみてください。

最後にもう一点、当記事はArchLinux、macOSに展開した環境の下作成されたものです。お使いのOSによってはこの記事の他に必要な手順が発生する可能性がありますことをご留意ください。


配線が済んだら、次にソフトウェアの準備をします。

qmkのrepository(以降、repo)からforkしたものを、手元の、任意のフォルダ下にcloneします。(GitHubのアカウントを持っていない場合は、qmkのrepoからcloneすることもできます)

git clone https://github.com/[YOUR_USERNAME]/qmk_firmware.git

cd qmk_firmwareなどでqmk_firmwareのフォルダ内に入ります。

手元のrepoは自分がforkしたものを本流として持っているので、本家qmkのrepoをremoteのリストに追加します。

git remote add [本家とわかる略称、ここでは‘upstream’] https://github.com/qmk/qmk_firmware.git

これでforkした自分のrepoとは別に本家qmkのrepoからも差分を取得できるようになりました。
以下のコマンドで確認することができます。

git remote -v

出力が以下のようになっていることを確認します。

origin       https://github.com/[YOUR_USERNAME]/qmk_firmware.git (fetch)
origin       https://github.com/[YOUR_USERNAME]/qmk_firmware.git (push)
upstream     https://github.com/qmk/qmk_firmware (fetch)
upstream     https://github.com/qmk/qmk_firmware (push)

次に、新しい作業用のbranchを用意します。
masterのbranchで作業/commitしてしまうと、本家qmkとの差分で競合が発生したときの調整が大変になってしまうためです。

git checkout -b [開発branchとわかる名称、ここでは‘dev_branch’] master

git statusを実行すると、いま作業しているbranchの名前が(例えば以下のように)わかるので、時々確認するのも良いかと思います。

On branch dev_branch
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

これで、新しくキーボードを作成する準備が大方整いました。早速、やっていきましょう。

新しいキーボードを作成する上で、雛形となるファイルはutil/new_project.sh [あなたのキーボードプロジェクト名]の実行にって生成することができます。今回は、

./util/new_project.sh universal16

を実行したと仮定して、進めていきます。

先程のコマンドを実行すると、keyboards/配下にuniversal16というフォルダができると思います。その中に以下のファイル群が含まれることを確認してください。

  • config.h
  • info.json
  • keymaps
    • keymaps/default/
      • keymaps/default/config.h
      • keymaps/default/keymap.c
      • keymaps/default/readme.md
  • readme.md
  • rules.mk
  • universal16.c
  • universal16.h

以降、特に言及がない限り"Hogehogeというファイル"とあるものはkeyboards/universal16/の下にあるものを指します。


まずは、config.hというファイル。

@@ -1,3 +1,3 @@
/*
-Copyright 2018 REPLACE_WITH_YOUR_NAME
+Copyright 2018 keyaki-namiki

@@ -22,8 +22,8 @@
/* USB Device descriptor parameter */
#define VENDOR_ID       0xFEED
#define PRODUCT_ID      0x0000
#define DEVICE_VER      0x0001
-#define MANUFACTURER    You
-#define PRODUCT         universal16
-#define DESCRIPTION     A custom keyboard
+#define MANUFACTURER    keyaki-namiki
+#define PRODUCT         universal16
+#define DESCRIPTION     4x4 simple key_matrix with universal board

@@ -30,4 +30,4 @@
/* key matrix size */
-#define MATRIX_ROWS 2
-#define MATRIX_COLS 3
+#define MATRIX_ROWS 4
+#define MATRIX_COLS 4

@@ -44,4 +44,4 @@
-define MATRIX_ROW_PINS { D0, D5 }
-#define MATRIX_COL_PINS { F1, F0, B0 }
+#define MATRIX_ROW_PINS { B1, B3, B2, B6 }
+#define MATRIX_COL_PINS { C6, D7, E6, B4 }
#define UNUSED_PINS

このファイルには、キーボードの配線(どのピンがどの回路に繋がっているかなど)や機能の設定について記述します。詳しくはこちら

docs.qmk.fm

今回は、Rows/Colsの部分のみを変更しました(ここでピンの接続について記述しますが、ピンの名前はArduinoで扱うときのものではない点に注意が必要です)。


次に、rules.mkというファイル。

@@ -42,9 +42.9 @@
# Bootloader selection
#   Teensy       halfkay
#   Pro Micro    caterina
#   Atmel DFU    atmel-dfu
#   LUFA DFU     lufa-dfu
#   QMK DFU      qmk-dfu
#   atmega32a    bootloadHID
-BOOTLOADER = atmel-dfu
+BOOTLOADER = caterina

今回はコントローラにPro Microを使用するのでcaterinaを選択します。


続いて、universal16.hというファイル。
universal16は4キーx4キーの16キーで構成されているため、デフォルトで用意される3キー+2キーの5キーで構成される部分を編集します。

@@ -29,9 +29,13 @@
#define LAYOUT( \
-    K00, K01, K02, \
-      K10,  K11   \
-) \
-{ \
-    { K00, K01,   K02 }, \
-    { K10, KC_NO, K11 }, \
-}
+    K00, K01, K02, K03,\
+    K10, K11, K12, K13,\
+    K20, K21, K22, K23,\
+    K30, K31, K32, K33\
+) \
+{ \
+    { K00, K01, K02, K03 }, \
+    { K10, K11, K12, K13 }, \
+    { K20, K21, K22, K23 }, \
+    { K30, K31, K32, K33 }, \
+}

K00からK33まで、16キーを配置しているのがわかるかと思います。


最後にkeyboards/universal16/keymaps/内の、default/keymap.cというファイルを編集します。

@@ -24,7 +24,9 @@
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  [0] = LAYOUT( /* Base */
-    KC_A,  KC_1,  KC_H, \
-      KC_TAB,  KC_SPC   \
-  ),
-};
+    KC_KP_1,   KC_KP_2, KC_KP_3,     KC_UP,\
+    KC_KP_4,   KC_KP_5, KC_KP_6,     KC_RIGHT,\
+    KC_KP_7,   KC_KP_8, KC_KP_9,     KC_LEFT,\
+    KC_KP_DOT, KC_KP_0, KC_KP_EQUAL, KC_DOWN\
+),
+};

最初なので、16あるキーにnumpadの0-9と"." "="、矢印キーをあててみました。ここから更に、レイヤー機能などを使ってuniversal16を便利にすることができるでしょう。

キーコードについてはこちらに詳しくあります。

docs.qmk.fm




以上が、universal16を使ってqmk_firmwareで新しいキーボードを作成する上で最低限編集の必要なファイルになります。

さっそく、Pro Microに書き込んでみましょう。

これまでの手順を書いたとおりになぞっている場合、書き込みに必要なツールはまだインストールされていないかと思います。qmk_firmwareのある位置(pwdなどをして今居るディレクトリがqmk_firmwareであることを確認できます)に移動し、以下のコマンドを実行します。

./util/qmk_install.sh

このコマンドひとつで今使っている環境を調べて必要なパッケージをすべてインストールすることができます。

続いて、コンパイル

make universal16:default

書き込みまでひと思いに済ませてしまうには、

make universal16:default:avrdude

を実行します。

書き込み用ソフトウェア、QMK Toolboxを使うこともできます。

github.com



。。。

どうでしょうか。

カーソルキーがとても細くて見づらいかと思いますが、うまくいくとこんな風に機能します。

次はMxLEDBitPCB、通称"無限の可能性"を使ってもう2つ、キーを増やしてみます💪


github.com

#universal16 v0.2をqmk_firmwareで使う(その1) 配線/はんだ付け編

今回は"universal16 v0.2"についての更新になります。"universal16 v0.2"については、こちらをご覧ください。

keyaki-namiki.booth.pm

keyaki-namiki.hatenablog.jp


Note

universal16を使ってqmk_firmwareで新しいキーボードを作成する手順をご紹介します。私自身、キーボードを作成する一連の操作は初めてのものであり、手順に誤りや不足がある可能性があります。この手順のコピペだけでなく公式のDocumentなどを読みながらの操作をおすすめします。また、当記事についてお気づきの点がありましたら、Twitter(@keyaki_namiki)までお知らせいただけると幸いです。

docs.qmk.fm


さて、universal16は多種多様なコントローラでの実験を想定した基板であり、ラスト数センチの配線がなされていません。まずは基板の準備から進めていきましょう。


基板には、それぞれ回路を引き出したパッドが用意してあります。

https://pbs.twimg.com/media/DsI02swVAAAVQtL.jpg

https://pbs.twimg.com/media/DsI02sxVsAAyRDn.jpg

パッドの詳細については、こちらをご確認ください。

github.com

また、UnderglowLED用の信号線など、上部に置いてあるパッドの一部に「片面にしかないもの」があります。

https://pbs.twimg.com/media/DsXNGAvVAAIaoAH.jpg

https://pbs.twimg.com/media/DsXNGA2UUAAVfan.jpg

これらのある面にスイッチを実装する予定の場合、まず最初にポリウレタン銅線などを使ってうら面(スイッチを実装しない面)に線を引き出してください。

https://pbs.twimg.com/media/DsXOYuGU0AAZ-zj.jpg

https://pbs.twimg.com/media/DsXOYuIVsAUYMnN.jpg

ICソケットの間を抜ける線の画像

https://pbs.twimg.com/media/DsXOYuGUcAAVFQd.jpg

つづいて、ダイオードを実装します。

https://pbs.twimg.com/media/DsXfCb6VAAAwl9b.jpg

Cherry MX互換タイプのスイッチを使う場合、どちらの面にどのタイプのダイオードを使っていただいても問題ありませんが、なにかあった時のためにうら面に部品が来る状態をおすすめします。
Kailh LPスイッチを使い、ユニバーサル基板部分を右側に置いて基板を使う場合、SMDタイプのダイオードを使用してください。

https://pbs.twimg.com/media/DsY_ISpV4AAflm3.jpg

ユニバーサル基板部分を左側に置いて、Kailh LPスイッチを使う場合、リードタイプのダイオードの脚が出ないように工夫する必要があります。横から見たときに基板から足が出ていると、プレートに傷がつき、破損する恐れがあります。

ダイオードが実装できたら、次に、スイッチをプレートにはめます。

https://pbs.twimg.com/media/DsXgmhfUUAIbDkS.jpg

(画像は脚(スペーサー)がついた状態ですが、この時点で特につける必要はありません。)

https://pbs.twimg.com/media/DsXlEfWVsAAQwg_.jpg

https://pbs.twimg.com/media/DsXlEfZUUAEkvFC.jpg

スイッチをはめ終わったら、プレートを基板に載せ、はんだ付けします。

https://pbs.twimg.com/media/DsXySKYV4AEzuV4.jpg

ここまで作業を進めてしまうと、先述の上部パッドにアクセスすることが極めて困難になります。使いそうな配線は先に逃しておいてください。

スイッチのはんだ付けが終わったら、コントローラと基板を配線していきます。

https://pbs.twimg.com/media/DsX3oELU4AAouaa.jpg

今回はArduino Microの互換品、Pro Microを使用します。

https://pbs.twimg.com/media/DsYquXZU0AA5jXG.jpg

どの配線をどのピンに繋いだかをしっかり正確にメモしておくことで、後々迷路のような配線たどりをしなくて済むことになります。(また、スペーサーの通る穴はGNDと接続がありますので、お近くのGNDが使用中の場合、ここに逃がすこともできます。)

f:id:keyaki-namiki:20181123193317j:plain

実現したい機能、実験したい部品によってコントローラとの配線は変わってくると思いますが、今回はCol0-3をPro Microの5-8ピンに、Row0-3を15,14,16,10ピンにつなぎました。

(その2)に続きます。


github.com

keyaki-namiki.booth.pm

LEDマトリクスの操作

github.com

前回、Pro Microとは別にLED制御用のArduino(ATmega328P:以降、328P)を用意することでuniversal16のLEDマトリクスを点灯させることができました。

今回もゆかりさん (https://twitter.com/eucalyn_)の「ねこでも作れる! オリジナルキーボード」とともに、Pro Microからキー入力をシリアル通信で受け取ってバックライトの点灯/消灯を操作してみます。

eucalyn.booth.pm

Pro Microはシリアル通信用のピンがUSBシリアルとは別に用意してあるためTxやRxとあるピンを使いますが、328Pにはシリアル通信用のピンがない(シリアルモニタが使えなくなる)ため、SoftwareSerialを使って通信を行います。今回はTxにA4ピンを、RxにA5ピンを使用し、それぞれUEWで配線してシリアル通信を受け取れるようにしました。

(とても分かりづらい配線の図)

次に、Pro Microから328Pに送るデータを考えます。今回必要なのは押された/離されたキーの座標のみですが、右側のユニバーサル基板部分で2つのロータリーエンコーダを扱いたいので、そのことを念頭に置いて2進数8桁1バイトの中に情報を詰め込みます。

0b0000000
  _     matrix(0) or renc(1)
  *_        press or release
  **_       master or slave
  ***__     matrix position (row)
  *****__   matrix position (col)
  *******0  blank

少し見づらいかと思いますが、右から

  • 1桁目は空白(いつでも0)
  • 2~3桁目は列成分
  • 4~5桁目は行成分
  • 6桁目はmaster/slave判定
  • 7桁目は押されたか/離されたか
  • 8桁目はmatrixについての通信かロータリーエンコーダについての通信か

について必要な情報を2進数にして押し込んでいます。 master/slave判定は現時点で必要な情報ではないのですが、後々使うことになるかもしれないので、ひと桁分を用意しました。

以上を反映したPro Micro側のプログラムはこのようになりました。

const int Rowpin[] = {4,5,7,8};
const int Colpin[] = {10,15,14,16};
const int Cols = (sizeof(Rowpin)/sizeof(Rowpin[0]));
const int Rows = (sizeof(Colpin)/sizeof(Colpin[0]));
bool beforeState[Rows][Cols];
bool currentState[Rows][Cols];
byte sendData,readData;
/* data description
 * 
 * 0b0000000
 *   _         matrix or renc
 *   if matrix(0)
 *   *_            press or release
 *   **_       master or slave
 *   ***__     matrix position (row)
 *   *****__   matrix position (col)
 *   *******0  blank
 *   if renc(1)
 *   *_            renc0 or renc1
 *   **_       button press or release
 *   ***_      rotate (en/dis)able
 *   ****_     rotate direction
 *   *****000  blank
 */
void setup(){
    Serial.begin(9600);
    Serial1.begin(115200);
    Serial1.write("hello!");
// while(!Serial);
    Serial.println("Started.");
    for(int i=0;i<Cols;i++){
        pinMode(Rowpin[i],OUTPUT);
    }
    Serial.print("num of Rowpin: ");
    Serial.println(Rows);
    Serial.println("Rowpin initialized.");
    for(int i=0;i<Rows;i++){
        pinMode(Colpin[i],INPUT_PULLUP);
    }
    Serial.print("num of Colpin: ");
    Serial.println(Cols);
    Serial.println("Colpin initialized.");
    for(int i=0;i<Rows;i++){
        for(int j=0;j<Cols;j++){
            currentState[i][j] = HIGH;
            beforeState[i][j] = HIGH;
        }
    }
    Serial.println("initialize finished");
}
void loop(){
    int isPress = 0;
    delay(1);
    for(int i=0;i<Rows;i++){
        digitalWrite(Rowpin[i],LOW);
        for(int j=0;j<Cols;j++){
            currentState[i][j] = digitalRead(Colpin[j]);
            if (currentState[i][j] != beforeState[i][j]){
                    Serial.print("key ");
                    Serial.print(i);
                    Serial.print(",");
                    Serial.print(j);
                if(currentState[i][j] == LOW){
                    Serial.println(" pressed!");
                    isPress = 1;
                } else {
                    Serial.println(" released!");
                    isPress = 0;
                }
                beforeState[i][j] = currentState[i][j];
                sendData = isPress << 5 | i << 3 | j << 1 | 0 ;
                Serial1.write(sendData);
                Serial.print("sent :");
                Serial.println(sendData);
            }
        }
        digitalWrite(Rowpin[i],HIGH);
    }
}

View code on GitHub.com

さて、これでPro Microからキー座標を送ることができるようになりました。

次に、328P側での挙動を考えます。水滴が落ちるようなアニメーション動作ができるととてもかっこいいのですが、まずは押したキーのバックライトが点灯するようにプログラムを書いてみました。

#include <SoftwareSerial.h>
const int ledcols = 4;
const int ledrows = 4;
const int ledcol[ledcols] = {A2,A3,4,2};
const int srclk = 7;
const int srclr = 8;
const int sra = A0;
const int srb = A1;
//const int renc = 2;
//const int rencr[renc] = {11,6};
//const int rencg[renc] = {10,5};
//const int rencb[renc] = {9,3};

const int Tx = A4;
const int Rx = A5;
SoftwareSerial keyserial(Rx,Tx);

byte sendData,readData;

//int r[renc] = {0};
//int g[renc] = {0};
//int b[renc] = {0};
int matrixDefault[ledrows][ledcols] = {
    {1,1,1,1},
    {1,1,1,1},
    {1,1,1,1},
    {1,1,1,1}
};
int keyPressed[ledrows][ledcols]={0};
void srclock(){
    digitalWrite(srclk,1);
    digitalWrite(srclk,0);
};

void setup(){
    Serial.begin(9600);
    keyserial.begin(115200);
    while(!Serial);
    if(keyserial.available()){
        readSerial();
    }
    pinMode(srclk,OUTPUT);
    pinMode(srclr,OUTPUT);
    pinMode(sra,OUTPUT);
    pinMode(srb,OUTPUT);
    for(int i=0;i<4;i++){
        pinMode(ledcol[i],OUTPUT);
        digitalWrite(ledcol[i],0);
    }
    Serial.println("initialized");
    digitalWrite(srclk,0);
    digitalWrite(srclr,0);
    digitalWrite(sra,0);
    digitalWrite(srb,0);
}

void loop(){
    int *matrix[ledrows];
    for(int k=0;k<ledrows;k++){
        matrix[k] = matrixDefault[k];
    }
    for(int i=0;i<ledrows;i++){
        int swapMatrix = 0;
        for(int j=0;j<ledcols;j++){
            swapMatrix += keyPressed[i][j];
        }
        if(swapMatrix != 0){
            for(int k=0;k<ledrows;k++){
                matrix[k] = keyPressed[k];
            }
            break;
        }
    }
    for(int i=ledcols;i>=0;i--){
        digitalWrite(srclr,1);
        digitalWrite(srb,1);
        for(int j=ledrows;j>=0;j--){
            digitalWrite(sra,matrix[j][i]);
            srclock();
            digitalWrite(sra,0);
        }
        digitalWrite(ledcol[i],1);
        delay(3);
        digitalWrite(srclr,0);
        digitalWrite(ledcol[i],0);
    }
    if(keyserial.available()){
        readSerial();
    }
}

void readSerial(){
    int Row1, Col1, isPress;

    readData = keyserial.read();
    Serial.println(readData);

    if(readData & 0b00000000){

    } else {
        isPress = readData >> 5;
        Row1 = (readData & 0b00011000) >> 3;
        Col1 = (readData & 0b00000110) >> 1;
        Serial.print("key ");
        Serial.print(Row1);
        Serial.print(",");
        Serial.print(Col1);
        if(isPress){
            keyPressed[Row1][Col1] = 1;
            Serial.println(" pressed!");
        } else {
            keyPressed[Row1][Col1] = 0;
            Serial.println(" released!");
        }
    }
}

View code on GitHub.com

キーを押さない通常時は全点灯の状態にしたかったので、前回のプログラムに

  • シリアル通信を受け取る関数を足し、その中で新しい配列keyPressedに今押されているキーの座標を追加
  • void loop()の最初で押されたキーがあるかどうかを判断して、ひとつでもあるようなら新しい配列keyPressedから点灯するLEDの座標を読み出す

ように手を加えました。

(うごいている様子)

続きます。


一連の実験をお手元でお試しいただける基板、universal16 v0.2を少数ですがboothにて販売しています。プレート付属の基板キットを使って、あなただけの左手/右手デバイスを作ってみませんか?

keyaki-namiki.booth.pm

#universal16+4

universal16を描いていて、1枚あたり16キーではなく20キーにすると2枚用意して両手で40キーのsplit-keyboardとしてつかえるのでは🤔と思ったので、作ってみました。(発注して到着待ち) 到着しました!(🔜後日更新の予定)

https://raw.githubusercontent.com/keyaki-namiki/universal16/f46e48b27221f7aa29e03889dac8db30eb2b05e3/plus4/image/universal16_plus4_front.png

https://raw.githubusercontent.com/keyaki-namiki/universal16/f46e48b27221f7aa29e03889dac8db30eb2b05e3/plus4/image/universal16_plus4_back.png

基本的にはuniversal16 Stemに4キー足しただけですが、左手用に(裏返せば右手用にも)スペースバー(といっても2Uですが)を置けるように最下部にスタビライザ用の穴を配置してみました。

qmk_firmwareを用意してサクッと使ってみるもよし、気になったコントローラでSplit Keyboardとして使ってみるもよし、気になった部品を実用的な[要出典]キーボードと一緒に試してみるもよしといった基板になるのではないでしょうか。

github.com

LEDマトリクスの点灯

github.com

universal16のキーバックライトLEDは基板上でマトリクス状に配線されており、シフトレジスタなどを操作することでキーごとの点灯ができるようになっています。

これもプログラムの勉強にと追加した機能のひとつなのですが、手持ちのシフトレジスタをきちんと扱おうとすると4ピン必要になるため、Pro Microとは別にArduino(ATmega328P)を用意してそこからLED全般を制御することにしました。

今回使ったのはうちにあった74HC164というシフトレジスタですが、もう少し大きな電流を流せる部品をちゃんと選んだほうがいいかもしれません。

akizukidenshi.com

「何もわからん」とある通り、とても見るだけではわからない配線ですが、LED Cols 0-3にA2,A3,4,2を、74HC164のQA-QDにLED Rows 0-3を、などと配線しています。

諸々の配線を済ませた上で以下のプログラムを実行すると、左斜め対角線を消灯した状態になるかと思います。

const int ledcols = 4;
const int ledrows = 4;
const int ledcol[ledcols] = {A2,A3,4,2};
const int srclk = 7;
const int srclr = 8;
const int sra = A0;
const int srb = A1;
int matrix[ledrows][ledcols] = {
    {1,1,1,0},
    {1,1,0,1},
    {1,0,1,1},
    {0,1,1,1}
};
void srclock(){
    digitalWrite(srclk,1);
    digitalWrite(srclk,0);
};
void setup(){
    pinMode(srclk,OUTPUT);
    pinMode(srclr,OUTPUT);
    pinMode(sra,OUTPUT);
    pinMode(srb,OUTPUT);
    for(int i=0;i<4;i++){
        pinMode(ledcol[i],OUTPUT);
        digitalWrite(ledcol[i],0);
    }
    digitalWrite(srclk,0);
    digitalWrite(srclr,0);
    digitalWrite(sra,0);
    digitalWrite(srb,0);
}
void loop(){
    for(int i=ledcols;i>=0;i--){
        digitalWrite(srclr,1);
        digitalWrite(srb,1);
        for(int j=ledrows;j>=0;j--){
            digitalWrite(sra,matrix[j][i]);
            srclock();
            digitalWrite(sra,0);
        }
        digitalWrite(ledcol[i],1);
        delay(5);
        digitalWrite(srclr,0);
        digitalWrite(ledcol[i],0);
    }
}

今回は適当なチップ抵抗の手持ちがなかったため、途中に余計なdelay(5);を置いてごまかしていますが、ちゃんと抵抗値を選んだ上で、delayの値をもっと小さくするか、そもそもdelayさせないことでちらつきの少ないキーバックライトを実現できるでしょう。

(キーバックライトが暗いの図)

動作イメージ(上の動画では配列の扱い方が逆になっていて右対角線が消灯しています)

次の課題はPro Microからキー入力を受け取ってバックライト点灯を操作するあたりでしょうか。。。

Arduinoとキーマトリクスで遊んでみる

ゆかりさん (https://twitter.com/eucalyn_)の「ねこでも作れる! オリジナルキーボード」をもとに、universal16のキーマトリクスからpress/releaseを捕まえるコードを書いて実験してみました。

eucalyn.booth.pm

Pro Microの4,5,7,8ピンをそれぞれRow 0-3に、10,15,14,16ピンをそれぞれCol 0-3に配線します。

const int Rowpin[] = {4,5,7,8};
const int Colpin[] = {10,15,14,16};
const int Cols = (sizeof(Rowpin)/sizeof(Rowpin[0]));
const int Rows = (sizeof(Colpin)/sizeof(Colpin[0]));
bool beforeState[Rows][Cols];
bool currentState[Rows][Cols];
void setup(){
    Serial.begin(9600);
    while(!Serial);
    Serial.println("Started.");
    for(int i=0;i<Cols;i++){
        pinMode(Rowpin[i],OUTPUT);
    }
    Serial.print("num of Rowpin: ");
    Serial.println(Rows);
    Serial.println("Rowpin initialized.");
    for(int i=0;i<Rows;i++){
        pinMode(Colpin[i],INPUT_PULLUP);
    }
    Serial.print("num of Colpin: ");
    Serial.println(Cols);
    Serial.println("Colpin initialized.");
    for(int i=0;i<Rows;i++){
        for(int j=0;j<Cols;j++){
            currentState[i][j] = HIGH;
            beforeState[i][j] = HIGH;
        }
    }
    Serial.println("initialize finished");
}
void loop(){
    for(int i=0;i<Rows;i++){
        digitalWrite(Rowpin[i],LOW);
        for(int j=0;j<Cols;j++){
            currentState[i][j] = digitalRead(Colpin[j]);
            if (currentState[i][j] != beforeState[i][j]){
                if(currentState[i][j] == LOW){
                    Serial.print("key ");
                    Serial.print(i);
                    Serial.print(",");
                    Serial.print(j);
                    Serial.println(" pressed!");
                } else {
                    Serial.print("key ");
                    Serial.print(i);
                    Serial.print(",");
                    Serial.print(j);
                    Serial.println(" released!");
                }
                beforeState[i][j] = currentState[i][j];
            }
        }
        digitalWrite(Rowpin[i],HIGH);
    }
}

View code on GitHub.com

うごいている様子

左右間の通信などほかの処理を一切含まないため、チャタリングをよく捕まえてしまうのでdelay(1)などを挟んでみてもいいかもしれません。

次回は、universal16のLEDマトリクスについて更新の予定です♨

github.com