• 硬件平台:tiny4412
  • 系统:Android  5.0.2
  • 编译器: arm-linux-gcc-4.5.1

首先来看一下android的系统框图。google后期加入一层HAL层,硬件访问层HAL

https://developer.android.com/guide/platform/index.html

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第1张图片

1、android访问硬件驱动的两种方式

android如何管理多个应用对硬件的访问:硬件访问服务。

方法1:

java的JNI技术 使得java可以访问C库。那我们就可以写好一个操作硬件的C库,然后加入到应用的工程中去,通过JNI来访问C库,从而实现对硬件的访问,这是操作硬件最简单的方法,但是没有凸显出android的特色。

优点:传统方法,简单易实现

缺点:jni多个设备同时访问,都可以来open吗?显然效率不好。
技术思路:

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第2张图片

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第3张图片

方法2:

硬件访问服务:发送请求服务—jni。不同硬件对应不同服务。

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第4张图片

2、基于JNI的硬件访问

 2.1、LED应用开发

首先我们来写一个应用程序,这个应用程序主要目的是 实现对硬件LED的操作。

开发框图

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第5张图片

编写android应用程序

(1)创建一个android应用程序工程 (2)编写布局代码 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第6张图片
<?xml version="1.0" encoding="utf-8"?>        

(3)添加按键和复选框的监听事件: 代码片段:
button.setOnClickListener(new MyButtonListener());
    
class MyButtonListener implements View.OnClickListener {    @Override    public void onClick(View v) {        HardControl hardControl = new HardControl();//依赖硬件        led_on = !led_on;        if (led_on) {            button.setText("ALL OFF");            led1.setChecked(true);            led2.setChecked(true);            led3.setChecked(true);            led4.setChecked(true);            for (int i = 0; i < 4; i++)                HardControl.ledCtrl(i, 1);        }
    
    
android:onClick="onCheckboxClicked"
public void onCheckboxClicked(View view) {    // Is the view now checked?    boolean checked = ((CheckBox) view).isChecked();    // Check which checkbox was clicked    switch(view.getId()) {        case R.id.led1:            if (checked)            {                Toast.makeText(getApplicationContext(),"led1_on",Toast.LENGTH_LONG).show();                HardControl.ledCtrl(1, 1);            }
    else    {        Toast.makeText(getApplicationContext(),"led1_off",Toast.LENGTH_LONG).show();        HardControl.ledCtrl(1, 0);    }    break;case R.id.led2:
(4)申明本地java方法
    
Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第7张图片

HardControl.JAVA:

package com.example.yangfei.hardlibrary;public class HardControl {    public static native int ledCtrl(int which, int status);    public static native int ledOpen();    public static native void ledClose();//申明三个本地方法。    static {        try {            System.loadLibrary("hardcontrol");        } catch (Exception e) {            e.printStackTrace();        }    }}

下载到单板出错,是因为找不到库

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第8张图片

(5)修改build.gradle,告诉系统库在哪里放着

sourceSets {    main {        jniLibs.srcDirs = ['libs']    }}
(6)在app/libs下建armeabi子目录,放入so文件(so怎么得到看下一节JNI文件的编写)
Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第9张图片

onCreate: HardControl.ledCtrl(0, 1);

2.2 JNI文件编写hardcontrol.c

(1)基本的JNI访问C库实现hardcontrol.c
#include   /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */#include #include #if 0typedef struct {    char *name;          /* Java里调用的函数名 */    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */    void *fnPtr;          /* C语言实现的本地函数 */} JNINativeMethod;#endifjint ledOpen(JNIEnv *env, jobject cls){return 0;}void ledClose(JNIEnv *env, jobject cls){}jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status){return 0;}static const JNINativeMethod methods[] = {{"ledOpen", "()I", (void *)ledOpen},{"ledClose", "()V", (void *)ledClose},{"ledCtrl", "(II)I", (void *)ledCtrl},};/* System.loadLibrary */JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){JNIEnv *env;jclass cls;if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {return JNI_ERR; /* JNI version not supported */}cls = (*env)->FindClass(env, "com/example/yangfei/hardlibrary/HardControl");if (cls == NULL) {return JNI_ERR;}/* 2. map java hello <-->c c_hello */if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0)return JNI_ERR;return JNI_VERSION_1_4;}
编译hardcontrol.c生成SO文件
arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/  -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so

-I   /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ : jni.h的存放目录


-nostdlib  不使用标准库 是android系统源码里的 如下:

/work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so   : 指定libc.so,因为依赖于这个库


Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第10张图片Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第11张图片Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第12张图片Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第13张图片

(2)加入打印信息hardcontrol.c

使用:__android_log_print(ANDROID_LOG_DEBUG,"LEDDemo", "native ledOpen ...");

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第14张图片

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第15张图片



Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第16张图片




Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第17张图片Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第18张图片


#include   /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */#include #include #include   /* liblog *///__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ..."); #if 0typedef struct {    char *name;          /* Java里调用的函数名 */    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */    void *fnPtr;          /* C语言实现的本地函数 */} JNINativeMethod;#endifjint ledOpen(JNIEnv *env, jobject cls){__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledOpen ...");return 0;}void ledClose(JNIEnv *env, jobject cls){__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledClose ...");}jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status){__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d", which, status);return 0;}static const JNINativeMethod methods[] = {{"ledOpen", "()I", (void *)ledOpen},{"ledClose", "()V", (void *)ledClose},{"ledCtrl", "(II)I", (void *)ledCtrl},};/* System.loadLibrary */JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){JNIEnv *env;jclass cls;if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {return JNI_ERR; /* JNI version not supported */}cls = (*env)->FindClass(env, "com/thisway/hardlibrary/HardControl");if (cls == NULL) {return JNI_ERR;}/* 2. map java hello <-->c c_hello */if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0)return JNI_ERR;return JNI_VERSION_1_4;}

编译

arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/  -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so -I /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so

(3)hardcontrol.c加入底层控制生成 libhardcontrol.so

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第19张图片 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第20张图片 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第21张图片 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第22张图片 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第23张图片 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第24张图片 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第25张图片
#include   /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */#include #include #include #include #include #include #include   /* liblog *///__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ...");#if 0typedef struct {    char *name;          /* Java里调用的函数名 */    char *signature;    /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */    void *fnPtr;          /* C语言实现的本地函数 */} JNINativeMethod;#endifstatic jint fd;jint ledOpen(JNIEnv *env, jobject cls){fd = open("/dev/leds", O_RDWR);__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledOpen : %d", fd);if (fd >= 0)return 0;elsereturn -1;}void ledClose(JNIEnv *env, jobject cls){__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledClose ...");close(fd);}jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status){int ret = ioctl(fd, status, which);__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d, %d", which, status, ret);return ret;}static const JNINativeMethod methods[] = {{"ledOpen", "()I", (void *)ledOpen},{"ledClose", "()V", (void *)ledClose},{"ledCtrl", "(II)I", (void *)ledCtrl},};/* System.loadLibrary */JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){JNIEnv *env;jclass cls;if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {return JNI_ERR; /* JNI version not supported */}cls = (*env)->FindClass(env, "com/example/yangfei/hardlibrary/HardControl");if (cls == NULL) {return JNI_ERR;}/* 2. map java hello <-->c c_hello */if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0)return JNI_ERR;return JNI_VERSION_1_4;}
编译:
arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/  -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so -I /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so

2.3 编写驱动程序leds_4412.c

(驱动编译进linux内核,并创建设备节点)

(1)驱动程序编写

应用程序的不会看原理图,只会用open read write。

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第26张图片

参考内核中的厂家驱动代码:

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第27张图片

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第28张图片

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第29张图片


Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第30张图片Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第31张图片

#include #include #include #include #include #include #include #include #include #include #include  #include #include #include static int led_gpios[] = {EXYNOS4212_GPM4(0),EXYNOS4212_GPM4(1),EXYNOS4212_GPM4(2),EXYNOS4212_GPM4(3),};static int led_open(struct inode *inode, struct file *file){/* 配置GPIO为输出引脚 */int i;for (i = 0; i < 4; i++)s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);return 0;}/* app : ioctl(fd, cmd, arg) */static long led_ioctl(struct file *filp, unsigned int cmd,unsigned long arg){/* 根据传入的参数设置GPIO *//* cmd : 0-off, 1-on *//* arg : 0-3, which led */if ((cmd != 0) && (cmd != 1))return -EINVAL;if (arg > 4)return -EINVAL;gpio_set_value(led_gpios[arg], !cmd);return 0;}static struct file_operations leds_ops = {/* 结构 */    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */    .open   =   led_open,     .unlocked_ioctl= led_ioctl,};static int major;static struct class *cls;int leds_init(void)/* 入口函数 */{major = register_chrdev(0, "leds", &leds_ops);/* 为了让系统udev,mdev给我们创建设备节点 *//* 创建类, 在类下创建设备 : /sys */cls = class_create(THIS_MODULE, "leds");device_create(cls, NULL, MKDEV(major, 0), NULL, "leds"); /* /dev/leds */return 0;}void leds_exit(void)/* 出口函数 */{device_destroy(cls, MKDEV(major, 0));class_destroy(cls);unregister_chrdev(major, "leds");}module_init(leds_init);module_exit(leds_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("www.100ask.net");
(2)编译驱动程序 Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第32张图片

leds_4412.c放入内核 drivers/char

修改drivers/char/Makefile,添加:

obj-y += leds_4412.o

重新编译内核

make zImage

work/linux-3.0.86/arch/boot/zImage

下载内核到开发板

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第33张图片

Cat /proc/devices

Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件_第34张图片

3、总结

(1)写了一个java类,通过 System.loadLibrary("hardcontrol");来加载本地C库。 (2)在app/libs下建armeabi子目录,放入so文件。 需要制定lib库的位置
sourceSets {    main {        jniLibs.srcDirs = ['libs']    }}
编译c库:
(3)-I   /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ : jni.h的存放目录 (4) -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so   :指定libc.so, 不使用标准库libc.so.6   libc.so是android系统源码里有的, 使用这个这个库 增加android打印: (5)打印信息: __android_log_print(ANDROID_LOG_DEBUG,"LEDDemo", "native ledOpen ..."); 需要加入头#include
(6)   指定liblog.so库路径   /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so

启动应用 测试程序


APP,JNI,驱动代码下载地址:

点击打开链接

http://download.csdn.net/detail/fengyuwuzu0519/9755859

更多相关文章

  1. Android 利用JNI调用Android Java代码函数
  2. Android模拟 HTTP multipart/form-data 请求协议信息实现图片上
  3. Android android:scaleType属性 图片按比例缩放
  4. Android中SensorManager.getRotationMatrix函数原理解释
  5. Android 相机拍照获取图片并保存到指定位置。
  6. Android 上传图片到后台的一直方式Base64的String形式
  7. android富文本 加载带图片的html
  8. Android开发笔记——以Volley图片加载、缓存、请求及展示为例理
  9. Android使用BitmapRegionDecoder获取指定区域的图片

随机推荐

  1. MySQL 重命名表的操作方法及注意事项
  2. Mysql官方性能测试工具mysqlslap的使用简
  3. MySQL官方导出工具mysqlpump的使用
  4. 新手必备之MySQL msi版本下载安装图文详
  5. MySQL数据库压缩版本安装与配置详细教程
  6. MySQL 8.0 之不可见列的基本操作
  7. Mysql Online DDL的使用详解
  8. MySQL 存储过程的优缺点分析
  9. IDEA 链接Mysql数据库并执行查询操作的完
  10. MySQL 覆盖索引的优点