MENU

ATMEGA328PをArduinoとして動かしてみる

何番煎じの内容だよって感じですが、ATMEGA328PをArduinoとして動かしてみました。
とっても簡単でした。


実装にあたっては下記サイトを参考にさせていただきました。

Arduino as ISP and Arduino Bootloaders | Arduino

ATMEGA328P を Arduino として使う

Arduinoで作った回路の小型化(Arduino互換機の製作)(2) - しなぷすのハード製作記

回路を作る

Arduino UNO R3のオリジナルの回路図がこちらになります。

https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

この回路図のZU4 (ATMEGA328P-PU)がArduinoとしてメインで動いています。
他にICはU1,U2,U3,U5が乗っていますが、それぞれ12V->5V変換IC、5V->3.3V変換IC、USB->Serial変換IC、オペアンプ(電源選択のためのコンパレーターとLED駆動のためのボルテージフォロワとして使用)であり、純粋にArduinoとして動かす分には不要です。

というわけで、今回作るArduino互換機の回路はこんな感じにします。

Arduino互換機 回路図

ブレッドボードに乗せるとこんだけ。(動作確認目的なので、C2とSW1は省略)

自作Arduino互換機
 

Arduino bootloaderを書き込む

ATMEGA328PをArduinoとして動かすにはArduinoのBootloaderを書き込む必要があります。
手元にProMicroがあるので、こちらを使って書き込みをしてみようと思います。

まずはProMicroにBootloader書き込み用のスケッチ(Arduino ISP)を書き込みます。

Bootloader書き込み用のスケッチ
次にProMicroとブレッドボードで作ったArduinoの回路とを下表のように接続します。
念のため接続はProMicroにUSBを接続していない状態で行います。

信号 ProMicro Pin名 Arduino(ATMEGA328P) Pin No.
電源 VCC 電源
GND GND GND
SCK 15 19
MISO 14 18
MOSI 16 17
RST 10 1
               ※基板上に印字されているピン名

ProMicroを接続したところ (右上のLEDマトリックスは何かの残骸)

最後に”ツール”タブの”ボード”と”書き込み装置”でそれぞれ”Arduino UNO”と”Arduino as ISP(ATmega32U4)”を選んでから、”ブートローダーを書き込む”をクリックし書き込みを実行します。

ボードと書き込み装置を選んでからブートローダーを書き込むを実行

これでATMEGA328PはArduinoになりました。

スケッチを書き込む

Arduino UNOにはUSBポートがついていて直接PCと接続してスケッチを書き込めるようになっています。
これは、UNOに乗っているATMEGA16U2がUSB→Serial変換を行ってくれているからです。
今回のようにArduinoを自作した場合は、自分でUSB→Serial変換などを用意してATMEGA328Pへ接続する必要があります。*1 *2
今回は秋月電子通商さんのモジュール基板 AE-UM232Rを使用しました。

akizukidenshi.com

接続はArduino UNO R3の回路図を参考に次のようにつなぎます。
RST端子への接続は100 nFのコンデンサが間に入ります。(AE-232R→コンデンサ→ATMEGA328Pの接続になります。)

信号 AE-UM232R Pin No. Arduino(ATMEGA328P) Pin No.
電源 14 電源
GND 7 GND
Tx→Rx 1 2
Rx←Tx 5 3
RST 2→100nFコンデンサ 100nFコンデンサ→1

接続すると、普通のArduino UNOのようにスケッチの書き込みができます。

試しにATMEGA328Pのピン19にプルダウン抵抗とLEDを接続してLチカのサンプルプログラムを書き込んでみると、問題なく動きました。

自作Arduino互換機でLチカ

今回作った構成だと1セット当たり300円しないくらいなので、何かをつくったときに気軽に組み込めますね。

今回はこれでおわりです。


Arduino互換機とゼロプレッシャーソケットを使ってBootloader書き込み装置を作りました↓
geekyfab.com


GEEKY Fab.ではなんかいろいろ作って頒布してます。
よかったら↓から見ていってください。

*1:今時はあんまりない気がしますが、PCにシリアルポートがついていればそちらでもOKです。その場合はRS232Cをブレッドボードに取り付けられるようにする基板とか売ってるのでそちらをお使いください。

*2:一回書き込むだけであればBootloaderを書き込んだ接続のままArduinoIDEの"スケッチ"→"書き込み装置を使って書き込む"で書き込めます。

Aliexpressでキーボードキットを購入して自作キーボードに挑戦してみる ~スタビライザー取付編~

キーボードを作ったものの、スタビライザーを付けていなかったためスペースキーがすごく押しにくいので、やっぱりスタビライザーを付ける話です。

前回↓ geekyfab.com

スタビライザーを購入

スタビライザーをAliexpressで買うと届くまでに二週間はかかるので、今回は遊舎工房さんで購入しました。こちらのリンクの2Ux4, 6.25Ux1ってやつです。

MXスイッチ スタビライザーyushakobo.jp

で、届いたのでスペースキーのキースイッチを外して早速つけようと思ったんですが、どうにもつかない。
どうやらプレートを付ける前につけるのが正解のようですね…。必要になったらあとからつければいいや、という目論見が外れました…

キーキャップとキースイッチをすべて外す

ということで諦めてキーキャップとキースイッチを全部外すことにします。ホットスワップモデルにしてて助かりました。半田付けしてたらたぶん諦めてました。

キーキャップは取外し用の工具が同封されていたので簡単に外せましたが、キースイッチを外す用の工具は持っておらず、これがけっこう大変でした。というのもキースイッチは前後の爪がプレートに引っかかる形で固定されているからです。
無理やり外そうとするとキースイッチ本体の上蓋が緩み、中のばねが飛び出してパッカーンと四分五裂してしまうかもしれません(体験談)。
なので、キースイッチを外すときは↓の動画のように前後の爪の部分にピンセットなどを交互につっこみ、少しずつ緩めるように外しましょう。

 

f:id:moutakusan:20201128154413g:plain
キースイッチを外すときは慎重に

スタビライザーを取り付ける

すべてのキースイッチを外し終えたら、ケースの蓋を開けて基板にスタビライザーを取り付けます。
スタビライザーを取り付けるときは、下の画像のように、爪がある方を先に基板の穴に挿入して爪を基板に引っ掛けてから、返しのある方をもう一方の穴に挿入するようにしましょう。

f:id:moutakusan:20201128155412p:plain
スタビライザーの付け方

f:id:moutakusan:20201128154807p:plain
基板にスタビライザーを取り付けたところ

スタビライザーを取り付けたら、指でキーキャップが刺さる部分を動かしてみてスムーズに動くことを確認しましょう。
スムーズに動かなければスタビライザーが傾いていることが原因かもしれません。それぞれの足がちゃんと基板の穴に入っているか確認しましょう(これも体験談)。

さて、スタビライザーを全部取り付けたので、プレートをはめて、ちゃんと動くかどうか確認しました。結果…

f:id:moutakusan:20201128160203p:plain
キーが押されたまま戻ってこない…

はい。キーが押されたまま戻ってきてくれませんでした。シフトキーもエンターキーもスペースキーも。

なんで戻ってきてくれないの?

調査の結果、下記が原因であることが分かりました。

① プレートとスタビライザーの金属バーが干渉している。
② そもそもクリア軸のキースイッチの押し返す力が弱すぎる。

①に関してはプレートとスタビライザーの相性の問題かと思います。どうしても解消できませんでした。キーボードキットを買ったショップで売ってるやつなら、干渉しなかったのかしら?次に作ることがあればこちらで試してみます。

s.click.aliexpress.com

②に関しては、スタビライザーを使っているところには赤軸や黒軸といったもっと強めのキースイッチを選べば解消できるかと思います。
が、家にはクリア軸しかなく、新しく注文するのも時間がかかるので、面倒だなと思っていた私はひらめきました。

「ばねを二倍にすれば強さも二倍になるんじゃ…」

ということで、余っていたクリア軸を分解し、中のばねを取り出し、別のキースイッチの中に入れました(ばねの長さがそのままだとめちゃくちゃ入れにくかったので、ばねは半分に切りました)。

f:id:moutakusan:20201129071101p:plain
バラバラにされて、中のばねが半分に切られたキースイッチ。あるいは合成素材。

これによりばねの長さが1.5倍となり、キースイッチが押し返してくる強さも体感1.5倍くらいになりました。
で、早速このスーパークリア軸で動作確認をしたところ、

  • スペースキーは動くようになった!
  • その他キーの動きもよくなったが、時々引っかかって戻らなかった。

という結果になりました。その他キーについてはこの後も頑張りましたが、先ほどの①による抵抗が大きくどうしようもなかったので、スタビライザーは無しにすることにしました。もともとなくてもいいと思ってたのもあります。
スペースキーが問題なく動いてくれるようになっただけでも万々歳です。

f:id:moutakusan:20201129080530g:plain
スペースキーの端を叩いてもまっすぐ押下されるようになった

ということで、これで自作キーボードは完成です。めでたしめでたし。

おわりに

キーボードを組み立てて形にするところまではとっても簡単だったんですが、スタビライザーはめちゃくちゃ苦労しました。
これから作る方はキースイッチを付ける前にちゃんとスタビライザーをつけましょう。スタビライザーなんていらないでしょ、必要になれば後から付ければいいでしょ、とか考えてたら私みたいにとても苦労するかもしれません。

そういうわけなので、同じようにKPrepublic Storeでキットを買う方はkit3か4 (Stabilizer付、switchなし)とキースイッチを別で買うのがいいかなと思います。

s.click.aliexpress.com

s.click.aliexpress.com

kit3/4についてくるスタビライザーなら大丈夫かはわかりませんが、少なくともストアからサポートor返品対応は受けれるかなと思います。むしろ問題ないかだれか人柱になって確認してほしい…

ちなみに、ホットスワップモデルはUS配列限定です。無印の方はJIS配列対応可能らしいので、JIS配列が良い方は無印の方を選びましょう。私も本当はJIS配列が良かったですが、届いてから気づきました。確認不足です。

s.click.aliexpress.com



そういえば使い心地ですが、とーっても軽いです。ほぼ指を乗せるだけで打鍵できる感じ。スムーズに打てるととても気持ちいいです。あとは無刻印、US配列になれる時間が必要です…
 

f:id:moutakusan:20201129081141p:plain
完成した自作キーボード(テンキーレス、クリア軸、US配列、無刻印)

それでは今回はこれで終わります。お疲れ様でした。


おしまい。



自作キーボードを二台のPCで共有するためにUSB切替器を作りました。
geekyfab.com

Aliexpressでキーボードキットを購入して自作キーボードに挑戦してみる ~組立編~

前回の続きで、自作キーボード用のキット(XD87 HS)とキーキャップを組み立てていきます。
最初に書いておくと、めちゃくちゃ簡単でした。

↓前回 geekyfab.com

まずは、購入したケースはベースと蓋がカチッと組み合わされた状態なので、同封されていたピックで開けていきます。

f:id:moutakusan:20201122223912p:plain
ケース

f:id:moutakusan:20201122224012p:plain
同封されているピックを使って外していく

次にケース(ベース側)についてる基板から伸びてるハーネスを、キーボード基板上のコネクタに接続し、キーボード基板をケース(ベース側)にはめます。

f:id:moutakusan:20201122224412p:plain
ハーネスを接続する

f:id:moutakusan:20201122224623p:plain
そしてベースにはめる

次はプレートをケース(蓋側)にはめます。

f:id:moutakusan:20201122224945p:plain
プレートをケース(蓋側)にはめる

そして、基板をはめたケース(ベース側)とプレートをはめたケース(蓋側)をはめ合わせます。

f:id:moutakusan:20201122225438p:plain
ケースをはめ合わせる

次に各ソケットにスイッチを挿入していきます。ソケットは結構堅かったです。ぐりぐりしながら挿入すると上手くいきました。

f:id:moutakusan:20201122225713p:plain
スイッチを挿入していく

ときどき足が曲がっているスイッチがあったので、まっすぐにしてから挿しましょう。

f:id:moutakusan:20201122230222p:plain
ときどき足が曲がっていた

全部挿すとこんな感じ

f:id:moutakusan:20201122230322p:plain
スイッチを全部挿したところ
  私はここで全部のキースイッチが反応するかテストをしました。テストにはこちらのキーボードテスト用サイトを使わさせていただきました、

あとはキーキャップをつけて完成!

f:id:moutakusan:20201122233611p:plain
完成!!
かっこいい!Escの赤とEnterキーのメッセージ刻印がいい感じのアクセントになっています。
ちなみに、「we stand together」の刻印が入ったEnterキーキャップはキットにおまけ?で同封されていました。コロナ禍を共に乗り越えよう的な意味かと受け取り、いいなと思ったのでつけてみました。

  かなり簡単にできたなと思ってたのですが、問題がありました。スペースキーを押すと…

f:id:moutakusan:20201122232959p:plain
スペースキーの端を押すと、スペースキーが跳ね上がる
スペースキーが跳ね上がってしまい、上手く押せません。本来ならこういうことが起こらないようにスタビライザーを付けるのですが、前回書いた通りスタビライザーが付いていないキットを注文してしまったうえ、まぁ大丈夫だろうと思ってスタビライザーを付けずに組んでしまいました。これではさすがに使いにくいのでスタビライザーを付けたいと思います。

ということで、続きます。
geekyfab.com


自作キーボードを二台のPCで共有したい人にはこちらもおすすめ。
geekyfab.com

Aliexpressでキーボードキットを購入して自作キーボードに挑戦してみる ~購入編~

キーボードはずっとPC付属のものを使ってきたんですけど、そろそろちょっといいやつが欲しくなってきました。
それでお店に行っていろいろ触ってみたんですけど、正直あんまり違いわからなかったんですよね。
メカニカルキーボードだと軸の色で押し心地が違うことはわかったし、それは実感できたけど、軸が一緒ならもう全然わからない。

どうせ違いがわからないなら、自分で作るのが愛着がわくしいいかなと思って作ってみようと思ったのが今回の成り行きです。

今回は購入編になります。
組立は次回の記事で書きます。

Aliexpressで自作キーボードキットを選んでみる

調べてみたところ、自作キーボードには以下のパーツが必要なようですね。

  • キーキャップ
  • スイッチ
  • プレート
  • スタビライザー
  • 基板
  • ケース

とはいえ、初めてなのでキットがいいかなと思い、今回はキットを中心に探しました。
で、たどり着いたのがAliexpressで売っていたテンキーレスのXD87 HSキット↓です。

s.click.aliexpress.com

どのキットを買えばいいんだろう

選択肢としてkit1~kit7があり、それぞれの説明が製品ページの下の方に書いてありました。
ざっくりと以下の感じ。

  • kit1とkit2:基板 + プレート + ケース(黒/白)
  • kit3とkit4:基板 + プレート + ケース(黒/白) + スタビライザー
  • kit5:基板 + プレート + ケース + Gateronスイッチ
  • kit6:基板 + プレート + ケース + Gateronスイッチ + LED
  • kit7:基板 + プレート + ケース + Gateronスイッチ + LED + USB type Cケーブル

光らなくていいんでkit5を選択。
あと、kit5, 6, 7には一見スタビライザーが付いてなさそうだったけど、XD87(無印)のQ&Aを見ると下記のようなやりとりを発見しました。

Q: Does kit 6 or 7 come with stabilizers? It is not in the description
A: any kit come with stabs

 こちらにも付属していると期待しておきましょう。 届いたキットを確認したところ、スタビライザーは付属していませんでした。
チャットでショップに聞いてみましたが、やはりついてないとのことです。
Q&Aはあくまでユーザーが回答したものだから、正しい回答が欲しいなら直接聞いて欲しいとのこと。
チャットのレスポンスも早かったですし、他のショップでも次からそうすることにします。

もう一つ迷ったのが、kit5,6,7を選んだ時のケースとスイッチの色指定の方法ですね。 元ページでは

Kit5=XD87 PCB +Stainless steel plate+Plastic Case(Pls mark Black or White one)+90 Gateron Swithces(Pls mark type)

って書いてあるんですけど、注文確定まで選択できるタイミングはなかったです。
なので、注文後にMy Ordersのページの購入製品のところからストアへのメッセージを送れるチャット画面に飛べるので、そこで希望の色を連絡しました。

スイッチの色はどうしようか

Gateronスイッチの色は「キーボードスイッチいろいろ」を参考にさせていただき、Cherry MXの赤軸よりさらに軽いクリア軸というやつを選択しました。

ちなみに、GateronっていうのはCherry MXっていうやつの互換スイッチらしいですね。Cherry MXの特許が切れたから互換スイッチが多く出回るようになっただとか、なんとか。

ホットスワップ

そういえば、今回買ったKPrepublic Storeにもう一つほぼ同じ内容のキットがあったんですけど、こっちはホットスワップ用のパーツが付いてないタイプのようですね。

s.click.aliexpress.com

ホットスワップっていうのは、スイッチを簡単に挿抜できる機構のことみたいです。
ホットスワップ用のパーツがあらかじめ基板に実装されているため、はんだ付け不要でスイッチを付けることができて、製作も楽になりますね。

PCが電源ONのときでも周辺機器を認識できる意味のホットスワップとは別の意味みたいですね。ややこしい。

キットにはキーキャップが付属していないので、キーキャップは別でこちらを購入しました。

s.click.aliexpress.com

届きました

はい。届きました。
キットの方が注文から約2週間、キーキャップの方が約3週間くらいで来ました。

キットの中身はこんな感じ。

f:id:moutakusan:20201117222428p:plain
キーボードキット 左からケース、基板、プレート、スイッチ
他に、ケースを開けるためのピックとおまけのキーキャップが一個、予備のねじが四本ついてました。

基板の表面はこんな感じ。ねこちゃんがかわいい。

f:id:moutakusan:20201117224526p:plain
基板表面
基板の裏面はこんなん。ホットスワップ用の部品が各スイッチの位置に実装されています。
f:id:moutakusan:20201117224715p:plain
基板裏面
基板上にはAtmel製のATMEGA32U4が実装されていました。Arduino LeonardoとかProMicroでおなじみの、USBデバイスとしてふるまえるAVRマイコンですね。
f:id:moutakusan:20201117223848p:plain
マイコンはATMEGA32U4
基板の下の窓みたいになっている部分は内層の銅箔が全部抜かれていて、光にかざすとねこちゃんが透けて見えます。
表面のねこちゃんは、ねこちゃんのかたちに銅箔を抜いて書かれてるみたいですね。
周辺のランドはLED実装用っぽいので、光らせるとねこちゃんが光って見えるのかしら。遊び心が合って素敵です。
f:id:moutakusan:20201117225220p:plain
ねこちゃんが透けて見える

キーキャップはこんな感じ。調子に乗って無刻印にしてしまいました。キーキャップの取外し用の治具も付いてきました。

f:id:moutakusan:20201117225943p:plain
キーキャップ
ちゃんとお行儀よく並んでパッケージングされてました。

次回、組み立てていきたいと思います。



組立編につづく
geekyfab.com

5x7ドットマトリクスLEDで文字を出力してみる

なんかのときに秋月で買った5x7 ドットマトリクスLEDが家にあったんで光らせてみました。

今回はArduino (ProMicro)で5x7ドットマトリクスLEDを光らせて文字を出力するまでの手順を紹介しています。
原理確認のために、5x7ドットマトリクスLEDをゆっくりと光らせた動画も載せてますので、興味があればそちらだけでも見ていってください。→動画位置までジャンプ

ドットマトリクスLEDについて

ドットマトリクスLEDのデータシートを確認すると、中身の回路はこんな感じです。

f:id:moutakusan:20201103210417p:plain
5x7ドットマトリックス回路図

光らせ方の原理は前回作ったキーマトリックススイッチと同じですね。

geekyfab.com

キーマトリックススイッチのスイッチ部をLEDに置き換えたものと言えます。

COL①~⑤を順番にHighにしていって、タイミングを合わせて光らせたい場所のROW①~⑦をLowにして電流を流すことで、特定のLEDだけを光らせることができます。 例えば左上端のLEDだけを光らせたければ、COL①がHighのタイミングでROW①をLowにすればいいですね。
(ROW②~⑦は電流が流れないようにHighか開放状態にします)

これを人の目にもとまらぬ速さで全LEDに対して行うと、残像効果でまるで全LEDが同時に光っているように見えるという算段です。

この記事の最後に、ドットマトリクスLEDをゆっくり光らせたときの動画も載せてます。
そちらを見れば、わかりやすいかも。→動画位置までジャンプ

回路を描いてみる

ドットマトリクスLEDを光らせるための回路はこんな感じにしました。

f:id:moutakusan:20201103220236p:plain
5x7ドットマトリクスLED点灯回路
抵抗はLEDに流れる電流を制限して、LEDの明るさを調整するためのものです。
抵抗値は、LEDに流したい電流値とデータシートに書いてあるLEDの順方向電圧から計算します。
今回は、電流を適当に10mAとして、順方向電圧が3.2Vくらいになるようなので、
  (5-3.2)V/0.01A = 180ohm
の抵抗を使用しました。

コードを書いてみる

COL①~⑤をHighに走査して、タイミングを合わせてROW①~⑦をLOWにします。
とりあえず、"A"と出力してみましょうか。

const int columnPinNumber[] = {9,10,14,15,16};
const int rowPinNumber[] = {2,3,4,5,6,7,8};

// "A"
bool LEDMatrix[7][5] ={
  {0,1,1,1,0},
  {1,0,0,0,1},
  {1,0,0,0,1},
  {1,0,0,0,1},
  {1,1,1,1,1},
  {1,0,0,0,1},
  {1,0,0,0,1}
};

void init5x7DotMatrixLED(int columnPinNumber[5], int rowPinNumber[7]);
void bright5x7DotMatrixLED(int columnPinNumber[5], int rowPinNumber[7], bool LEDMatrix[7][5]);
void openDrain(int pin, bool state);

void setup() {
  init5x7DotMatrixLED(columnPinNumber,rowPinNumber);
}

void loop() {
  bright5x7DotMatrixLED(columnPinNumber,rowPinNumber,LEDMatrix);
}

//5x7 Dot Matrix LED初期化関数
void init5x7DotMatrixLED(int columnPinNumber[5], int rowPinNumber[7]){
  for(int i=0; i<=4; i++){
    pinMode(columnPinNumber[i],OUTPUT);
    digitalWrite(columnPinNumber[i],LOW);
  }

  for(int i=0; i<=6; i++){
    openDrain(columnPinNumber[i],HIGH);
  }
}

//5x7 Dot Matrix LED 点灯関数
void bright5x7DotMatrixLED(int columnPinNumber[5], int rowPinNumber[7], bool LEDMatrix[7][5]){
  for(int i=0; i<=4; i++){
    digitalWrite(columnPinNumber[i],HIGH);
    for(int j=0; j<=6; j++){
      openDrain(rowPinNumber[j],1-LEDMatrix[j][i]);
      delayMicroseconds(476);     //=60Hz
      openDrain(rowPinNumber[j],HIGH);
    }
    digitalWrite(columnPinNumber[i],LOW);
  }
}

//オープンドレイン動作関数
void openDrain(int pin, bool state){
  if(state == HIGH){
    pinMode(pin,INPUT);
  }
  else if (state == LOW){
    pinMode(pin,OUTPUT);
    digitalWrite(pin,LOW);    
  }
}

オープンドレイン動作関数について少し補足です。
Arduinoの出力ピンはハイインピーダンス(開放)出力ができないため、ピンを入力に切り替えて無理やりハイインピーダンスにする必要があります。
そんなことをやっているのがオープンドレイン動作関数さんです。

動かしてみる

では、実際に回路を組んで動かしてみましょう。

かなり簡単な回路なんですが、一点だけ、ドットマトリクスLEDのピン配置がなぜかデータシートに書かかれていませんでした。
いや、書かれてはいるんですがデータシートに書かれてるような識別マークは手元のものには書いてないし、どちらにしろ1ピンの位置しかわからない内容だし…

ともかく、裏面から見ると透明な樹脂のしたにうっすらと”1”と”12”の表記があり、下図のように時計回りに割り当てられていると推測できます。

f:id:moutakusan:20201107153429p:plain
5x7ドットマトリックスLED ピン配置

で、実際に回路を組んでコードを書き込むと…

f:id:moutakusan:20201107154735p:plain
”A”が表示された!!

”A”が表示されました!やったー!

何が起こってるか見てみる

5x7=35個のLEDを12本のピンで制御してるなんて不思議ですね。
原理は初めに説明した通りなんですが、本当に?って思いはありますよね。

ということで、コード中の一つ当たりの点灯時間を476usから100msくらいに伸ばしてみましょう。
すると、こうなります。

f:id:moutakusan:20201107161520g:plain
スロー点灯
一つずつ順番に光らせている様子が見ることができましたね。
これを目にもとまらぬ速さで繰り返すことで”A”を表示させていたようです。


今回はこれで終わります。

おしまい。


[追記]
64x32ドットマトリクスLEDの光らせ方の紹介記事も公開しました。
こっちではカラーのドット絵とかも出力してます。 geekyfab.com

4x4キーマトリックススイッチを作ってみる その2

 前回、4x4キーマトリックスの回路を描いて、ユニバーサル基板上に実装してみました。

geekyfab.com

 今回はプログラムを書いてキーマトリックスが動作することを確認していきたいと思います。

…の前に、前回作った回路の導通チェックをしているとおかしいところがあったんで、半田付けを修正しました。修正後が↓になります。

赤丸のとこが修正箇所
…まぁ、接続が間違ってたんでつなぎ変えたんですけど、Afterの写真だけ見てもわかりませんよね。

Arduinoにつないでみる。

 Arduino(ProMicro)に接続したキーマトリックスの回路図はこんなんです。

ProMicroにキーマトリックスを接続

単純にGPIOポートにキーマトリックスのKEYIN、KEYOUTを接続しただけです。

部品表はこちら。

緒言 部品 購入先リンク
U1 ProMicro Amazon
SW1~16 6x6x5mm タクトスイッチ Amazon
D1~4 1N4148 秋月電子
R1~4 15kohm 1/4W 1% 金属被膜抵抗 Aliexpress
- ユニバーサル基板 秋月電子
- ピンヘッダ 秋月電子

コードを書いてみる

 KEYOUT1~4を順番にHIGHにしていって、どのタイミングでKEYIN1~4のどれがHGIHになるかを見ればいいわけです。ですので、動作確認用のコードはこんな感じにしました。

const int KEYIN[] = {18,19,20,21};
const int KEYOUT[] = {10,14,15,16};

unsigned long previousMillis = 0;  
const long interval = 50;          
int columnNum=0;
int sw[4][4]={0};

void setup() {
  for(int i=0; i<=3; i++){
    pinMode(KEYIN[i],INPUT);
    pinMode(KEYOUT[i],OUTPUT);
    digitalWrite(KEYOUT[i], LOW);
  }
  Serial.begin(9600);
}

void loop() {
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    digitalWrite(KEYOUT[columnNum], HIGH);
    for(int rowNum=0; rowNum<=3; rowNum++){
      sw[columnNum][rowNum]=digitalRead(KEYIN[rowNum]);
      delay(10);
    }
    digitalWrite(KEYOUT[columnNum], LOW);
    columnNum++;
    columnNum &=3;
  }

  if(columnNum==3){
    for(int i=0; i<=3; i++){
      for(int j=0; j<=3; j++){
        Serial.print(sw[i][j]);
      }
      Serial.println();
    }
    Serial.println();
    Serial.println();
    delay(500);
  }
  
}

 一列ずつ順番にスイッチの状態を見ていって、4x4の配列sw[4][4]にスイッチの状態を書き込んでるって感じですね。で、結果をシリアル出力で見てます。

動かしてみた

 回路図に沿ってキーマトリックスとProMicroを接続し、書いたコードをProMicroに書き込みます。

ProMicroと接続してコードを書き込む

 走らせてみると、こんな感じで反応してくれました。

0100
0000
0000
0000


0000
0000
0010
0000


0000
0000
0000
0000

.
.
.

 ちゃんと動いてくれました。よしよし。

おわりに

 キーマトリックスは昔からあるものなので、技術情報も多く、あまり苦労せずに回路やコードを書くことができました。ユニバーサル基板のサイズを攻めすぎたせいか、配線が悩ましく、半田付けには少し苦労しました。
 キーマトリックスの製作はこれにて一旦完了です。お疲れ様でした。


おしまい。


GEEKY Fab.では思い出のゲームで遊ぼうをテーマにハードウェアを作ってます。
よかったら↓から見ていってください。


4x4キーマトリックススイッチを作ってみる

前回はマルチリモコンを作りました。
geekyfab.com

でも、作ったマルチリモコンにはスイッチは二つだけ…
これでは用途が限られすぎています。
そこで今回はマルチリモコンにスイッチをいっぱい追加したいので、キーマトリックスを作ってみようと思います。



キーマトリックスとは

キーマトリックスとはたくさんのスイッチのON/OFF判定を少ない入出力ポート数で達成する方法の一つです。キー (スイッチ)がマトリックス上に並んでる回路なので、キーマトリックスです。

例えば、16個のスイッチのON/OFF判定をしようと思ったら、単純に各スイッチを一つずつマイコンのポートにつなげばできます。
ただ、それだと当然マイコンのポートを16ポート使ってしまうことになります。
Arduino UNO rev.3だとDigital pinとして使えるポートは全部で22ポートなので、仮に16ポートをボタンだけで埋めると残りはたった6ポートです。
これはさすがにもったいない。

Arduino UNO Rev.3だとこういうことになる

そこでキーマトリックスの出番です。キーマトリックスを使用すると、元の半分の8ポートで16個のスイッチのON/OFF判定ができるようになります。

キーマトリックスを使えば8ポートでOK

では、そんな便利なキーマトリックスをどうやって実現するのでしょうか?
次からは、実際に回路を描いて説明してみます。

キーマトリックス回路

4x4キーマトリックスの回路図は下図の感じになります。

4x4 キーマトリックス回路図
KEYOUT1~4がマイコン(今回はArduino)のデジタル出力端子、KEYIN1~4がデジタル入力端子につながります。
各スイッチ(SW1~16)の一方のピンが、電源ではなくデジタル出力端子につながっているところがポイントです。
もしKEYOUT1~4が、1ポートにつきボタン1個を使う単純な回路のように、5V(High)で固定されていたらどうなるでしょうか?

仮にSW1を押したときはKEYIN1が反応することになります。

SW1を押すとKYEIN1が反応する
ではSW5を押したときは?
…同じくKEYIN1が反応することになります。
SW5を押したときもKYEIN1が反応する
つまり、マイコンからはSW1を押したときもSW5を押したときも同じように見えてしまい、実際にはどのスイッチが押されているかわかりません。

では、KEYOUT1だけがHigh(5V)でKYEOUT2~4がLow(0V)とした場合、SW1とSW5を押したときの反応はどうなるでしょうか?

SW1を押したときの反応はさっきと同じですね。
KEYIN1が反応します。

SW5を押したときは?
ここがさっきと変わってきますね。
KEYOUT2は0Vなので、SW5は押しても押さなくても0Vのままとなり、KEYIN1は反応しません。

キーマトリックスではこのKEYOUT側を一つだけHighにするってやつを、順番に行い続けます。
例えば、初めの10ms間はKYEOUT1だけをHighにし、次の10ms間ではKYEOUT2だけをHighにし…という具合に。
このように、キーマトリックスでは同時に見るスイッチの数を絞ることで、少ないピン数で多くのスイッチを見ることができてるんですね。

スイッチ以外の部品について

回路図で使われてるスイッチ以外の部品の役割も説明しておきます。D1~4は逆流防止用のダイオードです。
例えば、SW1とSW5が同時に押された場合にダイオードがなければKEYOUT1からKEYOUT2に電流が流れてしまい、最悪故障してしまいます。

ダイオードがなければ逆流する
こういうことがないようにするためのダイオードです。
ちなみに、SWごとにダイオードをつけることでボタンを同時押ししても誤判定されなくなりますが、今回はそこまでしてません。

R1~R4はプルダウン抵抗です。
これがないとスイッチが押されてないときのKEYIN1~4の状態は不定となります。
値は適当です。

ユニバーサル基板で作ってみた

キーマトリックスは使う機会が多いと思うので、ユニバーサル基板上に実装してモジュール化してみました。

作ったキーマトリックス(表面)
作ったキーマトリックス(裏面)
ギリギリサイズすぎて抵抗が無理のある付け方になってしまいました。
抵抗が付いている方がKEYIN,ダイオードが付いている方がKEYOUT。
抵抗側のピンが5ピンなのは、pin1(一番手前)でArduino側のGNDと接続するためです。

使った部品リストは下記です。

緒言 部品 購入先リンク
SW1~16 6x6x5mm タクトスイッチ Amazon
D1~4 1N4148 秋月電子
R1~4 15kohm 1/4W 1% 金属被膜抵抗 Aliexpress
- ユニバーサル基板 秋月電子
- ピンヘッダ 秋月電子

タクトスイッチは100個入りで¥615という安さ。
抵抗もAliexpressで買ったので、3120個入の抵抗キットで$15という安さ。
ただし、余りまくり。


次回、Arduinoとつないでプログラムを組んで実際に動かしてみたいと思います。




つづく。

geekyfab.com

*1:例えばしなぷすさんのHPでとてもわかりやすく解説されている。

Arduino (ProMicro)で家用のマルチリモコンを作る  その4

 前回の続きで、IRremoteライブラリを使ってエアコンのリモコンを実装してみたいと思います。

 まずは受信機でエアコンの”冷房ボタン”を押したときの受信データを確認すると…

f:id:moutakusan:20201001152722g:plain
止まらない!

あららららら。エアコンの信号の長さに対して受信データを格納する配列が足りてないため、暴走してしまうみたいですね。
 受信データを格納している配列はIRremoteInt.h内で宣言されているrawbufなので、このサイズを大きくすれば対応できそうです。↓はIRremoteInt.hの一部抜粋。

struct irparams_struct {
    // The fields are ordered to reduce memory over caused by struct-padding
    volatile uint8_t rcvstate;      ///< State Machine state
    uint8_t recvpin;                ///< Pin connected to IR data from detector
    uint8_t blinkpin;
    uint8_t blinkflag;              ///< true -> enable blinking of pin on IR processing
    unsigned int rawlen;            ///< counter of entries in rawbuf
    unsigned int timer;             ///< State timer, counts 50uS ticks.
    unsigned int rawbuf[RAW_BUFFER_LENGTH];  ///< raw data
    uint8_t overflow;               ///< Raw buffer overflow occurred
};

見たまんまRAW_BUFFER_LENGTHの値を変更すればrawbufを拡張できそうです。デフォルトでRAW_BUFFER_LENGTHは101となっていたので、これを801とかにして再度エアコンの冷房信号を受信してみると…

f:id:moutakusan:20201001154157p:plain
エアコンの冷房信号の受信結果

ちゃんと受信できたっぽいです。配列長が531だったみたいですね。かなり長いなあ。
 では、早速受信できたrawDataを前回作ったマルチリモコン用のプログラムのirSignal[]にべた書きで代入してみてエアコンを制御できるか確認してみます。
 あ、その前にRAW_BUFFER_LENGTHの値が801のままだとメモリをいっぱい使ってしまうので、値は戻しておきましょう。私が使っているPro Microでは、801のままだとメモリ不足でコンパイル通りませんでした。
 スケッチを書き込んでLEDをエアコンでタクトスイッチを押してみると…

f:id:moutakusan:20201001234159g:plain
エアコンをON!
ちゃんと点きました~。
 そしてもう一個の方のタクトスイッチを押すとテレビのオンオフもできてるので、もうこれはマルチリモコンといってもいいでしょう。完成だ完成。

とりあえずできた

 ということでArduinoで作るマルチリモコンいったん完成!!シーリングライトでつまずきましたが、そのほかの部分はけっこうすんなり実装できました。事前に調べていたときはエアコンの制御が苦労しそうかなと思っていましたが、そこはすんなりできましたね。IRremoteライブラリは偉大です。
 今後はできたリモコンをベースに機能拡張をしていけたらいいなと思います。下記は次にやりたいことリストです。

  • ボタンの数を増やす
  • 受信信号をボタンに直接割り当てる学習機能の追加
  • ユニバーサル基板上へ実装する
  • シーリングライトを制御する

 ここまでで、Arduinoで作るマルチリモコンはひと段落とします。上記リストの内容はおいおいクリアして、普段使いできるレベルには仕上げたいとは思っています。




 次は何をやろうかな。

Arduino (ProMicro)で家用のマルチリモコンを作る  その3

 前回の続きです。

moutakusan.hatenablog.com

 テレビへのリモコン操作はできたので、プラスで何か別のものもリモコン操作できたらマルチリモコンって言ってもいいですよね。エアコンのリモコンはハードルが高そうなので、単純であろうシーリングライトのリモコンを実装してみます。

 前々回作った受信器でシーリングライトのON/OFF信号を受信してみると…

f:id:moutakusan:20200920233735p:plain
シーリングライトのリモコン受信データ
 0x46BBC5EEというデータが送られているという結果になりましたが、rawDataを見る限り32bitsもないですよね。どう読めばいいんでしょうか。

 おさらいですが、赤外線リモコンリーダー→データ→リピート→データ→リピート→… の流れで信号が来ます。IRremoteライブラリは読み取ったリーダーの長さからライブラリ内のどの規格に合致するかを確かめ、合致した規格でリーダー後の信号をデコードしていくという流れになっています。そして、合致する規格がない場合はハッシュ関数を通して32 bitの値にして出力しているようです。そのため、ライブラリ内のどの規格にも合致しなかったシーリングライトの信号の復調結果は32bitで出力されているみたいです。
 ただ、残念ながらこのデコード値だけを記録したところで実際の信号のHigh, Low期間が分からないので使えません。ライブラリ内に用意されていない規格はsendRaw関数を使ってHigh, Low期間を直接指定して信号を送信してあげる必要がありそうです。いったん受信したrawDataをコード内にべた書きしてsendRaw関数と前回作った赤外送信部回路で送信してみましょう。

シーリングライトへの信号送信実験

 サンプルスケッチのIRSendRawDemo.inoの送信データirSignalに先ほど受信したrawDataを放り込んで、

#include <IRremote.h>

IRsend IrSender;

// On the Zero and others we switch explicitly to SerialUSB
#if defined(ARDUINO_ARCH_SAMD)
#define Serial SerialUSB
#endif

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);

    Serial.begin(115200);
#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL)
    delay(2000); // To be able to connect Serial monitor after reset and before first printout
#endif
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__));
    Serial.print(F("Ready to send IR signals at pin "));
    Serial.println(IR_SEND_PIN);  //IR_SEND_PIN=5
}

void loop() {
    int khz = 38; // 38kHz carrier frequency for the NEC protocol
    /*
     * Send data from RAM
     */
    unsigned int irSignal[] = {1250,450, 1200,500, 350,1300, 1250,450, 400,1300, 400,1250, 450,1250, 1200,500, 400,1250, 1250,450, 400,1300, 350};
    Serial.print("send data:");
    for(int i=0; i<sizeof(irSignal); i++){
        Serial.print(sizeof(irSignal));
        Serial.print(",");
    }
    Serial.println("");
    for(int i=0; i <3; i++){
        IrSender.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); // Note the approach used to automatically calculate the size of the array.
    }
    delay(2000);

}

として、実行すると…ライトがオンオフしてくれません…
 何が悪いんでしょうか?試しにテレビのリモコンの信号をirSignalに入れてkhzを37に変更して実行してみると…こちらは動きました。上記のコードで動くのは動くみたいです。オシロとかあれば切り分けも楽だなぁと思ったら、どうやらArduinoで作ってる人もいる模様。今度やってみよう。
 ともかく、シーリングライトが動かない問題はなかなか解決しそうにありませんのでいったん置いておいて、先にマルチリモコンの回路とコードを書いていくことにします。

回路

 テレビのON/OFF用とシーリングライトのON/OFF用にタクトスイッチを一つずつつけます。 タクトスイッチの接続ピンは割り込みに対応したピンにしておきます。  テレビとシーリングライトの二方向に同時に信号を送信できるように、LEDを1つ直列に追加します。 前回と同程度の信号強度にするためには電流を100mAのままにしないといけないので、
    RIR = ( 5-1.35 x 2 ) V / 0.1 A = 23 ohm
なので、電流制限抵抗は22ohmに変更します。
 これらを反映させると、回路図は下図のようになりました。

f:id:moutakusan:20200928230959p:plain
マルチリモコン回路図

コード

 テレビとシーリングライトの送信用コードを関数にして、それぞれのタクトスイッチが押されたときに割り込みで実行されるようにしました。

#define SERIAL_PRT_ON 1

#include <IRremote.h>

IRsend irsend;

const int TV_SW_PIN = 3;
const int LIGHT_SW_PIN = 7;

struct sendTV{
  static bool TVState;
  void TVCtrl(unsigned long tAddress, unsigned long tData);
  static void TVStateChage();
};

struct sendLight{
  static bool LightState;
  void LightOnOff();
  static void LightStateChage();
};

sendTV sTV;
sendLight sLight;
bool sendTV::TVState=0;
bool sendLight::LightState=0;

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    pinMode(TV_SW_PIN, INPUT);
    pinMode(LIGHT_SW_PIN, INPUT);

#if SERIAL_PRT_ON
    Serial.begin(115200);
#if defined(__AVR_ATmega32U4__)
    while (!Serial); //delay for Leonardo, but this loops forever for Maple Serial
#endif
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__));
    Serial.print(F("Ready to send IR signals at pin "));
    Serial.println(IR_SEND_PIN);  //IR_SEND_PIN=5
#endif    

    attachInterrupt(digitalPinToInterrupt(TV_SW_PIN),sendTV::TVStateChage, RISING);
    attachInterrupt(digitalPinToInterrupt(LIGHT_SW_PIN),sendLight::LightStateChage, RISING);

}

void loop() {
  if(sendTV::TVState){
    sTV.TVCtrl(0x555a, 0xf148688B); //0x555a:TV address, 0xf148688B:Power ON/OFF
    sendTV::TVState=0;
  }

  if(sendLight::LightState){
    sLight.LightOnOff();
    sendLight::LightState=0;
  }  
}

void sendTV::TVCtrl(unsigned long tAddress, unsigned long tData){    
  for (int i = 0; i < 3; i++) {
    irsend.sendPanasonic(tAddress, tData);
#if SERIAL_PRT_ON
    Serial.print(F("sendPanasonic(0x"));
    Serial.print(tAddress,HEX);
    Serial.print(F(", 0x"));
    Serial.print(tData,HEX);
    Serial.println(F(")"));
#endif
    delay(40);
  }
}

void sendTV::TVStateChage(){
  sendTV::TVState = 1;
}

void sendLight::LightOnOff(){
  int khz = 38; // 38kHz carrier frequency for the NEC protocol
  unsigned int irSignal[] = {1300,400, 1250,450, 450,1200, 1300,400, 450,1200, 500,1200, 450,1250, 1300,400, 450,1200, 1300,400, 450,1200, 500};

#if SERIAL_PRT_ON
  Serial.print("send data:");
  for(int i=0; i<sizeof(irSignal)/ sizeof(irSignal[0]); i++){      
    Serial.print(i);
    Serial.print(":");
    Serial.print(irSignal[i]);
    Serial.print(",");
    
  }
  Serial.println("");
#endif

  for(int i=0; i <3; i++){
      irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); // Note the approach used to automatically calculate the size of the array.
      delay(10);
  }
}

void sendLight::LightStateChage(){
  sendLight::LightState = 1;
}

コードが汚いのは許して欲しい。

結果

 タクトスイッチを押すとテレビが付きました!これはかなりリモコンっぽい!シーリングライトの方は相変わらずつきませんが…
 シーリングライトについてはその後いろいろ頑張りましたが、点かず。エアコンのリモコンの実装のほうが簡単なのではなかろうか。次回、エアコンのリモコンの実装をやってみます。




まだつづく。

Arduino (ProMicro)で家用のマルチリモコンを作る  その2

 前回の続きです。

moutakusan.hatenablog.com

 ↓こういうデータがダンプできたわけですが、どういう規格になってるんでしょうか。

f:id:moutakusan:20200908223306p:plain
ダンプされたデータ

 規格についてはこちらのサイトやこちらのサイトが参考にさせていただきました。 あと、Arduinoを使用した解析についてはdok kozoさんの記事jumbleatさんのブログも参考にさせていただきました。
 ポイントは、

  • 赤外線規格には数種類ある
    • 出力結果のEncodingってとこですね。
  • いずれの規格も全体の流れはリーダー→データ→リピート→データ→リピート→… の流れ
    • 出力結果のTimingの"+3450, -1600"がリーダー、その後の"500, -300"と"+550, -1150"がデータ。数字には少しばらつきがある。
  • データはHi期間とLow期間の比であらわされる
    • 出力結果のTimingの"+"がHigh期間、"-"がLow機関に対応している。

の三点ですかね。
 加えて、EncodingのフォーマットがPanasonicの場合は、アドレスが信号に含まれるみたいです。
 ここでちゃんとEncodingフォーマットが表示されていて、上手くデコードできている場合は、IRRemoteライブラリを使えば簡単に送信側もできそうですね。先にそっちをちょっとやってみることにします。

テレビの赤外線送信部を作ってみる

 テレビの赤外線信号はIRRemoteライブラリをそのまま使えば上手くデコードできてたみたいなので、デコードしたデータを参考に赤外線送信部を作ってみます。
 とりあえず、下記にデコードした結果の一部を書いてみました。

リモコンキー デコード結果
電源 0x555A F148688B
1ch 0x555A F148724C
2ch 0x555A F148F244
録画 0x555A F148C9F7

 デコード結果の前半の0x555Aがアドレス、後半がデータです。では試しにこれらのデータをテレビに投げてみましょう。

回路

回路はこう。

f:id:moutakusan:20200917165515p:plain
送信部回路図、 ピン5の先は前回作った受光部の回路につながってる
 赤外LEDはコレを使いました。赤外LEDの順方向電圧はTyp. 1.35V、最大定格電流はPulse駆動の場合は1000mAなんで、
    RIR = (5-1.35)V/1A = 3.65 ohm
ということで、3.65ohm以上ならOK。実際にはUSBの供給電流は最大500mAなので、余裕をもって100mA (RIR=36.5 ohm)くらいで使うことにします。1000 mA流したければ、別電源いりますね。これに合わせてトランジスタ2SC1815を使うことにしました。150mAまで流せるやつです。
 注意点として、定電流のときのLEDの最大定格は100mAなので、前のスケッチが残っていたりしてD5ピンがHighになっている状態で回路の電源入れるとLEDが壊れます。スケッチを書き込んでからLEDを接続するようにするなどして対策してください。

コード

 コードはスケッチ例のIRSendDemo.inoを編集して、テレビのON/OFF信号を5秒に1回投げるようにしました。

#include <IRremote.h>

IRsend irsend;

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);

    Serial.begin(115200);
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__));
    Serial.print(F("Ready to send IR signals at pin "));
    Serial.println(IR_SEND_PIN);  //IR_SEND_PIN=5
}

void loop() {
    unsigned long tAddress = 0x555a;  //TV address
    unsigned long tData = 0xf148688B;  //Power ON/OFF
    
    for (int i = 0; i < 3; i++) {
        irsend.sendPanasonic(tAddress, tData);
        Serial.print(F("sendPanasonic(0x"));
        Serial.print(tAddress,HEX);
        Serial.print(F(", 0x"));
        Serial.print(tData,HEX);
        Serial.println(F(")"));
        delay(40);
    }

    delay(5000); 
}

結果

 スケッチを回路に書き込むと赤外LEDがチカチカ(目視ではもちろん見えませんが、スマホのカメラ越しだと赤外LEDの光が見えます。)

f:id:moutakusan:20200917164434g:plain
赤外LEDチカチカ
 赤外LEDをテレビの方に向けると…ちゃんとテレビがON/OFFしてくれました!!ちなみに、テレビからどれくらい離れても届くか試したところ、だいたい4.5mくらいまでは反応してくれました。家の中で使う分には十分なので、回路はこのまま進めようと思います。

 次回はもう少しIRremoteライブラリをいじってみようかなぁ。


つづく