免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

Android 串口編程原理和實現(xiàn)方式(附源碼)

 軟件團隊頭目 2012-03-04

Android 串口編程原理和實現(xiàn)方式(附源碼)

分類: Linux Android 1158人閱讀 評論(12) 收藏 舉報

    提到串口編程,就不得不提到JNI,不得不提到JavaAPI中的文件描述符類:FileDescriptor。下面我分別對JNI、FileDescriptor以及串口的一些知識點和實現(xiàn)的源碼進行分析說明。這里主要是參考了開源項目android-serialport-api。

    串口編程需要了解的基本知識點:對于串口編程,我們只需對串口進行一系列的設置,然后打開串口,這些操作我們可以參考串口調(diào)試助手的源碼進行學習。在Java中如果要實現(xiàn)串口的讀寫功能只需操作文件設備類:FileDescriptor即可,其他的事都由驅(qū)動來完成不用多管!當然,你想了解,那就得看驅(qū)動代碼了。這里并不打算對驅(qū)動進行說明,只初略闡述應用層的實現(xiàn)方式。

 

(一)JNI:

    關于JNI的文章網(wǎng)上有很多,不再多做解釋,想詳細了解的朋友可以查看云中漫步的技術文章,寫得很好,分析也很全面,那么在這篇拙文中我強調(diào)3點:

    1、如何將編譯好的SO文件打包到APK中?(方法很簡單,直接在工程目錄下新建文件夾 libs/armeabi,將SO文件Copy到此目錄即可)

    2、命名要注意的地方?(在編譯好的SO文件中,將文件重命名為:libfilename.so即可。其中filename.so是編譯好后生成的文件)

    3、MakeFile文件的編寫(不用多說,可以直接參考package/apps目錄下用到JNI的相關項目寫法)

    這是關鍵的代碼:

  1. <span style="font-size:18px;">        int fd;  
  2.         speed_t speed;  
  3.         jobject mFileDescriptor;  
  4.   
  5.         /* Check arguments */  
  6.         {  
  7.                 speed = getBaudrate(baudrate);  
  8.                 if (speed == -1) {  
  9.                         /* TODO: throw an exception */  
  10.                         LOGE("Invalid baudrate");  
  11.                         return NULL;  
  12.                 }  
  13.         }  
  14.   
  15.         /* Opening device */  
  16.         {  
  17.                 jboolean iscopy;  
  18.                 const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);  
  19.                 LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);  
  20.                 fd = open(path_utf, O_RDWR | flags);  
  21.                 LOGD("open() fd = %d", fd);  
  22.                 (*env)->ReleaseStringUTFChars(env, path, path_utf);  
  23.                 if (fd == -1)  
  24.                 {  
  25.                         /* Throw an exception */  
  26.                         LOGE("Cannot open port");  
  27.                         /* TODO: throw an exception */  
  28.                         return NULL;  
  29.                 }  
  30.         }  
  31.   
  32.         /* Configure device */  
  33.         {  
  34.                 struct termios cfg;  
  35.                 LOGD("Configuring serial port");  
  36.                 if (tcgetattr(fd, &cfg))  
  37.                 {  
  38.                         LOGE("tcgetattr() failed");  
  39.                         close(fd);  
  40.                         /* TODO: throw an exception */  
  41.                         return NULL;  
  42.                 }  
  43.   
  44.                 cfmakeraw(&cfg);  
  45.                 cfsetispeed(&cfg, speed);  
  46.                 cfsetospeed(&cfg, speed);  
  47.   
  48.                 if (tcsetattr(fd, TCSANOW, &cfg))  
  49.                 {  
  50.                         LOGE("tcsetattr() failed");  
  51.                         close(fd);  
  52.                         /* TODO: throw an exception */  
  53.                         return NULL;  
  54.                 }  
  55.         }  
  56. </span>  

(二)FileDescritor:

    文件描述符類的實例用作與基礎機器有關的某種結(jié)構(gòu)的不透明句柄,該結(jié)構(gòu)表示開放文件、開放套接字或者字節(jié)的另一個源或接收者。文件描述符的主要實際用途是創(chuàng)建一個包含該結(jié)構(gòu)的FileInputStreamFileOutputStream。這是API的描述,不太好理解,其實可簡單的理解為:FileDescritor就是對一個文件進行讀寫。

(三)實現(xiàn)串口通信細節(jié)

1)  建工程:SerialDemo包名:org.winplus.serial,并在工程目錄下新建jni和libs兩個文件夾和一個org.winplus.serial.utils,如下圖:


2) 新建一個類:SerialPortFinder,添加如下代碼:

  1. <span style="font-size:18px;">package org.winplus.serial.utils;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileReader;  
  5. import java.io.IOException;  
  6. import java.io.LineNumberReader;  
  7. import java.util.Iterator;  
  8. import java.util.Vector;  
  9.   
  10. import android.util.Log;  
  11.   
  12. public class SerialPortFinder {  
  13.   
  14.     private static final String TAG = "SerialPort";  
  15.   
  16.     private Vector<Driver> mDrivers = null;  
  17.   
  18.     public class Driver {  
  19.         public Driver(String name, String root) {  
  20.             mDriverName = name;  
  21.             mDeviceRoot = root;  
  22.         }  
  23.   
  24.         private String mDriverName;  
  25.         private String mDeviceRoot;  
  26.         Vector<File> mDevices = null;  
  27.   
  28.         public Vector<File> getDevices() {  
  29.             if (mDevices == null) {  
  30.                 mDevices = new Vector<File>();  
  31.                 File dev = new File("/dev");  
  32.                 File[] files = dev.listFiles();  
  33.                 int i;  
  34.                 for (i = 0; i < files.length; i++) {  
  35.                     if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {  
  36.                         Log.d(TAG, "Found new device: " + files[i]);  
  37.                         mDevices.add(files[i]);  
  38.                     }  
  39.                 }  
  40.             }  
  41.             return mDevices;  
  42.         }  
  43.   
  44.         public String getName() {  
  45.             return mDriverName;  
  46.         }  
  47.     }  
  48.   
  49.     Vector<Driver> getDrivers() throws IOException {  
  50.         if (mDrivers == null) {  
  51.             mDrivers = new Vector<Driver>();  
  52.             LineNumberReader r = new LineNumberReader(new FileReader(  
  53.                     "/proc/tty/drivers"));  
  54.             String l;  
  55.             while ((l = r.readLine()) != null) {  
  56.                 // Issue 3:  
  57.                 // Since driver name may contain spaces, we do not extract  
  58.                 // driver name with split()  
  59.                 String drivername = l.substring(00x15).trim();  
  60.                 String[] w = l.split(" +");  
  61.                 if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) {  
  62.                     Log.d(TAG, "Found new driver " + drivername + " on "  
  63.                             + w[w.length - 4]);  
  64.                     mDrivers.add(new Driver(drivername, w[w.length - 4]));  
  65.                 }  
  66.             }  
  67.             r.close();  
  68.         }  
  69.         return mDrivers;  
  70.     }  
  71.   
  72.     public String[] getAllDevices() {  
  73.         Vector<String> devices = new Vector<String>();  
  74.         // Parse each driver  
  75.         Iterator<Driver> itdriv;  
  76.         try {  
  77.             itdriv = getDrivers().iterator();  
  78.             while (itdriv.hasNext()) {  
  79.                 Driver driver = itdriv.next();  
  80.                 Iterator<File> itdev = driver.getDevices().iterator();  
  81.                 while (itdev.hasNext()) {  
  82.                     String device = itdev.next().getName();  
  83.                     String value = String.format("%s (%s)", device,  
  84.                             driver.getName());  
  85.                     devices.add(value);  
  86.                 }  
  87.             }  
  88.         } catch (IOException e) {  
  89.             e.printStackTrace();  
  90.         }  
  91.         return devices.toArray(new String[devices.size()]);  
  92.     }  
  93.   
  94.     public String[] getAllDevicesPath() {  
  95.         Vector<String> devices = new Vector<String>();  
  96.         // Parse each driver  
  97.         Iterator<Driver> itdriv;  
  98.         try {  
  99.             itdriv = getDrivers().iterator();  
  100.             while (itdriv.hasNext()) {  
  101.                 Driver driver = itdriv.next();  
  102.                 Iterator<File> itdev = driver.getDevices().iterator();  
  103.                 while (itdev.hasNext()) {  
  104.                     String device = itdev.next().getAbsolutePath();  
  105.                     devices.add(device);  
  106.                 }  
  107.             }  
  108.         } catch (IOException e) {  
  109.             e.printStackTrace();  
  110.         }  
  111.         return devices.toArray(new String[devices.size()]);  
  112.     }  
  113. }  
  114. </span>  

上面這個類在“android-serialport-api串口工具測試隨筆”中有詳細的說明,我就不多說了。

3)新建SerialPort類,這個類主要用來加載SO文件,通過JNI的方式打開關閉串口

  1. <span style="font-size:18px;">package org.winplus.serial.utils;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileDescriptor;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8. import java.io.InputStream;  
  9. import java.io.OutputStream;  
  10.   
  11. import android.util.Log;  
  12.   
  13. public class SerialPort {  
  14.     private static final String TAG = "SerialPort";  
  15.   
  16.     /* 
  17.      * Do not remove or rename the field mFd: it is used by native method 
  18.      * close(); 
  19.      */  
  20.     private FileDescriptor mFd;  
  21.     private FileInputStream mFileInputStream;  
  22.     private FileOutputStream mFileOutputStream;  
  23.   
  24.     public SerialPort(File device, int baudrate, int flags)  
  25.             throws SecurityException, IOException {  
  26.   
  27.         /* Check access permission */  
  28.         if (!device.canRead() || !device.canWrite()) {  
  29.             try {  
  30.                 /* Missing read/write permission, trying to chmod the file */  
  31.                 Process su;  
  32.                 su = Runtime.getRuntime().exec("/system/bin/su");  
  33.                 String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"  
  34.                         + "exit\n";  
  35.                 su.getOutputStream().write(cmd.getBytes());  
  36.                 if ((su.waitFor() != 0) || !device.canRead()  
  37.                         || !device.canWrite()) {  
  38.                     throw new SecurityException();  
  39.                 }  
  40.             } catch (Exception e) {  
  41.                 e.printStackTrace();  
  42.                 throw new SecurityException();  
  43.             }  
  44.         }  
  45.   
  46.         mFd = open(device.getAbsolutePath(), baudrate, flags);  
  47.         if (mFd == null) {  
  48.             Log.e(TAG, "native open returns null");  
  49.             throw new IOException();  
  50.         }  
  51.         mFileInputStream = new FileInputStream(mFd);  
  52.         mFileOutputStream = new FileOutputStream(mFd);  
  53.     }  
  54.   
  55.     // Getters and setters  
  56.     public InputStream getInputStream() {  
  57.         return mFileInputStream;  
  58.     }  
  59.   
  60.     public OutputStream getOutputStream() {  
  61.         return mFileOutputStream;  
  62.     }  
  63.   
  64.     // JNI  
  65.     private native static FileDescriptor open(String path, int baudrate,  
  66.             int flags);  
  67.   
  68.     public native void close();  
  69.   
  70.     static {  
  71.         System.loadLibrary("serial_port");  
  72.     }  
  73. }  
  74. </span>  

4) 新建一個Application 繼承android.app.Application,用來對串口進行初始化和關閉串口

  1. <span style="font-size:18px;">package org.winplus.serial;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.security.InvalidParameterException;  
  6.   
  7. import org.winplus.serial.utils.SerialPort;  
  8. import org.winplus.serial.utils.SerialPortFinder;  
  9.   
  10. import android.content.SharedPreferences;  
  11.   
  12. public class Application extends android.app.Application {  
  13.     public SerialPortFinder mSerialPortFinder = new SerialPortFinder();  
  14.     private SerialPort mSerialPort = null;  
  15.   
  16.     public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {  
  17.             if (mSerialPort == null) {  
  18.                     /* Read serial port parameters */  
  19.                     SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE);  
  20.                     String path = sp.getString("DEVICE""");  
  21.                     int baudrate = Integer.decode(sp.getString("BAUDRATE""-1"));  
  22.   
  23.                     /* Check parameters */  
  24.                     if ( (path.length() == 0) || (baudrate == -1)) {  
  25.                             throw new InvalidParameterException();  
  26.                     }  
  27.   
  28.                     /* Open the serial port */  
  29.                     mSerialPort = new SerialPort(new File(path), baudrate, 0);  
  30.             }  
  31.             return mSerialPort;  
  32.     }  
  33.   
  34.     public void closeSerialPort() {  
  35.             if (mSerialPort != null) {  
  36.                     mSerialPort.close();  
  37.                     mSerialPort = null;  
  38.             }  
  39.     }  
  40. }  
  41. </span>  

5) 新建一個繼承抽象的Activity類,主要用于讀取串口的信息

  1. <span style="font-size:18px;">package org.winplus.serial;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6. import java.security.InvalidParameterException;  
  7.   
  8. import org.winplus.serial.utils.SerialPort;  
  9.   
  10. import android.app.Activity;  
  11. import android.app.AlertDialog;  
  12. import android.content.DialogInterface;  
  13. import android.content.DialogInterface.OnClickListener;  
  14. import android.os.Bundle;  
  15.   
  16. public abstract class SerialPortActivity extends Activity {  
  17.     protected Application mApplication;  
  18.     protected SerialPort mSerialPort;  
  19.     protected OutputStream mOutputStream;  
  20.     private InputStream mInputStream;  
  21.     private ReadThread mReadThread;  
  22.   
  23.     private class ReadThread extends Thread {  
  24.   
  25.         @Override  
  26.         public void run() {  
  27.             super.run();  
  28.             while (!isInterrupted()) {  
  29.                 int size;  
  30.                 try {  
  31.                     byte[] buffer = new byte[64];  
  32.                     if (mInputStream == null)  
  33.                         return;  
  34.                       
  35.                     /** 
  36.                      * 這里的read要尤其注意,它會一直等待數(shù)據(jù),等到天荒地老,??菔癄€。如果要判斷是否接受完成,只有設置結(jié)束標識,或作其他特殊的處理。 
  37.                      */  
  38.                     size = mInputStream.read(buffer);  
  39.                     if (size > 0) {  
  40.                         onDataReceived(buffer, size);  
  41.                     }  
  42.                 } catch (IOException e) {  
  43.                     e.printStackTrace();  
  44.                     return;  
  45.                 }  
  46.             }  
  47.         }  
  48.     }  
  49.   
  50.     private void DisplayError(int resourceId) {  
  51.         AlertDialog.Builder b = new AlertDialog.Builder(this);  
  52.         b.setTitle("Error");  
  53.         b.setMessage(resourceId);  
  54.         b.setPositiveButton("OK"new OnClickListener() {  
  55.             public void onClick(DialogInterface dialog, int which) {  
  56.                 SerialPortActivity.this.finish();  
  57.             }  
  58.         });  
  59.         b.show();  
  60.     }  
  61.   
  62.     @Override  
  63.     protected void onCreate(Bundle savedInstanceState) {  
  64.         super.onCreate(savedInstanceState);  
  65.         mApplication = (Application) getApplication();  
  66.         try {  
  67.             mSerialPort = mApplication.getSerialPort();  
  68.             mOutputStream = mSerialPort.getOutputStream();  
  69.             mInputStream = mSerialPort.getInputStream();  
  70.   
  71.             /* Create a receiving thread */  
  72.             mReadThread = new ReadThread();  
  73.             mReadThread.start();  
  74.         } catch (SecurityException e) {  
  75.             DisplayError(R.string.error_security);  
  76.         } catch (IOException e) {  
  77.             DisplayError(R.string.error_unknown);  
  78.         } catch (InvalidParameterException e) {  
  79.             DisplayError(R.string.error_configuration);  
  80.         }  
  81.     }  
  82.   
  83.     protected abstract void onDataReceived(final byte[] buffer, final int size);  
  84.   
  85.     @Override  
  86.     protected void onDestroy() {  
  87.         if (mReadThread != null)  
  88.             mReadThread.interrupt();  
  89.         mApplication.closeSerialPort();  
  90.         mSerialPort = null;  
  91.         super.onDestroy();  
  92.     }  
  93. }  
  94. </span>  

6)編寫string.xml 以及baudrates.xml文件

    在string.xml文件中添加:

  1. <span style="font-size:18px;">    <string name="error_configuration">Please configure your serial port first.</string>  
  2.     <string name="error_security">You do not have read/write permission to the serial  port.</string>  
  3.     <string name="error_unknown">The serial port can not be opened for an unknown  reason.</string>  
  4. </span>  

在baudrates.xml文件中添加

  1. <span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <string-array name="baudrates_name">  
  5.         <item>50</item>  
  6.         <item>75</item>  
  7.         <item>110</item>  
  8.         <item>134</item>  
  9.         <item>150</item>  
  10.         <item>200</item>  
  11.         <item>300</item>  
  12.         <item>600</item>  
  13.         <item>1200</item>  
  14.         <item>1800</item>  
  15.         <item>2400</item>  
  16.         <item>4800</item>  
  17.         <item>9600</item>  
  18.         <item>19200</item>  
  19.         <item>38400</item>  
  20.         <item>57600</item>  
  21.         <item>115200</item>  
  22.         <item>230400</item>  
  23.         <item>460800</item>  
  24.         <item>500000</item>  
  25.         <item>576000</item>  
  26.         <item>921600</item>  
  27.         <item>1000000</item>  
  28.         <item>1152000</item>  
  29.         <item>1500000</item>  
  30.         <item>2000000</item>  
  31.         <item>2500000</item>  
  32.         <item>3000000</item>  
  33.         <item>3500000</item>  
  34.         <item>4000000</item>  
  35.     </string-array>  
  36.     <string-array name="baudrates_value">  
  37.         <item>50</item>  
  38.         <item>75</item>  
  39.         <item>110</item>  
  40.         <item>134</item>  
  41.         <item>150</item>  
  42.         <item>200</item>  
  43.         <item>300</item>  
  44.         <item>600</item>  
  45.         <item>1200</item>  
  46.         <item>1800</item>  
  47.         <item>2400</item>  
  48.         <item>4800</item>  
  49.         <item>9600</item>  
  50.         <item>19200</item>  
  51.         <item>38400</item>  
  52.         <item>57600</item>  
  53.         <item>115200</item>  
  54.         <item>230400</item>  
  55.         <item>460800</item>  
  56.         <item>500000</item>  
  57.         <item>576000</item>  
  58.         <item>921600</item>  
  59.         <item>1000000</item>  
  60.         <item>1152000</item>  
  61.         <item>1500000</item>  
  62.         <item>2000000</item>  
  63.         <item>2500000</item>  
  64.         <item>3000000</item>  
  65.         <item>3500000</item>  
  66.         <item>4000000</item>  
  67.     </string-array>  
  68.   
  69. </resources>  
  70. </span>  

7)開始編寫界面了:在main.xml布局文件中添加兩個編輯框,一個用來發(fā)送命令,一個用來接收命令:

  1. <span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas./apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <EditText  
  8.         android:id="@+id/EditTextReception"  
  9.         android:layout_width="fill_parent"  
  10.         android:layout_height="fill_parent"  
  11.         android:layout_weight="1"  
  12.         android:gravity="top"  
  13.         android:hint="Reception"  
  14.         android:isScrollContainer="true"  
  15.         android:scrollbarStyle="insideOverlay" >  
  16.     </EditText>  
  17.   
  18.     <EditText  
  19.         android:id="@+id/EditTextEmission"  
  20.         android:layout_width="fill_parent"  
  21.         android:layout_height="wrap_content"  
  22.         android:hint="Emission"  
  23.         android:lines="1" >  
  24.     </EditText>  
  25.   
  26. </LinearLayout>  
  27. </span>  

8) SerialDemoActivity類的實現(xiàn):

  1. <span style="font-size:18px;">package org.winplus.serial;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import android.os.Bundle;  
  6. import android.view.KeyEvent;  
  7. import android.widget.EditText;  
  8. import android.widget.TextView;  
  9. import android.widget.TextView.OnEditorActionListener;  
  10.   
  11. public class SerialDemoActivity extends SerialPortActivity{  
  12.     EditText mReception;  
  13.   
  14.     @Override  
  15.     protected void onCreate(Bundle savedInstanceState) {  
  16.             super.onCreate(savedInstanceState);  
  17.             setContentView(R.layout.main);  
  18.   
  19. //          setTitle("Loopback test");  
  20.             mReception = (EditText) findViewById(R.id.EditTextReception);  
  21.   
  22.             EditText Emission = (EditText) findViewById(R.id.EditTextEmission);  
  23.             Emission.setOnEditorActionListener(new OnEditorActionListener() {  
  24.                     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {  
  25.                             int i;  
  26.                             CharSequence t = v.getText();  
  27.                             char[] text = new char[t.length()];  
  28.                             for (i=0; i<t.length(); i++) {  
  29.                                     text[i] = t.charAt(i);  
  30.                             }  
  31.                             try {  
  32.                                     mOutputStream.write(new String(text).getBytes());  
  33.                                     mOutputStream.write('\n');  
  34.                             } catch (IOException e) {  
  35.                                     e.printStackTrace();  
  36.                             }  
  37.                             return false;  
  38.                     }  
  39.             });  
  40.     }  
  41.   
  42.     @Override  
  43.     protected void onDataReceived(final byte[] buffer, final int size) {  
  44.             runOnUiThread(new Runnable() {  
  45.                     public void run() {  
  46.                             if (mReception != null) {  
  47.                                     mReception.append(new String(buffer, 0, size));  
  48.                             }  
  49.                     }  
  50.             });  
  51.     }  
  52. }  
  53. </span>  

    寫到這里,代碼基本上寫完了。下面就是要實現(xiàn)JNI層的功能了,要實現(xiàn)JNI,必須首先生成頭文件,頭文件的生成方式也很簡單, 我們編譯工程,在終端輸入 javah org.winplus.serial.utils.SerialPort 則會生成頭文件:org_winplus_serial_utils_SerialPort.h,這個頭文件的名字可以隨意命名。我們將它命名為:SerialPort.h拷貝到新建的目錄jni中,新建SerialPort.c 文件,這兩個文件的代碼就不貼出來了。直接到上傳的代碼中看吧。


(四)串口的應用,可實現(xiàn)掃描頭,指紋識別等外圍USB轉(zhuǎn)串口的特色應用。

 

還蠻繁瑣的,以上只是對開源項目android-serialport-api 進行精簡想了解此項目請點擊此處!就這樣吧,晚了準備見周公去!

 源碼下載地址==》

精心準備的串口編程資料,歡迎下載==》

原創(chuàng)文章,轉(zhuǎn)載請注明出處:http://www.blog.csdn.net/tangcheng_ok


    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多