ところで、これだとLEDは点灯し続けるだけですし、仮にスイッチを付けたとしても手でOn、Offしなければ点滅しないのであまり面白くありません。図4のスイッチと同じ働きを Sun SPOTで実現するにはどうすればいいでしょう?
Sun SPOTを含め、マイコンには一般的に汎用入出力ポート(図2のD0~D4)というインタフェースが用意されていて、出力をプログラムから制御することで、出力ポートに接続した負荷(LED、リレー、モータ、トランジスタなど)を駆動することができます。出力値としてはHighまたはLowの2値の電圧をとります(例えば High(3V)、Low(0V)など)。
リスト4: ToneGeneratorDemoSpot1 スピーカーを使って”ドレミファソラシド”を演奏する Sun SPOTアプリケーション
/*
* Copyright (c) 2006, 2007 Sun Microsystems, Inc.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
package org.sunspotworld.demo;
import com.sun.spot.sensorboard.EDemoBoard;
import javax.microedition.midlet.*;
/**
* ToneGeneratorDemoSpot1:
* 外付けスピーカーを使って"ドレミファソラシド" と繰り返し演奏する
* Sun SPOTアプリケーション
* 付属のデモアプリ GPIOToneGeneratorSampleCode をベースに作成
*/
public class ToneGeneratorDemoSpot1 extends MIDlet {
private MelodyPlayer player; // メロディ演奏用クラス
// 長調の音階
static int major[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
/** アプリケーション起動時にVMによって最初に呼び出されるメソッド */
protected void startApp() throws MIDletStateChangeException {
// メロディ演奏用クラスのインスタンスを生成
// 今回はスピーカーを汎用入出力ポート D0に接続する
player = new MelodyPlayer(EDemoBoard.D0);
int start_note = 21; // 開始の音 C or "ド"
try {
while(true){
// "ドレミファソラシド" を繰り返す
for (int i=0;i<major.length;i++) {
player.playNote(major[i] + start_note, 500, 80);
}
}
} catch (Exception ex) { //A problem in reading the sensors.
ex.printStackTrace();
notifyDestroyed();
}
}
protected void pauseApp() {
}
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
}
}
リスト5: MelodyPlayer - 音の生成用クラス
/*
* Copyright (c) 2006, 2007 Sun Microsystems, Inc.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
package org.sunspotworld.demo;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ToneGenerator;
import com.sun.spot.util.Utils;
import java.io.IOException;
/**
* MelodyPlayer:
* メロディ演奏用クラス
* Sun SPOTの汎用入出力ポートに接続したスピーカーを使ってメロディを演奏する
* 付属のデモアプリ GPIOToneGeneratorSampleCode をベースに作成
*/
public class MelodyPlayer {
private ToneGenerator toneGen; // トーンジェネレータ
/**
* @param pinId スピーカーで使用する汎用入出力ポートのID
*/
public MelodyPlayer(int pinId) {
// トーンジェネレータの生成
toneGen = new ToneGenerator(EDemoBoard.getInstance().getIOPins()[pinId]);
}
/**
* note で指定された音を演奏する
* @param note The note number (0=A110)
* @param dur 全演奏時間
* @param len 音を鳴らす時間
*/
public void playNote(int note, int dur, int len) {
int on = dur * len/100;
// note の値から、その音の周波数に対応する周期を取得する
toneGen.setPeriod(note2period(note));
toneGen.setDuration(on);
toneGen.beep();
Utils.sleep(dur);
}
// 一番下のオクターブの音の周期
private static final int tone_map[] = {
4545, 4290, 4050, 3822, 3608, 3405, 3214, 3034, 2863, 2703, 2551, 2408
};
/**
* note で指定された音の周期を計算する
**/
private static int note2period(int note) {
int octave = note/12;
return tone_map[note%12] / (1<<octave);
}
}
一方、スピーカー側の Sun SPOTアプリケーションはStep 2で作成したものを修正したもので、メッセージ受信の機能を追加しています。リスト9~11に全ソースコードを示します。
クラス名
説明
1
ToneGeneratorDemoSpot2
受信した演奏用データの音をスピーカーを使って演奏するSun SPOTアプリケーション
2
MessageReceiver
メッセージ受信用クラス
3
MelodyPlayer
音の生成用クラス
リスト9: ToneGeneratorDemoSpot2 - 受信した演奏用データの音をスピーカーを使って演奏する Sun SPOTアプリケーション
/*
* Copyright (c) 2006, 2007 Sun Microsystems, Inc.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
package org.sunspotworld.demo;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.util.BootloaderListener;
import java.io.IOException;
import javax.microedition.midlet.*;
/**
* ToneGeneratorDemoSpot2:
* BendSensorDemoSpot2 がブロードキャストするメッセージ(演奏データ)を
* 受信して、外付けスピーカーを使って演奏するSun SPOTアプリケーション
* 付属のデモアプリ GPIOToneGeneratorSampleCode をベースに作成
*/
public class ToneGeneratorDemoSpot2 extends MIDlet {
// メッセージ受信で使用する無線通信プロトコル
private final String PROTOCOL = "radiogram://:240";
private MelodyPlayer player; // メロディ演奏用クラス
private MessageReceiver receiver; // メッセージ受信用クラス
/* アプリケーション起動時にVMによって最初に呼び出されるメソッド */
protected void startApp() throws MIDletStateChangeException {
new BootloaderListener().start();
try {
initAndRun();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/* メイン部分 */
private void initAndRun() throws IOException {
// メロディ演奏用クラスのインスタンスを生成
// 今回はスピーカーを汎用入出力ポート D0に接続する
player = new MelodyPlayer(EDemoBoard.D0);
// データ受信用クラスのインスタンスを生成
receiver = new MessageReceiver(PROTOCOL);
try {
// メッセージを受信する度に、受け取った演奏データの音を演奏する
while(true){
try {
int note = receiver.getNote();
if (note != -1) {
System.out.println("Playing note...: " + note);
player.playNote(note, 500, 80);
}
} catch (IOException ex) {
System.out.println("Error receiving a datagram: " + ex.getMessage());
}
}
} catch (Exception ex) { //A problem in reading the sensors.
ex.printStackTrace();
notifyDestroyed();
}
}
protected void pauseApp() {
}
protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
}
}
/*
* Copyright (c) 2006, 2007 Sun Microsystems, Inc.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**/
package org.sunspotworld.demo;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ToneGenerator;
import com.sun.spot.util.Utils;
import java.io.IOException;
/**
* MelodyPlayer:
* メロディ演奏用クラス
* Sun SPOTの汎用入出力ポートに接続したスピーカーを使ってメロディを演奏する
* 付属のデモアプリ GPIOToneGeneratorSampleCode をベースに作成
*/
public class MelodyPlayer {
private ToneGenerator toneGen; // トーンジェネレータ
/**
* @param pinId スピーカーで使用する汎用入出力ポートのID
*/
public MelodyPlayer(int pinId) {
// トーンジェネレータの生成
toneGen = new ToneGenerator(EDemoBoard.getInstance().getIOPins()[pinId]);
}
/**
* note で指定された音を演奏する
* @param note The note number (0=A110)
* @param dur 全演奏時間
* @param len 音を鳴らす時間
*/
public void playNote(int note, int dur, int len) {
int on = dur * len/100;
// note の値から、その音の周波数に対応する周期を取得する
toneGen.setPeriod(note2period(note));
toneGen.setDuration(on);
toneGen.beep();
Utils.sleep(dur);
}
// 一番下のオクターブの音の周期
private static final int tone_map[] = {
4545, 4290, 4050, 3822, 3608, 3405, 3214, 3034, 2863, 2703, 2551, 2408
};
/**
* note で指定された音の周期を計算する
**/
private static int note2period(int note) {
int octave = note/12;
return tone_map[note%12] / (1<<octave);
}
}
アプリケーションの実行結果を図21に示します。
図21: Step 3の実行結果
画像だとよく分からないと思いますので、以下の動画もご覧下さい。
Playing with a Bend Sensor and a Speaker
■まとめ
第4回『入出力ポートにセンサーやアクチュエータを取り付けてみよう』はいかがでしたか?ぜひ、身近にあるセンサーやデバイスを Sun SPOTにつないで、みなさんのセンサーネットワークを創造してみてください。