android modbus協議之(三)modbus-TCP/IP通信(安卓系統作爲modbus_slave)

上兩部分是使用android作爲主站通信的,今天寫的是將android做成modbus_slave。

整體思路modbus服務,0x 1x 3x 4x區各申請1000個寄存器,其中0x和4x部分是保持寄存器,所以我從1000個寄存器中拿出500個做爲掉電保持寄存器。外部類拿到這個服務後,可以讀取與寫入服務裏面的寄存器。

一、創建一個服務

可以自己手動創建:繼承 Service類 並重寫onCreate()方法。也可以使用下圖樣子新建服務類,android studio創建服務自動回添加依賴秩序重寫方法
在這裏插入圖片描述

重寫onCreate()方法

onCreate()方法主要是提取保存的數據,添加寄存器,暫時不啓動modbus監聽線程.看一下代碼:

 // todo:0-499是非掉電存儲區   500-999是掉電存儲區
    private boolean[] registe_0x=new boolean[500];//申請500個布爾變量作爲0x區掉電存儲緩衝地址(這部分變量是外部可讀可寫區)
    // todo:0-499是非掉電存儲區   500-999是掉電存儲區
    private int[] registe_4x=new int[500];//申請500個整數變量作爲4x區掉電存儲緩衝地址(這部分是可讀可寫區)
     SimpleProcessImage modbus_data = null;
@Override
    public void onCreate() {
        super.onCreate();
        Log.e("信息","開始創建modbus服務");
        takeOutSaveData();//取出保存的數據
        //創建500個非掉電存儲區 0x數據
        int i=0;
        modbus_data = new SimpleProcessImage();
        int abc=0;
        for(i=0;i<500;i++){
            modbus_data.addDigitalOut(new SimpleDigitalOut(false));//設置0x區
            abc++;
        }
        //創建500個掉電存儲區 0x數據
        for(i=0;i<500;i++){
            modbus_data.addDigitalOut(new SimpleDigitalOut(registe_0x[i]));
            abc++;
        }
        /** 創建1X 數據    離散輸入寄存器沒有掉電存儲區            */
        for(i=0;i<1000;i++){
            modbus_data.addDigitalIn(new SimpleDigitalIn(false));//設置0x區
        }
        /**創建3X數據        輸入寄存器沒有掉電存儲區 */
        for(i=0;i<1000;i++){
            modbus_data.addInputRegister(new SimpleInputRegister(0));
        }
        /**創建4X 非掉電存儲區 保持寄存器可讀可寫區*/
        for(i=0;i<500;i++){
            modbus_data.addRegister(new SimpleRegister(0));
        }
        //創建500個掉電存儲區
        for(i=0;i<500;i++){
            modbus_data.addRegister(new SimpleRegister(registe_4x[i]));
        }
        ModbusCoupler.getReference().setProcessImage(modbus_data);
        ModbusCoupler.getReference().setMaster(false);
        ModbusCoupler.getReference().setUnitID(1);//設備地址
    }

開啓服務

modbus監聽服務開啓後,check_data_handler()這個方法是校驗外部存儲區部分是否改變了如果改變了需要保存一下,防止突然掉電未做保存。

    /**
     * 運行網絡通訊協議服務
     * modbus服務運行
     *
     * @param setLocalIP 設置本地IP 設置本機IP地址(因爲有可能多網卡運行所以需要設置本機IP運行)
     * @param maxClient  最大的客戶  最多允許多少客戶端連接 默認3個
     * @param port       端口 應該大於1024(因爲1024以下的端口由android使用
     */
    public void runModbusService(final String setLocalIP,final int maxClient,final int port )  {

        if(!isRunner()){//如果沒有連接則建立連接

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e("信息","開始運行服務");
                    Log.e("信息","IP="+setLocalIP);
                    Log.e("信息","連接="+maxClient);
                    Log.e("信息","端口="+port);
                    try{
                        final InetAddress localIp=InetAddress.getByName(setLocalIP);
                        listener = new ModbusTCPListener(maxClient);//設置最大客戶端連接
                        listener.setPort(port);//1024一下的端口是系統端口不能隨便調用
                        listener.setAddress(localIp);
                        is_run=true;
                        listener.start();
                        check_data_handler.postDelayed(check_data_runable,1000);//1秒鐘後開啓檢測數據是否改變
                    }catch (Exception e){
                        Log.e("信息",e.toString());
                    }

                }
            }).start();
        }
    }

上面的代碼如果不做Service的話直接放到其他activity中就可以測試modbus-slav,使用下面的軟件進行測試

在這裏插入圖片描述

預留出外部activity綁定此服務的方法

    /**
     * Moudbus Tcp服務綁定
     * @author 騰飛
     * @date 2020/02/22
     */
    public class MoudbusTcpServiceBinder extends Binder {
        public MoudbusTcpService get_service(){
            return MoudbusTcpService.this;
        }
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
//        throw new UnsupportedOperationException("Not yet implemented");
            return new  MoudbusTcpServiceBinder();
    }

其他的activity綁定服務的方法(包含了一些測試代碼)

        moudbus_connection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
               moudbus_binder=(MoudbusTcpService.MoudbusTcpServiceBinder)service;
               my_modbus_service=moudbus_binder.get_service();
               String ip_addr=new IpAddress().getHostIp();
                   my_modbus_service.runModbusService(ip_addr,2,2000);
                   //測試服務是否正常(包含了一些測試代碼)
                   Log.i("信息","dd"+my_modbus_service.get_0x_value(5));
                Log.i("信息","dd"+my_modbus_service.get_0x_value(5,10));
                Log.i("信息","dd"+my_modbus_service.get_1x_value(6));
                Log.i("信息","dd"+my_modbus_service.get_1x_value(1,10));
                Log.i("信息","dd"+my_modbus_service.get_3x_value(5));
                Log.i("信息","dd"+my_modbus_service.get_3x_value(5,5));
                Log.i("信息","dd"+my_modbus_service.get_4x_value(7));
                Log.i("信息","dd"+my_modbus_service.get_4x_value(8,10));
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
        };
        Intent modbusIntent=new Intent(this,MoudbusTcpService.class);
        startService(modbusIntent);//開啓服務//必須先start否則如果切換activity後bingService自動卸載此服務,會造成服務不正常工作
        bindService(modbusIntent,moudbus_connection,BIND_AUTO_CREATE);//自動綁定如果沒有啓動服務會自動啓動服務

掉電保存使用了SharedPreferences類,這個類挺好用的用來保存一些簡單的數據方便快捷,JSONArray類格式化數組並存儲

   private final String MOUDBUS_STORAGE_NAME="modbus_unit01";//modbus存儲區的名字
    private final String STORAGE_0X_NAME="0x_storage";//0x存儲區名字
 /**
     * 保存0 x數據
     */
    private void save_0x_Data(){
        JSONArray array_data=new JSONArray();
        for(int i=0;i<500;i++){
            array_data.put(registe_0x[i]);
        }
        SharedPreferences wp=getApplicationContext().getSharedPreferences(MOUDBUS_STORAGE_NAME,MODE_PRIVATE);//得到存儲區的名字 如果沒有則創建一個
        SharedPreferences.Editor wp_edit=wp.edit();
        wp_edit.putString(STORAGE_0X_NAME,array_data.toString());//存入
        wp_edit.commit();//提交
    }

數據取出並轉換成數組用來對比modbus服務的區別

    /**
     * 取出保存數據
     */
    private void takeOutSaveData(){
        SharedPreferences read_share=getApplicationContext().getSharedPreferences(MOUDBUS_STORAGE_NAME,MODE_PRIVATE);//得到存儲區的名字 如果沒有則創建一個
        String storage_0x_list_str=read_share.getString(STORAGE_0X_NAME,"NULL");//獲取0x區的存儲的數據
        String storage_4x_list_str=read_share.getString(STORAGE_4X_NAME,"NULL");//獲取4x區的存儲的數據
        //嘗試把字符串轉換成bool數組
        try{
            JSONArray storage_0x_list = new JSONArray(storage_0x_list_str);
            for (int i=0;i<storage_0x_list.length();i++){
                registe_0x[i]=storage_0x_list.getBoolean(i);//獲取布爾值
            }
        }catch (Exception e){
            Log.i("信息",e.toString());
            save_0x_Data();//初始化數據
            //如果出錯重新填入
        }
        //嘗試把字符串轉換成int數組
        try{
            JSONArray storage_4x_list = new JSONArray(storage_4x_list_str);
            for (int i=0;i<storage_4x_list.length();i++){
                registe_4x[i]=storage_4x_list.getInt(i);
            }
        }catch (Exception e){
            Log.i("信息",e.toString());
            save_4x_Data();//初始化4x區
            //如果出錯重新填入
        }
    }

一些用來和Sevice交互的方法


    /**
     * 設置0 x值
     * 0x區是一個可讀可寫的離散變量區
     * 這部分區域可分爲 掉電存儲和掉電清零區
     * 其中 寄存器地址0-499是非掉電存儲區
     * 寄存器地址500-999是掉電存儲區
     *
     * @param registe_addr 寄存器地址
     * @param bool_value   bool值
     */
    public void set_0x_value(int registe_addr,boolean bool_value){
        modbus_data.setDigitalIn(registe_addr,new SimpleDigitalIn(bool_value));
    }

    /**
     * 得到0 x值
     *
     * @param regist_addr 寄存器地址
     * @return 當前地址的值
     */
    public boolean get_0x_value(int regist_addr){
        return modbus_data.getDigitalOut(regist_addr).isSet();
    }
    public ArrayList<Boolean> get_0x_value(int regist_addr,int count){
        ArrayList<Boolean> data_array=new ArrayList<>(count);
        for (int i=0;i<count;i++){
            data_array.add(get_0x_value(regist_addr+i));
        }
        return data_array;
    }

上面的註釋已經很多了看完了基本上就能瞭解modbus-slave了,剩下的就是讀取一些其他寄存器的代碼了跟上面類似,我就不貼了,感謝jamod團隊的奉賢,讓我們操作modbus這麼容易

有時間把這幾節內容整理成源代碼或者APK文件發上來讓大家測試一下.

大家可以收藏一下留作備用.有什麼問題可以給我留言

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