<nav id="gb9pn"></nav>

  1. <form id="gb9pn"><legend id="gb9pn"></legend></form>

    <form id="gb9pn"><legend id="gb9pn"><video id="gb9pn"></video></legend></form>
  2. 当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > 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-2021 北京华清远见科技发展有限公司 版权所有 ,京ICP备16055225号-5,京公海网安备11010802025203号

    回到顶部

    welcome购彩中心