Android serial communication RS485 to send and receive data

Recently, there is a demand like this. The customer bought our indoor video extension, and the
customer DIYs his own software. We need to provide RS485 serial communication demo demonstration and SDK integration here.
The general demand is like this, don't say much, let's look down.

1. SDK part

1. Copy the libxxx.so file to the armeabi-v7a directory

Copy the .so library (used for 485 serial communication) to the libs/armeabi-v7a directory. The name of the .so file is based on the name of the specific function module of your project.
Copy the so library

2. Delete all resource files in the res directory

Delete all resource files

3、build.gradle(Module:serialport485)

apply plugin: 'com.android.library'

android {
    
    
    compileSdkVersion 26

    defaultConfig {
    
    
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
        ndk {
    
    
            // 设置支持的SO库架构
            abiFilters 'armeabi', 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
        }
    }

    buildTypes {
    
    
        release {
    
    
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets {
    
    
        main {
    
    
            jniLibs.srcDirs = ['libs']
        }
    }
}

dependencies {
    
    
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    configurations.all {
    
    
        resolutionStrategy.force 'com.android.support:support-annotations:25.3.1'
    }
}

4. Library library of serialport485, AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.leecore.serialport" />

5. Implementation of serial communication

Serial communication type, static block loading .so file, open/close serial port, get input stream/output stream, define JNI package interface, etc.

/*
 * Copyright 2009 Cedric Priscal
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.leecore.serialport;

import android.util.Log;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @description: 串口通讯
 * @version: v1.0
 * @author: yeyl
 * @date: 2020/12/22 18:46
 * @history:
 */
public class SerialPort {
    
    

    static {
    
    
        System.loadLibrary("xxx");
    }

    private static final String TAG = "SerialPort";
    private FileDescriptor mFd;
    private FileInputStream mFileInputStream;
    private FileOutputStream mFileOutputStream;

    public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
    
    
        /* Check access permission */
        if (!device.canRead() || !device.canWrite()) {
    
    
            try {
    
    
                /* Missing read/write permission, trying to chmod the file */
                Process su;
                su = Runtime.getRuntime().exec("/system/bin/su");
                String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n";
                su.getOutputStream().write(cmd.getBytes());
                if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
    
    
                    throw new SecurityException();
                }
            } catch (Exception e) {
    
    
                throw new SecurityException();
            }
        }
        mFd = serialPortOpen(device.getAbsolutePath(), baudrate, flags);
        if (mFd == null) {
    
    
            Log.e(TAG, "native open returns null");
            throw new IOException();
        }
        mFileInputStream = new FileInputStream(mFd);
        mFileOutputStream = new FileOutputStream(mFd);
    }

    // Getters and setters
    public InputStream getInputStream() {
    
    
        return mFileInputStream;
    }

    public OutputStream getOutputStream() {
    
    
        return mFileOutputStream;
    }

    public void close() {
    
    
        try {
    
    
            mFileInputStream.close();
        } catch (IOException e) {
    
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
    
    
            mFileOutputStream.close();
        } catch (IOException e) {
    
    
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        serialPortClose();
    }

    /**
     * 打开串口
     *
     * @param path     设备路径
     * @param baudrate 波特率
     * @param flags    标志位
     */
    private native FileDescriptor serialPortOpen(String path, int baudrate, int flags);

    /**
     * 串口关闭
     */
    private native void serialPortClose();

}

6, packaged into aar file dependency method

Compile aar method one:
Compile aar way one
compile aar method two:
Compile aar way two
aar file has no debug and release version, whichever is ok, the result of compiling aar:
Compile aar result

Second, the DEMO part

1. Copy the serialport485.aar file to the libs directory

The serialport485.aar file name is modified
Copy aar file

2、build.gradle(Module:app)

Depend on aar method one:

apply plugin: 'com.android.application'

android {
    
    
    compileSdkVersion 26
    defaultConfig {
    
    
        applicationId "com.xxx.phone.demo"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk {
    
    
            // 设置支持的SO库架构
            abiFilters 'armeabi', 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
        }
    }
    buildTypes {
    
    
        release {
    
    
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    sourceSets {
    
    
        main {
    
    
            jniLibs.srcDirs = ['libs']
        }
    }
}

dependencies {
    
    
    implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    configurations.all {
    
    
        resolutionStrategy.force 'com.android.support:support-annotations:25.3.1'
    }
}

Rely on aar method two:

apply plugin: 'com.android.application'

android {
    
    
    ...//此处省略代码
    repositories {
    
    
        flatDir {
    
    
            dirs 'libs'
        }
    }
}

dependencies {
    
    
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation(name: 'serialport485', ext: 'aar')
    ...//此处省略代码
}

3、MainActivity.java

For example, open/close serial port API, read/write data API, etc., serial port communication 485 interface description, have been implemented in this class.

package com.xxx.phone.demo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import com.leecore.serialport.SerialPort;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

/**
 * @description: 串口通讯485,打开/关闭串口、读取/写入数据演示
 * @version: v1.0
 * @author: yeyl
 * @date: 2020/12/23 17:20
 * @history:
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
    

    private SerialPort mSerialPort;
    private OutputStream mOutputStream;
    private InputStream mInputStream;
    /**
     * 波特率
     */
    private static final int BAUDRATE = 9600;
    /**
     * 串口路径
     */
    private static final String UART_PATH = "/dev/uart_dev/UART_485";
    /**
     * 读取到的数据
     */
    private TextView mTvReadData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTvReadData = findViewById(R.id.tv_main_read_data);
        findViewById(R.id.btn_main_open).setOnClickListener(this);
        findViewById(R.id.btn_main_close).setOnClickListener(this);
        findViewById(R.id.btn_main_read_data).setOnClickListener(this);
        findViewById(R.id.btn_main_write_data).setOnClickListener(this);
    }

    /**
     * 字节数组转16进制字符串
     *
     * @param buf
     * @return
     */
    public static String bytesToHexString(byte[] buf) {
    
    
        final String HEX = "0123456789ABCDEF";
        if (buf == null) {
    
    
            return "";
        }
        StringBuffer result = new StringBuffer(2 * buf.length);
        for (int i = 0; i < buf.length; i++) {
    
    
            result.append(HEX.charAt((buf[i] >> 4) & 0x0f)).append(HEX.charAt(buf[i] & 0x0f));
        }
        return result.toString();
    }

    /**
     * 读取数据请求
     */
    private void readDataRequest() {
    
    
        if (mInputStream == null) {
    
    
            return;
        }
        try {
    
    
            if (mInputStream.available() > 0) {
    
    
                byte[] response = new byte[mInputStream.available()];
                mInputStream.read(response);
                mTvReadData.setText(bytesToHexString(response));
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 写入数据请求
     */
    private void writeDataRequest() {
    
    
        if (mOutputStream == null) {
    
    
            return;
        }
        byte[] data = new byte[3];
        data[0] = 97;
        data[1] = 98;
        data[2] = 99;
        try {
    
    
            mOutputStream.write(data);
            mOutputStream.flush();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View v) {
    
    
        switch (v.getId()) {
    
    
            case R.id.btn_main_open:
                init(UART_PATH, BAUDRATE);
                break;
            case R.id.btn_main_close:
                closeSerialPort();
                break;
            case R.id.btn_main_read_data:
                readDataRequest();
                break;
            case R.id.btn_main_write_data:
                writeDataRequest();
                break;
            default:
                break;
        }
    }

    /**
     * 初始化串口
     *
     * @param uartPath 串口路径
     * @param baudrate 波特率
     */
    public void init(String uartPath, int baudrate) {
    
    
        try {
    
    
            mSerialPort = getSerialPort(uartPath, baudrate);
            mInputStream = mSerialPort.getInputStream();
            mOutputStream = mSerialPort.getOutputStream();
        } catch (SecurityException e) {
    
    
            mSerialPort = null;
        } catch (IOException e) {
    
    
            mSerialPort = null;
        } catch (InvalidParameterException e) {
    
    
        }
    }

    /**
     * 根据设备串口路径以及波特率设置串口
     *
     * @param path     串口路径
     * @param baudrate 波特率
     * @return 打开的串口
     * @throws SecurityException
     * @throws IOException
     * @throws InvalidParameterException
     */
    private SerialPort getSerialPort(String path, int baudrate) throws SecurityException, IOException, InvalidParameterException {
    
    
        if (mSerialPort == null) {
    
    
            /* Check parameters */
            if ((path.length() == 0) || (baudrate == -1)) {
    
    
                throw new InvalidParameterException();
            }
            /* Open the serial port */
            mSerialPort = new SerialPort(new File(path), baudrate, 0);
        }
        return mSerialPort;
    }

    /**
     * 关闭串口
     */
    public void closeSerialPort() {
    
    
        if (mSerialPort != null) {
    
    
            mSerialPort.close();
            mSerialPort = null;
        }
        mInputStream = null;
        mOutputStream = null;
    }
}

4、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context="com.xxx.phone.demo.MainActivity">

    <Button
        android:id="@+id/btn_main_open"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="打开串口" />

    <Button
        android:id="@+id/btn_main_close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="关闭串口" />

    <Button
        android:id="@+id/btn_main_read_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="读取数据" />

    <Button
        android:id="@+id/btn_main_write_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="写入数据" />

    <TextView
        android:id="@+id/tv_main_read_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="16dp" />

</LinearLayout>

Third, the serial port debugging part

1. Demo screenshot

demo screenshot

2. Screenshot of serial port debugging software

Write (send) data:
Write (send) data
Read (receive) data: After
Serial port debugging software input data
inputting 97 98 99 data in the serial port debugging software, click Manual Send, then go back to the Modbus485Demo interface and click Read Data, the lower left corner of the interface displays 979899 data, the verification result is correct of.
Click to read data, display data

Guess you like

Origin blog.csdn.net/discode/article/details/115262165