2017.8.12 -

WebIO: Arduino流IO制御(Arduino ProMicro版)[WebIOtest]
コンピュータの仕組み: ATtiny2313版
Arduino流: ATtiny4313版ATmega328P版NANO版ESP8266版
tinyBasic流: NANO版ProMicro版(web)・ ESP8266版
WebIO: Arduino流IO制御(ProMicro版)

小山智史(弘前大学教育学部)


0. 準備
1. JavaScript命令の実行
2. デジタル出力(1): LEDの点滅
3. デジタル入力: スイッチ操作でLEDのオンオフ
4. アナログ出力: LEDの明るさを変える
5. アナログ入力
6. センサーの利用
7. 音の出るものを作る
8. イルミネーション
9. 動くものを作る
10. さまざまな例
(付録1) WebIOの主な仕様
(付録2) Midiコマンドとの対応
(付録3) 入出力モジュールの例
(付録4) 使用する主な部品


 WebIOは、PCに接続したMidiデバイスをブラウザから制御するWeb Midi APIという機能を使って、IO制御を試みたものです。FirmataのWeb版のような感じですが、Web Midi APIではSysEXコマンドがhttpsに制限されているため、Midiコマンドと入出力の対応はFirmataとは異なっています。

 システムの概要は下図のようになっています。Arduinoにはあらかじめプログラム(webio.ino)を書き込んでおきます。

 プログラムはWebコンテンツ(HTML+JavaScript)としてサーバに置き、パソコンのブラウザで表示し、ブラウザ画面で操作します。ブラウザから制御できるのは自身のパソコンに接続されているデバイスであり、遠隔操作できるというわけではありません。動作の確認はWeb Midi API に対応しているChromeを使い、Windows10で行っています。

 後ほど紹介するように、ブラウザ画面で操作するさまざまなWebコンテンツを作ることができます。今話題のIoTを小中学校で扱う場合も、適当なWebコンテンツをサーバに置いておけば、児童生徒一人一人がさまざまな学習が可能になるのではないかと思います。また、10章で紹介するように、パソコンに接続した温湿度センサのデータをブラウザから遠方のサーバに送ることもできるので、さまざまな応用が考えられると思っています。

0. 準備

0.1 ソフトウェアの準備[webio20171228.zip]

 上のzipファイルをダウンロードして解凍してください。

(1) Arduino用プログラム: webio.ino
Arduino Pro Micro(またはLeonardo, Davinciなど)にwebio.ino(スケッチ)を書き込んでおきます。2章以降で、LEDを接続して実際にIO制御を行う時に必要になります。Arduino UNOやnanoはMidiデバイスにすることができないので注意してください。Arduinoの準備ができれば、このページを使ってすぐに動作を確かめることができます。また、10.3の動作テスト用のページでさまざまな動作を確かめることができます。
(2) JavaScriptライブラリ: webio.js
2章以降で、LEDの制御など実際にIO制御を行うWebページの中で「<script src=webio.js></script>」のように使います。このページもそのようになっているので、フォーム入力で実際に試すことができます。

0.2 ブレッドボードの使い方

 ここでは下図(a)のブレッドボード(EIC-301)を使います。ボードの内部は下図(b)のように接続されています。


(a) ブレッドボード(EIC-301)の外観

(b) ブレッドボードの内部の接続

 Arduino Pro Microをブレッドボードに下図(b)のように装着します。USBケーブルをパソコンに接続すると、電源(5V)がパソコンから供給されます。(a)が回路図、(b)が実体配線図です。


(a) 回路図(電源はUSBから供給される)

(b) 実体配線図

 ここで、初めてブレッドボードを使う場合は、練習としてLEDと抵抗を下図(a)のように接続してみます。電流の流れは(c)のようになります。ブレッドボードの内部の結線も含めて「電流が流れる経路」を意識することが重要です。


(a) 回路図

(b) 実体配線図

(c) 電流の流れ

1. JavaScript命令の実行

コマンド:

 上のコマンド入力欄にJavaScriptの命令文を入力し、実行ボタンを押すかEnterキーを押すと、その命令が実行されます。次のように入力してみてください。

alert(100)
これは、「100をアラート表示しなさい」というJavaScriptの「命令」を表しています。

 以下のふたつめの例では文字列と数値((100+200)の演算結果)の連接演算(+)になっていて、数値(演算結果)が文字列に変換されて文字列の連接演算が行われます。

alert(100+200) alert("答えは"+(100+200))

2. デジタル出力(1): LEDの点滅

 ここから以降は、WebIOのプログラムを書き込んだArduino Pro Micro(LeonardoやDavinciでもよい)を接続し、ブラウザはChromeを使って行ってください。

2.1 LEDを点灯・消灯する

 以下の回路を組み立ててください。


(a) 回路図

(b) 実体配線図
コマンド:

 LEDは9ピンに接続します。「digitalWrite」というコマンドで9ピンに高い電圧を出力したり低い電圧を出力したりすることができます。上のコマンド入力欄に

digitalWrite(9,1) または digitalWrite(9,HIGH)

のように入力し、実行ボタンを押すかEnterキーを押すと、9ピンに高い電圧(5V)が出力され、接続したLEDが点灯します。
digitalWrite(9,0) または digitalWrite(9,LOW)

と操作すると、9ピンに低い電圧(0V)が出力され、LEDは消灯します。「digitalWrite(9,1)」または「digitalWrite(9,HIGH)」は「9ピンに1(高い電圧)を出力しなさい」という意味です。

 LEDが点灯する時の電流の流れは下図のようになります。下図中のスイッチをJavaScriptの命令で切り替えていると考えるといいでしょう。

(練習)「digitalWrite(9,1)」および「digitalWrite(9,0)」を実行した時の9ピンの電圧を、テスターで測りなさい。

(練習)LEDを他のピンにつなぎ替えて、点灯・消灯してみなさい。

2.2 プログラムによるLEDの点滅

 プログラムのはじめの一歩は「Lチカ」です。以下のWebページを作成し、ブラウザ(Chrome)で表示してください。冒頭の5行はWebページの常套句で、その先がWebページの本体とプログラムになります。

 Webページは単に「LEDの点滅」と表示するだけです。「<script>」と「</script>」の間がJavaScriptプログラムになります。

 プログラムは、はじめに広域変数としてledの値を0にしています。ledはLEDの点灯状態(0で消灯状態、1で点灯状態)を表しています。次にsetup()とtoggle()の2つの関数を定義しています。

 ここで、「setup()」は特別な関数の名前になっていて、ページが表示された時にこの関数が実行されます。そこでは、まずpinModeでLEDが接続されているpin9を出力(OUTPUT)にしています。OUTPUTは予め定義された組み込み変数です。次の「setInterval("toggle()",1000)」で、1000ms(1秒)毎に「toggle()」が呼び出されるよう指示しています。toggle()が呼び出されると、LEDの点灯状態ledを0なら1に、1なら0にし、その値をそのままdigitalWrite()で出力します。

 JavaScriptプログラムでは「delay」や「wait」などの関数は用意されておらず、setInterval()やsetTimeout()を使ってプログラムを作ります。

blink.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(9,OUTPUT); // ledを出力に setInterval("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に digitalWrite(9,led);// 9ピンにledを出力 } </script> <!-- ここまで --> </body></html>

2.3 LEDの点灯・消灯

 画面上のボタンが押されるとプログラムが実行される例です。「<button>点灯</button>」でのようにボタンが表示されます。このボタンを押した時にプログラムが実行されるようにするには「<button onclick=プログラム>点灯</button>」のように書きます。

 以下の例では「点灯」ボタンが押されると「digitalWrite(9,1)」が呼び出されます。

button0.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <button onclick=digitalWrite(9,1)>点灯</button> <button onclick=digitalWrite(9,0)>消灯</button> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(9,OUTPUT); // 9ピンを出力に } </script> <!-- ここまで --> </body></html>


3. デジタル入力: スイッチ操作でLEDのオンオフ

3.1 スイッチが押されているかどうか調べる

 下図左のように1ピンにスイッチを接続し、「pinMode(1, INPUT_PULLUP)」とすると、下図右のようにマイコンに内蔵された抵抗が有効になります。すると、1ピンはスイッチをオンにすると低い電圧(0V)になり、スイッチをオフにすると高い電圧(5V)になります。この抵抗を「プルアップ抵抗」といいます。「高い電圧に引っ張り上げる抵抗」というような意味です。

回路図
スイッチを接続
回路図
プルアップ抵抗

 コマンド入力欄を使い、1ピンをプルアップ入力に設定した後、1ピンが高い電圧(1)か低い電圧(0)かをアラート表示してみましょう。

コマンド:
pinMode(1,INPUT_PULLUP) alert(digitalRead(1))
回路図

(練習) 1ピンに接続したスイッチを押した時と放した時のスイッチ両端の電圧を、テスターで測りなさい。

(練習) スイッチを押した時と放した時の「alert(digitalRead(1))」の結果を確かめなさい。

3.2 スイッチの状態をデジタル値としてブラウザ画面に表示する

 以下のプログラムはスイッチの状態をデジタル値としてブラウザ画面に数字で表示します。

button1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>デジタル値の表示</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <center><span id=VAL style='font-size:80pt'></span></center> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(1,INPUT_PULLUP);// 1ピンをプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(1); // 1ピンの値を読み取りvalに代入 $("VAL").innerHTML=val; // valをブラウザ画面に表示 } </script> <!-- ここまで --> </body></html>

3.3 スイッチ操作でLEDを点灯・消灯する

 以下は、ブラウザ画面への表示に加え、LEDの点灯・消灯も行うようにしたプログラムです。

button2.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>デジタル値の表示</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(1,INPUT_PULLUP);// 1ピンをプルアップ入力に pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(1); // 1ピンの値を読み取りvalに代入 digitalWrite(9,val); // valの値を9ピンに出力 $("VAL").innerHTML=val; // valをブラウザ画面に表示 } </script> <!-- ここまで --> </body></html>

(練習) スイッチを押した時にLEDが点灯しブラウザ画面に「ON」が表示され、スイッチを放した時にLEDが消灯しブラウザ画面に「OFF」が表示されるようにしなさい。

3.4 スイッチ操作で交互に点灯・消灯する

 以下のプログラムは、スイッチを押すと交互にLEDが点灯・消灯します。考え方は、「スイッチが押された瞬間に(つまりさっき押されていなくて今押されたら)LED表示を反転する」というものです。buttonSには「今のスイッチの状態(0または1)」、lastSには「さっきのスイッチの状態(0または1)」、変数ledSには「今のLEDの点灯状態(1が点灯、0が消灯)」を保存します。

 まず現在の4ピンの状態(1または0)を読み取り、buttonSに入れます。そして、スイッチがさっきまで押されていなくて今押されているならledSの値を0なら1、1なら0にします。その後、9ピン(LED)にledSの値を出力し、今のスイッチの状態を記憶します。

button3.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) var button; // 現在のbuttonの状態 var lastbutton; // 直前のbuttonの状態 function setup(){ // --- はじめに自動実行 --- pinMode(1,INPUT_PULLUP);// 1ピンをプルアップ入力に pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- button=digitalRead(1); // 1ピンを読みbuttonに代入 if(button!=lastbutton && button==0)// buttonが前と違いかつ0なら led=(led==0?1:0); // ledが0なら1に、1なら0に digitalWrite(9,led); // 9ピンにledを出力 lastbutton=button; // lastbuttonを更新 } </script> <!-- ここまで --> </body></html>

(練習) 緑色LEDを増設し、スイッチを押すと赤色LEDと緑色LEDが交互に点灯するようにしなさい。

3.5 スイッチを4回押すと点灯する

 以下のプログラムは、スイッチ操作4回に一度LEDが点灯します。

 スイッチが押されると、Cにスイッチが押された回数を記憶します。つまり、スイッチがさっきまで押されていなくて今押されたならCの値に1を加えます。その後、「C%4==0」つまりCの値を4で割った余りが0であればLEDを点灯し、そうでなければLEDを消灯します。最後に、今のスイッチの状態を記憶します。

button4.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var C=0; // カウントCを0にする var button; // 現在のbuttonの状態 var lastbutton; // 直前のbuttonの状態 function setup(){ // --- はじめに自動実行 --- pinMode(1,INPUT_PULLUP);// 1ピンをプルアップ入力に pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- button=digitalRead(1); // 1ピンを読みbuttonSに代入 // buttonが直前が1で現在が0ならCをカウントアップ if(lastbutton==1 && button==0) C++; if(C%4==0) digitalWrite(9,1); // Cが4の倍数なら点灯 else digitalWrite(9,0); // そうでなければ消灯 lastbutton=button; // lastbuttonを更新 } </script> <!-- ここまで --> </body></html>

(練習) 「C%4==0」の箇所を「C%7==0」や「C%4!=0」などに変えて、どのような動作になるか調べなさい。

(練習) 2個の押しボタンスイッチを使い、一方のスイッチを押すとLEDが点灯し、もう一方のスイッチを押すと消灯するようにしなさい。


4. アナログ出力: LEDの明るさを変える

4.1 アナログ出力する

 はじめに、コマンド入力でLEDの明るさを変えてみます。analogWrite(ピン,値)は、指定したピンに0~255のアナログ値を出力します。0~255の値に応じて電圧(0~5V)ピンの電圧は0~5Vになります。ただし、アナログ出力に利用できるピンは3, 5, 6, 9, 10に限られているので注意が必要です。

コマンド:
pinMode(9,OUTPUT) analogWrite(9,0) analogWrite(9,255) analogWrite(9,100) analogWrite(9,10)
回路図

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

slider.html:

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


5. アナログ入力

5.1 アナログ入力値を調べる

 下図左のようにA0ピンにボリュームを接続すると、ボリュームの操作に応じてA0ピンの電圧は0~5Vに変化します。analogRead(A0)は、A0ピンの電圧(0~5V)に応じて0~1023の値を返します。

 コマンド入力欄を使い、をanalogRead(A0)でA0ピンの値を読み取り、アラート表示してみましょう。

コマンド:
pinMode(A0,ANALOG_INPUT) alert(analogRead(A0))
回路図

(練習) ボリュームを操作し、A0の電圧がどの範囲で変化するか、テスターで測りなさい。

(練習) ボリュームを操作し、「alert(analogRead(A0))」の結果を確かめなさい。

5.2 アナログ値をブラウザ画面に表示する

 以下のプログラムはA0ピンの電圧値を0~1023の値としてブラウザ画面に表示します。

 以下のプログラムはこの値をブラウザに数字で表示します。

analog.html:

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

 以下のプログラムは読み取ったアナログ値をブラウザにバーグラフで表示します。

bargraph.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> A0: <meter id=A0 style="width:260px;height:60px" max=1023></meter> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("A0").value=analogRead(A0); } </script> <!-- ここまで --> </body></html>

5.3 アナログ値に応じてLEDの点滅時間を変える

 analogRead(A0)は、A0ピンの電圧(0~5V)に応じて0~1023の値をとります。以下のプログラムはこれを利用し、ボリュームの値に応じてLEDの点滅時間が変化します。

analogblink.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT);// A0をアナログ入力に pinMode(9,OUTPUT); // 9ピンを出力に toggle(); } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に digitalWrite(9,led); // 9ピンにledを出力 setTimeout("toggle()",analogRead(A0)); // A0後にtoggle() } </script> <!-- ここまで --> </body></html>

5.4 アナログ値に応じてLEDを点灯・消灯する

 以下のプログラムは、ボリュームのアナログ値(0~1023)が400未満の時にLEDを点灯します。

autolight.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に pinMode(9,OUTPUT); // 9ピンを出力にする } function loop(){ // --- 20ms毎に自動実行 --- var val=analogRead(A0); // A0の値を読取りvalに代入 if(val<400) digitalWrite(9,1);// ledを点灯 else digitalWrite(9,0);// ledを消灯 } </script> <!-- ここまで --> </body></html>


6. センサーの利用

6.1 スイッチをセンサーとして使う

 押しボタンスイッチやスライドスイッチは、操作用のスイッチですが、センサーとしても活躍しています。例えば、CD/DVDデッキやコピー機やプリンタなど動きを伴う機器には、所定の位置に来たがどうかを検知するために、マイクロスイッチが必ずといっていいほど使われています。このような使われ方をするスイッチを「リミットスイッチ」と呼ぶこともあります。

 9.7のモーターカーでは車の先端にマイクロスイッチを使いました。ふたつの金属片を接触させるだけでスイッチ(センサー)となるので、オリジナルのスイッチを作ることも難しくはありません。所定の水位になったかどうかを検知するピンポン球を使った浮力スイッチ、傾けると金属ボールが移動する傾斜スイッチなど、用途に応じて工夫するのも楽しいでしょう。

6.2 明るさをブラウザ画面に表示する(明るさの計測)

 5.2のボリュームの代わりに明るさセンサー(CDS)をつないでみましょう。明るくなるほどCDSの抵抗値が低くなり、A0ピンの電圧は高くなります。一定以下に暗くなるとLEDが点灯します。プログラムは5.2と同様です。ただし、明るさの閾値「400」の値は適切な値に変更する必要があります。

analog.html:

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

 以下のプログラムは読み取ったアナログ値をブラウザにバーグラフで表示します。

bargraph.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> A0: <meter id=A0 style="width:260px;height:60px" max=1023></meter> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("A0").value=analogRead(A0); } </script> <!-- ここまで --> </body></html>

6.3 暗くなるとLEDを点灯する

 街路灯は、暗くなると点灯します。以下のプログラムは、明るさの値が400未満の時にLEDを点灯します。プログラムは5.4と同じです。

autolight.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=analogRead(A0); // A0の値を読取りvalに代入 if(val<400) digitalWrite(9,1);// ledを点灯 else digitalWrite(9,0);// ledを消灯 } </script> <!-- ここまで --> </body></html>

 街路灯では、境界値付近でledが点灯したり消灯したり不安定になるのを避けるために、下図のような「ヒステリシス特性」を持たせます。

ledが消灯している時(ledSが0)に400以下の明るさになったらledを点灯状態にし(ledSを1)、ledが点灯している時(ledSが1)に500以上の明るさになったらledを消灯状態にします(ledSを0)。

hysteresis.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=analogRead(A0); // 明るさを読み取りvalに代入 if(led==0 && val<400) led=1; else if(led==1 && val>=500) led=0; digitalWrite(9,led); // 9ピンにledを出力 } </script> <!-- ここまで --> </body></html>

(練習) ヒステリシス特性の効果を確かめなさい。また、400と500の値を変えて、適切な値をみつけなさい。

6.6 音を検知する: 音量センサー

 以下のプログラムは音量をバーグラフで表示します。5.3と同じプログラムです。

bargraph.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> A0: <meter id=A0 style="width:260px;height:60px" max=1023></meter> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("A0").value=analogRead(A0); } </script> <!-- ここまで --> </body></html>

 以下のプログラムは、音を検知したらLEDを3秒点灯するものです。

sound3.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) var val; // 現在の音量 var lastval=0; // 直前の音量 function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- val=analogRead(A0); // 音量を読み取りvalに代入 if(led==0 && val>=400){// 消灯状態で音量が400を超えたら led=1; // 点灯状態にし setTimeout("led=0",3000);// 3秒後に消灯 } digitalWrite(9,led); // 9ピンにledを出力 lastval=val; // lastvalを更新 } </script> <!-- ここまで --> </body></html>

<

(練習) 手をたたくとカウントアップしブラウザに回数を表示するプログラムを作りなさい。

6.7 赤外線反射センサーを使う

 赤外線の反射光で数mm程度の距離に反射物を検知するセンサーです。モーターカーと組み合わせると、ライントレースや衝突回避などが可能になります。以下のプログラムは5.2と同じものです。センサを接続して、analogRead(A0)でどの程度の値が返されるかがわかります。

analog.html:

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


7. 音の出るものを作る

7.1 電子オルゴール

 以下のプログラムは、電子オルゴールです。midi音源を接続しても動作します。

midimelody.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>電子オルゴール</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>電子オルゴール</h2> <!-- ここからプログラム --> <script> // ----------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, Note] [4,"C5"], [8,"G4"],[8,"G4"],[4,"A4"],[4,"G4"], [4,""], [4,"B4"], [4,"C5"] ]; // ----------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var p=0; function setup(){ // --- はじめに自動実行 --- playNotes(); } function playNotes(){ var T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 var u=notes[p][1]; sendNote(midiPitch[u], T*.9); if(++p<notes.length) setTimeout("playNotes()", T); } </script> <!-- ここまで --> </body></html>

<

 楽譜はさまざまな方法で表現することができます。以下は、少し長い曲を演奏するプログラムです。

playmidi.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>電子オルゴール</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>電子オルゴール</h2> <!-- ここからプログラム --> <script> // ----------------------------------------------------------------------------- var notes="RDDBAGDR RDDBAGER REEcBAFR RdddcABR RDDBAGDR RDDBAGER REEcBAdd ddedcAGR dR BBBR BBBR BdGABRRR cccccBBB BAABAR dR BBBR BBBR BdGABRRR cccccBBB ddcAGR gR"; // ----------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var p=0; function setup(){ // --- はじめに自動実行 --- playNotes(); } function playNotes(){ for(;p<notes.length&&notes.charAt(p)==" ";p++); // スペースは無視 var T=60000/TEMPO*4/8; // 8分音符 0.25秒 固定 var c=notes.charAt(p); if(c.toUpperCase()!="R"){ // 休符でなければ if(c==c.toLowerCase()) c=c.toUpperCase()+"5"; // 小文字ならC5-B5 else c=c+"4"; // 大文字ならC4-B4 sendNote(midiPitch[c], T*.9); } if(++p<notes.length) setTimeout("playNotes()", T); } </script> <!-- ここまで --> </body></html>

 以下は、「私だけの電子オルゴール」のように「ドドソソララソー」のように楽譜を入力できるようにした例です。


7.2 オモチャのドラムの自動演奏(詳しくはこちら)

 オモチャのドラムを左右2つのスティックで叩きます。左のスティックはセンタードラム(L)とサイドドラム(S)、右のスティックはセンタードラム(R)とハイハット(H)を担当し、サーボモータでそれぞれのドラム位置にスティックを移動します。

drum1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>ドラムの自動演奏</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>ドラムの自動演奏</h2> <button onclick=playNotes()>演奏開始</button> <!-- ここからプログラム --> <script> // ----------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, ドラム] [4,"L"],[8,"L"],[8,"R"],[4,"L"],[4,"R"], [4,""], [4,"S"], [4,"H"] ]; // ----------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var Td=100; // ドラムを打つ時間(100ms)...バチによって調整 var Ts=500; // サーボモーターの移動時間 var Lmotor=8, Rmotor=7, Lservo=10, Rservo=9; // モーターとサーボモーターのpin var Lstick={L:150, S:80}; // ドラムの左サーボの角度(個別に調整) var Rstick={R:0, H:60}; // ドラムの右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- } function playNotes(){ var T, u; if(p<0) T=Ts; // 初回は準備 else{ // 1音目からは T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 u=notes[p][1]; // L R S H if(u.match(/L/) || u.match(/S/)) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u.match(/R/) || u.match(/H/)) digitalWrite(Rmotor, 1, Td); // 右を叩く } if(++p<notes.length){ // 次音の準備 u=notes[p][1]; if(u.match(/L/)) setTimeout("servo(Lservo,"+Lstick["L"]+",Ts)", T/2); else if(u.match(/S/)) setTimeout("servo(Lservo,"+Lstick["S"]+",Ts)", T/2); if(u.match(/R/)) setTimeout("servo(Rservo,"+Rstick["R"]+",Ts)", T/2); else if(u.match(/H/)) setTimeout("servo(Rservo,"+Rstick["H"]+",Ts)", T/2); setTimeout("playNotes()", T); }else p=-1; // 演奏終了 } </script> <!-- ここまで --> </body></html>



7.3 オモチャの鉄琴の自動演奏(詳しくはこちら)

 オモチャの鉄琴を左右2つのスティックで叩きます。左のスティックはドレミファ(C4 D4 E4 F4)、右のスティックはソラシド(G4 A4 B4 C5)を担当し、サーボモータでそれぞれの位置にスティックを移動します。

tekkin1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>鉄琴の自動演奏</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>鉄琴の自動演奏</h2> <button onclick=playNotes()>演奏開始</button> <!-- ここからプログラム --> <script> // ----------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, Note] [4,"C5"], [8,"G4"],[8,"G4"],[4,"A4"],[4,"G4"], [4,""], [4,"B4"], [4,"C5"] ]; // ----------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var Td=80; // 鉄琴を打つ時間(80ms)...バチによって調整 var Ts=500; // サーボモーターの移動時間 var Lmotor=8, Rmotor=7, Lservo=10, Rservo=9; // モーターとサーボモーターのpin var Langle={C4:10, D4:35, E4:60, F4:80}; // 鉄琴の左サーボの角度(個別に調整) var Rangle={G4:75, A4:95, B4:120,C5:155} // 鉄琴の右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- } function playNotes(){ var T, u; if(p<0) T=Ts; // 初回は準備 else{ // 1音目からは T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 u=notes[p][1]; // C4 D4 ... A4 B4 C5 if(u in Langle) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u in Rangle) digitalWrite(Rmotor, 1, Td); // 右を叩く } if(++p<notes.length){ // 次音の準備 u=notes[p][1]; if(u in Langle) setTimeout("servo(Lservo,"+Langle[u]+",Ts)", T/2); if(u in Rangle) setTimeout("servo(Rservo,"+Rangle[u]+",Ts)", T/2); setTimeout("playNotes()", T); }else p=-1; // 演奏終了 } </script> <!-- ここまで --> </body></html>


7.4 みんなでセッション(詳しくはこちら)

 複数の楽器で「セッション」も楽しめます。グループ学習でやってみると面白いと思います。ブラウザ画面から音が出ますので、楽器が1台でも十分楽しめます。

 それぞれのパソコンのブラウザ画面でを押すと、「正10秒」まで待って演奏を開始します。ボタンを押すタイミングが少しずれても大丈夫です。パソコンの時刻同期の設定をきちんとしておくと時刻のズレを少なくできます(NICTのページで確認できます)。ここではパソコン毎に多少時刻がずれていてもいいように、±1秒の範囲で調整できるようにしてあります。

session1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>みんなでセッション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>みんなでセッション</h2> <button onclick=playNotes()>演奏開始</button> <!-- ここからプログラム --> <script> // ----------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, Note, ドラム] [4,"C5","LH"], [8,"G4","SH"],[8,"G4","SH"], [4,"A4","LH"], [4,"G4","SH"], [4,"",""], [4,"B4","LR"], [4,"C5","SH"] ]; // ----------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var Td=80; // ドラムを打つ時間(100ms)...バチによって調整 var Ts=500; // サーボモーターの移動時間 var Lmotor=8, Rmotor=7, Lservo=10, Rservo=9; // モーターとサーボモーターのpin var Lstick={L:150, S:80}; // ドラムの左サーボの角度(個別に調整) var Rstick={R:0, H:60}; // ドラムの右サーボの角度(個別に調整) var Langle={C4:10, D4:35, E4:60, F4:80}; // 鉄琴の左サーボの角度(個別に調整) var Rangle={G4:75, A4:95, B4:120, C5:150} // 鉄琴の右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- pinMode(5, INPUT_PULLUP); // 鉄琴はpin5をGNDに接続する } function playNotes(){ var T, u; if(p<0) T=Ts; // 初回は準備 else{ // 1音目からは u=notes[p][1]; // C3 D3 ... C4 T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 if(u){ sendNote(midiPitch[u], T*.9); // スピーカから電子音 playNote(midiPitch[u], T*.9); // ブラウザから合成音 if(digitalRead(5)==0){ // 鉄琴(pin5をGNDに接続)ならば if(u in Langle) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u in Rangle) digitalWrite(Rmotor, 1, Td); // 右を叩く } } u=notes[p][2]; // S(sidedrum) L R(centerdrum) H(hihat) if(u.match(/L/) || u.match(/R/)) drumKick(); // ブラウザからcenterdrum音 if(u.match(/S/)) drumSnare(); // ブラウザからsidedrum音 if(u.match(/H/)) drumHihat(); // ブラウザからhihat音 if(digitalRead(5)==1){ // ドラム(pin5を解放)ならば if(u.match(/L/) || u.match(/S/)) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u.match(/R/) || u.match(/H/)) digitalWrite(Rmotor, 1, Td); // 右を叩く } } if(++p<notes.length){ // 次音の準備 if(digitalRead(5)==0){ // 鉄琴(pin5をGNDに接続)ならば u=notes[p][1]; if(u in Langle) setTimeout("servo(Lservo,"+Langle[u]+",Ts)",T/2); if(u in Rangle) setTimeout("servo(Rservo,"+Rangle[u]+",Ts)",T/2); }else{ // ドラム(pin5を解放)ならば u=notes[p][2]; if(u.match(/L/)) setTimeout("servo(Lservo,"+Lstick["L"]+",Ts)", T/2); else if(u.match(/S/)) setTimeout("servo(Lservo,"+Lstick["S"]+",Ts)", T/2); if(u.match(/R/)) setTimeout("servo(Rservo,"+Rstick["R"]+",Ts)", T/2); else if(u.match(/H/)) setTimeout("servo(Rservo,"+Rstick["H"]+",Ts)", T/2); } setTimeout("playNotes()", T); }else p=-1; // 演奏終了 } </script> <!-- ここまで --> </body></html>


 以下は楽譜データを分けて(sample.js, akahana.js, ...)、曲を選択できるようにした例です。NeoPixelをつなぐと演奏に連動してカラフルに光ります。イルミネーションのオブジェはngo-tecさんのページを見て作りました。「正10秒」で同期演奏できますし、「正時」に演奏させれば「からくり時計」となります。ブラウザ画面上で楽譜を入力して演奏させることもできます。詳しくは「ミニドラム・ミニ鉄琴」のページをご覧ください。




8. イルミネーション

8.1 NeoPixelの利用

 NeoPixelはフルカラーLEDがシリアルに連結されていて(ここでは10連LEDを使用)、1本の信号線で任意のLEDの発光をコントロールできるのが特徴です。WebIOでは、4ピンに接続した10連NeoPixelをpixelコマンドで制御することができます。パラメータで、順にLEDの番号(0~9)、Redの明るさ(0~255)、Greenの明るさ(0~255)、Blueの明るさ(0~255)を指定します。

 まず、コマンド操作で試してみてください。

コマンド:
pixel(0,50,0,0) pixel(0,0,0,0) pixel(0,50,0,0) pixel(1,0,50,0) pixel(2,0,0,50) pixel(3,50,50,0) pixel(4,0,50,50) pixel(5,50,50,50)

8.2 プログラムによる点滅とフラッシュ

 以下のプログラムは、ひとつ目のLEDを赤で点滅させます。1秒点灯・1秒消灯をくりかえします。下図右は点滅の時間的な変化をタイムチャートで示したものです。

pixelblink1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- setInterval("toggle()",1000);// 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に if(led==1) pixel(0,50,0,0); // ledが1なら点灯 else pixel(0, 0,0,0); // 0なら消灯 } </script> <!-- ここまで --> </body></html>

 次のようにすると10個のLEDが緑で点滅します。

pixelblink10.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- setInterval("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に for(var i=0;i<10;i++){ // iを0から9まで if(led==1) pixel(i, 0,50,0);// ledが1なら点灯 else pixel(i, 0,0,0); // 0なら消灯 } } </script> <!-- ここまで --> </body></html>

 次のようにすると明るく短時間点灯する「フラッシュ」になります。

pixelflash10.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- setTimeout("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に for(var i=0;i<10;i++){ // iを0から9まで if(led==1) pixel(i, 0,50,0);// ledが1なら点灯 else pixel(i, 0,0,0); // 0なら消灯 } if(led==1) setTimeout("toggle()",100); else setTimeout("toggle()",900); } </script> <!-- ここまで --> </body></html>

(練習) 10個のLEDが1秒毎に「青→黄→赤」を繰り返すプログラムを作りなさい。

8.3 ワイプ

 以下のプログラムは、10個のLEDを順に点灯させます。このようなイルミネーション効果は「ワイプ」と呼ばれます。

pixelwipe.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) function setup(){ // --- はじめに自動実行 --- setInterval("nextled()",1000); // 1秒毎にnextled() } function nextled(){ if(L==10){ // Lが10なら for(var i=0;i<10;i++) pixel(i,0,0,0); //全消灯 L=0; // Lを0に }else{ pixel(L,50,0,0); // LのLEDを点灯 L++; // Lを次に } } </script> <!-- ここまで --> </body></html>

(練習) 「赤のワイプ→緑のワイプ→青のワイプ」を繰り返すプログラムを作りなさい。

8.4 スイープ

 以下のプログラムは、10個のLEDを順に点灯・消灯させます。

pixelsweep.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) function setup(){ // --- はじめに自動実行 --- pixel(L, 50,0,0); // 0番目のLEDを点灯 setInterval("sweep()",1000);// 1秒毎にsweep()を実行 } function sweep(){ pixel(L, 0,0,0); // L番目のLEDを消灯 if(++L==10) L=0; // Lを次に pixel(L, 50,0,0); // L番目のLEDを点灯 } </script> <!-- ここまで --> </body></html>

(練習) 100ms毎にスイープするようにしてみなさい。

8.5 ウェーブ

 以下のプログラムは、4個に1個の点灯がスイープし、波(ウェーブ)のように(あるいは追いかけているように)見えます。「P=3」にすると3個に1個の点灯になります。

pixelwave.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var P=4; var j=P; function setup(){ // --- はじめに自動実行 --- setInterval("chase()",100); // 100ms毎にchase()を実行 } function chase(){ for(var i=0;i<10;i++){ // iを0から9まで if((i+j)%P==0) pixel(i, 50,0,0); else pixel(i, 0,0,0); } if(--j==0) j=P; } </script> <!-- ここまで --> </body></html>

(練習) 「1個おき」「3個おき」のウェーブにしてみなさい。

8.6 フェードイン・フェードアウト

 以下のプログラムは、ひとつ目のLEDをだんだん明るくし(赤を0→50)、だんだん暗くし(赤を50→0)、これを繰り返します。

pixelfade.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var R=0; // R(赤)の明るさ var r=1; // Rの変化分 function setup(){ // --- はじめに自動実行 --- setInterval("fade()",20); // 20ms毎にfade()を実行 } function fade(){ pixel(0, R,0,0); // 0番のLEDを明るさRに R+=r; if(R==50) r=-1; else if(R==0) r=1; } </script> <!-- ここまで --> </body></html>

(練習) 色を変えてみなさい。また速さを変えてみなさい。

(練習) 10個のLEDを同時にフェードイン・フェードアウトさせなさい。

8.7 クロスフェード

 ひとつ目のLEDをフェードアウトしながら、ふたつ目のLEDをフェードインすると滑らかに変化させることができます。これを「クロスフェード」といいます。

pixelxfade.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var R=0; // R(赤)の明るさ function setup(){ // --- はじめに自動実行 --- xfade(); } function xfade(){ pixel(0, 50-R,0,0); pixel(1, R,0,0); R++; if(R<50) setTimeout("xfade()",20); } </script> <!-- ここまで --> </body></html>

 以下は、クロスフェードをスイープに応用した例で、LEDの点灯が滑らかに移動します。

pixelxsweep.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) var R=0; // R(赤)の明るさ function setup(){ // --- はじめに自動実行 --- setInterval("xsweep()",10); } function xsweep(){ pixel(L, 50-R,0,0); pixel((L+1)%10, R,0,0); R=(R+1)%50; if(R==0) L=(L+1)%10; } </script> <!-- ここまで --> </body></html>

8.8 フルカラー表示

 クロスフェードを用いると色を滑らかに変化させることができます。以下のプログラムは、ひとつ目のLEDの色が赤→緑に滑らかに変化します。

pixelxrg.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var G=0; // G(緑)の明るさ function setup(){ // --- はじめに自動実行 --- xrg(); } function xrg(){ pixel(0, 50-G,G,0); G++; if(G<50) setTimeout("xrg()",50); } </script> <!-- ここまで --> </body></html>

 RGBの値と表示色の関係は下図のようになっています。


 以下のプログラムは、すべてのLEDの色をフルカラーで連続的に変化させます(明るさ最大85)。

pixelxrgb.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var W=0; // 0~255 function setup(){ // --- はじめに自動実行 --- setInterval("xrgb()",20); } function xrgb(){ for(var i=0;i<10;i++) pixel(i,W,50); W=(W+1)%256; } </script> <!-- ここまで --> </body></html>

 以下のプログラムは、すべてのLEDの色を場所を変えながらフルカラーで連続的に変化させます(明るさ最大85)。rgb()は0~255の色相Wを与えると、R,G,Bの変数に値(各々0~85)がセットされます。

pixelrgb.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var j=0; function setup(){ // --- はじめに自動実行 --- setInterval("rgb()",10); } function rgb(){ for(var i=0;i<10;i++) pixel(i,(i*256/10+j)%256,50); j=(j+8)%256; } </script> <!-- ここまで --> </body></html>

8.9 イルミネーションの例

 以下は、「ドロップ」のイルミネーションの作例です。水滴が滴り落ちるイメージで、最後にキラッと光ります。

pixeldrop.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var S=0; // 0:休止 var N; // ドロップの長さ var led; // LEDの番号 var b=0; // 明るさ var u; // 最大の明るさ function loop(){ if(S==0){ // 休止 N=6+Math.floor(Math.random()*5);//ドロップ長(ランダムに6~10) led=0; // ledは0から b=0; // 明るさbは0から u=(led+1)*10 // uは最大の明るさ S=1; setTimeout("S=2",Math.random()*2000); }else if(S==2){ // ドロップ pixel(led, u-b,u-b,u-b);// ledをu-bの明るさ(だんだん暗く) pixel((led+1)%10,b,b,b);// led+1をbの明るさ(だんだん明るく) b=(b+1)%u; if(b==0){ led++; if(led==N-1){ S=3; b=u;} } }else if(S==3){ // 明るさbを最大までだんだん明るく(キラリ) if((b+=4)>255){S=4; b=255;} pixel(N-1,b,b,b); }else if(S==4){ // 明るさbを0までだんだん暗く if((b-=4)<0){ S=0; b=0;} pixel(N-1,b,b,b); } } </script> <!-- ここまで --> </body></html>

 以下は、NeoPixelリング(12個)を使い、ランダムに点灯させるようにした例です。オブジェの作り方はngo-tecさんのページを参考にしました(クッキングシートを使ってみました)。点灯位置と点灯色と点灯時間間隔をランダムにし、点灯後はだんだん暗くしています。

pixelfire.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション</h2> <!-- ここからプログラム --> <script> var brightness=[], color=[]; // NeoPixelの明るさと色 function setup(){ // --- はじめに自動実行 --- for(var i=0;i<NPIXEL;i++){ // すべて消す brightness[i]=0; pixel(i, 0,0); } setInterval("decayPixel()", 50); // NeoPixelを50ms毎に減衰 fire(); } function decayPixel(){ // 明るさを減衰 for(i=0;i<NPIXEL;i++)if(brightness[i]>0){ brightness[i]=Math.floor(brightness[i]*.95); pixel(i, color[i], brightness[i]); } } function fire(){ var p=Math.floor(Math.random()*NPIXEL); // 場所はランダムに brightness[p]=255; // 明るさ最大で color[p]=Math.random()*256; // 色はランダムに setTimeout("fire()",(Math.random()+Math.random())*1000); // 0~2秒後にfire() } </script> <!-- ここまで --> </body></html>

(練習) オリジナルのイルミネーションを考え、作ってみなさい。


9. 動くものを作る

9.1 サーボモータを動かす

 ラジコン用のサーボモーターは、右図のようなPWM波形で角度(0~180°)を制御するように作られています。

 以下の例は、サーボモーターが車のワイパーのように動きます。

sweep.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>サーボモーター</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>サーボモーター</h2> <!-- ここからプログラム --> <script> var angle=0; // 角度(0~180) var d=1; // angleの変化分 function setup(){ // --- はじめに自動実行 --- pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- servo(9, angle); angle=angle+d; if(angle>=180) d=-1; else if(angle==0) d=1; } </script> <!-- ここまで --> </body></html>

 以下のプログラムは、ボリュームの値によってサーボモーターの位置(角度)が変わります。

knob.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>サーボモーター</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>サーボモーター</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(9,OUTPUT); // 9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var angle=analogRead(A0)*180/1024; // 角度(0~180) servo(9, angle); } </script> <!-- ここまで --> </body></html>

(練習) 上記のknob.htmlでボリュームの代わりに明るさセンサーを使い、明るさで位置が変わるようにしなさい。

9.2 モーターを動かす

 下図のようにモーターを接続します。まず、motorコマンドでモーターを動かしてみてください。左右のモーターの速度は-256~255で指定します。電源への負荷を軽減するために、早さを変える場合は一旦停止させてください。

コマンド:
motor(100,100) motor(0,0) motor(100,50) motor(0,0) motor(-100,-100) motor(0,0)

9.3 ブラウザ画面からモーターを制御する

 以下はブラウザに表示されたスライダを操作することによってモーターの回転速度が変わります。

motorslider.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示とプログラム --> <h2 align=center>モーターの制御</h2> <input type=range style="width:300px" onchange=motor(this.value, this.value) value=0 min=0 max=255 step=1> <!-- ここまで --> </body></html>

 以下は、ブラウザ画面のボタン操作で前後左右に動かします。

motorbutton.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示とプログラム --> <h2 align=center>モーターの制御</h2> <center><table> <tr><td></td> <td><button onclick=motor(255,255)>前進</button></td> <td></td></tr> <tr><td><button onclick=motor(50,255)>左回転</button></td> <td><button onclick=motor(0,0)>停止</button></td> <td><button onclick=motor(255,50)>右回転</button></td></tr> <tr><td></td> <td><button onclick=motor(-255,-255)>後退</button></td> <td></td></tr> </table></center> <!-- ここまで --> </body></html>

9.4 ボリュームでモーターを制御する

 以下はボリュームの値によってモーターの回転速度が変わります。

motorvr.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>モーターの制御</h2> <!-- ここからプログラム --> <script> function loop(){ // --- 20ms毎に自動実行 --- var speed=analogRead(A0)*180/1024; // 角度(0~180) motor(speed,speed); } </script> <!-- ここまで --> </body></html>

 以下は音センサモジュールと組み合わせた例で、手を叩く(A0に接続した音センサーが400以上)と1秒間前進します。

motorsound.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>モーターの制御</h2> <!-- ここからプログラム --> <script> var S=0; // モーターの状態(0:停止 1:回転) function setup(){ // --- はじめに自動実行 --- pinMode(A0,ANALOG_INPUT); // A0をアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- if(S==0 && analogRead(A0)>=400){ motor(255,255); S=1; setTimeout("motor(0,0);S=0",1000); } } </script> <!-- ここまで --> </body></html>

 以下の例は、車の先端がテーブルから落ちそう(A0に接続した赤外線反射センサーが30以上)になると、少し後退し、右回転して、再び前進します。

motorir.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>モーターの制御</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- } function loop(){ // --- 20ms毎に自動実行 --- var angle=analogRead(A0)*180/1024; // 角度(0~180) servo(8, angle); } </script> <!-- ここまで --> </body></html>


10. さまざまな例

10.1 温湿度計

 以下は、デジタル温湿度センサSHT31を使った温湿度計です。TEMPとHUMIは特別なアナログ入力ピンでA0やA1と同じように使います。

thermometer.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>温湿度計</title> <script src=webio.js></script> </head><body> <!-- ここから画面表示 --> <div id=TEMP style='font-size:80pt'></div> <div id=HUMI style='font-size:80pt'></div> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(TEMP,ANALOG_INPUT); // TEMPをアナログ入力に pinMode(HUMI,ANALOG_INPUT); // HUMIをアナログ入力に setInterval("measure()",1000); } function measure(){ $("TEMP").innerHTML=analogRead(TEMP)+"<small>℃</small>"; $("HUMI").innerHTML=analogRead(HUMI)+"<small>%RH</small>"; } </script> <!-- ここまで --> </body></html>

 以下は、グラフ表示など多目的に使えるようにした例です。データは使用するパソコンのブラウザに保存され、そのデータをネットワーク経由で見ることはできません。理科や保健の授業などで利用できるかもしれません。ネットワークを利用した気温・湿度・熱中症指数(WBGT)・CO2モニタリングシステムはこちらをご覧ください。


以下はCO2センサも利用できるようにした例です。

10.2 押しボタン信号機

 イルミネーションの時と同じLEDを使い、押しボタン信号機を作ってみます。下図の状態遷移図で考え、LEDの割り当ては

とします。LEDと連動して、ブラウザ画面も変化するようにしました。また、押しボタンの操作は画面上のでも同じように動作します。


signal.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>押しボタン信号機</title> <script src=webio.js></script> <style>td{font-size:32pt}</style> </head><body> <!-- ここから画面表示 --> <center><table> <tr><th>自動車</th><th>歩行者</th></tr> <tr><td align=center width=60> <span id=R>●</span><br><span id=Y>●</span><br><span id=B>●</span> </td><td align=center valign=bottom width=60> <span id=RR>■</span><br><span id=BB>■</span> </th></tr> <tr><th></th> <th><button onclick="S=1;timer(4000);">押す</button></th></tr> </table></center> <!-- ここからプログラム --> <script> var S; // 現在の状態 var TOUT; // タイムアウトフラグ var C; // 歩青点滅用カウンタ function signal(c1, c2){ if(c1=="赤"){ pixel(0,50,0,0); $("R").style.color="orangered"; pixel(1,0,0,0); $("Y").style.color="darkgoldenrod"; pixel(2,0,0,0); $("B").style.color="darkblue"; }else if(c1=="黄"){ pixel(0,0,0,0); $("R").style.color="darkred"; pixel(1,50,50,0);$("Y").style.color="gold"; pixel(2,0,0,0); $("B").style.color="darkblue"; }else if(c1=="青"){ pixel(0,0,0,0); $("R").style.color="darkred"; pixel(1,0,0,0); $("Y").style.color="darkgoldenrod"; pixel(2,0,0,50); $("B").style.color="aqua"; } if(c2=="赤"){ pixel(8,50,0,0); $("RR").style.color="orangered"; pixel(9,0,0,0); $("BB").style.color="darkblue"; }else if(c2=="青"){ pixel(8,0,0,0); $("RR").style.color="darkred"; pixel(9,0,0,50); $("BB").style.color="aqua"; }else if(c2=="消"){ pixel(8,0,0,0); $("RR").style.color="darkred"; pixel(9,0,0,0); $("BB").style.color="darkblue"; } } function setup(){ // --- はじめに自動実行 --- pinMode(1,INPUT_PULLUP); // 1ピンはプルアップ入力 for(var i=0;i<10;i++) pixel(i, 0,0,0); // はじめに全消灯 signal("青", "赤"); // 車青・歩赤 S=0; } function timer(t){TOUT=false; setTimeout("TOUT=true",t);} function loop(){ // --- 20ms毎に自動実行 --- if(S==0 && digitalRead(1)==0){ // ボタンが押されたら S=1; timer(4000); // S=1 }else if(S==1 && TOUT){ // 4秒後に S=2; signal("黄","赤"); timer(4000); // S=2 車黄・歩赤 }else if(S==2 && TOUT){ // 4秒後に S=3; signal("赤","赤"); timer(2000); // S=3 車赤・歩赤 }else if(S==3 && TOUT){ // 2秒後に S=4; signal("赤","青"); timer(16000); // S=4 車赤・歩青 }else if(S==4 && TOUT){ // 16秒後に S=5; signal("赤","青"); timer(500);C=0;// S=5 車赤・歩青 }else if(S==5 && TOUT){ // 0.5秒後に if(C%2==0) signal("赤","青"); // 車赤・歩青点滅 else signal("赤","消"); C++; if(C>=16){ // S=6 車赤・歩赤 S=6; signal("赤","赤"); timer(4000); }else timer(500); }else if(S==6 && TOUT){ // 4秒後に S=0; signal("青","赤"); // S0 車青・歩赤 } } </script> <!-- ここまで --> </body></html>

 また、以下は小学校などで利用されている「交通安全教室用信号機」ですが、上記と組み合わせればWebページと連動した指導ができるようになるかもしれません。

10.3 WebIOの動作テスト

 下図のように、WebIOの動作を確かめるページを作りました。プログラムをクッキーに保存することもできます。


(付録1) WebIOの主な仕様

(1) 使用できるピン

Pro micro 備考
D0/TX midi Out / TX
D1/RX midi In / RX
D2/SDA I2C
D3#/SCL I2C
D4 NeoPixel
D5#
D6#/A7 Bzz...sendNote()に対応
D7
D8
D9# Servo
D10# Servo
D14/MISO
D15/SCK
D16/MOSI
A0/D18
A1/D19
A2/D20
A3/D21
A4/TEMP SHT31
A5/HUMI SHT31
A6/CO2 CDM7160
種類ピン番号
デジタル出力ピン0~10, 14~16, 18~21
デジタル入力ピン
アナログ出力ピン3, 5, 6, 9, 10
アナログ入力ピンA0, A1, A2, A3, A7
A4(TEMP), A5(HUMI)はI2C接続したSHT31の値、
A6(CO2)はI2C接続したCDM7160の値を読み取る際の仮想ピン

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

定数名内容
HIGH, LOWデジタル出力またはデジタル入力されたピンの状態(HIGHは1、LOWは0)
OUTPUT
INPUT, INPUT_PULLUP
ANALOG_INPUT
pinMode()で設定するピンの入出力
A0, A1, A2, A3, A7
A4(TEMP), A5(HUMI), A6(CO2)
アナログ入力pin
A4(TEMP), A5(HUMI)はI2C接続したSHT31の値、
A6(CO2)はI2C接続したCDM7160の値を読み取る際の仮想ピン

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

関数名内容
pinMode(pin, mode) pinをmodeにする(modeはOUTPUT, INPUT, INPUT_PULLUP, ANALOG_INPUT)
digitalRead(pin) pinの値を読んでHIGHまたはLOWの値を返す
digitalWrite(pin, HIGH)
digitalWrite(pin, 1, t)
pinにHIGHを出力する(値はHIGHまたはLOW)
pinをt(ms) 1にする
analogRead(A0) A0, A1, A2, A3, A7ピンのアナログ値を読み、0~1023の値を返す。
A4(TEMP), A5(HUMI), A6(CO2)ピンのアナログ値を返す。
analogWrite(pin, value)pin(3,5,6,9,10,11のいずれか)にvalue(0~255)を出力する
sendNote(key, t) ピン6にkeyのブザー音をt[ms]出力する
playNote(key, t) ブラウザからkeyの合成音をt[ms]出力する
servo(pin, pos) pinに接続したサーボの角度をpos(0~180)にする(pinは9と10を推奨)
motor(lspeed, rspeed)左右のモーターの速度をlspeed, rspeed(それぞれ-255~255)にする
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に接続
$(id) document.getElementById(id)の短縮表現

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

関数名内容
setup() ページが表示された時にこの関数が呼び出される
loop() 20ms毎にこの関数が呼び出される

(付録2) Midiコマンドとの対応

機能 send(PC → I/O) receive(I/O → PC)JavaScript関数備考
byte1byte2byte3 byte1byte2byte3
8x [midi] NoteOff 1000nnnn0kkkkkkk0vvvvvvv 1000nnnn0kkkkkkk0vvvvvvv ピン6の音を停止
9x[midi] NoteOn 1001nnnn0kkkkkkk0vvvvvvv 1001nnnn0kkkkkkk0vvvvvvv sendNote(key, t)ピン6にkey0-125のブザー音をt[ms]出力
Ax[midi] Pressure 1010nnnn0kkkkkkk0vvvvvvv
NeoPixel 1010nnnn0rgbllll0rrrrrrr Pixel(LED, R,G,B) LED0-15の色をR(0-255)G(0-255)B(0-255)にする
1010nnnn0ggggggg0bbbbbbb
analogIn 1010nnnn0vvvvvaa0vvvvvvv analogRead(pin) A4(22),A5(23),A6(24)の値0-4095を返す(20ms毎に更新)
Bx[midi] Control Change 1011nnnn0ccccccc0vvvvvvv
PinMode 1011nnnn011100pp0pppmmmm pinMode(pin, mode) pin0-21のpinModeをmode0-13にする
DigitalOut 1011nnnn011100pp0ppp111v digitalWrite(pin, val)
digitalWrite(pin, 1, t)
pin0-21を0/1にする
tを指定した場合は t[ms] 1にする
DigitalIn 1011nnnn011100pp0ppp111v digitalRead(ch, pin) pin0-21の値0/1を返す(20ms毎に更新)
Set Channel 1011nnnn0111010000000000 setCh(ch)
Character IO 1011nnnn011101010ccccccc 1011nnnn 01110101 0ccccccc sendChar(char) 文字0-127を送る
文字0-127を返す
([midi] Program Change) 1011nnnn011111110ppppppp setVoice(ch, voice) ch0-15を音源0-127にする
Reset 1011nnnn0111100100000000 reset() Reset All Control
AllNoteOff 1011nnnn0111101100000000 All Note Off
Cx[midi] Program Change 1100nnnn0ppppppp
Dx[midi] Pressure 1101nnnn0vvvvvvv
Ex[midi] Pitch Bend 1110nnnn0lllllll0mmmmmmm
Servo 1110nnnn00vppppp0vvvvvvv servo(pin, val)
servo(pin, val, t)
pin0-21のサーボモーターを0-180にする
tを指定した場合はt[ms]後に停止する
Motor 1110nnnn00v1111p0vvvvvvv motor(lspeed, rspeed) 左モーター(pin30) 右モーター(pin31)のスピードを -128~127 にする
analogOut 1110nnnn01vppppp0vvvvvvv analogWrite(pin, val) pin3,5,6,9,10を0-255にする
analogIn 1110nnnn00vvvaaa0vvvvvvv analogRead(pin) A0(18),A1(19),A7(6)の値0-1023を返す(20ms毎に更新)
Fx[midi] SysEx 1111xxxx

(付録3) 入出力モジュールの例

 ブレッドボードで利用できる入出力モジュールの製作例です。

モジュール回路図製作例
可変抵抗モジュール
明るさセンサーモジュール
赤外線反射モジュール
音量センサーモジュール
10連LEDモジュール
NeoPixel(Dinはpin10に接続)
モーターモジュール
右モーターはA0とA1をGNDに接続

(付録4) 使用する主な部品

部品表
名称 外観 備考
Arduino Pro Micro スイッチサイエンス 2492円
(互換品が600円程度で入手できます)
ブレッドボード EIC-301 EIC-301 秋月 190円
ブレッドボード ジャンパーワイヤ 15cm   秋月 10本 300円
ブレッドボード ジャンパーワイヤ EIC-J-S   秋月 250円
LED 秋月 10個 120円
フルカラーシリアルLEDテープ SwitchScience 756円
圧電スピーカー 秋月 2個 100円
プッシュスイッチ DS-660R-C 千石 84円
抵抗 1/4W 4.7Ω, 100Ω, 220Ω, 470Ω, 1kΩ, 10kΩ 秋月 100本 100円
CDS(光センサ)秋月 30円
温湿度センサ SHT31秋月 950円
赤外線反射センサ LBR-127HLD   秋月 50円
サーボモーター SG-90   秋月 400円
モータードライバ DRV8830   秋月 170円

(以下はメモ)

WebMidiAPIによるArduino Micro の接続

Arduino Pro Micro / Davinci / NANO のピン接続

Pro micro Leonardo
/ Davinci
NANO 備考
D0/TX D0/TX D0/TX midi Out / TX
D1/RX D1/RX D1/RX midi In / RX
D2/SDA D2/SDA D2 I2C
D3#/SCL D3#/SCL D3# I2C
D4 D4 D4 NeoPixel
D5# D5# D5#
D6#/A7 D6#/A7 D6#
D7 D7 D7
D8/A8 D8/A8 D8
D9#/A9 D9#/A9 D9# servo
D10# D10# D10# servo
- D11#/A11 D11#/MOSI
- D12 D12/MISO
- D13# D13/SCK
D14/MISO D14/MISO -
D15/SCK D15/SCK -
D16/MOSI D16/MOSI -
- D17/SS -
A0/D18 A0/D18 A0/D14
A1/D19 A1/D19 A1/D15
A2/D20 A2/D20 A2/D16
A3/D21 A3/D21 A3/D17
- A4/D22 A4/D18/SDA I2C
- A5/D23 A5/D19/SCL I2C
- - A6
- - A7

koyama@hirosaki-u.ac.jp