概述
- 硬件平台: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访问硬件驱动的两种方式
方法1:
java的JNI技术 使得java可以访问C库。那我们就可以写好一个操作硬件的C库,然后加入到应用的工程中去,通过JNI来访问C库,从而实现对硬件的访问,这是操作硬件最简单的方法,但是没有凸显出android的特色。
优点:传统方法,简单易实现
缺点:jni多个设备同时访问,都可以来open吗?显然效率不好。
技术思路:
方法2:
硬件访问服务:发送请求服务—jni。不同硬件对应不同服务。
2、基于JNI的硬件访问
2.1、LED应用开发
首先我们来写一个应用程序,这个应用程序主要目的是 实现对硬件LED的操作。
开发框图
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720067384466.png)
编写android应用程序
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720062673563.png)
<?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>
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方法
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720071901078.png)
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();
}
}
}
下载到单板出错,是因为找不到库
(5)修改build.gradle,告诉系统库在哪里放着
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
(6)在app/libs下建armeabi子目录,放入so文件(so怎么得到看下一节JNI文件的编写)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720077993351.png)
onCreate: HardControl.ledCtrl(0, 1);
2.2 JNI文件编写hardcontrol.c
#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文件
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_log_print(ANDROID_LOG_DEBUG,"LEDDemo", "native ledOpen ...");
#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;
}
编译
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
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720084240544.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720094216513.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720096780553.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720096766725.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720096555609.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720098246522.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720091525904.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720099027634.png)
#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;
}
编译:
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。
参考内核中的厂家驱动代码:
#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)编译驱动程序
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720107378592.png)
leds_4412.c放入内核 drivers/char
修改drivers/char/Makefile,添加:
obj-y += leds_4412.o
重新编译内核
make zImage
work/linux-3.0.86/arch/boot/zImage
下载内核到开发板
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720103842743.png)
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720101614213.png)
Cat /proc/devices
![](https://file2.kaopuke.com:8081/files_image/2023060717/202306071720101480018.png)
3、总结
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
编译c库:
(6) 指定liblog.so库路径 /work/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so
启动应用 测试程序
点击打开链接
http://download.csdn.net/detail/fengyuwuzu0519/9755859
最后
以上就是自觉黑裤为你收集整理的Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件1、android访问硬件驱动的两种方式2、基于JNI的硬件访问3、总结启动应用 测试程序的全部内容,希望文章能够帮你解决Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件1、android访问硬件驱动的两种方式2、基于JNI的硬件访问3、总结启动应用 测试程序所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复