Javaシリアル通信によるLED表示データの制御例


注:本文はオリジナルの文章です.転載するときは転載先を明記してください.
多くのアプリケーションでは、組み込みシステム、センサ、スイッチングデバイスなどの外部デバイスとpcマシンを使用してデータ通信を行う必要があります.その中で、最もよく使われるインターフェースはRS-232シリアルポートとパラレルポートです.SUNのCommAPIは、一般的なRS 232シリアルポートとIEEE 1284パラレルポート通信のサポートをそれぞれ提供しています.
Javaシリアル通信の構成および通信モードについてはsunのdemoおよびネット上に多くの具体的な例がある.
以下は私が1つの番号を呼ぶ機能のモジュールを開発する時にシリアル通信を通じてLEDの表示を制御する例で、初めて関連する開発を行うため、1つのとても簡単な機能が実際に開発する中でいくつかの問題に出会ったように見えて、本人の解決の方式がみんなに役に立つことができることを望んで、みんながもっと良い解決の方式を提出することができることをも望みます.
まず、LEDディスプレイメーカーが提供する通信プロトコルを見てみましょう.
---リモート制御モノクロ、モノクロ、ミックススクリーン1、いずれかの特定のアドレスに対して送信される情報は、イントラコードフレーム(7 f/7 e)、デジタルフレーム(6 f/6 e)、タイミングフレーム(5 f)、時間フレーム(4 f)のうちの1つまたは複数からなり、終了時に終了フレームが送信される.二、フレーム構造:フレームごとに84バイトで構成される.1.イントラコードフレーム:一幕は一緒の開始フレームとゼロ或いは複数の中間フレームから構成され、一度に送信すると複数の幕があることができる.1)開始フレーム:アドレス(1バイト)+フレーム制御7 F(1バイト)+幕番号(1バイト)+COMMAND(8バイト)+内符号/ASCII(73バイト)2)中間フレーム:アドレス(1バイト)+フレーム制御7 E(1バイト)+幕番号(1バイト)+COMMAND(8バイト)+内符号/ASCII(73バイト)3)COMMAND:最初の4バイトは定義されておらず、後の4バイトは順次アニメーション(0~4)である.移入および移出(各16種)、速度(0~255)、追加(D 3連続、D 2停止、D 0点滅、D 4時間、D 6一時停止、D 7アニメーション)4)内符号/ASCII構造:a、内符号4バイト、順に制御バイト(D 7ワイド/ノーマル、D 4グリーン、D 5赤、D 3太字、D 2細体反白、D 1太字反白、D 0細体)、内符号高位、内符号低位、b、ASCII 2バイトは、制御バイト(D 7ワイド/ノーマル、D 5緑、D 4赤、D 3太字、D 2細体反転白、D 1太字反転白、D 0細体)の順であり、ASCIIコード2、デジタルフレーム:一斉開始フレームとゼロまたはマルチ中間フレームからなる.1)開始フレーム:アドレス(1バイト)+フレーム制御6 F(1バイト)+データ(82バイト)2)間フレーム:アドレス(1バイト)+フレーム制御6 E(1バイト)+データ(82バイト)3、タイミングフレーム:1フレームからなる.開始フレーム:アドレス(1バイト)+フレーム制御5 F(1バイト)+データ(48バイト)+無効データは8個のタイマーを含み、6バイト毎に、開閉(0はOFF、1はON)、日付(0~6はsunday~satday、7は毎日)、時間(0~23)、分(0~59)、開始幕、終了幕となる.4、時間フレーム:1フレームからなる.アドレス(1バイト)+フレーム制御4 F(1バイト)+年高二位(1バイト)+年低二位(1バイト)+月(1バイト)+日(1バイト)+時(1バイト)+分(1バイト)+曜日(1バイト)+無効データ日付はすべて十進法で表され、曜日0は日曜日である.4、終了フレーム:1フレームからなる.アドレス(1バイト)+フレーム制御7 D(1バイト)+無効データ(82バイト)3)移入、移出モード:各16パターン、任意に組み合わせ可能.三、移入モード:移出モード:モード0:移入←移出←モード1:移入→移出→モード2:移入↑移出↑モード3:移入↓移出↓モード4:跳入←跳出←モード5:展開→展開→モード6:展開←展開←モード7:展開↑展開↑モード8:展開↓展開↓モード9:展開←→展開←モード10:展開→←展開→←モード11:展開↑↓展開↑モード12:展開↓展開↑展開↓モード13:入即出モード14:予備モード15:ランダム(ループ設定済み)ランダム(ループ設定済み)4、通信カードインターフェース:1)通信カードを初期化:a、0 xFFをアドレス211 H bに書き込み、211 Hから1バイトを読み込み、D 3が‘1’であるか否かを判断し、‘0’であればこのステップcを繰り返し、0 x 00をアドレス211 H dに書き込み、211 Hから1バイト読み込んでD 3が‘0’であると判断し、‘1’であればこのステップeを繰り返し、初期化完了2)書き込みデータアドレス:210 H 3)読み出し状態アドレス:211 H状態フラグ:D 0書き込み許可、高電平有効注:未使用バイトは0 X 00.232口:8ビットデータビット、1ビット停止ビット、無効なビット検査、ボーレートは9600.*フレームごとに84バイトで、1幕ごとに7 Fフレームを出して、18字を超えるストライプスクリーン、1幕ごとに1つの7 Eフレームをプラスして、すべての幕が終わった後に、7 Dフレーム(終了フレーム)を出します
シリアル通信に関連する主要コードの一部:
import java.io.*;
import javax.comm.*;

public class SerialBean {
    static SerialBean bean;
    String PortName;
    CommPortIdentifier portId;
    SerialPort serialPort;
    OutputStream out;
    InputStream in;


    public String getPortName() {
        return PortName;
    }

    public void setPortName(String portName) {
        PortName = portName;
    }

    private SerialBean(int PortID) {
        PortName = "COM" + PortID;

    }

    public static SerialBean getInstance() {
        if (bean == null) {
            if (!portInit(1))
                return null;
        }
        return bean;
    }

    public static boolean portInit(int port) {
        if (bean != null) {
            bean.ClosePort();
        }
        bean = new SerialBean(port);
        return bean.initialize();

    }


    public boolean initialize() {
        try {
            portId = CommPortIdentifier.getPortIdentifier(PortName);
            try {
                serialPort = (SerialPort)
                        portId.open("SerialBean", 3000);

            } catch (PortInUseException e) {
                e.printStackTrace();
                return false;
            }
            try {
                in = serialPort.getInputStream();
                out = serialPort.getOutputStream();
            } catch (IOException e) {
                return false;
            }
            try {
                serialPort.setSerialPortParams(9600,
                        SerialPort.DATABITS_8,

                        SerialPort.STOPBITS_1,
                        SerialPort.PARITY_NONE);
            } catch (UnsupportedCommOperationException e) {
                e.printStackTrace();
                return false;
            }
        } catch (NoSuchPortException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }


    public void writePort(byte[] bytes) {
        for(byte b:bytes){
            writePort(b);
        }

    }

    public void writePort(byte b) {
        try {
            out.write(b);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void ClosePort() {
        if (out != null) {
            try {
                out.close();
                in.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        serialPort.close();
    }
}

 
 LEDにデータコードを送信し、以下のテストコードは通信プロトコルに関わるモードや命令の大部分をプログラムに書き込んで、再構築する必要がある.
 static int number = 0;
    static byte target = 0x00;
    static byte font = (byte) 0;     //    
    static int LED_LENGTH = 16;      //  LED      (  )
    static byte MODULE=0x00;         //    
    static byte[] beg = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    byte[] end = new byte[]{0x7D,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00
    };

    public void display(String meg) {
        SerialBean sb = SerialBean.getInstance();
        int bytes = LED_LENGTH * 4;
        writeNext(sb);
       //   LED                2 ,      
        for (int i = 0; i < meg.length(); i++) {
            String s = meg.substring(i, i + 1);
            byte[] b = s.getBytes();
            if (b.length == 2) {
                if (bytes < 4) {
                    for (int n = 0; n < bytes + 73 - LED_LENGTH * 4; n++) {
                        sb.writePort(0x00);
                    }
                    bytes = LED_LENGTH * 4;
                    writeNext(sb);
                }
                sb.writePort(font);
                sb.writePort(s.getBytes());
                sb.writePort(0x00);
                bytes -= 4;
            } else if (b.length == 1) {
                if (bytes < 2) {
                    for (int n = 0; n < bytes + 73 - LED_LENGTH * 4; n++) {
                        sb.writePort(0x00);
                    }
                    bytes = LED_LENGTH * 4;
                    writeNext(sb);
                }

                sb.writePort(font);
                sb.writePort(meg.charAt(i));
                bytes -= 2;

            }
        }
        for (int n = 0; n < bytes + 73 - LED_LENGTH * 4; n++) {
            sb.writePort(0x00);
        }
        sb.writePort(target);
        sb.writePort(end);
        sb.ClosePort();
    }

    private void writeNext(SerialBean sb) {
        sb.writePort(target);
        sb.writePort(0x7F);
        sb.writePort((byte) number++);
        sb.writePort(beg);
        sb.writePort(MODULE);
    }

 以上のコードは書き終わったばかりで、テストを行うのは基本的に問題がないと思っていましたが、テストをするとLEDに何の反応もなく、データを送信していないと思っていましたが、いくつかのシリアルポートモニタリングツールを採用して、データが送信されたことに気づきました.ネット上でも何の资料も调べられず、しばらく振り回していたが、パソコンのデータの送信が速すぎてLEDでデータを処理していた时にデータフレームが失われたのではないかと思い、バイトごとに时间の遅延を加えた结果、すぐに反応し、遅延时间を适切に调整してOKした.
public void writePort(byte b) {        try {            out.write(b);            out.flush();            Thread.sleep(10);        } catch (Exception e) {            e.printStackTrace();        }    }
(後で考えてみると、LEDがデータを処理する際にキャッシュ操作を採用する可能性があり、pcが情報を送信する際にまずキャッシュ領域に送信すると、LEDがキャッシュを読み出して処理データを開始するが、pcが情報を送信するのが速すぎてledがデータを処理しきれず、データの大きさがLEDのキャッシュ領域を超えている場合、以前のデータを上書きするという質問が発生する可能性がある問題、以上は推測にすぎないが、その後プログラムのデバッグが終わっても気にしない)