HOME > ものづくり(電子工作) > ブラウザ操作でIO制御 WebIO(webio2.js)
2017.9.26-(更新中)

ブラウザ操作でIO制御 WebIO2 [テキスト]

小山智史

(更新履歴)


目次

1. 概要
2. 動作環境とソフトウェアの準備
3. 動作の説明
(付録1) ピン接続
(付録2) ピンモード (付録3) Javascriptライブラリ(webio2.js)
(付録4) WebIO2のプロトコル(Midi通信との関係)


1. 概要

 Web技術の進歩により、最近ではパソコンに接続したMIDIデバイスで演奏するWebページが作れるようになりました(下図)。

 WebIO は、この仕組みを用いてブラウザからIO制御できるようにしたものです(下図)。

 上図左は、温湿度センサをつないだマイコン(図ではXIAO M0)とパソコンをUSB接続し、パソコンのWebブラウザの画面にセンサの値を表示する様子を表しています。

 上図右は、赤外線送信機をつないだマイコン(図ではATOM lite)とスマホをBluetooth接続し、スマホでテレビのリモコン操作をする様子を表しています。

 マイコンにプログラム(webio2.ino)を書き込んでおくことにより、パソコンやスマホからは見かけ上MIDIデバイスとなります。温湿度計やリモコンのWebアプリはサーバに置きます。

 パソコンやスマホに特別なアプリは必要なく、ブラウザでページ(Webアプリ)を表示するだけです。そのページはサーバに置かずに、パソコン上に置いても構いません。

 操作対象は「ブラウザが動作しているパソコンやスマホに接続したデバイス」です(上図)。遠隔地のデバイスを操作できるわけではありません。

 以下はWebIOを用いた制作例で、それぞれリンク先に詳しい説明があります。

(1) ブラウザ画面に表示する温湿度計[リンク]

 大きなモニタに表示すれば、体育館やイベント会場などで熱中症対策に利用できます。

(2) ブラウザ画面に表示するCO2モニタ[リンク]

 大きなモニタを使えば、イベント会場や飲食店の店頭などで換気の目安を表示できます(新型コロナ対策)。

(3) ブラウザで操作する赤外線リモコン[リンク]

 よく使うボタンだけを表示するリモコンや、複数の機器を操作できるリモコンを作ることができます。通常のリモコンボタンを押せない重度障害者も、パソコン操作ができればリモコンを利用できます。

(4) ブラウザで操作するラジオ[リンク]

 高機能のラジオIC SI4732をブラウザで操作するラジオです。通常のラジオを操作できない重度障害者も、パソコン操作ができれば利用できます。

(5) ブラウザと連動して自動演奏するミニドラム[リンク]

 ブラウザのメロディーと連動して、ミニドラムのスティックをモータで制御します。

(6) 電子工作の導入教材[リンク]

 ブラウザの操作でLEDをオンオフ、スイッチでブラウザ画面を操作、センサの値をブラウザ画面に表示などの簡単なWebアプリを作りながら、電子工作の導入教材として利用できます。


2. 動作環境とソフトウェアの準備

 以下のブラウザおよびマイコンで動作を確認しています。どのブラウザが Web MIDI API やWebBluetoothに対応しているかは「Can I Use」で確認できます。

パソコンとUSB接続の場合 パソコンやスマホとBluetooth接続の場合
マイコン Leonardo, Micro, Wio, XIAO M0(samd21) XIAO ESP32C3, ATOM lite(C3)
ブラウザ Windows版Chrome, Edge など
(Web MIDI API 対応ブラウザ)
Windows版Chrome, Edge
Android版Chrome
(Web MIDI APIおよび Web Bluetooth 対応ブラウザ)

 webio2.zipをダウンロードし、解凍すると、以下のファイルが復元されます。


3. 動作の説明

3.1 MIDIデバイス(マイコン)の接続

(1) パソコンに「本物のMIDIデバイス(ここではnsx-39)」を接続してwebio2.jsを使ったページ(このページもそうです)を表示すると、ページ冒頭の表示がのようになります。これで、ブラウザ画面から接続したMIDI音源(nsx-39)で演奏させることができます。

 WebIOは、「さまざまなオリジナルのMIDIデバイスを作って演奏(?)するページを作る」ということに他なりません。

(2) 今度はパソコンにマイコン(XIAO M0)をUSB接続し、このページを表示すると、ページ冒頭にのような表示が現れます。これは、接続したマイコンがSeeed XIAO M0という名前で認識されていることを表しています。

(3) USB接続のMIDIデバイスが無い場合は、のような表示になります。近くにマイコン(ATOM C3)を置き、ボタンを押すと、下図右のような画面が現れます。一覧の中から接続するMIDIデバイス(この例では ATOM C3)を選択し、ボタンを押します。マイコンとBluetooth接続され、ページ冒頭の表示はのようになります。これは、接続したマイコンがATOM C3という名前で認識されたことを表しています。


 以下では、MIDIデバイス(マイコン)として Leonardo, Micro または XIAO M0 をUSB接続、または ATOM lite をBluetooth接続した時の、基本的な入出力の様子について説明しています。ATOMの場合は、スマホからこのページで動作を確認することもできます。ATOMに内蔵されているLEDやスイッチを使っているので、外部に何も接続する必要はありません。なお、このページには所々に

のような箇所があります。選択したボードに対応した説明が表示されます。


3.2 ブラウザの操作でLEDの点灯・消灯

 画面上のボタンを押すとマイコンに接続したLEDが点灯・消灯する例です。

led1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <h2>LEDの点灯・消灯</h2> <button onclick=digitalWrite(D9,1)>点灯</button> <button onclick=digitalWrite(D9,0)>消灯</button> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9を出力に } </script> </body></html>

led1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <h2>LEDの点灯・消灯</h2> <button onclick=digitalWrite(D9,1)>点灯</button> <button onclick=digitalWrite(D9,0)>消灯</button> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9を出力に } </script> </body></html>

led1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <h2>LEDの点灯・消灯</h2> <button onclick=digitalWrite(D9,1)>点灯</button> <button onclick=digitalWrite(D9,0)>消灯</button> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9を出力に } </script> </body></html>

led1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <h2>LEDの点灯・消灯</h2> <button onclick=digitalWrite(PIN_LED,1)>点灯</button> <button onclick=digitalWrite(PIN_LED,0)>消灯</button> <script> function setup(){ // --- はじめに自動実行 --- pinMode(PIN_LED,OUTPUT); // PIN_LEDを出力に } </script> </body></html>

ブラウザの表示は以下のようになります。

 このページが表示され、MIDIデバイス(マイコン)が認識されると、setup関数が呼び出されます。

 setupの関数定義の中の

はLEDが接続されたピンをOUTPUTモード(出力)にする指示です。

 pinMode関数はwebio2.jsの中で定義されています。利用できるピンや入出力モードは使用するマイコンによって異なり、webio2.jsの中で定義されていて、MIDIデバイス(マイコン)が認識された時点で値が決まります。

 pinMode()が呼び出されると、その指示がMIDIデバイス(マイコン)に送信されます。実際にどのようなデータが送られるかは、ブラウザでF12キーを押すと確認することができます(データの詳細はこちら)。

 MIDIデバイス(マイコン)はMIDIデータを受け取ると、内容を解読し、LEDが接続されたピンを出力モードにします。

 ブラウザ画面のボタンが押されると、

が呼び出され、これはLEDに1を出力する指示になります。digitalWrite関数はwebio2.jsの中で定義されていて、呼び出されるとその指示がMIDIデバイス(マイコン)に送信されます。実際にどのようなデータが送られるかは、ブラウザでF12キーを押すと確認することができます(データの詳細はこちら)。

 MIDIデバイス(マイコン)はMIDIデータを受け取ると、内容を解読し、LEDが接続されたピンに1(高い電圧)を出力し、LEDが点灯します。

 同様に、ブラウザ画面のボタンが押されると、

が呼び出され、その指示がMIDIデバイス(マイコン)に送信されます。MIDIデバイス(マイコン)はMIDIデータを受け取ると、LEDが接続されたピンに0(低い電圧)を出力し、LEDが消灯します。


3.3 スイッチの状態をブラウザ画面に表示

 スイッチの状態(オフで1, オンで0)をブラウザ画面に表示します。

button1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2をプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2の値を読み取りvalに代入 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

button1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2をプルアップ入力に pinMode(D9,OUTPUT); // D9を出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2の値を読み取りvalに代入 digitalWrite(D9,val); // D9にvalを出力 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

button1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2をプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2の値を読み取りvalに代入 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

button1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(PIN_BUTTON,INPUT_PULLUP);// PIN_BUTTONをプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(PIN_BUTTON); // PIN_BUTTONの値を読み取りvalに代入 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

ブラウザの表示は以下のようになります。

 このページが表示され、MIDIデバイス(マイコン)が認識されると、setup関数が呼び出されます。

 setupの関数定義の中の

はスイッチが接続されたピンをINPUT_PULLUPモードにする指示です。

 pinMode()が呼び出されると、その指示がMIDIデバイス(マイコン)に送信され、MIDIデバイス(マイコン)はこれを受け取り、内容を解読し、スイッチが接続されたピンをプルアップ入力モードにします。スイッチがオフの時に1(高い電圧)、オンの時に0(低い電圧)になります。マイコンは定期的(20ms毎)にこの値を読み取り、「初回および変化があった時」に、ピンの状態(0か1)を表すMIDIデータをパソコンに送信します。

 ブラウザは、20ms毎に実行されるloop関数の中の

で、スイッチの状態(0または1)がvalに代入されます。

 loop関数の中では引き続き、

で「VAL」の箇所(<span id=VAL ...></span>)にvalの値(0または1)を表示します。


3.4 スイッチの状態をブラウザ画面に表示しLEDを点灯

 スイッチの状態をブラウザ画面に表示するとともに、LEDも連動して点灯・消灯します。ブラウザのプログラムで点灯・消灯するため、若干の遅れが生じ、その遅れを体感できます。

button2.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2をプルアップ入力に pinMode(D9,OUTPUT); // D9を出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2の値を読み取りvalに代入 digitalWrite(D9,val); // D9にvalを出力 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

button2.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2をプルアップ入力に pinMode(D9,OUTPUT); // D9を出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2の値を読み取りvalに代入 digitalWrite(D9,val); // D9にvalを出力 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

button2.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2をプルアップ入力に pinMode(D9,OUTPUT); // D9を出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2の値を読み取りvalに代入 digitalWrite(D9,val); // D9にvalを出力 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

button2.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>スイッチの状態</title> <script src=webio2.js></script> </head><body> <h2>スイッチの状態</h2> <span id=VAL style='font-size:80pt'></span> <script> function setup(){ // --- はじめに自動実行 --- pinMode(PIN_BUTTON,INPUT_PULLUP);// PIN_BUTTONをプルアップ入力に pinMode(PIN_LED,OUTPUT); // PIN_LEDを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(PIN_BUTTON); // PIN_BUTTONの値を読み取りvalに代入 digitalWrite(PIN_LED,val); // PIN_LEDにvalを出力 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

ブラウザの表示は以下のようになります。

 このページが表示され、MIDIデバイス(マイコン)が認識されると、setup関数が呼び出されます。

 setupの関数定義の中の

はボタンスイッチが接続されたピンをINPUT_PULLUPモードにする指示で はLEDが接続されたピンをOUTPUTモードにする指示です。

 D2/PIN_BUTTONはピン番号、INPUT_PULLUPは入出力モードで、XIAO M0の場合、D2の値は2、INPUT_PULLUPの値は2です。

 pinMode(9,1)が呼び出されると、MIDIデータがMIDIデバイス(マイコン)に送信され、MIDIデバイス(マイコン)はこれを受け取り、内容を解読し、9ピンを出力モードにします。

 pinMode(2,2)が呼び出されると、MIDIデータがMIDIデバイス(マイコン)に送信され、MIDIデバイス(マイコン)はこれを受け取り、内容を解読し、2ピンをプルアップ入力モードにします。2ピンには押しボタンスイッチがつながっていて、スイッチがオフの時に1(高い電圧)、オンの時に0(低い電圧)になります。マイコンは定期的(20ms毎)にこの値を読み取り、「初回および変化があった時」に、ピンの状態(0か1)を表すMIDIデータをパソコンに送信します。

 ブラウザは、20ms毎に実行されるloop関数の中の

で、スイッチの状態(0または1)がvalに代入されます。続く で、LEDを点灯させる指示(MIDIデータ)がMIDIデバイス(マイコン)に送信されます。

 MIDIデバイス(マイコン)はMIDIデータを受け取ると、内容を解読し、LEDに0(低い電圧)または1(高い電圧)を出力します。

 loop関数の中では引き続き、

で「VAL」の箇所(<span id=VAL ...></span>)にvalの値(0または1)を表示します。


3.5 アナログ出力

 はじめに、コマンド入力でLEDの明るさを変えてみます。

コマンド:
pinMode(D9,OUTPUT) analogWrite(D9,0) analogWrite(D9,255) analogWrite(D9,100) analogWrite(D9,10)

コマンド:
pinMode(D9,OUTPUT) analogWrite(D9,0) analogWrite(D9,255) analogWrite(D9,100) analogWrite(D9,10)

コマンド:
pinMode(D9,OUTPUT) analogWrite(D9,0) analogWrite(D9,255) analogWrite(D9,100) analogWrite(D9,10)

 ATOM内蔵のLEDを使います。

コマンド:
pinMode(LED,OUTPUT) analogWrite(LED,0) analogWrite(LED,255) analogWrite(LED,100) analogWrite(LED,10)

 analogWrite(ピン,値)は、指定したピンに0~255のアナログ値を出力します。0~255の値に応じてピンの電圧は0~3.3Vに変化します。

 次に、ブラウザ画面のスライダーの操作でLEDの明るさを変化させます。

slider.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>LEDの点灯・消灯</h2> <input type=range style="width:300px" onchange=analogWrite(D9,this.value) value=0 min=0 max=255 step=1> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>

slider.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>LEDの点灯・消灯</h2> <input type=range style="width:300px" onchange=analogWrite(D9,this.value) value=0 min=0 max=255 step=1> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>

slider.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>LEDの点灯・消灯</h2> <input type=range style="width:300px" onchange=analogWrite(D9,this.value) value=0 min=0 max=255 step=1> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>

slider.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>LEDの点灯・消灯</h2> <input type=range style="width:300px" onchange=analogWrite(LED,this.value) value=0 min=0 max=255 step=1> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(LED,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>

「<input type=range ...>」の箇所でスライダーの表示を指示していて、「value=0」は初期値を0、「min=0 max=255 step=1」はスライダーの返す値を0~255で1きざみにする指示です。また、「onchange=...」の箇所にスライダーの値が変化した時に呼び出すプログラムを書いています。

LEDの明るさはブラウザのスライダーの操作により変化します。


3.6 アナログ入力

 A1ピンにつないだボリュームを操作して電圧値を変えると、ブラウザ画面に0~1023の値として表示されます。

analog.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A1); } </script> <!-- ここまで --> </body></html>

analog.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A1); } </script> <!-- ここまで --> </body></html>

analog.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A1); } </script> <!-- ここまで --> </body></html>

analog.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(GROVE1pin,INPUT_ANALOG); // GROVE1pinをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(GROVE1pin); } </script> <!-- ここまで --> </body></html>

ブラウザの表示はボリュームの操作により変化します。


(付録1) ピン接続

LeonardoMicro

I/O 電圧: 5V

I/O 電圧: 5V
D0/TX
D1/RX
D2/SDA
D3#/SCL
D4/A6
D5#
D6#/A7
D7
D8/A8
D9#/A9
D10#/A10
D11#-
D12/A11-
D13#/PIN_LED/LED_BUILTIN-
-D14
-D15
-D16
D18/A0
D19/A1
D20/A2
D21/A3
D22/A4
D23/A5
61/PIN_CO2(仮想ピン)
62/PIN_HUMI(仮想ピン)
63/PIN_TEMP(仮想ピン)
Wio terminal

I/O 電圧: 3.3V
0/D0/A0/GROVE1
1/D1#/A1/GROVE2
2/D2#/A2
3/D3#/A3
4/D4#/A4
5/D5#/A5
6/D6#/A6
7/D7#/A7
8/D8#/A8
12/D12#/WIO_BUZZER
13/D13#/PIN_LED/LED_BUILTIN
14/D14/WIO_IR
27/D27/WIO_LIGHT
28/D28/BUTTON_1/WIO_KEY_A/PIN_BUTTON/BUTTON_BUILTIN
29/D29/BUTTON_2/WIO_KEY_B
30/D30/BUTTON_3/WIO_KEY_C
31/D31/WIO_5S_UP
32/D32/WIO_5S_LEFT
33/D33/WIO_5S_RIGHT
34/D34/WIO_5S_DOWN
35/D35/WIO_5S_PRESS
45/D45#/SCL
46/D46#/SDA
61/PIN_CO2(仮想ピン)
62/PIN_HUMI(仮想ピン)
63/PIN_TEMP(仮想ピン)
XIAO M0(samd21) XIAO ESP32C3 XIAO ESP32S3

I/O 電圧: 3.3V

I/O 電圧: 3.3V

I/O 電圧: 3.3V
0/D0/A0 2/D0/A0 1/D0/A0
1/D1#/A1 3/D1#/A1 2/D1#/A1
2/D2#/A2 4/D2#/A2 3/D2#/A2
3/D3#/A3 5/D3# 4/D3#
4/D4#/A4/SDA6/D4#/SDA5/D4#/SDA
5/D5#/A5/SCL7/D5#/SCL6/D5#/SCL
6/D6#/A6 21/D6# 43/D6#/TX
7/D7#/A7 20/D7# 44/D7#/RX
8/D8#/A8 8/D8# 7/D8#
9/D9#/A9 9/D9# 8/D9#
10/D10#/A1010/D10# 9/D10#
13/D13#/PIN_LED/LED_BUILTIN--
61/PIN_CO2(仮想ピン)
62/PIN_HUMI(仮想ピン)
63/PIN_TEMP(仮想ピン)
ATOM(C3) lite

I/O 電圧: 3.3V
(GROVE端子は5V)
G25
G21
G22
G19
G23
G33
G32 / GROVE1 / SCL
G26 / GROVE2 / SDA
G27 / PIN_RGBLED / RGBLED_BUILTIN
PIN_NEOPIXEL / NEOPIXEL_BUILTIN
PIN_LED / LED_BUILTIN
G12 / PIN_IRLED / IRLED_BUILTIN
G39 / PIN_BUTTON / BUTTON_BUILTIN
G61 / PIN_CO2(仮想ピン)
G62 / PIN_HUMI(仮想ピン)
G63 / PIN_TEMP(仮想ピン)

(付録2) ピンモード

mode Leonardo
Micro
XIAO M0 XIAO ESP32C3
ATOM C3 lite
INPUT 001
OUTPUT 113
INPUT_PULLUP225
INPUT_PULLDOWN-39
INPUT_ANALOG6
OUTPUT_ANALOG 7
OUTPUT_TONE 10
OUTPUT_NEOPIXEL 11
INPUT_IR- 12
OUTPUT_IR- 13

(付録3) Javascriptライブラリ webio2.js

 パソコンやスマホとマイコンの間の情報交換はMIDI通信で、ブラウザの Web MIDI API を介して行われます。Webアプリから利用しやすいように、以下のようにArduino風のJavascriptの関数や定数をJavascriptライブラリ(webio2.js)で定義しています。

(1) 組み込み定数(拡張分)

定数名内容
HIGH, LOW デジタル出力またはデジタル入力されたピンの状態
(HIGHは1、LOWは0)
OUTPUT, INPUT, INPUT_PULLUP
INPUT_ANALOG, OUTPUT_TONE,
OUTPUT_NEOPIXEL, OUTPUT_IR, INPUT_IR
pinMode()で設定する入出力のモード(マイコンにより異なる)
(INPUT, OUTPUT, INPUT_PULLUP以外は独自の名称)
D0~, A0~, G0~ デジタル入出力およびアナログ入力のピン番号
(実際のピン番号はマイコンにより異なる: 付録2参照)
LED / LED_BUILTIN 内蔵LEDのピン番号 (ATOM C3)
IRLED / IRLED_BUILTIN 内蔵赤外線LEDのピン番号 (ATOM C3)
RGBLED / RGBLED_BUILTIN 内蔵RGBLED(NEOPIXEL)のピン番号 (ATOM C3)
NEOPIXEL / NEOPIXEL_BUILTIN
BUTTON / BUTTON_BUILTIN 内蔵押しボタンスイッチのピン番号 (ATOM C3)
GROVE1 / IRIN GROVE1またはGROVEに接続したIRユニット(受信)のピン番号 (ATOM C3)
GROVE2 / IROUT GROVE2またはGROVEに接続したIRユニット(送信)のピン番号 (ATOM C3)
TEMP, HUMI, CO2 I2C接続した温湿度センサSHT30/SHT31または
CO2センサSCD30の仮想ピン番号

(2) 組み込み関数(拡張分)

関数名内容
pinMode(pin, mode) pinをmodeにする(modeは(1)の表参照)
digitalRead(pin) pinの値を読んでHIGH(1)またはLOW(0)の値を返す
digitalWrite(pin, HIGH)
digitalWrite(pin, HIGH, t)
pinにHIGH(1)を出力する...値はHIGH(1)またはLOW(0)
pinをt(ms) HIGH(1)にする
analogRead(a) aはA0~のアナログピンで指定する。ピンaのアナログ値を読み、0~1023の値を返す。
TEMP(63), HUMI(62), CO2(61)は仮想ピンで(値は0~4096)。
analogWrite(pin, value) pinにvalue(0~255)を出力する
sendNote(key, t) ピン6にkeyのブザー音をt[ms]出力する
keyの指定はmidiのノート番号(21~108)または文字列("A0"~"C8")
playNote(key, t) ブラウザからkeyの合成音をt[ms]出力する
keyの指定はmidiのノート番号(21~108)または文字列("A0"~"C8")
ただし 0 または "R" は休符
drumKick(key, t)
drumSnare(key, t)
drumHihat(key, t)
ブラウザからドラムの合成音を出力する
ブラウザからスネアの合成音を出力する
ブラウザからハイハットの合成音を出力する
talk(str)
talk(str,voice)
talk(str,voice,pitch)
talk(str,voice,pitch,rate)
・ブラウザから文字列(str)を合成音声で読み上げる。
・利用できる声(voice)はブラウザによって異なる(こちらを参考に)。
 デフォルトは「日本語で初めに見つかった声」。
 Windows10版Chromeの場合、日本語は
  Ayumi, Haruka, Ichiro, Sayaka, 日本語
 英語は
  US, UK, Female, Male
 などが指定できる(文字列が一致する最初の声になる)。
・音程(pitch)を指定する場合は 0.1~2 (無指定時は1)
・速さ(rate)は 0.1~10 (無指定時は1)
pixel(i, r,g,b)
pixel(i, hue, brightness)
NeoPixelのi番目のLEDをr,g,bにする(それぞれ0~255)。
NeoPixelのi番目のLEDを色相hue(0~255), 明るさbrightness(0~255 省略時255)にする。
NeoPixelはピン4に接続
IRsend(protocol, command, address) IRリモート信号を出力する
$(id) document.getElementById(id)の短縮表現

 上記とは別に、以下の関数をプログラム中に定義すると特別な役割を果たします。

関数名内容
setup() ページが表示され、MIDIデバイスが認識された時にこの関数が呼び出される
loop() 20ms毎にこの関数が呼び出される
onIRreceived(protocol, address, command) IRリモコン信号を受信した時に呼び出される


(付録4) WebIO2のプロトコル(Midiプロトコルを含む)

機能 send(PC → I/O) receive(I/O → PC)JavaScript関数備考
byte1byte2byte3 byte1byte2byte3
8x NoteOff 1000nnnn0kkkkkkk0vvvvvvv 音を停止
9xNoteOn 1001nnnn0kkkkkkk0vvvvvvv sendNote(key, t)
sendNote(key, t, ch)
key0-125のブザー音をt[ms]出力
ch0-15を指定できる
AxPressure 1010nnnn0kkkkkkk0vvvvvvv
BxControl Change 1011nnnn0ccccccc0vvvvvvv
Reset 1011nnnn0111100100000000 Reset All Control
AllNoteOff 1011nnnn0111101100000000 All Note Off
CxProgram Change 1100nnnn0ppppppp setVoice(ch, voice) ch0-15を音源0-127に
DxPressure 1101nnnn0vvvvvvv
ExPitch Bend 1110nnnn0lllllll0mmmmmmm
F0 analogWrite
servo
motor
11110000(F0)
01111111(7D)
01101111(6F)
0ppppppp
0vvvvvvv
0vvvvvvv
11110111(F7) analogWrite(pin, val)
servo(pin, val)
servo(pin, val, t)
motor(lspeed, rspeed)
pin 0~127 を 0-255 に
pin 0~127 のサーボモーターを 0-180 に
tを指定した場合はt[ms]後に停止
L(126) R(127) モーターのスピードを -128~127 に
analogRead 11110000(F0)
01111111(7D)
01101111(6F)
0ppppppp
0vvvvvvv
0vvvvvvv
11110111(F7) analogRead(pin) pin 0~127 の値 0-1023
TEMP(125), HUMI(126), O2(127C) の値 0-4095
(20ms毎に更新)
pinMode 11110000(F0)
01111111(7D)
01110000(70)
0ppppppp
0100mmmm
11110111(F7) pinMode(pin, mode) pin 0-127 のpinModeをmode 0-15 に
digitalWrite 11110000(F0)
01111111(7D)
01110000(70)
0ppppppp
0000000v
11110111(F7) digitalWrite(pin,val)
digitalWrite(pin,1,t)
pin 0-127 を 0/1 に
tを指定した場合は t[ms] 1に
digitalRead 11110000(F0)
01111111(7D)
01110000(70)
0ppppppp
0000000v
11110111(F7) digitalRead(pin) pin 0-127 の値 0/1
(20ms毎に更新)
String 11110000(F0)
01111111(7D)
01110001(71)
... 11110111(F7) 11110000(F0)
01111111(7D)
01110001(71)
... 11110111(F7) string message with 14-bits per char
NeoPixel 11110000(F0)
01111101(7D)
01110010(72)
0LLLLLLL
00000rgb
0rrrrrrr
0ggggggg
0bbbbbbb
11110111(F7) Pixel(LED, R,G,B) LED 0-127 の色を R(0-255) G(0-255) B(0-255) に
IRsend
IRreceive
11110000(F0)
01111101(7D)
01110011(73)
0PPPPPPP
0000aacc
0aaaaaaa
0aaaaaaa
0ccccccc
0ccccccc
11110111(F7) 11110000(F0)
01111101(7D)
01110011(73)
0PPPPPPP
0000aacc
0aaaaaaa
0aaaaaaa
0ccccccc
0ccccccc
11110111(F7) IRsend(&IRDATA)
IRreceive(&IRDATA)
IRリモート信号を送信/受信
IRDATA内に protocol, address, command
SMP display
(DaVinciのみ)
11110000(F0)
01111101(7D)
01110100(74)
00000001 11110111(F7) SMPbegin() SMP displayの利用を開始
00000010
0ttttttt
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
0000dddd(LSB)
0000dddd(MSB)
11110111(F7) SMPdrive([y1,.. y8], t) SMP displayに8×8ドットを表示
y1-y8 は各行の横8ドット(x1-x8)のパターン
tは0-127(0.1秒単位)
SI4732A
(XIAO M0のみ)
11110000(F0)
01111101(7D)
01110101(75)
00000001(01)
00000000(00) 11110111(F7) RXreset() SI4732をリセット
00000001(01) 11110111(F7) RXalive() SI4732動作中
0pppmmm0 11110111(F7) RXsetup(pin, mode) SI4732の利用を開始
11110000(F0)
01111101(7D)
01110101(75)
00000010(01)
0vvvvvvv 11110111(F7) RXgetCurrentRSSI() ... 0-127
11110000(F0)
01111101(7D)
01110101(75)
00000010(02)
00vvvvvv(0-63) 11110111(F7) RXsetVolume(0-63)
01xxxxxx(64-) 11110111(F7) RXvolumeUp(64)
RXvolumeDown(65)
RXsetAudioMute(66(true))
RXsetAudioMute(67(false))
RXfrequencyUp(68)
RXfrequencyDown(69)
RXseekStationUp(70)
RXseekStationDown(71)
RXseekStationProgress(72/73)
11110000(F0)
01111101(7D)
01110101(75)
00000010(02)
00vvvvvv(0-63) 11110111(F7) RXgetVolume() ... 0-63
01xxxxxx(64-) 11110111(F7) RXisCurrentTuneAM() ... 64
RXisCurrentTuneFM() ... 65
RXgetCurrentPilot() ... 66
RXisCurrentTuneSSB() ... 67
11110000(F0)
01111101(7D)
01110101(75)
00000011(03)
0fffffff(LSB)
0fffffff
000000ff(MSB)
または
000001ff(MSB)
11110111(F7) RXsetFrequency(0-65535)
0fffffff(LSB)
0fffffff
000000ff(MSB)
または
000001ff(MSB)
11110111(F7) RXsetSSBBfo(-16383 - 16383)
11110000(F0)
01111101(7D)
01110101(75)
00000011(03)
0fffffff(LSB)
0fffffff
00000cff(MSB)
11110111(F7) RXgetFrequency() ... 0-65535(c=0)
RXgetcurrentFrequency() ... 0-65535(c=1)
11110000(F0)
01111101(7D)
01110101(75)
00000100(04)
00aaaaaa(0-36) 11110111(F7) RXsetAutomaticGainControl(0(enable)/1(disable), 0(minAtt)-36) AGC: 0-36
0100pbbb 11110111(F7) RXsetBandwidth(b(0-6), p(0/1)) 0:6kHz 1:kHz 2:3kHz 3:2kHz(default) 4:1kHz 5:1.8kHz 6:2.5kHz
01010sss 11110111(F7) RXsetSSBAudioBandwidth(s(0-5)) 0:1.2kHzLPF(default) 1:2.2kHzLPF 2:3kHzLPF 3:4kHzLPF 4:500HzBPF 5:1kHzBPF
11110000(F0)
01111101(7D)
01110101(75)
00000100(04)
00aaaaaa 11110111(F7) RXgetAutomaticGainControl() ... 0-36
11110000(F0)
01111101(7D)
01110101(75)
00000101(05)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
11110111(F7) RXsetAM(minFreq, maxFreq, Freq, Step)
11110000(F0)
01111101(7D)
01110101(75)
00000110(06)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(0-127)
11110111(F7) RXsetFM(minFreq, maxFreq, Freq, Step)
11110000(F0)
01111101(7D)
01110101(75)
00000111(07)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
0000ULff(MSB)
0fffffff(0-127)
11110111(F7) RXsetSSB(minFreq, maxFreq, Freq, Step, 1(LSB)/2(USB))
11110000(F0)
01111101(7D)
01110101(75)
00001000(08)
0fffffff(LSB)
0fffffff
000000ff(MSB)
0fffffff(LSB)
0fffffff
000000ff(MSB)
11110111(F7) RXsetSeekAmLimits(minfreq, maxfreq)
0fffffff(LSB)
0fffffff
000001ff(MSB)
0fffffff(LSB)
0fffffff
000001ff(MSB)
11110111(F7) RXsetSeekFmLimits(minfreq, maxfreq)
11110000(F0)
01111101(7D)
01110101(75)
00001001(09)
00vvvvvv(0-63) 11110111(F7) RXsetAmSpacing(0-63) 0-63kHz
01vvvvvv(0-63) 11110111(F7) RXsetFmSpacing(0-63) 0-630kHz
11110000(F0)
01111101(7D)
01110101(75)
00001010(0A)
00vvvvvv(0-63) 11110111(F7) RXsetSeekAmRssiThreshold(0-63) 0-63(default 25dBuV)
01vvvvvv(0-63) 11110111(F7) RXsetSeekFmRssiThreshold(0-63) 0-63(default 20dBuV)
11110000(F0)
01111101(7D)
01110101(75)
00001011(0B)
00vvvvvv(0-63) 11110111(F7) RXsetSeekAmSNRThreshold(0-63) 0-63(default 5dB)
01vvvvvv(0-63) 11110111(F7) RXsetSeekFmSNRThreshold(0-63) 0-63(default 3dB)
I2C Request 11110000(F0)
01111111(7D)
01110110(76)
0aaaaaaa(LSB)
0aaaaaaa(MSB)
0ddddddd(LSB)
0ddddddd(MSB)
0ddddddd(LSB)
0ddddddd(MSB)
...
11110111(F7) I2C request messages
0aaaaaaa(MSB):
b7:0
b6:autorestart 0(stop) 1(restart)
b5: 1(address 10bit mode)
b4-3: 00(write)
01(read once)
10(read continuously)
11(stop reading)
b2-0: address mode
I2C Reply 11110000(F0)
01111111(7D)
01110111(77)
0aaaaaaa(LSB)
0aaaaaaa(MSB)
0rrrrrrr(LSB)
0rrrrrrr(MSB)
0ddddddd(LSB)
0ddddddd(MSB)
...
11110111(F7) I2C reply messages
0aaaaaaa(MSB):
b0-2: transaction sequence from the request in 7 bit mode
I2C Config 11110000(F0)
01111111(7D)
01111000(78)
delay(LSB)
delay(MSB)
...
11110111(F7) Configure special I2C settings
such as power pins and delay times
(optional)
FFSystemReset 11111111(FF) ioreset() SystemReset