以前にもオンボードデバイスの制御のためにBBC micro:bitのI2Cバスを使用したことがあったです。しかしその記憶は定かでないです。いざMakeCodeエディタで書こうとしてこの引数なんだっけと困りました。この際ということでメモを残します。I2C接続の最初の題材は「例によって」AQM1602LCDモジュールです。
※「ブロックを積みながら」投稿順 index はこちら
(末尾にJavaScript表現のサンプルコード全文を掲げました。)
まず、BBC micro:bitでI2Cバス使うときに読んでおかないとイケないマニュアル類へのリンクを貼っておきます。最初はピンアウトの説明。
幸い、v1系でもv2でもI2Cバス(外部接続用)はカードエッジコネクタの同じ端子に出ているのでバージョン違いで間違う心配はないです。またとなりにGNDと3Vも出ているので接続しやすいです。配慮していただいている感じ。
- P19 SCL
- P20 SDA
今回、接続につかうのは、v1.5のmicro:bit です。v1.5の中でも搭載ペリフェラル・デバイスに差異があり、内部で使われているI2Cアドレスは異なるので注意が必要です。v2は内部接続用のI2Cバスとカードエッジコネクタに出ている外部I2Cバスは異なるので内部のI2Cバスのアドレスを気にする必要が無いので楽です。v1.5に関するI2Cアドレスの情報などは以下にあります(ページの上の方にv2や、v1.3へ切り替えるボタンがあります。)
秋月製AQM1602 LCDモジュール
I2C接続のテストで、毎度使わせていただいている表示モジュールです。狭ピッチのLCDをブレッドボードに刺しやすいように 2.54mm ピッチのピンに変換してくれる変換基板。搭載しているLCDモジュールは、16文字x2行のキャラクタのものです。電源は5Vでも3.3Vでも動作可能です。ただし、3V電源はスペック割れています。BBC micro:bitを単三電池動作させた場合、電源は3Vになってしまうので、スペック的にはmicro:bitから電源与えるのはマズイかも。実際は動作するでしょうが。
今回はUSBから5V与えているので、サブマイコン、KL26のレギュレータから3.3Vが供給されているはずです。今回使用のLCDモジュールは、変換基板の上のオプショナル(半田ブリッジ)なプルアップ抵抗をイネーブルにしてあるので、SCL、SDAともにプルアップはピッチ変換基板上の素子を使用。
MakeCodeでのI2C制御
今回のモジュールはI2C Writeのみ対応のモジュールなので、以下のブロックのみを使用することで制御できます。
i2c write number
ここでこのブロックに与える引数が問題です。細かいところを毎度忘れる。まず addressには、0x3E(MakeCodeが16進で入力しても、自動的に十進表現に変換してしまうので十進だと 62)を与えます。いつも混乱するのですが、最下位のR/Wビットを除き、bit 1 をLSBとしてアドレスを読む記法です。Arduino表現と同じ。bit0をLSBとする記法だと0x7C(READの場合bit0に1を立てるので0x7D)ですが、そちらではないです。いつも間違えて、「動かん」とか言って時間使ってしまう部分。
I2Cアドレスに引き続き、このデバイスの場合、1バイトのコマンド/データの識別用のバイト、と実際に書き込むデータまたは設定値のバイト(複数バイトも可)を与えます。しかし、MakeCodeのi2c write numberブロックには、1個のvalue引数しかないです。しかし与える数値のフォーマットを指定することで、複数バイトを送信可能です。ここでは、
UInt16BE
を指定しました。符号なし16ビット、ビッグエンディアンです。16ビットなので、8ビット2回の転送が起こります。またI2Cは「通信系」なので、MSBが先に来るビッグエンディアンです。上位バイトにコマンド/データの識別コードをのせ、下位バイトにキャラクタコードあるいは設定値をのせてやればOKでした。
なお、16進表現のままならコメント不要と思ったのです(私は、「普段は」ドキュメンテーション・コメントを結構な分量書く方なのですが、本サイトでは短いコードでもあり掲載スペースの問題もありでバッサリ省略しています。すみません。地の文章がコメントみたいなもの、とご理解ください。)しかし、MakeCodeエディタ上では、16進入力は許されているものの、10進表現に変換されてしまうと何だか分からなくなってしまいます。10進変換を抑える方法ないものかしら。仕方ないのでMakeCodeでコメント機能を初めて使いました。使い方は以下に。
秋月殿のArduino用サンプルコードの同名の関数と同じになるように作成した、コマンド書き込み関数とデータ書き込み関数がこちら。
1点、困ったのは、データ(表示文字)書き込み用の関数です。
- 上位層では文字列を与えて表示させたい
- MakeCode上は、文字列を扱うための関数ブロック群はあるが、文字コードに変換する関数ブロックが見当たらない
しかたなく、JavaScript表現に切り替えて、charCodeAt()を呼んでみました。そこからブロック表現に戻ると上のような感じです。ブロックとしてはないけれど、JavaScriptの関数は使えるのね。。。良かった。
micro:bit v1.5のI2Cバスの動作の様子
一応、波形も確認しました。黄色がSCL、青がSDAです。それらしく動いているし、I2Cに見えるのでまあOKっと。
サンプルコードの上位層
以下のサンプルコードでやっているのは以下の処理です。
- AQM1602の初期化。モジュール添付の秋月殿のArduinoサンプルコードと同じ設定値。
- 送信文字列 “Hello World.” 設定
- 以下4~5を毎秒1回繰り返す
- LEDマトリックスの左上をトグル
- AQM1602の表示をクリア
- AQM1602の表示RAMのポインタを先頭に戻す
- 送信文字列をAQM1602へ転送
こんな感じ。
細かいところがクリアになってよかった(本当か?)
ブロックを積みながら(27) BBC micro:bitとラズパイでサウンドモニタ その4 へ戻る
ブロックを積みながら(29) BBC micro:bit、EEPROMをI2C接続 へ進む
JavaScript表現のサンプルプログラム
function initAQM1602 () { basic.pause(100) writeCommand(56) writeCommand(57) writeCommand(20) writeCommand(115) writeCommand(86) writeCommand(108) writeCommand(56) writeCommand(1) writeCommand(12) } /** * 62=0x3E * * 16384=0x4000 */ function writeData (dat: string) { pins.i2cWriteNumber( 62, 16384 + dat.charCodeAt(0), NumberFormat.UInt16BE, false ) basic.pause(1) } function writeCommand (command: number) { pins.i2cWriteNumber( 62, 0 + command, NumberFormat.UInt16BE, false ) basic.pause(20) } initAQM1602() let msg = "Hello World." basic.forever(function () { led.toggle(0, 0) writeCommand(1) writeCommand(0) for (let index = 0; index <= msg.length; index++) { writeData(msg.charAt(index)) } basic.pause(1000) })