树莓派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下直接下载包就可以用了,树莓派下需要安装一下。

第一步,下载包
wget http://rxtx.qbang.org/pub/rxtx/rxtx-2.1-7r2.zip

第二步,解压
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电平的,所以测试的时候需要注意以下

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;
public class Serial {
      private SerialPort port = null ;
      private InputStream in = null ;
      private OutputStream out = null ;
      private Serial() {}
      private Serial(String name) {
           //获得本地所有串口列表,这里其实只能获得ttyS开头的串口
          Enumeration 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( new EventListener());
                         //把数据到达通知打开
                        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();
                   }
              }
          }
     }
      /**
      * 打开串口
      *
      * @param port
      */
      public static final Serial open(String name) {
          Serial serial = new Serial(name);
           if (serial. port != null ){
               return serial;
          }
           return null ;
     }
     
      /**
      * 发送数据。
      * @param data
      */
      public void send( byte [] data){
           try {
               out .write(data);
               out .flush();
          } catch (IOException e) {
              e.printStackTrace();
          }
     }
     
      /**
      * 关闭串口。
      */
      public void close(){
           //当然,这里可以做一下事件侦听,再给close加个参数,这样在串口异常报错的时候能能捕获到了。
           port .close();
           port = null ; out = null ; in = null ;
     }
     
      private class EventListener implements SerialPortEventListener{
           @Override
           public void serialEvent(SerialPortEvent event) {
               switch (event.getEventType()) { 
               //这些属性应该跟串口特性有关,我还没搞清楚,暂时不解释
             case SerialPortEvent. BI :
             case SerialPortEvent. OE :
             case SerialPortEvent. FE :
             case SerialPortEvent. PE :
             case SerialPortEvent. CD :
             case SerialPortEvent. CTS :
             case SerialPortEvent. DSR :
             case SerialPortEvent. RI :
             case SerialPortEvent. OUTPUT_BUFFER_EMPTY :
                 break
             case SerialPortEvent. DATA_AVAILABLE :     //获取到串口返回信息 
                 byte [] data = new byte [512];
                 int len=0;
                 try {
                         while ((len= in .read(data))>=0){
                              //这里处理你获得的数据即可。
                        }
                   } catch (IOException e) {
                         //读信息报错后直接关闭串口
                        close();
                        e.printStackTrace();
                   }
                 //如果len读到-1的话,说明串口出问题了,这里直接关闭就行了
                 //以下的部分自由发挥吧
                 close();
                 break
             default
                 break
             } 
          }
     }
}

你可能感兴趣的:(树莓派)