Arduino用の64キープロトタイピングキーボードマトリックス
コンポーネントと消耗品
> |
| × | 1 | |||
| × | 64 | ||||
| × | 64 | ||||
| × | 1 | ||||
| × | 1 |
必要なツールとマシン
> |
|
アプリとオンラインサービス
> |
|
このプロジェクトについて
更新:コードを改善しました。最後の「更新」を参照してください。
私は現在、統合キーボードを使用するプロジェクトに取り組んでいますが、問題が発生しました。開発ボードのプロトタイプにキーボードを含めるにはどうすればよいですか。実際のプロジェクトのキーボードは、他のすべての機能を処理するマイクロコントローラーに直接接続されているため、USBキーボードまたは既存のArduinoベースのキーボードを使用できません。そこで、この基本的なPCBベースの64キープロトタイピングキーボードマトリックスを設計しました。
このPCBにはIC(集積回路)は含まれていません。キーボードマトリックスの行と列はピンヘッダーに直接接続されているため、キーボードをArduinoやその他のマイクロコントローラーに接続できます。統合キーボードを含むプロジェクトのプロトタイピングに最適です。
十分なI / Oピンが利用可能なArduino互換の開発ボードでこれを機能させるために詳細でコメントの多いコードを含めました。11ピンが必要です。キーボードには、shift、caps、ctrl、alt、fn、および「特殊」の修飾子を含む64個のキーがあります。好きなように使用できる6つの追加キーもあります。修飾子がアクティブな場合の各キーの機能を含め、すべてのキーの機能を個別に定義できます。私の意見では、これは大幅にです キーの動作をカスタマイズする能力を大幅に制限する既存のキーボードコードよりも便利です。
提供されたコードは、テキストをシリアルに出力します。テキストを別の場所に移動したい場合は、これを簡単に変更できます。
プログラムサイズに関する注意:
私が提供するコードは、既存のライブラリをまったく利用していないため、かなり大きくなります。必要なカスタマイズ性を実現するために、このコードを完全にゼロから作成しました。 Arduino UNOでは、これは9100バイト(28%)のプログラムストレージスペースを使用し、グローバル変数は394バイト(19%)の動的メモリを使用します。
私のコードはおそらくもっと効率的で、キーボードのライブラリとスケッチは確かに小さいですが、これは、すべての修飾子を使用してすべてのキーに完全な柔軟性を提供するために考案できる唯一の方法です。また、実際のキーボードの使用法も考慮に入れています。たとえば、Caps Lockが有効になっているときにShiftキーを押すと、コードは小文字になります。デフォルトでは、FNキーを押しながらESCを押しても何も起こりません。ただし、その動作は完全にカスタマイズ可能であるため、好きなように変更できます。
備品:
- カスタムPCB
- 6x6x5mmの触覚瞬間プッシュボタン(x64)
- 1N4148スイッチングダイオード(x64)
- 1x8ピンヘッダー、メスまたはオス(x2)
- 74HC595シフトレジスタ
- ジャンパー線
- ブレッドボード
- ArduinoUnoまたはArduino互換のマイクロコントローラー開発ボード
ステップ1:キーボードマトリックスのしくみ <図> <図>
キーボードマトリックスが必要なのはなぜですか?
このキーボードには64個のキーがあります。これらのボタンをすべて開発ボードに直接接続する場合は、64個のI / Oピンが必要になります。それはたくさん ピンの数とほとんどの開発ボードが利用可能です。これをはるかに妥当な数に減らすために、キーボードマトリックスを使用できます。これには、キーの数の平方根(切り上げ)に等しいピンの数だけが必要です。
キーボードマトリックスは、行のすべてのキースイッチが接続され、列のすべてのキースイッチが接続されるように設定されています。どのキーが押されているかを確認したい場合は、最初の行を「アクティブ化」してから、各列を確認します。特定の列がアクティブな場合、その列と行1のキーが押されたことがわかります。次に、行1を非アクティブ化し、行2をアクティブ化してから、すべての列を再度チェックします。すべての行がアクティブ化されたら、最初の行からやり直すだけです。
キーボードマトリックスをスキャンする方法:
マイクロコントローラーを使用しているため、「アクティブ化」とは、その行をLOWまたはHIGHに設定することを意味します。この場合、マイクロコントローラの組み込みのプルアップ抵抗を使用しているため、行をLOWに設定しています。 カラム入力ピンにあります。プルアップ抵抗またはプルダウン抵抗がないと、インターフェイスの結果として入力ピンが予期せず反応し、誤ったボタンの押下が記録されます。
Arduino UNOで使用されているATmega328Pマイクロコントローラーには、プルダウン抵抗が組み込まれておらず、プルアップ抵抗のみが組み込まれています。だから私たちはそれらを使用しています。プルアップ抵抗は各入力ピンを5Vに接続し、ボタンが押されるまで常にHIGHを読み取るようにします。
また、通常、すべての行がHIGHに設定されているため、ボタンが押されているかどうかに関係なく、列ピンが行ピンに接続されません。ただし、行をチェックする準備ができたら、その行をLOWに設定できます。 。その行のボタンを押すと、入力ピンをグランドに引き下げるためのパスが提供されます。その結果、その列は LOWとして読み取られます 。
したがって、要約すると、行をLOWに設定してから、どの列ピンがLOWを読み取っているのかを確認します。それらは押されたボタンに対応します。このプロセスは非常に発生します すばやく、キーボード全体を1秒間に何度もスキャンできます。私のコードでは、これを1秒あたり200回に制限しています。これにより、パフォーマンス、バウンス、およびすべてのキー押下が確実にキャッチされるようになります。
ダイオード、ゴースティング、およびnキーロールオーバー:
回路内のダイオードは、特定のボタンの組み合わせが押されたときに意図しないキーが押されるのを防ぐためにあります。ダイオードは電流が一方向にのみ流れることを可能にし、ゴースティングを防ぎます。ダイオードを使用しなかった場合、電流が隣接するスイッチを流れるため、特定のキーを押すと、押されていない別のキーが登録される可能性があります。これは簡略化された図に示されています。隣接する3つのキーを押すと、押されていなくても4番目のコーナーのキーが登録されます。ダイオードはそれを防ぎ、「nキーロールオーバー」を有効にします。これは、問題なく、好きな組み合わせで好きなだけキーを押すことができることを意味します。
シフトレジスタを使用したピンの保存:
キーボードマトリックスにはキーの数の平方根に等しいピンの数が必要だと言ったのに、私も 私のキーボードのデザインは11ピンしか必要ないと言った。 16でしょ?いいえ、74HC595シフトレジスタを使用しているためです。このシフトレジスタにより、ArduinoのI / Oピンのうち3つだけを使用して、最大8つの出力ピンを制御できます。これらの3つのピンにより、1バイト(8ビット)をシフトレジスタに送信できます。シフトレジスタは、8つの出力ピンをHIGHまたはLOWに設定します。出力行ピンにシフトレジスタを使用することで、5つのI / Oピン全体を節約できます!
「では、入力ピンにもシフトレジスタを使用してみませんか?」あなたが尋ねる。最も簡単な答えは、入力には別の種類のシフトレジスタが必要であり、私はそのタイプを手元に持っていなかったということです。ただし、入力にシフトレジスタを使用すると、列の読み取り方法も複雑になり、ノイズや「バウンス」の問題が発生する可能性があります。この場合、私が引き受ける必要がなかったのは頭痛の種だと言えば十分です。
Schematic.pdf
ステップ2:PCB設計 <図> <図> <図>
回路設計
キーボードマトリックスがどのように機能するかを理解したので、私のPCB設計は単純なはずです。私はKiCAD(申し訳ありませんがイーグルジャッジ)でPCBを設計し、回路図から始めました。ボタン記号とダイオード記号を配置し、64個のキーのグリッドができるまでそれらをコピーして貼り付けました。次に、2つの1x8ピンヘッダーシンボルを追加しました。1つは行用、もう1つは列用です。ボタンの片側は列で接続され、ボタンの反対側は行で接続されていました。
次のステップは、これらの回路図記号のそれぞれにPCBフットプリントを割り当てることでした。 KiCADに含まれているフットプリントライブラリには、必要なフットプリントが組み込まれていました。独自のPCBを設計するときは、正しいフットプリントを選択するように非常に注意する必要があります。これは、実際にPCBにフットプリントが配置されるためです。フットプリントが非常に似ているが、ピッチがわずかに異なるコンポーネントが多数あります。実際のコンポーネントに一致するものを選択してください。
フットプリントとピン番号
ピン番号には特に注意してください。 KiCADには、回路図のダイオードシンボルのピン番号がフットプリントのピン番号と一致しないという奇妙な問題があります。これにより、ダイオードが逆方向になります。これは、極性を考えると深刻な問題です。私はその間違いを捕らえず、注文したPCBの最初のバッチを捨てなければなりませんでした。 2番目のリビジョンでこの問題を修正するには、ピン番号を交換してカスタムダイオードフットプリントを作成する必要がありました。
PCBレイアウト
回路図が完成し、フットプリントが割り当てられたので、実際のPCBレイアウトに移動しました。ボードのアウトラインはAutodeskFusion 360で作成され、DXFとしてエクスポートされてから、EdgeCutsレイヤーのKiCADにインポートされました。その後の作業の大部分は、通常のキーボードと同様のレイアウトになるようにボタンを配置することでした。
次に、すべてのトレースがルーティングされました。実際のボタンのレイアウトは回路図のきちんと整頓されたマトリックスと一致しないため、この部分は少し乱雑になり、いくつかの場所でビアを使用することに頼らざるを得ませんでした。 Viasを使用すると、あるレイヤーから別のレイヤーにトレースをルーティングできます。これは、トレースが重複している2レイヤーのボードを使用している場合に非常に役立ちます。最後に、塗りつぶし領域を追加しました。これは良い習慣だからです。
PCB製造
ボードを設計したら、すべてのレイヤーをプロットしてzipフォルダーに追加しました。そのフォルダはここで提供され、JLCPCBなどのPCB製造サービスに直接アップロードできます。
PCBガーバーファイルへのリンクは次のとおりです:https://drive.google.com/file/d/10YriLLtghV0Sb84Wm ...
ステップ3:PCBアセンブリ <図>
これは、プロジェクト全体で最も簡単ですが、最も面倒な手順です。すべてのコンポーネントを所定の位置にはんだ付けするだけです。これらはすべてスルーホールコンポーネントであり、はんだ付けが簡単です。ダイオードの向きに特に注意してください。ダイオードのマークはPCBのマークと一致している必要があります。
私の経験では、PCBをサードハンドで所定の位置に保持し、すべてのダイオードを最初に配置するのが最も簡単でした。次に、ボードを裏返し、すべてをはんだ付けしてから、リード線をクリップします。次に、すべてのボタンを配置し、それらをはんだ付けします。次に、ピンヘッダーを所定の位置にはんだ付けします。メスまたはオスのピンヘッダーを使用できます。完全にあなた次第です。男性の頭を使って下に置く場合 ボードの場合、ブレッドボードに直接貼り付けるのに適切な間隔です。
ステップ4:キーボードをArduinoに接続する <図> <図> <図>
配線は複雑に見えますが、すべてがどこに向かっているのかに注意を払えば、それほど悪くはありません。
8本のジャンパー線がカラムヘッダーから次のArduinoピンに直接接続されます:
- 列1> A0
- 列2> A1
- 列3> A2
- 列4> A3
- 列5> A4
- 列6> A5
- 列7> 5
- 列8> 6
次に、74HC595シフトレジスタをミドルブレイクにまたがるブレッドボードに配置します。チップの向きに注意してください!ドットはピン1を示します
配線図を見て、5Vとアースの接続がどこに行くかを確認してください。シフトレジスタには、5Vに接続された2つのピンと、グランドに接続された2つのピンがあります。
シフトレジスタをArduinoに接続するのに必要なワイヤは3本だけです。それらは:
- シフト(時計)11> 4
- シフト(ラッチ)12> 3
- シフト(データ)14> 2
いくつかのばかげた理由で、シフトレジスタの出力ピンは直感に反する方法で配置されています。これらを行ピンに接続するときは、シフトレジスタのピン配置図に特に注意してください。それらは:
- 行1>シフト(Q0)15
- 行2>シフト(Q1)1
- 3行目>シフト(Q2)2
- 行4>シフト(Q3)3
- 行5>シフト(Q4)4
- 行6>シフト(Q5)5
- シフト7>シフト(Q6)6
- シフト8>シフト(Q7)7
Arduinoの0ピンまたは1ピンはシリアルポートにも使用され、競合を引き起こすため、何も接続されていません。
ステップ5:Arduinoコードをフラッシュする <図>
ここで提供されるコードでArduinoをフラッシュします。これについて特別なことは何もありません。他のArduinoプロジェクトと同じようにコードをアップロードするだけです。
コード内のすべてに、読み通すことができる詳細なコメントが含まれているため、ここではあまり詳しく説明しません。基本的に、ピンは入力と出力として設定されます。メインループにはタイマー機能が含まれています。 5msごとに、キーボードをスキャンする関数を呼び出します。この関数は、各列がチェックされる前に、別の関数を呼び出してシフトレジスタを設定します。キーを押すと、その値がシリアルに出力されます。
キーを押したときに印刷される内容を変更する場合は、 Serial.print( "_"); を変更するだけです。 条件に対応するifステートメント内。たとえば、FNを押しながらNを押したときに印刷される内容を設定できます。同じことが、各修飾子を持つ他のすべてのキーにも当てはまります。
多くのキーは、シリアルに出力するだけなので、このコードでは何もしません。つまり、シリアルモニターからデータを削除することはできないため、バックスペースキーは効果がありません。つまり、データはすでに受信されています。ただし、必要に応じて変更を自由に使用できます。
独自のプロジェクトでのキーボードの使用
シリアルに印刷するのはいいことですが、それはこのキーボードのポイントではありません。このキーボードの目的は、より複雑なプロジェクトのプロトタイプを作成することです。そのため、機能を簡単に変更できます。たとえば、入力したテキストをOLED画面に印刷したい場合は、すべての Serial.print()を置き換えるだけで済みます。 display.print( または特定のディスプレイに必要なものは何でも。 ArduinoIDEのすべて置換 ツールは、これらすべてを1つのクイックステップで置き換えるのに最適です。
これを読んでいただきありがとうございます。このキーボードがプロジェクトに役立つことを願っています!
ProtoKeyboardV1.1-Shifted.ino
1/30/21更新:
この新しいコードは完全に書き直されており、元のコードよりも優れたパフォーマンスを発揮します。これは主に、キーが押されるたびに文字が入力されないという私のアルゴリズムの問題に対処するために行われました。元のコードは、特定のキーが最後のではないことを確認するためにチェックされました 押すキー。これにより、2つ以上のキーを押したままにすると、「fgfgfgfgfgfgfgfgfgfg」のようなものが入力されるという問題が発生しました。これにより、「バマー」という単語に2つのmを入力した場合など、同じキーを何度もすばやく入力することもできなくなりました。
新しいコードは、これらの問題の両方を解決し、よりエレガントです。最後に押されたキーを追跡する代わりに、キーボード全体の状態をチェックし、最後のループのキーボード全体の状態と比較します。これは、ループがはるかに高速に実行できることを意味し、同じキーを非常にすばやく何度も入力することもできます。パフォーマンスが劇的に向上します。すべての文字も上部に配列されているため、簡単に見つけて変更できます。すべての修飾子には独立した配列があります。コードもはるかに短いです。
この新しいアプローチの唯一の欠点は、使用するプログラムスペースが大幅に少ないにもかかわらず、より動的なメモリを使用することです。 Arduino Unoでは、現在、3532バイト(10%)のプログラムストレージスペースと605バイト(29%)の動的メモリを使用しています。
追加のボーナスとして、このコードはARMCortex-M4のような高速マイクロコントローラーでも同様に機能します。キーボードをチェックするインターバルタイマーはマイクロ秒単位であるため、どのボードでも同じように実行されます。キーボードをチェックする頻度も簡単に調整できます。デフォルトでは、500マイクロ秒ごとに1つのループが実行されます。キーボードのチェックには8ループかかり、合計4000マイクロ秒(4ミリ秒、つまり1秒あたり250回)です。ただし、マイクロがコードをすばやく実行するのに十分な速度でない場合は、さらに時間がかかる場合があります。
コード
- ProtoKeyboardV1.1-Shifted.ino
- ProtoKeyboardV1-Bits.ino
ProtoKeyboardV1.1-Shifted.ino Arduino
プレビューなし(ダウンロードのみ)。
ProtoKeyboardV1-Bits.ino Arduino
Arduinoコードを更新/ *キーボードV1.2のプロトタイピング用スケッチ* CameronCowardによる1/30/21 * * ArduinoUnoでテスト済み。カスタムPCB *と74HC595シフトレジスタが必要です。 * *詳細:https://www.hackster.io/cameroncoward/64-key-prototyping-keyboard-matrix-for-arduino-4c9531 * / const int rowData =2; // rowsconstのレジスタデータピンをシフトしますintrowLatch =3; //行のシフトレジスタラッチピンconstint rowClock =4; //行のシフトレジスタクロックピン//これらは列入力ピンです。ピン0とピン1は使用されません//問題が発生するため(おそらくTXとRXであるため)const int colA =A0; const int colB =A1; const int colC =A2; const int colD =A3; const int colE =A4; const int colF =A5; const int colG =5; const int colH =6; // shiftRowは各行に必要なシフトレジスタバイトであり、rowStateにはそれぞれの押されたキーが含まれますrowconst byte shiftRow [] ={B01111111、B10111111、B11011111、B11101111、B11110111、B11111011、B11111101、B11111110}; byte rowState [] ={B00000000、B00000000、B00000000、B00000000、B00000000、B00000000、B00000000、B00000000}; byte prevRowState [ ] ={B00000000、B00000000、B00000000、B00000000、B00000000、B00000000、B00000000、B00000000}; //修飾子が押されていないキーのASCIIコード。修飾子はNULL(0)、//個別にチェックし、値を出力しないためです。constcharkey [] ={0、49、50、51、52、53、54、55、56、57、 48、45、61、0、9、113、119、101、114、116、121、117、105、111、112、91、93、92、7、97、115、100、102、103、104、 106、107、108、59、39、0、0、122、120、99、118、98、110、109、44、46、47、0、0、0、0、32、0、0、0、 0、0、0、0}; //シフトが押されたANDキャップを持つキーのASCIIコードはactiveconstchar capsShiftKey [] ={0、33、64、35、36、37、94、38、42、40、41、 95、43、0、9、113、119、101、114、116、121、117、105、111、112、123、125、124、7、97、115、100、102、103、104、106、 107、108、58、22、0、0、122、120、99、118、98、110、109、44、46、47、0、0、0、0、32、0、0、0、0、 0、0、0}; //シフトが押されたキーのASCIIコード.constcharshiftKey [] ={0、33、64、35、36、37、94、38、42、40、41、95、43、 0、9、81、87、69、82、84、89、85、73、79、80、123、125、124、7、65、83、68、70、71、72、74、75、76、 58、22、0、0、9 0、88、67、86、66、78、77、44、46、47、0、0、0、0、32、0、0、0、0、0、0、0}; // ctrlが押されたキー.constcharctrlKey [] ={0、0、0、0、0、0、0、0、0、0、0、0、0、0、9、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、32、0、0、0、0、0、0、0}; // spclが押されたキーのASCIIコード.const char spclKey [] ={0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0}; // altが押されたキーのASCIIコード.constcharaltKey [] ={0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0}; // fnが押されたキーのASCIIコード.constcharfnKey [] ={ 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、 0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0}; //大文字のキーのASCIIコードはactiveconst char capsKey [] ={0、49、50、51、52、53、54、55、56、57、48、45、61、0、9、81、87、69、82、84、89、85 、73、79、80、91、93、92、7、65、83、68、70、71、72、74、75、76、59、39、0、0、90、88、67、86、66 、78、77、44、46、47、0、0、0、0、32、0、0、0、0、0、0、0}; long previousKeyboardMicros =0; //キーボードが最後にチェックされた時刻を格納します//ミリ秒単位で測定される時間が長いため、次の変数は長くなります//int.longに格納できる数値よりもすぐに大きくなりますkeyboardInterval =500; //キーボードをチェックする間隔(マイクロ秒)int rowToCheck =0; // checkKeyboard()のループごとに1行をチェックします。これをkeyboardIntervalと組み合わせて、// shiftRegisterに行間の完全な更新時間を与えますchecksboolcaps =false; // Caps Lockはオンですか?boolshift =false; //左または右シフトが押されていますか?boolcapsShift =false; //シフトANDキャップはアクティブですか?bool ctrl =false; // Ctrlキーが押されていますか?bool spcl =false; // spclキーが押されていますか?bool alt =false; // Altキーが押されていますか?bool fn =false; //ファンクションキーが押されていますか?voidsetup(){Serial.begin(9600); //すべての列ピンを内部プルアップ抵抗を使用して入力として設定しますpinMode(colA、INPUT_PULLUP); pinMode(colB、INPUT_PULLUP); pinMode(colC、INPUT_PULLUP); pinMode(colD、INPUT_PULLUP); pinMode(colE、INPUT_PULLUP); pinMode(colF、INPUT_PULLUP); pinMode(colG、INPUT_PULLUP); pinMode(colH、INPUT_PULLUP); // 74HC595シフトレジスタを制御するために必要な出力pinMode(rowLatch、OUTPUT); pinMode(rowClock、OUTPUT); pinMode(rowData、OUTPUT); updateShiftRegister(B11111111); //シフトレジスタがすべてHIGHで開始することを確認します} void loop(){mainTimer();} void mainTimer(){unsigned long currentMicros =micros(); // Arduinoは何マイクロ秒実行されていますか? if(currentMicros --previousKeyboardMicros> KeyboardInterval){//最後のチェックからの経過時間が間隔を超えた場合//最後にキーボードがチェックされた時間を保存previousKeyboardMicros =currentMicros; checkKeyboard(); //すべてのキーをチェックし、結果をシリアルに出力します}} void updateShiftRegister(byte row){//この関数は、渡されたバイトに従ってシフトレジスタを設定しますdigitalWrite(rowLatch、LOW); //ラッチをローに設定して、バイト全体を一度に書き込むことができるようにしますshiftOut(rowData、rowClock、MSBFIRST、row); //そのバイトを書き込みますdigitalWrite(rowLatch、HIGH); //ラッチをハイに戻し、シフトレジスタが次の変更まで安定したままになるようにします} void checkKeyboard(){//シフトレジスタをshiftRow []バイト配列から現在の行のバイト値に設定しますupdateShiftRegister(shiftRow [rowToCheck]); //各列をチェックif(digitalRead(colA)==LOW){bitSet(rowState [rowToCheck]、0); } else {bitClear(rowState [rowToCheck]、0); } if(digitalRead(colB)==LOW){bitSet(rowState [rowToCheck]、1); } else {bitClear(rowState [rowToCheck]、1); } if(digitalRead(colC)==LOW){bitSet(rowState [rowToCheck]、2); } else {bitClear(rowState [rowToCheck]、2); } if(digitalRead(colD)==LOW){bitSet(rowState [rowToCheck]、3); } else {bitClear(rowState [rowToCheck]、3); } if(digitalRead(colE)==LOW){bitSet(rowState [rowToCheck]、4); } else {bitClear(rowState [rowToCheck]、4); } if(digitalRead(colF)==LOW){bitSet(rowState [rowToCheck]、5); } else {bitClear(rowState [rowToCheck]、5); } if(digitalRead(colG)==LOW){bitSet(rowState [rowToCheck]、6); } else {bitClear(rowState [rowToCheck]、6); } if(digitalRead(colH)==LOW){bitSet(rowState [rowToCheck]、7); } else {bitClear(rowState [rowToCheck]、7); } //すべてのシフトレジスタピンをHIGHに設定します。これにより、値が次のループに「ブリード」するのを防ぎますupdateShiftRegister(B11111111); rowToCheck =rowToCheck + 1; //次の行に繰り返します// 8番目の行を確認した後、状態を確認し(ボタンを押す)、最初の行からやり直しますif(rowToCheck> 7){checkPressedKeys(); rowToCheck =0; }} void checkPressedKeys(){//いずれかのシフトキーが押されているかどうかを確認if(bitRead(rowState [5]、1)| bitRead(rowState [6]、4)){shift =true; } else {shift =false; } //いずれかのCtrlキーが押されているかどうかを確認if(bitRead(rowState [6]、5)| bitRead(rowState [7]、3)){ctrl =true; } else {ctrl =false; } //いずれかのspclキーが押されているかどうかを確認if(bitRead(rowState [6]、6)| bitRead(rowState [7]、2)){spcl =true; } else {spcl =false; } //どちらかのAltキーが押されているかどうかを確認if(bitRead(rowState [6]、7)| bitRead(rowState [7]、1)){alt =true; } else {alt =false; } // FNキーが押されているかどうかを確認if(bitRead(rowState [7]、4)){fn =true; } else {fn =false; } //キャップがアクティブで、シフトが押されていることを確認しますif(shift ==true &&caps ==true){capsShift =true; } else {capsShift =false; } for(int i =8; i> =0; i-){//各行を反復処理for(int j =7; j> =0; j-){//その行の各ビットを反復処理bool newBit =bitRead(rowState [i]、j); //そのビットの状態を確認しますboolprevBit =bitRead(prevRowState [i]、j); //そのビットの以前の状態を確認しますif((newBit ==1)&&(prevBit ==0)){//状態がtrueに変更された場合にのみボタンを押すことができますint thisChar =(i * 8)+ j; //文字配列内のどの位置を選択するかを計算しますif(capsShift ==true){processKey(capsShiftKey [thisChar]); } else if(shift ==true){processKey(shiftKey [thisChar]); } else if(ctrl ==true){processKey(ctrlKey [thisChar]); } else if(alt ==true){processKey(altKey [thisChar]); } else if(spcl ==true){processKey(spclKey [thisChar]); } else if(fn ==true){processKey(fnKey [thisChar]); } else if(caps ==true){processKey(capsKey [thisChar]); } else {processKey(key [thisChar]); }} if(newBit ==1){bitSet(prevRowState [i]、j); //キーが押された場合、前のビット状態をtrueに設定します} else {bitClear(prevRowState [i]、j); //キーが押されていない場合は、前のビット状態をfalseに設定して、もう一度押すことができるようにします}}}} void processKey(char receiveKey){if(receivedKey ==7){//同じ方法で特殊関数をチェックしますas caps(新しい「elseif」ステートメントを追加)caps =!caps; } else {Serial.print(receivedKey); // charが特殊関数に対応していない場合は、そのcharを出力するだけです}}
カスタムパーツとエンクロージャー
.zipファイル全体をPCB製造サービスにアップロードします 回路図
製造プロセス