------------------------------------------作者xxxx------------------------------------------日期xxxxAndroid串口编程原理和实现方式(附源码)【精品文档】【精品文档】【精品文档】【精品文档】【精品文档】【精品文档】 提到串口编程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符类:FileDescriptor。下面我分别对JNI、FileDescriptor以及串口的一些知识点和实现的源码进行
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
说明。这里主要是参考了开源项目HYPERLINK"http://code.google.com/p/android-serialport-api/"android-serialport-api。 串口编程需要了解的基本知识点:对于串口编程,我们只需对串口进行一系列的设置,然后打开串口,这些操作我们可以参考HYPERLINK"http://www.gjwtech.com/vcandc/scommassistantcode.htm"串口调试助手的源码进行学习。在Java中如果要实现串口的读写功能只需操作文件设备类:FileDescriptor即可,其他的事都由驱动来完成不用多管!当然,你想了解,那就得看驱动代码了。这里并不打算对驱动进行说明,只初略阐述应用层的实现方式。 (一)JNI: 关于JNI的文章网上有很多,不再多做解释,想详细了解的朋友可以查看HYPERLINK"http://my.unix-center.net/~Simon_fu/?cat=3&paged=2"云中漫步的技术文章,写得很好,分析也很全面,那么在这篇拙文中我强调3点: 1、如何将编译好的SO文件打包到APK中?(方法很简单,直接在
工程
路基工程安全技术交底工程项目施工成本控制工程量增项单年度零星工程技术标正投影法基本原理
目录下新建文件夹libs/armeabi,将SO文件Copy到此目录即可) 2、命名要注意的地方?(在编译好的SO文件中,将文件重命名为:即可。其中是编译好后生成的文件) 3、MakeFile文件的编写(不用多说,可以直接参考package/apps目录下用到JNI的相关项目写法) 这是关键的代码:[cpp] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
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; } } (二)FileDescritor: 文件描述符类的实例用作与基础机器有关的某种结构的不透明句柄,该结构
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示开放文件、开放套接字或者字节的另一个源或接收者。文件描述符的主要实际用途是创建一个包含该结构的FileInputStream 或FileOutputStream。这是API的描述,不太好理解,其实可简单的理解为:FileDescritor就是对一个文件进行读写。(三)实现串口通信细节1) 建工程:SerialDemo包名:,并在工程目录下新建jni和libs两个文件夹和一个,如下图:2)新建一个类:SerialPortFinder,添加如下代码:[java] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
package org.winplus.serial.utils; import ; import ; import ; import ; import ; import ; import ; public class SerialPortFinder { private static final String TAG = "SerialPort"; private Vector mDrivers = null; public class Driver { public Driver(String name, String root) { mDriverName = name; mDeviceRoot = root; } private String mDriverName; private String mDeviceRoot; Vector mDevices = null; public Vector getDevices() { if (mDevices == null) { mDevices = new Vector(); File dev = new File("/dev"); File[] files = (); int i; for (i = 0; i < ; i++) { if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) { Log.d(TAG, "Found new device: " + files[i]); (files[i]); } } } return mDevices; } public String getName() { return mDriverName; } } Vector getDrivers() throws IOException { if (mDrivers == null) { mDrivers = new Vector(); LineNumberReader r = new LineNumberReader(new FileReader( "/proc/tty/drivers")); String l; while ((l = ()) != null) { // Issue 3: // Since driver name may contain spaces, we do not extract // driver name with split() String drivername = l.substring(0, 0x15).trim(); String[] w = (" +"); if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) { Log.d(TAG, "Found new driver " + drivername + " on " + w[ - 4]); mDrivers.add(new Driver(drivername, w[w.length - 4])); } } (); } return mDrivers; } public String[] getAllDevices() { Vector devices = new Vector(); // Parse each driver Iterator itdriv; try { itdriv = getDrivers().iterator(); while (()) { Driver driver = itdriv.next(); Iterator itdev = driver.getDevices().iterator(); while (()) { String device = ().getName(); String value = String.format("%s (%s)", device, ()); (value); } } } catch (IOException e) { (); } return (new String[()]); } public String[] getAllDevicesPath() { Vector devices = new Vector(); // Parse each driver Iterator itdriv; try { itdriv = getDrivers().iterator(); while (()) { Driver driver = itdriv.next(); Iterator itdev = driver.getDevices().iterator(); while (()) { String device = itdev.next().getAbsolutePath(); (device); } } } catch (IOException e) { (); } return (new String[()]); } } 上面这个类在“HYPERLINK"http://blog.csdn.net/lightsoure/article/details/6833450"\o"android-serialport-api串口工具测试随笔"android-serialport-api串口工具测试随笔”中有详细的说明,我就不多说了。3)新建SerialPort类,这个类主要用来加载SO文件,通过JNI的方式打开关闭串口[java] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
package org.winplus.serial.utils; import ; import ; import ; import ; import ; import ; import ; import ; public class SerialPort { private static final String TAG = "SerialPort"; /* * Do not remove or rename the field mFd: it is used by native method * close(); */ private FileDescriptor mFd; private FileInputStream mFileInputStream; private FileOutputStream mFileOutputStream; public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException { /* Check access permission */ if (!() || !()) { 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"; ().write(()); if ((() != 0) || !() || !()) { throw new SecurityException(); } } catch (Exception e) { (); throw new SecurityException(); } } mFd = open((), baudrate, flags); if (mFd == null) { (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; } // JNI private native static FileDescriptor open(String path, int baudrate, int flags); public native void close(); static { ("serial_port"); } } 4)新建一个Application继承,用来对串口进行初始化和关闭串口[java] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
package ; import ; import ; import ; import ; import ; import ; public class Application extends { public SerialPortFinder mSerialPortFinder = new SerialPortFinder(); private SerialPort mSerialPort = null; public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException { if (mSerialPort == null) { /* Read serial port parameters */ SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE); String path = ("DEVICE", ""); int baudrate = Integer.decode(sp.getString("BAUDRATE", "-1")); /* 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 = null; } } } 5)新建一个继承抽象的Activity类,主要用于读取串口的信息[java] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
package ; import ; import ; import ; import ; import ; import ; import ; import ; import ; import ; public abstract class SerialPortActivity extends Activity { protected Application mApplication; protected SerialPort mSerialPort; protected OutputStream mOutputStream; private InputStream mInputStream; private ReadThread mReadThread; private class ReadThread extends Thread { @Override public void run() { super.run(); while (!isInterrupted()) { int size; try { byte[] buffer = new byte[64]; if (mInputStream == null) return; /** * 这里的read要尤其注意,它会一直等待数据,等到天荒地老,海枯石烂。如果要判断是否接受完成,只有设置结束标识,或作其他特殊的处理。 */ size = (buffer); if (size > 0) { onDataReceived(buffer, size); } } catch (IOException e) { (); return; } } } } private void DisplayError(int resourceId) { b = new (this); ("Error"); (resourceId); ("OK", new OnClickListener() { public void onClick(DialogInterface dialog, int which) { SerialPortActivity.this.finish(); } }); (); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApplication = (Application) getApplication(); try { mSerialPort = (); mOutputStream = (); mInputStream = (); /* Create a receiving thread */ mReadThread = new ReadThread(); (); } catch (SecurityException e) { DisplayError(); } catch (IOException e) { DisplayError(); } catch (InvalidParameterException e) { DisplayError(); } } protected abstract void onDataReceived(final byte[] buffer, final int size); @Override protected void onDestroy() { if (mReadThread != null) (); (); mSerialPort = null; super.onDestroy(); } } 6)编写string.xml以及文件 在文件中添加:[html] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
Please configure your serial port first. You do not have read/write permission to the serial port. The serial port can not be opened for an unknown reason. 在文件中添加[html] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
- 50
- 75
- 110
- 134
- 150
- 200
- 300
- 600
- 1200
- 1800
- 2400
- 4800
- 9600
- 19200
- 38400
- 57600
- 115200
- 230400
- 460800
- 500000
- 576000
- 921600
- 1000000
- 1152000
- 1500000
- 2000000
- 2500000
- 3000000
- 3500000
- 4000000
- 50
- 75
- 110
- 134
- 150
- 200
- 300
- 600
- 1200
- 1800
- 2400
- 4800
- 9600
- 19200
- 38400
- 57600
- 115200
- 230400
- 460800
- 500000
- 576000
- 921600
- 1000000
- 1152000
- 1500000
- 2000000
- 2500000
- 3000000
- 3500000
- 4000000
7)开始编写界面了:在布局文件中添加两个编辑框,一个用来发送命令,一个用来接收命令:[html] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
8)SerialDemoActivity类的实现:[java] HYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"viewplain"viewplainHYPERLINK"http://blog.csdn.net/tangcheng_ok/article/details/7021470"\o"copy"copy
package ; import ; import ; import ; import ; import ; import ; public class SerialDemoActivity extends SerialPortActivity{ EditText mReception; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(); // setTitle("Loopback test"); mReception = (EditText) findViewById(R.id.EditTextReception); EditText Emission = (EditText) findViewById(R.id.EditTextEmission); Emission.setOnEditorActionListener(new OnEditorActionListener() { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { int i; CharSequence t = (); char[] text = new char[t.length()]; for (i=0; i<(); i++) { text[i] = (i); } try { mOutputStream.write(new String(text).getBytes()); ('\n'); } catch (IOException e) { (); } return false; } }); } @Override protected void onDataReceived(final byte[] buffer, final int size) { runOnUiThread(new Runnable() { public void run() { if (mReception != null) { mReception.append(new String(buffer, 0, size)); } } }); } } 写到这里,代码基本上写完了。下面就是要实现JNI层的功能了,要实现JNI,必须首先生成头文件,头文件的生成方式也很简单,我们编译工程,在终端输入javah则会生成头文件:,这个头文件的名字可以随意命名。我们将它命名为:拷贝到新建的目录jni中,新建文件,这两个文件的代码就不贴出来了。直接到上传的代码中看吧。(四)串口的应用,可实现扫描头,指纹识别等外围USB转串口的特色应用。