(更新中)

ブラウザ操作でIO制御 WebIO2 [WebIOtest][WebIOtest2]

小山智史

コンピュータの仕組み ATtiny2313版 - - - - -
Arduinoでものづくり ATtiny4313版 ATmega328P版 NANO版 - ESP8266版 XIAO M0版
tinyBasicでものづくり - - NANO版 ProMicro版 ESP8266版 XIAO M0版
Pythonでものづくり - - - - - XIAO M0版

目次


0. 準備
1. コマンド操作
2. デジタル出力(1): LEDの点滅
3. デジタル入力: スイッチ操作でLEDのオンオフ
4. アナログ出力: LEDの明るさを変える
5. アナログ入力
6. デジタル出力(2): 数字表示LED
7. デジタル出力(3): 液晶ディスプレイ
8. センサーの利用
9. ブザー音で演奏
10. 合成音声でおしゃべり
11. イルミネーション
12. 赤外線リモコン
13. 動くものを作る
14. 押しボタン信号機
15. さまざまな例
(付録1) 入出力モジュール
(付録2) 使用する主な部品


 WebIO は、MIDI通信を用いてブラウザからIO制御する仕組みです。こちらを先にご覧ください。

 このページは、MIDIデバイス(マイコン)として Leonardo, Micro または XIAO M0 をUSB接続、または ATOM lite をBluetooth接続した時の、さまざまな使用例を紹介しています。ATOMの場合は、スマホの操作で利用します。ATOMに内蔵されているLEDやスイッチを使う例もいくつかあるので、その場合は外部に何も接続する必要はありません。なお、このページには所々に

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

0. 準備

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

 ここではブレッドボードを使いません。

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

(外観) (内部の接続)

 ブレッドボードにマイコンを差し込み、GNDと3V3の端子をブレッドボードの電源ラインに接続します。USBケーブルをパソコンに接続すると、電源(3.3V)がパソコンから供給されます。マイコンにピンの番号を書いたラベルを貼っておくことをお勧めします。

(回路図) (実体配線図)

 初めてブレッドボードを使う場合は、練習としてLEDと抵抗を下図左のように接続して点灯を確認しましょう。電源はパソコンからUSB端子を通じて供給され、電流の流れは下図右のようになります。ブレッドボードの内部の結線も含めて「電流が流れる経路」を意識することが重要です。

(回路図) (実体配線図) (電流の流れ)

(練習) ブレッドボードで下記の回路を組み立て、スイッチを押すとLEDが点灯することを確認しなさい。

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

(外観) (内部の接続)

 ブレッドボードにマイコンを差し込み、GNDと3V3の端子をブレッドボードの電源ラインに接続します。USBケーブルをパソコンに接続すると、電源(3.3V)がパソコンから供給されます。マイコンにピンの番号を書いたラベルを貼っておくことをお勧めします。

(回路図) (実体配線図)

 初めてブレッドボードを使う場合は、練習としてLEDと抵抗を下図左のように接続して点灯を確認しましょう。電源はパソコンからUSB端子を通じて供給され、電流の流れは下図右のようになります。ブレッドボードの内部の結線も含めて「電流が流れる経路」を意識することが重要です。

(回路図) (実体配線図) (電流の流れ)

(練習) ブレッドボードで下記の回路を組み立て、スイッチを押すとLEDが点灯することを確認しなさい。

 ここではブレッドボードを使いません。

0.2 ソフトウェアの準備[webio2_20230805.zip]

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

(1) Arduino用プログラム: webio2.ino
XIAO M0(samd21) または ATOM lite にwebio2.ino(スケッチ)を書き込んでおきます(Arduino-2.3.4て確認)。準備ができれば、このページを使ってすぐに動作を確かめることができます。また、15.2の動作テスト用のページでさまざまな動作を確かめることができます。
(2) JavaScriptライブラリ: webio2.js
2章以降で、LEDの制御など実際にIO制御を行うWebページの中で のように使います(このページでも使っています)。MIDIデバイス(マイコン)をパソコンに接続し、webio2.jsを使ったページを表示すると、ページの冒頭にのような表示が現れます。これはSeeed XIAO M0という名前のMIDIデバイスが接続されていることを表しています。USB接続のMIDIデバイスが無い場合は、のような表示になるので、ボタンを押してBluetooth MIDIのデバイスと接続します(詳しくはこちら)。

 なお、いつからか、ChromeでMIDIデバイスを扱うサイトを表示する時に、下記のように許可が求められるようになったので、「許可する」をクリックします。

これは、このページ(サーバ上のページ)を初めて表示した時に現れるようです。ローカルファイルの場合は毎回現れるようです。


1. コマンド操作(JavaScript命令の実行)

コマンド:

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

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

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


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

 webio2.inoを書き込んだLEONARDOをパソコンにUSB接続します。

 ブラウザはWindows版ChromeまたはEdgeを使います

 webio2.inoを書き込んだMICROをパソコンにUSB接続します。

 ブラウザはWindows版ChromeまたはEdgeを使います

 webio2.inoを書き込んだXIAO M0をパソコンにUSB接続します。

 ブラウザはWindows版ChromeまたはEdgeを使います

 webio2.inoを書き込んだATOM liteをパソコンまたはスマホにBluetooth接続します。

 ブラウザはWindows版Chromeまたは Edge、Android版Chromeを使います。

2.1 LEDを点灯・消灯する

 ブラウザからのコマンド操作でLEDを点灯・消灯してみます。

 LEDはD9ピンに接続します。LEONARDOの場合は内蔵LED(D13ピン)も利用できます。

 LEDはD9ピンに接続します。

 LEDはD9ピンに接続します。XIAOの場合は内蔵LED(D13ピン)も利用できます。

(回路図) (実体配線図)

 ATOM内蔵のLED(27ピン)を使います。このピン番号はPIN_LEDやLED_BUILTINで参照できます(こちらを参照)。

コマンド:

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

または のように入力し、実行ボタンを押すかEnterキーを押すと、LEDに高い電圧(3.3V)が出力され、点灯します。

または と操作すると、LEDに低い電圧(0V)が出力され、消灯します。

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

 「digitalWrite()」や「 D9 D9 D9 D9 」「HIGH」「LOW」はwebio2.jsの中で定義されています(詳しくはこちら)。

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

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

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

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

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

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

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

 はじめの一歩「Lチカ」です。

blink.html:

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

blink.html:

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

blink.html:

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

blink.html:

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

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

 冒頭の5行はWebページの常套句で、その先がWebページの本体とプログラムになります。

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

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

 ここで、setup()は特別な関数の名前になっていて、MIDIデバイス(マイコン)が認識された時にこの関数が実行されます(こちらを参照)。setup()の中では、まずpinModeでLEDが接続されているピンを出力(OUTPUT)にしています。OUTPUTはwebio2.jsの中で定義された組み込み変数です(こちらを参照)。次の「setInterval("toggle()",1000)」で、1000ms(1秒)毎にtoggle()が呼び出されるよう指示しています。toggle()が呼び出されると、LEDの点灯状態ledを0なら1に、1なら0にし、その値をそのままdigitalWrite()で出力します。

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

2.3 ブラウザの操作で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(LED,1)>点灯</button> <button onclick=digitalWrite(LED,0)>消灯</button> <script> function setup(){ // --- はじめに自動実行 --- pinMode(LED,OUTPUT); // 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データがMIDIデバイス(マイコン)に送信されます。実際にどのようなデータが送られるかは、ブラウザでF12キーを押すと確認することができます(データの詳細はこちら)。

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

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

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


3. デジタル入力

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

 スイッチの状態(オフで1, オンで0)をコマンド入力欄を使って調べてみます。

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

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

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

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

 それでは調べてみましょう。

コマンド:
をコマンド入力し、プルアップ抵抗が有効にします。次に をコマンド入力し、スイッチの接続されたピンが現在高い電圧(1)か低い電圧(0)かをアラート表示します。

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

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

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

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

 スイッチの状態(オフで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)を表示します。

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

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

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

3.3 スイッチ操作で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);// BUTTONをプルアップ入力に pinMode(PIN_LED,OUTPUT); // LEDを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(PIN_BUTTON); // BUTTONの値を読み取りvalに代入 digitalWrite(PIN_LED,val); // LEDにvalを出力 $("VAL").innerHTML=val; // ブラウザ画面にvalを表示 } </script> </body></html>

ブラウザの表示はスイッチの操作により変化します。

 ブラウザのプログラムで点灯・消灯するため、若干の遅れが生じ、その遅れを体感できます。

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

 以下は、スイッチを押すと交互にLEDが点灯・消灯します。

button3.html:

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

button3.html:

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

button3.html:

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

button3.html:

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

ブラウザの表示はスイッチの操作により変化します。

 考え方は、「スイッチが押された瞬間に(つまりさっき押されていなくて今押されたら)LED表示を反転する」というものです。buttonには「今のスイッチの状態(0または1)」、lastbuttonには「さっきのスイッチの状態(0または1)」、変数ledには「今のLEDの点灯状態(1が点灯、0が消灯)」を保存します。

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

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

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

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

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

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

button4.html:

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

button4.html:

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

button4.html:

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

button4.html:

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

ブラウザの表示はスイッチの操作により変化します。

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

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

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


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

4.1 アナログ出力する

 はじめに、コマンド入力で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(PIN_LED,OUTPUT) analogWrite(PIN_LED,0) analogWrite(PIN_LED,255) analogWrite(PIN_LED,100) analogWrite(PIN_LED,10)

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

4.2 ブラウザの操作でLEDの明るさを変える

 ブラウザ画面のスライダーの操作で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(PIN_LED,this.value) value=0 min=0 max=255 step=1> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(PIN_LED,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>

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

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


5. アナログ入力

5.1 アナログ値を調べる

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

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

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

 下図左のようにボリュームユニット(回転角ユニット)を接続すると、ボリュームの操作に応じてGROVE1ピンの電圧は0~3.3Vに変化します。analogRead(GROVE1)は、電圧に応じて0~1023の値を返します。

 それでは調べてみましょう。

コマンド:
をコマンド入力し、次に をコマンド入力し、ピンの値をアラート表示します。

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

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

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

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

 ボリューム操作で変化するアナログ値(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(A0,INPUT_ANALOG); // A0ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A0); } </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(A0,INPUT_ANALOG); // A0ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A0); } </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(GROVE1,INPUT_ANALOG); // GROVE1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(GROVE1); } </script> <!-- ここまで --> </body></html>

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

 読み取った値をバーグラフで表示することもできます。

bargraph.html:

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

bargraph.html:

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

bargraph.html:

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

bargraph.html:

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

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


6. デジタル出力(2): 数字表示LED

 この章はありません。


7. デジタル出力(3): 液晶ディスプレイ

 この章はありません。


8. センサーの利用

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

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

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

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

 5.2のボリュームの代わりに明るさセンサー(CDS)をつないでみましょう。明るくなるほどCDSの抵抗値が低くなり、ピンに加わる電圧は高くなります。プログラムは5.2と同様です。

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(A0,INPUT_ANALOG); // A0ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A0); } </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(A0,INPUT_ANALOG); // A0ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A0); } </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(GROVE1,INPUT_ANALOG); // GROVE1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(GROVE1); } </script> <!-- ここまで --> </body></html>

ブラウザの表示は明るさに応じて変化します。

 読み取った値をバーグラフで表示することもできます。

bargraph.html:

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

bargraph.html:

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

bargraph.html:

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

bargraph.html:

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

ブラウザの表示は明るさに応じて変化します。

8.6 温湿度センサー: 温湿度計を作る

 ここでは高精度のデジタル温湿度センサー(SHT31)を使います。analogRead()で温湿度を直接読み取ることができます。温度が23度であればanalogRead(TEMP)は「23」という値を返し、相対湿度が45%であればanalogRead(HUMI)は「45」という値を返します。

 以下のプログラムは、温湿度センサー(SHT31)で測定した温度と湿度をブラウザ画面に表示します。

thermometer.html:

<!DOCTYPE html><html><head> <meta name="viewport" content="width=device-width,initial-scale=1"> <meta charset="utf-8"> <style>span{font-size:80pt}</style> <title>温湿度計</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=TEMP></span><br> <span id=HUMI></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(TEMP, INPUT_ANALOG); // TEMPをアナログ入力に pinMode(HUMI, INPUT_ANALOG); // HUMIをアナログ入力に setInterval("measure()",1000); // 1秒毎に測定 } function measure(){ $("TEMP").innerHTML=analogRead(TEMP)+"<small>℃</small>"; $("HUMI").innerHTML=analogRead(HUMI)+"<small>%RH</small>"; } </script> <!-- ここまで --> </body> </html>


9. ブザー音で演奏

9.1 コマンド操作で音を出す

コマンド:

 初めに「pinMode(D9,OUTPUT_TONE)」のように、ブザーを接続するピンを指定します。その後、「sendNote(key,長さ)」で指定したkeyの音を出すことができます。D9ピンにブザーを接続し、以下の操作で確認してください。

pinMode(D9,OUTPUT_TONE); sendNote(67,200) sendNote(67,200) sendNote(67,200) sendNote(72,2000) sendNote("G4",200) sendNote("G4",200) sendNote("G4",200) sendNote("C5",2000)
回路図

keyはmidiのノート番号(21~108)または文字列("A0"~"C8")で指定します。また、長さは[ms]で指定します。長さを省略すると300[ms]となります。

 sendNote()ではなくplayNote()を使うと、ブラウザから音を出すことができます。以下の操作で確認してください。

playNote(67,200) playNote(67,200) playNote(67,200) playNote(72,2000) playNote("G4",200) playNote("G4",200) playNote("G4",200) playNote("C5",2000)

 ブラウザからドラム音を出すこともできます。

drumKick() drumSnare() drumHihat()

9.2 プログラムで演奏する

 以下は、簡単な演奏プログラムで、D9ピンに接続したブザーから音が出ます。midi音源を接続しても動作します。Javascriptにはdelay()という関数がないため、setTimeout()で次の音に進みます。

sendnotes.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>ブザーで演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>ブザーで演奏</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 setTimeout("sendNote1()",1000); // 1秒後に演奏開始 } function sendNote1(){ // 1音目 sendNote("G4",200); // 演奏 setTimeout("sendNote2()", 1000);// 1秒後に2音目 } function sendNote2(){ // 2音目 sendNote("G4",200); // 演奏 setTimeout("sendNote3()", 1000);// 1秒後に3音目 } function sendNote3(){ // 3音目 sendNote("G4",200); // 演奏 setTimeout("sendNote4()", 1000);// 1秒後に4音目 } function sendNote4(){ // 4音目 sendNote("C5",2000); // 演奏 } </script> <!-- ここまで --> </body></html>

 以下は、ブラウザで演奏するプログラムです。

playnotes.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>ブラウザで演奏</title> <script src=webio2.js></script> </head><body> <!-- ここからWebページの本体とプログラム --> <h2>ブラウザで演奏</h2> <script> function setup(){ // --- はじめに自動実行 --- setTimeout("playNote1()",1000); // 1秒後に演奏開始 } function playNote1(){ // 1音目 playNote("G4",200); // 演奏 setTimeout("playNote2()", 1000);// 1秒後に2音目 } function playNote2(){ // 2音目 playNote("G4",200); // 演奏 setTimeout("playNote3()", 1000);// 1秒後に3音目 } function playNote3(){ // 3音目 playNote("G4",200); // 演奏 setTimeout("playNote4()", 1000);// 1秒後に4音目 } function playNote4(){ // 4音目 playNote("C5",2000); // 演奏 } </script> <!-- ここまで --> </body></html>

9.3 楽譜を演奏する

 以下は、楽譜データを参照しながら演奏するプログラムです。楽譜データがプログラムと分離されているので、長い曲も表しやすくなっています。midi音源を接続しても動作します。

midimelody.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>ブザーで楽譜を演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>ブザーで楽譜を演奏</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(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 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><head> <meta charset="utf-8"> <title>ブザーで電子オルゴール</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>ブザーで電子オルゴール</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(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 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>

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


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

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

drum1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>ドラムの自動演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>ドラムの自動演奏</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=5, Rmotor=4, Lservo=9, Rservo=8; // モータとサーボモータのpin var Lstick={L:150, S:80}; // ドラムの左サーボの角度(個別に調整) var Rstick={R:0, H:60}; // ドラムの右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 } 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>



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

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

tekkin1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>鉄琴の自動演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>鉄琴の自動演奏</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=5, Rmotor=4, Lservo=9, Rservo=8; // モータとサーボモータの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>


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

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

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

session1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>みんなでセッション</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>みんなでセッション</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=5, Rmotor=4, Lservo=9, Rservo=8; // モータとサーボモータの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){ playNote(midiPitch[u], T*.9); // ブラウザから合成音 if(digitalRead(0)==0){ // 鉄琴(pin0を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(0)==1){ // ドラム(pin0を解放)ならば 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(0)==0){ // 鉄琴(pin0を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{ // ドラム(pin0を解放)ならば 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秒」で同期演奏できますし、「正時」に演奏させれば「からくり時計」となります。ブラウザ画面上で楽譜を入力して演奏させることもできます。詳しくは「ミニドラム・ミニ鉄琴」のページをご覧ください。




10. 合成音声でおしゃべり

コマンド:

10.1 コマンド操作でおしゃべり(外部デバイスの接続不要)

 ブラウザの音声合成機能を用いて、おしゃべりするページを作ることができます。

talk("あいうえお") talk("あいうえお","Ichiro") talk("Hello, world.","US") talk("あいうえお","Haruka",0.1) talk("あいうえお","Ayumi",0.1,0.5) talk(123) talk("準備OK") talk(4+"かける"+5+"は"+(4*5)+"です")

 利用できる声はブラウザによって異なり、こちらのページで確認できます。

 デフォルトは「日本語で初めに見つかった声」になります。Windows10版Chromeの場合、日本語は

英語は などと指定できます(文字列が一致する最初の声になります)。

 音程は 0.1~2 で指定できます。無指定時は1となります。

 速さは 0.1~10 で指定できます。無指定時は1となります。

10.2 プログラムでおしゃべり(外部デバイスの接続不要)

 以下は、「九九」を合成音声で読み上げるプログラムです。

kuku.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>九九</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>九九</h2> <!-- ここからプログラム --> <script> var a=1, b=1; function setup(){ // --- はじめに自動実行 --- kuku(); } function kuku(){ $("VAL").innerHTML=a+"×"+b+"="+(a*b);// 画面表示 talk(a+"かける"+b+"は"+(a*b)+"です");// 合成音声で読み上げ if(++b==10){ a++; b=1; } if(a<10) kuku(); } </script> <!-- ここまで --> </body></html>

10.3 プログラムでおしゃべり(VOCA)

 以下は、外部スイッチが押されると「九九」をランダムに読み上げるプログラムです。

kukubutton.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>九九</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>九九</h2> <!-- ここからプログラム --> <script> var button; // 現在のbuttonの状態 var lastbutton; // 直前のbuttonの状態 function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2ピンをプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- button=digitalRead(D2); // D2ピンを読みbuttonに代入 if(button!=lastbutton && button==0){// buttonが前と違いかつ0なら var a=Math.floor(1+Math.random()*9);// aは1~9の乱数 var b=Math.floor(1+Math.random()*9);// bは1~9の乱数 $("VAL").innerHTML=a+"×"+b+"="+(a*b);// 画面表示 talk(a+"かける"+b+"は"+(a*b)+"です");// 合成音声で読み上げ } lastbutton=button; // lastbuttonを更新 } </script> <!-- ここまで --> </body></html>

 利用者に適したスイッチを使い、合成音声の読み上げで支援するさまざまなツール(VOCA)をWebで作ることができます。

(練習) 2個のスイッチを接続し、それぞれ「はい」「いいえ」の合成音声が出るようなVOCAを作りなさい。


11. イルミネーション

11.1 NeoPixelの利用

 NeoPixelはフルカラーLEDが連結されていて(ここでは10連LEDを使用)、1本の信号線で任意のLEDの発光をコントロールできるのが特徴です。

 初めに

のように、NeoPixelを接続するピンを指定します。その後、「pixel(...)」でLEDの点灯をコントロールできます。パラメータは、順にLEDの番号(0~9)、Redの明るさ(0~255)、Greenの明るさ(0~255)、Blueの明るさ(0~255)を指定します。NeoPixelを接続し、以下の操作で確認してください。

 LEDの番号(0~9)と色相(0~255)と明るさ(0~255)を指定することもできます。明るさの指定を省略すると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) pixel(0,0,50) pixel(0,128,50) pixel(0,128)

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

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

pixelblink1.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: 点滅</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: 点滅</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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><head> <meta charset="utf-8"> <title>イルミネーション: 点滅</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: 点滅</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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><head> <meta charset="utf-8"> <title>イルミネーション: フラッシュ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: フラッシュ</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel 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秒毎に「青→黄→赤」を繰り返すプログラムを作りなさい。

11.3 ワイプ

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

pixelwipe.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: ワイプ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: ワイプ</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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>

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

11.4 スイープ

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

pixelsweep.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: スイープ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: スイープ</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel 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毎にスイープするようにしてみなさい。

11.5 ウェーブ

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

pixelwave.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: ウェーブ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: ウェーブ</h2> <!-- ここからプログラム --> <script> var P=4; var j=P; function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel 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個おき」のウェーブにしてみなさい。

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

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

pixelfade.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: フェード</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: フェード</h2> <!-- ここからプログラム --> <script> var R=0; // R(赤)の明るさ var r=1; // Rの変化分 function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel 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を同時にフェードイン・フェードアウトさせなさい。

11.7 クロスフェード

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

pixelxfade.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: クロスフェード</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: クロスフェード</h2> <!-- ここからプログラム --> <script> var R=0; // R(赤)の明るさ function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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><head> <meta charset="utf-8"> <title>イルミネーション: スイープ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: スイープ</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) var R=0; // R(赤)の明るさ function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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>

11.8 フルカラー表示

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

pixelxrg.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: 赤から緑</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: 赤から緑</h2> <!-- ここからプログラム --> <script> var G=0; // G(緑)の明るさ function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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><head> <meta charset="utf-8"> <title>イルミネーション: フルカラー</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: フルカラー</h2> <!-- ここからプログラム --> <script> var W=0; // 0~255 function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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><head> <meta charset="utf-8"> <title>イルミネーション: フルカラー</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: フルカラー</h2> <!-- ここからプログラム --> <script> var j=0; function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel 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>

11.9 イルミネーションの例

(1) ドロップ

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

pixeldrop.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>イルミネーション: ドロップ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2>イルミネーション: ドロップ</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>

(2) イルミネーションオブジェ

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

pixelfire.html:

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

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


12. 赤外線リモコン

12.1 リモコン信号の送信

 以下はごくシンプルな東芝のTVリモコンです。赤外線送信モジュールを接続し、テレビに向けてボタンを押すと動作します。

toshiba_tv0.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>TVリモコン</title> <script src=webio2.js></script> </head><body> <button onclick=IRsend(8,0x40,0x12)>電源</button> <button onclick=IRsend(8,0x40,0x1b)>チャンネル▲</button> <button onclick=IRsend(8,0x40,0x1f)>チャンネル▼</button> </body></html>

 上記のようにブログラムは簡単で、が押されるとIRsend(8,0x40,0x12)が呼び出されるようになっています。「8, 0x40, 0x12」は、東芝のテレビリモコンの電源ボタンを押したときの赤外線信号で、順にプロトコル、アドレス、コマンドになっています。

※ 実際の赤外線信号についてはこちらに少し詳しい説明があります。

12.2 リモコン信号の受信

 上記のようなリモコンを作ろうとする時に、使いたいリモコンのボタンがどのような赤外線信号なのかを知る必要があります。以下は、そのためのものです。赤外線受信モジュールを接続し、受信モジュールに向けて(本物の)リモコンのボタンを押すと、その信号が下記のように画面に表示されます。

irreceive.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>リモコン信号の受信</title> <script src=webio2.js></script> <script> function setup(){ // MIDI接続後に行う処理 pinMode(IRINpin, INPUT_IR); // IR入力ピン } function onIRreceived(protocol, address, command){ // 受信データを表示 $("IRreceived").value=protocol +",0x"+address.toString(16).padStart(2,"0") +",0x"+command.toString(16).padStart(2,"0"); } </script> </head><body> リモコン信号: <input size=20 id=IRreceived> </body></html>

12.3 さまざまなリモコン(リモコンのページへ)

 下図のような、本物そっくりのリモコン、各社対応のリモコン、学習リモコンなど、さまざまなリモコンページを作ってみました。詳しくはこちらをご覧ください。

東芝テレビ
シャープテレビ
パナソニックBD

 ブラウザの操作ができる場合ではありますが、障害者にも使いやすいリモコンを作ることもできます。なんでもリモコンのブラウザ版です。


13. 動くものを作る

13.1 サーボモータを動かす

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

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

sweep.html:

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

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

knob.html:

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

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


14. 押しボタン信号機

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


signal.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>押しボタン信号機</title> <script src=webio2.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(D2,INPUT_PULLUP); // D2ピンはプルアップ入力 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ページと連動した指導ができるようになるかもしれません。


15. さまざまな例

15.1 温湿度計

 以下は、デジタル温湿度センサSHT31を使った温湿度計です。TEMPpinとHUMIpinは特別なアナログ入力ピンです。

thermometer.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>温湿度計</title> <script src=webio2.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,INPUT_ANALOG); // TEMPをアナログ入力に pinMode(HUMI,INPUT_ANALOG); // 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センサも利用できるようにした例です。

15.2 WebIOの動作テスト

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


(付録1) 入出力モジュール

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

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

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

部品表
名称 外観 備考
Seeeduino XIAO 秋月
ブレッドボード EIC-301 秋月
ブレッドボード ジャンパーワイヤ 15cm   秋月
ブレッドボード ジャンパーワイヤ EIC-J-S   秋月
LED 秋月
フルカラーシリアルLEDテープ SwitchScience
圧電スピーカー 秋月
プッシュスイッチ DS-660R-C 千石
抵抗 1/4W 4.7Ω, 100Ω, 220Ω, 470Ω, 1kΩ, 10kΩ 秋月
CDS(光センサ)秋月
温湿度センサ SHT31秋月
赤外線反射センサ LBR-127HLD   秋月
サーボモーター SG-90   秋月
モータードライバ DRV8830   秋月