Shuichi Machida's Weblog

« [Sun SPOT で外付けLEDを点滅... | メイン | [Sun SPOT(16)] SDC... »

http://blogs.sun.com/machida/date/20080310 2008年 3月 10日 月曜日

[Sun SPOT Demo(2)] LCD (μVolt SGD-A)をシリアル接続してみる。

今回は、Sun SPOTにLCDをつないで何か表示させてみようと思います。単なる "Hello World"だとつまらないので、eDemoボード上の温度センサーを使って簡単な温度計を作ってみます。

Sun SPOTのeDemoポート上の汎用I/Oピン D0, D1を使うと簡単に非同期シリアル通信(UART)ができるので、LCDは

  • シリアル通信をサポートする
  • マイコン系の電源(3~5V)で動作し、マイコンと直結できる

ものを使うと簡単につなげられそうです。

※ マイコンのUARTは電圧レベル+5Vや+3.3Vで動作するため、PCなどで使うRS-232Cインタフェース(+-12Vで動作)とは直結できません。この場合、間にレベルコンバータ(MAX232などがよく使われるようです)を入れて電圧を変換する必要があり、面倒です。

# UART で使用するI/Oピン

最大baud rate は 38400、data 8bits、no parity、1or2 stop bitsです。

今回は、μVolt SGD-A というLCDを使用することにします。Strawberry Linux 通販で購入しました。4480円です。ちなみにノキア携帯電話の液晶を流用しているそうで、確かに携帯の画面っぽい。。

# 4つのピン Vcc、Rx、Tx、GND  にジャンプワイヤーケーブルを半田づけしています。


では早速接続、といきたいところでしたが、データシートを読んでいると、Page6 のVccの説明の部分になにやら怪しげな記述が:

Vcc: Input.  DC power voltage required from 3V to 5V.  It is necessary to place an external 1uF condenser near this pin.

コ、コンデンサが必要。。。しかも回路書いてないし、、。いろいろ調べた結果、どうやらこれは

  • 電源に並列接続するバイパスコンデンサ(パスコン)

のことだと判明。

接続方法も分かったところで、今回も例によってブレッドボードを使って電子回路を組んでみます。

# コンデンサは+-の向きに注意します


。。。

完成です!

メッセージと温度が表示されています :-)

 

# 拡大


。。。

プログラムは例によって、「サーボモータを動かしてみる-その1」で書いた手順で NetBeans IDE を使って開発しました。

# メイン部分のプログラム(MIDlet)

package org.sunspotworld;

import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.ITemperatureInput;
import com.sun.spot.util.*;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class StartApplication extends MIDlet {
    private ILcd lcd;  // LCD
    private ITemperatureInput tempInput;  // 温度センサー
    
    protected void startApp() throws MIDletStateChangeException {
        new BootloaderListener().start();

        // SGD-A にアクセスするためのクラスのインスタンスを生成
        lcd = new SGDALcd();
        // 温度センサーにアクセスするためのクラスのインスタンスを取得
        tempInput = EDemoBoard.getInstance().getADCTemperature();
        
        try {
            // LCD にメッセージを表示
            lcd.clear();
            lcd.setText(2, 10, "Hi! This is a Sun SPOT!!" );

        } catch (Exception ex) {
            ex.printStackTrace();
            Utils.sleep(2000L);
        }
        
        // 10秒毎に温度を取得してLCDに表示
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                try {
                    double temp = tempInput.getCelsius();
                    String tempS = format(temp);
                    lcd.setText(4, 38, tempS + " deg C" );
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }, 0L, 10000L);

        // USBケーブルでPCにつないでいない状態で電源が切れないように、
        // 自動電源管理によるdeep sleepをオフにする
        ISleepManager sleepManager = Spot.getInstance().getSleepManager();
        sleepManager.disableDeepSleep(); 
    }
    
    // 温度を小数点以上2桁、以下1桁の文字列にフォーマットする
    // 例) 22.5, - 3.0, -10.5
    private String format(double temp) throws Exception {
        String tempS = String.valueOf(temp);
        StringBuffer buffer = new StringBuffer();        
        if (tempS.indexOf("-" ) != -1) {
            buffer.append("-" );
            tempS = tempS.substring(1);
        } else {
            buffer.append(" " );
        }
        
        int pos = tempS.indexOf("." );
        if (pos != -1) {
            tempS = tempS.substring(0, pos+2);
        }
        if (tempS.length() == 3) {
            buffer.append(" " );
        }
        buffer.append(tempS);
        
        return buffer.toString();
    }
    
    protected void pauseApp() {
    }

    protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
    }
}


ILcd は、LCDにアクセスするためのインタフェースを定義します。

package org.sunspotworld;

public interface ILcd {
    /** LCDの画面をクリア */
    void clear();
    /** xPos, yPos で指定されたピクセルに画面のポインタを移動する */
    void locate(int xPos, int yPos);
    /** 現在の画面ポインタの位置に引数で指定された文字列を表示する */
    void setText(String text);
    /** xPos, yPos で指定された位置に引数で指定された文字列を表示する */
    void setText(int xPos, int yPos, String text);
}

SGDALcd は ILed インタフェースの実装クラスで、SGD-A にアクセスするための機能を実装します。なお、ここでは最小限の機能のみ実装しています。このほか、ビットマップや線を表示したり、音を出したりと、SGD-Aはかなりの機能を持っています。

package org.sunspotworld;

import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.util.Utils;
import java.io.IOException;

public class SGDALcd implements ILcd{
    // ここでは、今回実際に使用するコマンドのみ定義
    public static final byte COMMAND_CLS = (byte)'N';
    public static final byte COMMAND_LOCATE = (byte)'P';
    public static final byte COMMAND_STRING = (byte)'S';
    
    // シリアルのパラメータ
    // baud: 9600bps, 8bits, no parity, 1 stop bit
    public static final int BAUD = EDemoBoard.SERIAL_SPEED_9600;
    public static final boolean TWO_STOPBIT = false;

    private EDemoBoard demo;

    public SGDALcd() {
        demo = EDemoBoard.getInstance();
        demo.initUART(BAUD, TWO_STOPBIT);
    }

    public void clear() {
        demo.sendUART(COMMAND_CLS);
        // This command needs aprox. 61 ms to execute.
        Utils.sleep(61L);
    }

    public void locate(int xPos, int yPos) {
        if (xPos < 0 || xPos > 83)
            throw new IllegalArgumentException("x out of range(0-83): " + xPos);
        if (yPos < 0 || yPos > 47)
            throw new IllegalArgumentException("y out of range(0-47): " + yPos);
        
        demo.sendUART(COMMAND_LOCATE);
        demo.sendUART((byte)xPos);
        demo.sendUART((byte)yPos);

    }

    public void setText(String text) {
        byte[] data = text.getBytes();
        if (data.length > 255)
            throw new IllegalArgumentException("text length out of range: " + data.length);
        
        demo.sendUART(COMMAND_STRING);
        demo.sendUART((byte)data.length);

        System.out.println("sending " + data.length + " bytes of data..." );
        for (int i = 0; i < data.length; i++) {
            System.out.print((char)data[i] + "(" + Integer.toHexString(data[i]) + " ) " );
            demo.sendUART(data[i]);
            Utils.sleep(1L);
        }
        System.out.println();
    }

    public void setText(int xPos, int yPos, String text) {
        locate(xPos, yPos);
        setText(text);
    }    
    
    private void send(final byte data) {
        demo.sendUART(data);
    }
    
    private byte receive(final int timeout) throws IOException {
        long startTime = System.currentTimeMillis();
        while (true) {
            try {
                byte data = demo.receiveUART();
                return data;
            } catch (IOException ex) {
                if ((timeout > 0) & (System.currentTimeMillis() - startTime) > timeout) {
                    throw ex;
                }
            }
            Utils.sleep(10L);
        }
    }
}

今回はコンデンサが必要だったため回路が少しだけ複雑になりましたが、プログラムは非常に簡単でした。

投稿されたコメント:

私も安価なLCDパネルを付けてみました.
http://www.klab.ai.kyutech.ac.jp/sunspotjp/modules/d3forum/index.php?topic_id=20

シリアル接続ではないのでプログラムは汚くなり
ましたが.LCDは入手し易いものだと思います.

Posted by koide on 8月月 11日, 2008年 at 10:28 午前 JST #

コメント
  • HTML文法 不許可

Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.