1. <track id="ob6no"><strike id="ob6no"><tt id="ob6no"></tt></strike></track>

      <track id="ob6no"></track>

      當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > Android串口調試助手實現

      Android串口調試助手實現 時間:2018-08-16      來源:未知

      串行接口 (Serial Interface) 是指數據一位一位地順序傳送,其特點是通信線路簡單,只要一對傳輸線就可以實現雙向通信(可以直接利用電話線作為傳輸線),從而大大降低了成本,特別適用于遠距離通信,但傳送速度較慢。一條信息的各位數據被逐位按順序傳送的通訊方式稱為串行通訊。串行通訊的特點是:數據位的傳送,按位順序進行,少只需一根傳輸線即可完成;成本低但傳送速度慢。串行通訊的距離可以從幾米到幾千米;根據信息的傳送方向,串行通訊可以進一步分為單工、半雙工和全雙工三種。

      日常中的很多設備都是通過串口來傳輸數據的。所以,本項目在安卓的平臺上,建立了一個通過串口來收發數據的平臺。用戶可以通過設定不同的參數來連接不同的串口。

      第 1 章 使用說明

      軟件共分為三個部分:數據接收區,數據發送區,參數設置區。

      使用之前需要設置參數:需要打開的設備文件和打開的波特率。

      點擊Open就可以打開串口,如果這時候串口有數據過來,就可以在左側顯示出來,同時可以設定是否以十六進制顯示數據。

      如果想要向串口發送數據,在下方輸入數據,點擊Send就可以發送。

      第 2 章 環境搭建

      2.1 Android 開發環境的安裝與配置

      Android應用軟件開發需要的開發環境在路徑“光盤\Android應用開發環境\”下:

      JDK: JDK\JDK8\jdk-8u5-windows-i586.exe(32bit)或者jdk-8u5-windows-x64.exe(64bit)

      (從JDK 8.0開始不支持Windows XP操作系統,使用Windows XP的用戶可以使用JDK7目錄下的內容)

      ADT: adt-bundle-windows-x86.7z(32bit)或者adt-bundle-windows-x86_64.7z(64bit)

      以下主要介紹在Windows環境下搭建Android開發環境的步驟和注意事項。

      2.2 安裝JDK和配置Java開發環境

      雙擊JDK\JDK8\jdk-8u5-windows-i586.exe(32bit操作系統)或者jdk-8u5-windows-x64.exe(64bit操作系統)進行安裝(從JDK 8.0開始不支持Windows XP操作系統,使用Windows XP的用戶可以使用JDK7目錄下的內容選擇代替JDK8目錄下的內容)。接受許可證,選擇需要安裝的組件和安裝路徑后,單擊“下一步”按鈕,完成安裝過程。

      安裝完成后,利用以下步驟檢查安裝是否成功:打開Windows CMD窗口,在CMD窗口中輸入java –version命令,如果屏幕出現下圖所示的代碼信息,說明JDK安裝成功。

      XP下安裝JDK7如下:

      非XP下安裝JDK8如下:

      2.3 解壓adt-bundle-windows

      JDK安裝成功后,使用軟件解壓ADT目錄下的adt-bundle-windows-x86.7z(32bit)或者adt-bundle-windows-x86_64.7z(64bit)。

      注意:解壓路徑不包含中文;

      2.4 運行Eclipse

      解壓完畢后,直接執行其中的eclipse\eclipse.exe文件,Eclipse可以自動找到用戶前期安裝的JDK路徑。

      2.5 配置Eclipse

      運行解壓目錄下的eclipse\eclipse.exe,為自己選擇一個工作目錄Workspace,不要有中文路徑,不選擇默認也可以。

      需要為Eclipse關聯SDK的安裝路徑,即解壓路徑下的sdk目錄。在Eclipse中,點擊Window->Preferences,會看到其中添加了Android的配置,按圖所示的操作,然后點擊Apply,后點擊OK即可。

      完成以上步驟后,設置Eclipse環境

      勾選Android相關的工具,點擊OK(如果已經勾選,則不理會)。

      第 3 章 NDK環境配置

      3.1 安裝NDK工具包

      安裝包已經放到“華清遠見開發環境”光盤當中,名字為“android-ndk-r10d-windows-x86”,這個是針對32位系統使用的工具包,如果有64位的需求可以到我們提供的網盤上進行下載。

      將安裝包拷貝到E:盤,雙擊程序即可在當前路徑進行安裝。

      3.2 配置Eclipse

      打開Eclipse,點Window->Preferences->Android->NDK,設置NDK路徑,例如E:\ android-ndk-r10d

      新建一個Android工程,在工程上右鍵點擊Android Tools->Add Native Support...,然后給我們的.so文件取個名字,例如:my-ndk

      這時候工程就會多一個jni的文件夾,jni下有Android.mk和my-ndk.cpp文件。Android.mk是NDK工程的Makefile,my-ndk.cpp就是NDK的源文件。

      完成了,然后運行。運行之前先編譯NDK,然后在編譯JAVA代碼。編譯也許會遇到Unable to launch cygpath. Is Cygwin on the path等問題?如何解決?如下:

      工程右鍵,點Properties->C/C++ Build的Building Settings中去掉Use default build command,然后輸入${NDKROOT}/ndk-build.cmd

      在C/C++ Build中點擊Environment,點Add...添加環境變量NDKROOT,值為NDK的根目錄

      接著,按照如下圖所示的位置,根據使用的SDK的版本的不同選擇不同的頭文件包,例如如果使用的是android4.0.3 的話,就選擇:E:\ android-ndk-r10d\platforms\android-15\arch-arm\usr\include

      之后,再次編譯運行工程,即可成功。

      第 1 章 源碼編譯

      1.1 導入源碼

      打開Eclipse環境,選擇File->Import。

      然后,導入光盤資料中的“BlueHelper”工程,勾選下圖中的選項。

      點擊finish完成工程的導入

      1.1 運行程序

      注意:如果在調試開發板的時候,出現ADB連接不上的問題(已知華清遠見FSPAD723開源平板),可以試著替換Android SDK的ADB工具(把光盤\Android應用開發環境\ADB\ADB1.0.26\下的4個文件拷貝到用戶ADT解壓目錄下的sdk\platform-tools中)

      開發期間,在實際的設備上運行Android程序與在模擬器上運行該程序的效果幾乎相同,需要做的就是用USB電纜連接手機與計算機,并安裝一個對應的設備驅動程序。如果模擬器窗口已打開,請將其關閉。只要將開發平臺通過USB下載線與計算機相連,應用程序就會在開發平臺上加載并運行。

      在Eclipse中選擇“Run” →“Run”(或Debug)命令(或者在工程上點擊右鍵),這時會彈出一個窗口,讓你選擇用模擬器還是手機來顯示,如果選擇手機,即可在手機上運行該程序。

      第 2 章 詳細設計

      2.1 UartTool串口工具

      因為本項目要連接上層java和底層c語言,所以需要先聲明本地方法。

      NormalText Code

      private static native int NativeFileOpen(String filename, int size);// 成功返回0,失敗-1

      private static native int NativeFileClose();// 返回是否關閉成功

      private static native int NativeFileRead(byte[] buf, int size);// 返回讀取數據的個數

      private static native int NativeFileWrite(byte[] buf, int size);// 返回寫入的數據長度

      串口初始化函數,需要傳遞想要打開的串口的文件名和波特率。

      NormalText Code

      public Boolean uartInit(String filename, int size) {

      if ((fd = NativeFileOpen(filename, size)) != -1) {

      uartInit = true;

      return true;

      } else {

      log.E("%%%%% _uart_init() == -1 !!!! %%%%%");

      return false;

      }

      }

      接下來要封裝讀函數和寫函數,利用的是底層的read和write。

      NormalText Code

      public String uartRead(int num) {

      byte[] data = new byte[num];

      int re = 0;

      if ((re = NativeFileRead(data, data.length)) > 0) {

      return new String(data, 0, re);

      } else {

      log.E("%%%%% _uart_read() != num !!!! %%%%%");

      return null;

      }

      }

      NormalText Code

      public Boolean uartWrite(byte[] data) {

      if (NativeFileWrite(data, data.length) > 0) {

      return true;

      } else {

      log.E("%%%%% _uart_write(data) == -1 !!!! %%%%%");

      return false;

      }

      }

      2.2 Uarthelper調試助手

      本項目中,線程和UI線程通信是通過Handler 機制實現的。作用是將數據傳輸到UI線程進行顯示。

      NormalText Code

      private Handler handler = new Handler() {

      @SuppressLint("SimpleDateFormat")

      public void handleMessage(Message msg) {

      switch (msg.what) {

      case 0:

      if (!check.isChecked()) {

      treceive.append(recdate + " ");

      } else {

      treceive.append("0x" + printHex(recdate.getBytes()) + " ");

      }

      scroll.scrollTo(0,

      treceive.getMeasuredHeight() - scroll.getHeight());

      recdate = "";

      break;

      default:

      break;

      }

      }

      };

      設定按鈕的監聽時間,當點擊Open按鈕的時候,按照設定的參數去打開對應的串口,成功后啟動讀和寫的線程,同時設定按鈕文字為Close,屏幕進行提示打開成功。

      NormalText Code

      save.setOnClickListener(new OnClickListener() {

      @Override

      public void onClick(View v) {

      if (open == false) {

      if (!fd.getText().toString().equalsIgnoreCase("")) {

      if (uart.uartInit("/dev/" + fd.getText().toString(),

      rate_t) == true) {

      Toast.makeText(Uarthelper.this, "打開成功".toString(),

      Toast.LENGTH_LONG).show();

      log.E("打開文件 " + "/dev/" + fd.getText().toString());

      open = true;

      threadon = true;

      readThread = new ReadThread();

      readThread.start();

      save.setText("Close".toString());

      } else {

      Toast.makeText(Uarthelper.this,

      "文件打開失敗".toString(), Toast.LENGTH_SHORT)

      .show();

      }

      } else {

      Toast.makeText(Uarthelper.this, "請填寫完整".toString(),

      Toast.LENGTH_SHORT).show();

      }

      } else {

      Toast.makeText(Uarthelper.this, "正在關閉串口。。。".toString(),

      Toast.LENGTH_LONG).show();

      threadon = false;

      uart.uartWrite("s".getBytes());

      UartQThread uartQThread = new UartQThread();

      uartQThread.start();

      open = false;

      save.setText("Open".toString());

      }

      }

      });

      讀取數據的線程,調用底層的uartRead函數,接收到數據后,將數據存入全局變量,然后通知主線程來顯示。

      NormalText Code

      class ReadThread extends Thread {

      String tmp = null;

      @Override

      public void run() {

      log.E("讀取數據線程啟動!");

      while (threadon) {

      tmp = uart.uartRead(10);

      if (threadon) {

      if (tmp == null) {

      // log.E("接收數據出錯!");

      } else {

      log.E("接收數據 " + tmp);

      recdate += tmp;

      NoteThread noteThread = new NoteThread();

      noteThread.start();

      }

      }

      }

      log.E("讀取數據線程結束!");

      }

      }

      如果想要發送數據,需要調用底層的uartWrite函數。

      NormalText Code

      send.setOnClickListener(new OnClickListener() {

      @Override

      public void onClick(View v) {

      if (uart.uartInit == true) {

      String date = tsent.getText().toString();

      if (uart.uartWrite(date.getBytes()) == true) {

      // tsent.setText("");

      log.E("發送數據 " + date);

      } else {

      Toast.makeText(Uarthelper.this, "發送失敗".toString(),

      Toast.LENGTH_SHORT).show();

      }

      } else {

      Toast.makeText(Uarthelper.this, "請先設置串口".toString(),

      Toast.LENGTH_SHORT).show();

      }

      }

      });

      2.3 NDK程序詳解

      2.3.1 jni.c

      這個文件的作用主要是連結上層和底層之間的函數。

      首先需要定義一個結構體,這個結構體表明了上層函數名稱和底層函數名稱的對應關系。并且函數名稱的書寫是有要求的,Java_cn_com_farsight_tool_UartTool_NativeFileRead類似這樣的,格式為java+程序包名+函數名稱。

      NormalText Code

      static JNINativeMethod gMethods[] = { { "NativeFileOpen",

      "(Ljava/lang/String;I)I",

      (void *) Java_cn_com_farsight_tool_UartTool_NativeFileOpen }, {

      "NativeFileRead", "([BI)I",

      (void *) Java_cn_com_farsight_tool_UartTool_NativeFileRead }, {

      "NativeFileWrite", "([BI)I",

      (void *) Java_cn_com_farsight_tool_UartTool_NativeFileWrite }, {

      "NativeFileClose", "()I",

      (void *) Java_cn_com_farsight_tool_UartTool_NativeFileClose }, };

      int register_cn_com_farsight_tool_UartTool(JNIEnv *env) {

      return jniRegisterNativeMethods(env, kClassPathName, gMethods,

      sizeof(gMethods) / sizeof(gMethods[0]));

      然后在這些函數中調用底層的函數來實現對應的功能。

      NormalText Code

      jint Java_cn_com_farsight_tool_UartTool_NativeFileRead(JNIEnv* env,

      jobject thiz, jbyteArray buf, jint size) {

      unsigned char *buf_char = (char*) ((*env)->GetByteArrayElements(env, buf,

      NULL));

      int result = uart_read(buf_char, size);

      (*env)->ReleaseByteArrayElements(env, buf, buf_char, 0);

      return result;

      }

      2.3.2 onLoad.cpp

      這個文件的主要作用是完成加載底層的庫文件的時候的工作。OnLoad函數在加載庫文件的時候會第一個執行。

      NormalText Code

      jint JNI_OnLoad(JavaVM* vm, void* reserved) {

      JNIEnv* env = NULL;

      jint result = JNI_ERR;

      sVm = vm;

      if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

      LOGE("GetEnv failed!");

      return result;

      }

      if (register_cn_com_farsight_tool_UartTool(env) != JNI_OK) {

      LOGE("can't load register_cn_com_farsight_tool_UartTool()");

      goto end;

      }

      LOGE("loaded succeed");

      result = JNI_VERSION_1_4;

      end: return result;

      }

      jniRegisterNativeMethods函數的作用是將剛才的關系結構體注冊進系統當中,同時,尋找上層需要調用這些底層函數的類。

      NormalText Code

      int jniRegisterNativeMethods(JNIEnv* env, const char* className,

      const JNINativeMethod* gMethods, int numMethods) {

      jclass clazz;

      LOGE("Registering %s natives\n", className);

      clazz = env->FindClass(className);

      if (clazz == NULL) {

      LOGE("Native registration unable to find class '%s'\n", className);

      return -1;

      }

      if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {

      LOGE("RegisterNatives failed for '%s'\n", className);

      return -1;

      }

      return 0;

      }

      2.3.3 uart.c

      這個文件就是底層函數的具體實現了。uart_get函數的功能就是打開串口,根據上層傳遞過來的參數和波特率來打開設備文件。

      NormalText Code

      int uart_get(char *filename, int rate) { //成功返回0,失敗-1

      struct termios opt;

      // uart

      if ((fd = open(filename, O_RDWR | O_NOCTTY, 0777)) == -1) {

      LOGE("UART open error!!! :%s ", strerror(errno));

      return -1;

      }

      //初始化串口

      tcgetattr(fd, &opt);

      LOGE("rate is %d", rate);

      switch (rate) {

      case 4800:

      cfsetispeed(&opt, B4800);

      cfsetospeed(&opt, B4800);

      break;

      case 9600:

      cfsetispeed(&opt, B9600);

      cfsetospeed(&opt, B9600);

      break;

      case 19200:

      cfsetispeed(&opt, B19200);

      cfsetospeed(&opt, B19200);

      break;

      case 38400:

      cfsetispeed(&opt, B38400);

      cfsetospeed(&opt, B38400);

      break;

      case 115200:

      LOGE("rate is %d", rate);

      cfsetispeed(&opt, B115200);

      cfsetospeed(&opt, B115200);

      break;

      default:

      cfsetispeed(&opt, B115200);

      cfsetospeed(&opt, B115200);

      break;

      }

      opt.c_cflag |= (CLOCAL | CREAD);

      opt.c_cflag &= ~CSIZE;

      opt.c_cflag &= ~CRTSCTS;

      opt.c_cflag |= CS8;

      opt.c_iflag |= IGNPAR;

      opt.c_cflag &= ~CSTOPB;

      opt.c_oflag = 0;

      opt.c_lflag = 0;

      tcsetattr(fd, TCSANOW, &opt);

      LOGE("UART open %s succeed!!!", filename);

      return 0;

      }

      當要讀取數據的時候,先將上層傳遞下來的緩沖清空,使用read函數進行數據的讀取,然后返回。

      NormalText Code

      int uart_read(unsigned char *buf, int size) { //返回讀取數據的個數

      int len = 0;

      memset(buf, 0, size);

      int result = read(fd, buf, size);

      if (result <= 0) {

      LOGE("uart_read(%d) is error %s", size, strerror(errno));

      return -1;

      }

      // while (result < size) {

      // len = read(fd, buf + result, size - result);

      // result += len;

      // }

      LOGE("uart_read is %s", buf);

      return result;

      }

      直接調用write來向設備寫入數據。

      NormalText Code

      int uart_write(const unsigned char *buf, int size) { //返回寫入的數據長度

      int result = write(fd, buf, size);

      if (result > 0) {

      LOGE("uart write is %s", buf);

      }

      return result;

      }

      后程序結束的時候,關閉設備文件。

      NormalText Code

      int uart_close() {

      close(fd);

      LOGE("UART close succeed!!!");

      return 0;

      }

      上一篇:linux make命令安裝詳解

      下一篇:fork函數的小誤區

      熱點文章推薦
      華清學員就業榜單
      高薪學員經驗分享
      熱點新聞推薦
      前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2018 北京華清遠見科技發展有限公司 版權所有 ,京ICP備16055225號,京公海網安備11010802025203號
      操你啦,操你啦视频,操你啦影院,操你啦网站