我是靠谱客的博主 自觉黑裤,这篇文章主要介绍Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件1、android访问硬件驱动的两种方式2、基于JNI的硬件访问3、总结启动应用 测试程序,现在分享给大家,希望可以做个参考。

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

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

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


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

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

方法1:

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

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

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



方法2:

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


2、基于JNI的硬件访问

 2.1、LED应用开发

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

开发框图


编写android应用程序

(1)创建一个android应用程序工程
(2)编写布局代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.yang.MainActivity" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:padding="10dp"/> <Button android:text="ALL on" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:id="@+id/button" /> <CheckBox android:layout_width="match_parent" android:layout_height="wrap_content" android:text="LED1" android:onClick="onCheckboxClicked" android:id="@+id/led1" /> <CheckBox android:layout_width="match_parent" android:layout_height="wrap_content" android:text="LED2" android:onClick="onCheckboxClicked" android:id="@+id/led2" /> <CheckBox android:layout_width="match_parent" android:layout_height="wrap_content" android:text="LED3" android:onClick="onCheckboxClicked" android:id="@+id/led3" /> <CheckBox android:layout_width="match_parent" android:layout_height="wrap_content" android:text="LED4" android:onClick="onCheckboxClicked" android:id="@+id/led4" /> </LinearLayout>

(3)添加按键和复选框的监听事件:
代码片段:
复制代码
1
button.setOnClickListener(new MyButtonListener());
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
复制代码
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方法
复制代码
1


HardControl.JAVA:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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(); } } }

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


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

复制代码
1
2
3
4
5
6
sourceSets { main { jniLibs.srcDirs = ['libs'] } }
(6)在app/libs下建armeabi子目录,放入so文件(so怎么得到看下一节JNI文件的编写)

onCreate: HardControl.ledCtrl(0, 1);

2.2 JNI文件编写hardcontrol.c

(1)基本的JNI访问C库实现hardcontrol.c
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <jni.h> /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */ #include <stdio.h> #include <stdlib.h> #if 0 typedef struct { char *name; /* Java里调用的函数名 */ char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */ void *fnPtr; /* C语言实现的本地函数 */ } JNINativeMethod; #endif jint 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 JNICALL JNI_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文件
复制代码
1
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,因为依赖于这个库



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

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











复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <jni.h> /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */ #include <stdio.h> #include <stdlib.h> #include <android/log.h> /* liblog */ //__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ..."); #if 0 typedef struct { char *name; /* Java里调用的函数名 */ char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */ void *fnPtr; /* C语言实现的本地函数 */ } JNINativeMethod; #endif jint 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 JNICALL JNI_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; }

编译

复制代码
1
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


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <jni.h> /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <android/log.h> /* liblog */ //__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ..."); #if 0 typedef struct { char *name; /* Java里调用的函数名 */ char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */ void *fnPtr; /* C语言实现的本地函数 */ } JNINativeMethod; #endif static 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; else return -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 JNICALL JNI_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; }
编译:
复制代码
1
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。

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





复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> 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)编译驱动程序

leds_4412.c放入内核 drivers/char

修改drivers/char/Makefile,添加:

obj-y += leds_4412.o

重新编译内核

make zImage

work/linux-3.0.86/arch/boot/zImage

下载内核到开发板



Cat /proc/devices



3、总结

(1)写了一个java类,通过 System.loadLibrary("hardcontrol");来加载本地C库。
(2)在app/libs下建armeabi子目录,放入so文件。
需要制定lib库的位置
复制代码
1
2
3
4
5
sourceSets { main { jniLibs.srcDirs = ['libs'] } }
复制代码
1
编译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 <android/log.h>
(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

最后

以上就是自觉黑裤最近收集整理的关于Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件1、android访问硬件驱动的两种方式2、基于JNI的硬件访问3、总结启动应用 测试程序的全部内容,更多相关Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件1、android访问硬件驱动的两种方式2、基于JNI的硬件访问3、总结启动应用内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部