1. 程式人生 > >智慧小車製作過程全紀錄: 三、軟體平臺--- Java 平臺串列埠通訊

智慧小車製作過程全紀錄: 三、軟體平臺--- Java 平臺串列埠通訊

嵌入式Linux上大部分都是有C/C++來做開發的,主要的原因還是為了效率,但本人最近幾年用Java比較多所以決定用Java比較多所以決定還是用Java來開發,再者個人認為現在硬體的發展,對於實時性沒有苛刻要求的環境Java足可以勝任了,所以言歸正傳,下面開始實際行動:

1、Java虛擬機器的安裝,OpenJava,Oracle Java都可以,這裡用Oracle Java為例

a. Ubuntu本身是Apt-get是沒有Oracle java的源的,所以首先的先新增源:

sudo sh -c ‘echo “deb http://ppa.launchpad.net/webupd8team/java/ubuntu

trusty main” >> /etc/apt/sources.list
sudo sh -c ‘echo “deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main” >> /etc/apt/sources.list
sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys EEA14886
b 用apt-get update安裝即可,Ubuntu core安裝Oracle Java時間比較久,要耐心等待
.sudo apt-get update
sudo apt-get install oracle-java8-installer

2、Java串列埠通訊

Java串列埠通訊用到了Rxtxcomm這個包,
下載地址:最新版本rxtx 2.2pre2 http://rxtx.qbang.org/wiki/index.php/Download
安裝說明
http://rxtx.qbang.org/wiki/index.php/Installation_on_Linux
官方給出了詳細的安裝說明,但是按照這個安裝說明,在呼叫這個包的時候提示jar包和動態連結庫.so 檔案不一致的問題,這是這個版本的一個bug,解決辦法如下:
首先用apt-get 安裝,已操作過的可以忽略此步驟
apt-get install librxtx-java
執行完此步驟後,會在/usr/lib/jni/目錄下發現動態連結庫檔案librxtxSerial.so,這時候用cp命令將此檔案拷貝到Java Home下
cp /usr/lib/jni/librxtxSerial.so /usr/lib/jvm/java-8-oracle/jre/lib/arm
接下來下載原始碼,按照官方按照教程,在原始碼目錄執行如下命令:
sh ./configure
make

執行完後會發現原始碼目錄下多出一個RXTXcomm.jar,在Java工程中直接引用即可,也可以到百度網盤下載https://pan.baidu.com/s/1jHD0aj0

執行完成後,在NanoPC T3呼叫官方示例中的listport還是找不到串列埠,後來研究程式碼發現Linux中的裝置是用檔案來表示的,所有的裝置都是放在/dev目錄下的,而NanoPC T3的串列埠是用ttySAC1,ttySAC3,ttySAC4這樣的方式命名的,而rxtxcomm的串列埠查詢沒有匹配這種命名方式,可以看/src/gnu/io/RXTXCommDriver.java 577~581行的程式碼
這裡寫圖片描述
只需要增加NanoPC T3的命名格式,重新編譯一下就好了,改完後的程式碼如下:

                    if(osName.equals("Linux"))
                    {
                        String[] Temp = {
                        "ttyS", // linux Serial Ports
                        "ttySA", // for the IPAQs
                        "ttySAC",///for friendarm
                        "ttyUSB", // for USB frobs
                        "rfcomm",       // bluetooth serial device
                        "ttyircomm", // linux IrCommdevices (IrDA serial emu)
                        };
                        CandidatePortPrefixes=Temp;
                    }

現在可以呼叫官方sample中的connect開啟串列埠了,開啟串列埠3和4的方式如下:
connect(“/dev/ttySAC3”);
connect(“/dev/ttySAC4”);
官方connect函式程式碼如下:

    public void connect ( String portName ) throws Exception  
    {  
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);  
        if ( portIdentifier.isCurrentlyOwned() )  
        {  
            System.out.println("Error: Port is currently in use");  
        }  
        else  
        {  
            CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);  

            if ( commPort instanceof SerialPort )  
            {  
                SerialPort serialPort = (SerialPort) commPort;  
                serialPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);  

                InputStream in = serialPort.getInputStream();  

                InputStreamReader reader = new InputStreamReader(in);  
                OutputStream out = serialPort.getOutputStream();

                BufferedReader r = new BufferedReader(reader);  

                //(new Thread(new ReaderSerial(r))).start();  
                //(new Thread(new WriterSerial(out))).start();

                rs=new ReaderSerial(r);
//                pool.execute(rs);
                rs.start();

                ws=new WriterSerial(out);
//                pool.execute(ws);
//               // ws.start();                                                

            }  
            else  
            {  
                System.out.println("Error: Only serial ports are handled by this example.");  
            }  
        }      
    }  

3、 最後針對小車驅動對串列埠通訊重新包裝了一下

SerialComm.java 串列埠操作的封裝類
ReaderSerial.java 串列埠讀的封裝類
WriterSerial.java 串列埠寫的類
DriverCMD.java 小車底盤控制命令類,配合Arduino 程式碼的串列埠命令

SerialComm.java

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class SerialComm {
    //private String  msg="";
    //private String lastmsg="";
    private  ReaderSerial rs=null;
    private WriterSerial ws=null;
    //ExecutorService pool = Executors.newCachedThreadPool(); 


    public void setMsg(String msg) {
        if (ws!=null){
            //System.out.println("******step 3");
            ws.setMsg(msg);         
            ws.writeSerial();
        }

    }

    public SerialComm()  
    {  
        super();  
    }  

    public void connect ( String portName ) throws Exception  
    {  
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);  
        if ( portIdentifier.isCurrentlyOwned() )  
        {  
            System.out.println("Error: Port is currently in use");  
        }  
        else  
        {  
            CommPort commPort = portIdentifier.open(this.getClass().getName(),2000);  

            if ( commPort instanceof SerialPort )  
            {  
                SerialPort serialPort = (SerialPort) commPort;  
                serialPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);  

                InputStream in = serialPort.getInputStream();  

                InputStreamReader reader = new InputStreamReader(in);  
                OutputStream out = serialPort.getOutputStream();

                BufferedReader r = new BufferedReader(reader);  

                //(new Thread(new ReaderSerial(r))).start();  
                //(new Thread(new WriterSerial(out))).start();

                rs=new ReaderSerial(r);
//                pool.execute(rs);
                rs.start();

                ws=new WriterSerial(out);
//                pool.execute(ws);
//               // ws.start();                                                

            }  
            else  
            {  
                System.out.println("Error: Only serial ports are handled by this example.");  
            }  
        }      
    }  
    public static void listPorts()  
    {  
        @SuppressWarnings("unchecked")  
        java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();  
        while ( portEnum.hasMoreElements() )   
        {  
            CommPortIdentifier portIdentifier = portEnum.nextElement();  
            System.out.println(portIdentifier.getName()  +  " - " +  getPortTypeName(portIdentifier.getPortType()) );  
        }         
    }  

    static String getPortTypeName ( int portType )  
    {  
        switch ( portType )  
        {  
            case CommPortIdentifier.PORT_I2C:  
                return "I2C";  
            case CommPortIdentifier.PORT_PARALLEL:  
                return "Parallel";  
            case CommPortIdentifier.PORT_RAW:  
                return "Raw";  
            case CommPortIdentifier.PORT_RS485:  
                return "RS485";  
            case CommPortIdentifier.PORT_SERIAL:  
                return "Serial";  
            default:  
                return "unknown type";  
        }  
        //return "";
    }        
}

ReaderSerial.java

import java.io.BufferedReader;
import java.io.IOException;

public class ReaderSerial extends Thread{

    BufferedReader in;  

    public ReaderSerial ( BufferedReader in )  
    {  
        this.in = in;  
    }  

    public void run ()  
    {  
        try  
        {  
            String line;  
            while ((line = in.readLine()) != null){  
                System.out.println(line);  
            }  
        }  
        catch ( IOException e )  
        {  
            e.printStackTrace();  
        }
    }
}

WriterSerial.java

public class WriterSerial/* extends Thread*/{

    private OutputStream out;  
    private String msg="";
    //private String lastmsg="";

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
        System.out.println("******step 4 this.msg= "+this.msg);
    }

    public WriterSerial ( OutputStream out)  
    {  
        this.out = out;  
    }  

    public void writeSerial(){
        if (msg != null && msg.length() != 0) {
            System.out.println("******before write,  the msg is " + msg);
            try {
                out.write(this.msg.getBytes());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
} 

DriverCMD.java

public class DriverCMD {
    private SerialComm driverCMDComm;
    private String stopcar="5";
    private String forward="1";
    private String backward="2";    
    private String right="3";
    private String left="4";
    private String automate="6";
    private String manual="7";

    public void openSAC(String portName){
        driverCMDComm=new SerialComm();
        try {
            driverCMDComm.connect(portName);
            System.out.println("******the SAC "+portName+" has been opened!");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void stop(){
        driverCMDComm.setMsg(stopcar);
    }
    public void forward(){
        //System.out.println("******step 2");
        driverCMDComm.setMsg(forward);      
    }
    public void backward(){
        driverCMDComm.setMsg(backward);
    }
    public void right(){
        driverCMDComm.setMsg(right);
    }
    public void left(){
        driverCMDComm.setMsg(left);
    }
    public void manual(){
        driverCMDComm.setMsg(manual);
    }
    public void automate(){
        driverCMDComm.setMsg(automate);
    }

    public void mycmd(String cmdstr){

        System.out.println("******"+cmdstr);
        try{
            if(cmdstr.equals("FORWARD")){
                forward();
                Thread.sleep(2000); 
                stop();
            }
            if(cmdstr.equals("BACKWARD")){
                backward();
                Thread.sleep(2000); 
                stop();
            }
            if(cmdstr.equals("RIGHT")){
                right();
                Thread.sleep(1000); 
                stop();
            }
            if(cmdstr.equals("LEFT")){
                left();
                Thread.sleep(1000); 
                stop();
            }
            if(cmdstr.equals("EXIT")){
                System.exit(0);
            }
            if(cmdstr.equals("STOP")){
                stop();
            }
            if(cmdstr.equals("MANUAL")){
                manual();
            }
            if(cmdstr.equals("AUTOMATE")){
                automate();
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(0);
        }

    }

    public void test(){

        try {
            System.out.println("******step 1");
            forward();
            Thread.sleep(3000);         
            backward();
            Thread.sleep(3000);
            right();
            Thread.sleep(3000);
            left();
            Thread.sleep(3000);
            stop();
            Thread.sleep(3000);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(0);
        }
    }
}

在main函式中可以按照如下方法呼叫:

public class Test {
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    SerialComm.listPorts();     

    DriverCMD driver =new DriverCMD();      
    driver.openSAC("/dev/ttySAC3");
    driver.test();
    //......
}

}