zoukankan      html  css  js  c++  java
  • android 串口 android-serialport-api

       最近在做Android串口的开发,找到一个开源的串口类android-serialport-api。其主页在这里http://code.google.com/p/android-serialport-api/  ,这里可以下到APK及对源码。

        但是下载源码之后发现源码不能直接使用,而且源码结构较为复杂。关于串口的操作不外乎几步:

       1.打开串口(及配置串口);

       2.读串口;

       3.写串口;

       4.关闭串口。

    android-serialport-api的代码使用了继承等复杂的行为,不容易使初学者很快掌握关于串口的上述4步,所以我特别自己写了一个demo,只有一个activity,其中包含了打开串口,写串口,读串口的操作,对于关闭串口,大家一开就会不明白怎么写了。

    http://www.cnblogs.com/CZM-/p/7943572.html

    参考此贴,利用NDK编译jni c文件为库并运行

     

    这里是工程结构

    首先新建jni包,添加SerialPort.c即可,

    /*
     * Copyright 2009-2011 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.
     */
    
    #include <termios.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    #include <jni.h>
    
    #include "SerialPort.h"
    
    #include "android/log.h"
    static const char *TAG="serial_port";
    //#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
    //#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
    //#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
    
    static speed_t getBaudrate(jint baudrate)
    {
        switch(baudrate) {
        case 0: return B0;
        case 50: return B50;
        case 75: return B75;
        case 110: return B110;
        case 134: return B134;
        case 150: return B150;
        case 200: return B200;
        case 300: return B300;
        case 600: return B600;
        case 1200: return B1200;
        case 1800: return B1800;
        case 2400: return B2400;
        case 4800: return B4800;
        case 9600: return B9600;
        case 19200: return B19200;
        case 38400: return B38400;
        case 57600: return B57600;
        case 115200: return B115200;
        case 230400: return B230400;
        case 460800: return B460800;
        case 500000: return B500000;
        case 576000: return B576000;
        case 921600: return B921600;
        case 1000000: return B1000000;
        case 1152000: return B1152000;
        case 1500000: return B1500000;
        case 2000000: return B2000000;
        case 2500000: return B2500000;
        case 3000000: return B3000000;
        case 3500000: return B3500000;
        case 4000000: return B4000000;
        default: return -1;
        }
    }
    
    /*
     * Class:     android_serialport_SerialPort
     * Method:    open
     * Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
     */
    JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
      (JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint flags)
    {
        int fd;
        speed_t speed;
        jobject mFileDescriptor;
    
        /* Check arguments */
        {
            speed = getBaudrate(baudrate);
            if (speed == -1) {
                /* TODO: throw an exception */
    //            LOGE("Invalid baudrate");
                return NULL;
            }
        }
    
        /* Opening device */
        {
            jboolean iscopy;
            const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
    //        LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
            fd = open(path_utf, O_RDWR | flags);
    //        LOGD("open() fd = %d", fd);
            (*env)->ReleaseStringUTFChars(env, path, path_utf);
            if (fd == -1)
            {
                /* Throw an exception */
    //            LOGE("Cannot open port");
                /* TODO: throw an exception */
                return NULL;
            }
        }
    
        /* Configure device */
        {
            struct termios cfg;
    //        LOGD("Configuring serial port");
            if (tcgetattr(fd, &cfg))
            {
    //            LOGE("tcgetattr() failed");
                close(fd);
                /* TODO: throw an exception */
                return NULL;
            }
    
            cfmakeraw(&cfg);
            cfsetispeed(&cfg, speed);
            cfsetospeed(&cfg, speed);
    
            if (tcsetattr(fd, TCSANOW, &cfg))
            {
    //            LOGE("tcsetattr() failed");
                close(fd);
                /* TODO: throw an exception */
                return NULL;
            }
        }
    
        /* Create a corresponding file descriptor */
        {
            jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
            jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
            jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
            mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
            (*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
        }
    
        return mFileDescriptor;
    }
    
    /*
     * Class:     cedric_serial_SerialPort
     * Method:    close
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close
      (JNIEnv *env, jobject thiz)
    {
        jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
        jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
    
        jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
        jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
    
        jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
        jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
    
    //    LOGD("close(fd = %d)", descriptor);
        close(descriptor);
    }

    接下来在工程的local.properties文件中添加NDK路径(上面下载好的那个NDK),类似其中的SDK路径一样,我的添加后如下:

    ndk.dir=/home/cam/Android/Sdk/ndk-bundle
    sdk.dir=/home/cam/Android/Sdk

    接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:

    复制代码
        defaultConfig {
    
            ndk {
                moduleName "testhello"
                ldLibs "log", "z", "m"  //添加依赖库文件,因为有log打印等
            }
        }
    复制代码

    新建android_serialport_api包,(包名字必须一模一样,不然需要根据你的包名重新编译产生头文件,并修改c文件)并在此包下新建SerialPort.java

    /*
     * 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 android_serialport_api;
    
    import android.util.Log;
    
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.LineNumberReader;
    import java.util.Iterator;
    import java.util.Vector;
    
    public class SerialPortFinder {
    
        public class Driver {
            private String mDriverName;
            private String mDeviceRoot;
            Vector<File> mDevices = null;
            public Driver(String name, String root) {
                mDriverName = name;
                mDeviceRoot = root;
            }
            public Vector<File> getDevices() {
                if (mDevices == null) {
                    mDevices = new Vector<File>();
                    File dev = new File("/dev");
                    File[] files = dev.listFiles();
                    if(null == files || files.length ==0){
                        return mDevices;
                    }
                    int i;
                    for (i=0; i<files.length; i++) {
                        if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
                            Log.d(TAG, "查找的设备: " + files[i]);
                            mDevices.add(files[i]);
                        }
                    }
                }
                return mDevices;
            }
            public String getName() {
                return mDriverName;
            }
        }
    
        private static final String TAG = "SerialPort";
    
        private Vector<Driver> mDrivers = null;
    
        Vector<Driver> getDrivers() throws IOException {
            if (mDrivers == null) {
                mDrivers = new Vector<Driver>();
                LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
                String l;
                while((l = r.readLine()) != null) {
                    String drivername = l.substring(0, 0x15).trim();
                    String[] w = l.split(" +");
                    if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
                        Log.d(TAG, "---串口设备=" + drivername + " on " + w[w.length-4]);
                        mDrivers.add(new Driver(drivername, w[w.length-4]));
                    }
                }
                r.close();
            }
            return mDrivers;
        }
    
        public String[] getAllDevices() {
            Vector<String> devices = new Vector<String>();
            // Parse each driver
            Iterator<Driver> itdriv;
            try {
                itdriv = getDrivers().iterator();
                while(itdriv.hasNext()) {
                    Driver driver = itdriv.next();
                    Iterator<File> itdev = driver.getDevices().iterator();
                    while(itdev.hasNext()) {
                        String device = itdev.next().getName();
                        String value = String.format("%s (%s)", device, driver.getName());
                        devices.add(value);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return devices.toArray(new String[devices.size()]);
        }
    
        public String[] getAllDevicesPath() {
            Vector<String> devices = new Vector<String>();
            Iterator<Driver> itdriv;
            try {
                itdriv = getDrivers().iterator();
                while(itdriv.hasNext()) {
                    Driver driver = itdriv.next();
                    Iterator<File> itdev = driver.getDevices().iterator();
                    while(itdev.hasNext()) {
                        String device = itdev.next().getAbsolutePath();
                        devices.add(device);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return devices.toArray(new String[devices.size()]);
        }
    }

    创建主活动MainActivity.java

    package com.otherway.myapplication;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.util.Log;
    import android.view.View;
    import android.widget.Toast;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    import android_serialport_api.SerialPort;
    
    public class MainActivity extends Activity implements View.OnClickListener {
        private static final String TAG = "MainActivity";
    
        protected SerialPort mSerialPort;
        protected InputStream mInputStream;
        protected OutputStream mOutputStream;
    
        private String prot = "/dev/ttySAC2";
        private int baudrate = 9600;
        private static long i = 0;
    
        private Toast mToast;
    
    
        Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                if (msg.what == 1) {
    
                }
            }
        };
        private Thread receiveThread;
        private Thread sendThread;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initLayout();
    
            mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
        }
    
        /**
         * 初始化Layout。
         */
        private void initLayout() {
            findViewById(R.id.btn_open).setOnClickListener(MainActivity.this);
            findViewById(R.id.btn_send).setOnClickListener(MainActivity.this);
            findViewById(R.id.btn_close).setOnClickListener(MainActivity.this);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btn_open:
                    showTip("btn_open");
    
                    // 打开
                    try {
                        mSerialPort = new SerialPort(new File(prot), baudrate, 0);
                        mInputStream = mSerialPort.getInputStream();
                        mOutputStream = mSerialPort.getOutputStream();
                        receiveThread();
                    } catch (SecurityException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        Log.e(TAG, "打开失败");
                        e.printStackTrace();
                    }
    
                    break;
                case R.id.btn_send:
                    showTip("btn_send");
    
                    // 发送
                    sendThread = new Thread() {
                        @Override
                        public void run() {
                            while (true) {
                                try {
                                    i++;
                                    mOutputStream.write((String.valueOf(i)).getBytes());
                                    Log.i("test", "发送成功:1" + i);
                                    Thread.sleep(1);
                                } catch (Exception e) {
                                    Log.i("test", "发送失败");
                                    e.printStackTrace();
                                }
                            }
                        }
                    };
                    sendThread.start();
    
                    break;
                case R.id.btn_close:
                    showTip("btn_close");
    
                    closeSerialPort();
    
                    break;
                default:
                    break;
            }
        }
    
        private void receiveThread() {
            // 接收
            receiveThread = new Thread() {
                @Override
                public void run() {
                    while (true) {
                        int size;
                        try {
                            byte[] buffer = new byte[1024];
                            if (mInputStream == null)
                                return;
                            size = mInputStream.read(buffer);
                            if (size > 0) {
                                String recinfo = new String(buffer, 0,
                                        size);
                                Log.i("test", "接收到串口信息:" + recinfo);
    //                            sb = recinfo;
    //                            handler.sendEmptyMessage(1);
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            receiveThread.start();
        }
    
        /**
         * 关闭串口
         */
        public void closeSerialPort() {
    
            if (mSerialPort != null) {
                mSerialPort.close();
            }
            if (mInputStream != null) {
                try {
                    mInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (mOutputStream != null) {
                try {
                    mOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        private void showTip(final String str) {
            mToast.setText(str);
            mToast.show();
        }
    }

    主界面布局

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.otherway.myapplication.MainActivity">
    
    
        <Button
            android:id="@+id/btn_open"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="100dp"
            android:text="打开" />
    
        <Button
            android:id="@+id/btn_send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/btn_open"
            android:text="发送" />
    
        <Button
            android:id="@+id/btn_close"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/btn_send"
            android:text="关闭" />
    
    </RelativeLayout>

    改为你需要的串口端口号及波特率;

    测试时将串口rx,tx短接,打开串口后,再点击发送程序会一直循环发送,在调试信息上会打印出串口接受数据;

     

  • 相关阅读:
    判断
    迭代器
    如何关闭弹框以外的区域来关闭弹框?
    如何使APP端的滑动事件兼容PC端?
    获取元素相对于视窗的位置?
    如何获取一个元素没有在style和样式表中设置的样式的值?
    如何寻找一个数值数组中的最大元素?
    table表格中字母和数字如何换行?
    js中将字符串作为函数名来调用的方法
    web开发中如何使用引用字体
  • 原文地址:https://www.cnblogs.com/CZM-/p/7954713.html
Copyright © 2011-2022 走看看