樹莓派3配置串口,JAVA實現串口通訊(2016年3月版本,重點提示,3月之後的版本配置貌似不一樣)

因爲公司產品的需求,需要用到樹莓派上的串口功能,但樹莓派3的串口直接不能用,因爲在樹莓派3用的CPU中本身有兩個串口,一個是硬件串口(PL011 UART),一個是迷你串口(mini-uart),在樹莓派2B和B+等老版本上,樹莓派將硬件串口分配給了GPIO14和GPIO15,因此可以直接使用這個串口。但在樹莓派3上,多了一個然並卵的藍牙模塊(起碼我感覺丫就是然並卵的東西,我們有自己的藍牙產品,完全不用這個多餘的貨,各位有其他用的另當別論了),官方將硬件串口無私的給了藍牙,而將一個沒有時鐘源,必須由內核提供時鐘參考源的“迷你串口”分配給了GPIO的串口,這樣以來由於內核的頻率本身是變化的,就會導致“迷你串口”的速率不穩定,這樣就出現了無法正常使用的情況。
網上給的提示是,關閉藍牙,直接回復硬件串口的GPIO,所以呢,如果想用串口的話,還是放棄藍牙吧。
還有一點噁心的,我的測試機用的是2016-03-18-raspbian-jessie,而現在我們正式環境用的是2016-09-23-raspbian-jessie-lite,本來在測試機調試好的,到生產環境就SB了,完全不通,所以各位看這個教程的時候,請務必先確認一下自己系統的版本,對於3月之後版本的,等我研究透了再另行發帖,到時候我會附在本帖後面。目前網上沒找到關於3月之後版本怎麼做串口的,大家靜候吧。

廢話過後,乾貨來了!

第一步,我們需要修改配置文件,
sudo vi /boot/config.txt
在最下面添加兩行內容
dtoverlay=pi3-miniuart-bt-overlay
force_turbo=1
這裏需要注意以下,做這一步的時候先去看看/boot/overlays下面是不是有一個叫pi3-miniuart-bt-overlay.dtb的文件,或者pi3-miniuart-bt.dtb,都行,根據文件名不同,上面配置的那個參數也不一樣
如果沒有,去下載以下,地址 http://ukonline2000.com/?attachment_id=881

第二步,配置串口
sudo vi /boot/cmdline.txt
把裏面的內容改成
dwc_otg.lpm_enable=0 console=serial1,115200  console=tty1 root=/dev/mmcblk0p2  kgdboc=serial1,115200 rootfstype=ext4 elevator=deadline fsck.repair=yes  rootwait
具體爲啥,我還沒來得及研究,有明白人可以回覆一下,或者等我有空了補上這塊內容

第三步,關閉藍牙
sudo systemctl disable hciuart

第四步,修改串口指向
sudo vi /lib/systemd/system/hciuart.service
將 “ttyAMA0”修改爲“ttyS0”就下面圖這樣子

只改這一樣就行了,下面的那個不用管他
如果這時候你看到的是After=def-serial1.device,那說明你是3月之後的版本,這篇教程不適用

第五步,重啓樹莓派,就OK了

還有一點需要提示的,如果你安裝的是精簡版(尾綴-lite的鏡像),有可能串口沒有打開,這個可以先去驅動裏確認一下
ls /dev看看有沒有ttyAMA0,如果沒有,就說明沒打開,這時候去配置中開一下就有了
sudo raspi-config
選擇Advanced Options -> Serial
選擇yes就行了
完事之後重啓樹莓派,就有ttyAMA0了


我們用的是JAVA開發程序,所以才做串口必須藉助一些開發包,當然首選應該是Pi4J,畢竟正在做這塊的翻譯嘛,但是我並沒用他,而是用了RXTX,比較方便。
先說安裝步驟,Windows下直接下載包就可以用了,樹莓派下需要安裝一下。

第一步,下載包

第二步,解壓
unzip rxtx-2.1-7r2.zip

第三步,修改參數
首先需要獲得一個版本號
uname -r
(我的是4.1.19-v7+)
sudo vi /usr/include/linux/version.h
最後面加一行
#define UTS_RELEASE "4.1.19-v7+"
那個版本號就是咱們剛纔查出來的版本號

第四步,修改安裝文件參數
在解壓好的包中,有個configure,我們要把裏面的所有1.2*|1.3*|1.4*|1.5*,都改成1.2*|1.3*|1.4*|1.5*|1.6*|1.7*|1.8*
這一步建議到Windows下面修改,大概有個四五處吧
sudo sh ./configure
make
sudo make install
最後一樣記得加 sudo
出現 /usr/bin/install -c RXTXcomm.jar /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/ext/就表示安裝成功了!

還有一點要注意的,安裝貌似需要JDK8環境,7試驗失敗,不知道能不能裝,建議大家還是升級一下吧

下面,開始寫程序
RXTX只支持ttyS開頭的設備,而我們要跟串口通訊用的是 ttyAMA0,所以在此之前還要做一下映射
sudo ln -s /dev/ttyAMA0 /dev/ttyS45
45只是我隨便起了個名字而已,大家隨意吧
樹莓派的串口是TTL電平的,所以測試的時候需要注意以下

importgnu.io.CommPortIdentifier;
importgnu.io.PortInUseException;
importgnu.io.SerialPort;
importgnu.io.SerialPortEvent;
importgnu.io.SerialPortEventListener;
importgnu.io.UnsupportedCommOperationException;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.util.Enumeration;
importjava.util.TooManyListenersException;
publicclassSerial {
     privateSerialPortport=null;
     privateInputStreamin=null;
     privateOutputStreamout=null;
     privateSerial() {}
     privateSerial(String name) {
          //獲得本地所有串口列表,這裏其實只能獲得ttyS開頭的串口
          Enumeration<CommPortIdentifier> portList =CommPortIdentifier.getPortIdentifiers();
          while(portList.hasMoreElements()){
              //獲得串口的標識符
              CommPortIdentifier portId = portList.nextElement();
              //通過標識符得到串口名字,並判斷這個名字是不是我們需要的那個串口
              if(portId.getName().equals("/dev/"+name)){
                   SerialPort p=null;
                   try{
                        //如果確實是我們需要的串口,則打開這個串口
                        //open(串口占用進程名稱,串口等待超時時間)
                        p = (SerialPort) portId.open("TTSTest", 2000);
                        //給串口一個數據到達偵聽(觸發器)
                        p.addEventListener(newEventListener());
                        //把數據到達通知打開
                        p.notifyOnDataAvailable(true);
                        //設置串口的波特率,參數依次是(波特率,數據位,停止位,校驗位)
                        p.setSerialPortParams(9600,SerialPort.DATABITS_8, SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
                        //獲得輸入輸出流,方便操作。
                        out= p.getOutputStream();
                        in= p.getInputStream();
                        port=p;
                   }catch(PortInUseException e) {
                        e.printStackTrace();
                   }catch(TooManyListenersException e) {
                        e.printStackTrace();
                   }catch(UnsupportedCommOperationException e) {
                        e.printStackTrace();
                   }catch(IOException e) {
                        e.printStackTrace();
                   }
              }
          }
     }
     /**
      * 打開串口
      *
      *@paramport
      */
     publicstaticfinalSerial open(String name) {
          Serial serial =newSerial(name);
          if(serial.port!=null){
              returnserial;
          }
          returnnull;
     }
     
     /**
      * 發送數據。
      *@paramdata
      */
     publicvoidsend(byte[] data){
          try{
              out.write(data);
              out.flush();
          }catch(IOException e) {
              e.printStackTrace();
          }
     }
     
     /**
      * 關閉串口。
      */
     publicvoidclose(){
          //當然,這裏可以做一下事件偵聽,再給close加個參數,這樣在串口異常報錯的時候能能捕獲到了。
          port.close();
          port=null;out=null;in=null;
     }
     
     privateclassEventListenerimplementsSerialPortEventListener{
          @Override
          publicvoidserialEvent(SerialPortEvent event) {
              switch(event.getEventType()) { 
              //這些屬性應該跟串口特性有關,我還沒搞清楚,暫時不解釋
            caseSerialPortEvent.BI:
            caseSerialPortEvent.OE:
            caseSerialPortEvent.FE:
            caseSerialPortEvent.PE:
            caseSerialPortEvent.CD:
            caseSerialPortEvent.CTS:
            caseSerialPortEvent.DSR:
            caseSerialPortEvent.RI:
            caseSerialPortEvent.OUTPUT_BUFFER_EMPTY:
                break
            caseSerialPortEvent.DATA_AVAILABLE:    //獲取到串口返回信息 
                byte[] data =newbyte[512];
                intlen=0;
                try{
                        while((len=in.read(data))>=0){
                             //這裏處理你獲得的數據即可。
                        }
                   }catch(IOException e) {
                        //讀信息報錯後直接關閉串口
                        close();
                        e.printStackTrace();
                   }
                //如果len讀到-1的話,說明串口出問題了,這裏直接關閉就行了
                //以下的部分自由發揮吧
                 close();
                break
            default
                break
             } 
          }
     }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章