android驱动学习1

编程入门 行业动态 更新时间:2024-10-15 02:25:16

<a href=https://www.elefans.com/category/jswz/34/1771384.html style=android驱动学习1"/>

android驱动学习1

QQ:971586331

软件环境:

操作系统:windows 10

IDE版本:Android Studio 3.4.2

JAVA版本:jdk-8u221-windows-x64

NDK版本:android-ndk-r20-windows-x86_64

Kernel版本:linux 3.0

开发板android版本:android 4.0.3

硬件环境:

开发板:itop-4412 精英版

本文内容:本文描述了如何使用android应用程序调用linux驱动控制LED灯的亮灭。要实现android应用程序控制LED,需要三个程序,LED的linux驱动,JNI库和android应用程序。android应用程序通过JNI库调用LED驱动程序,从而实现android应用程序控制LED。

1.开发板环境搭建

开发环境搭建请参考《iTOP-4412开发板之精英版使用手册_V3.1.pdf》,本文使用的配置是

uboot:iTop4412_uboot_20180320.tar

kernel:iTop4412_Kernel_3.0_20180604.tar

android:iTop4412_ICS_git_20151120.tar

编译完成后将ramdisk-uboot.img,system.img,zImage,u-boot-iTOP-4412.bin文件通过OTG或SD烧写到开发板的EMMC中,如果在uboot下使用OTG,发现windows 10装不上光盘中的android_drv_90000_64.exe驱动,可以谷歌搜索安装android_11000010001_x64_718.exe。

2.LED的驱动程序

LED驱动在kernel的drivers/char/itop4412-leds.c中,从itop4412-leds.c中我们可以得知LED驱动的设备文件名叫“leds”。驱动程序实现了ioctl函数。

long leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{printk("debug: leds_ioctl cmd is %d\n" , cmd);switch(cmd){case 0:case 1:if (arg > LED_NUM) {return -EINVAL;}gpio_set_value(led_gpios[arg], cmd);break;default:return -EINVAL;}return 0;
}

leds_ioctl的cmd参数表示灯的亮灯,arg参数表示灯的编号,根据文件中的定义可以知,0表示GPL2_0,也就是LED2,1表示GPK1_1,也就是LED3。

static int led_gpios[] = {EXYNOS4_GPL2(0),EXYNOS4_GPK1(1),
};

接下来我们查看drivers/char/Makefile文件,宏CONFIG_LEDS_CTL控制LED驱动是否编译

obj-$(CONFIG_LEDS_CTL)		+= itop4412_leds.o

再查看drivers/char/Kconfig文件,默认就是y

config LEDS_CTLbool "Enable LEDS config"default yhelpEnable LEDS config

再查看.config,已经将LED驱动编入了内核

CONFIG_LEDS_CTL=y

看来板子的驱动已经做好了,完全不用我们动手,接下我们看怎么编写JNI接口调用linux驱动

3.JNI和NDK

因为android是使用java语言进行开发的,但linux驱动是用C语言进行开发的,所以面临java如果调用C语言接口的问题,JNI提供的API就是解决java和其他语言通信的问题。NDK 是一套工具集合,允许你使用C语言来实现应用程序的部分功能。我们写好JNI接口后使用NDK打包成库文件,就可以提供给android应用程序调用了。接下来我们新建工程编写JNI。

新建一个空activity

填写工程名,选择工程路径,开发语言选择java,API选择15

创建工程后得待编译完成,然后在包名下创建一个名叫jni_led的类

文件内容如下:

package com.example.led_test;public class jni_led {public native static String Leds_Operation(int ledNum, boolean status); //操作接口
}

打开 Android Studio 的 Terminal,使用javac命令将java文件编译成.class文件

F:\OneDrive\Linux\android_project\led_test>javac .\app\src\main\java\com\example\led_test\jni_led.java

使用javah命令创建头文件。-encoding UTF-8表示指定编码格式,防止出现“错误: 编码GBK的不可映射字符”,-d jni表示在当前目录下创建jni目录,将生成的文件放在jni目录中,-classpath表示指定类文件的路径。这里有一个地方要注意,类文件在写的时候是包名+类名,所有路径只用写到java目录,后面的com,example和led_test虽然都是文件夹,但这里表示包名(第一次写在这里纠结了好久,我想我路径明明写对了啊,为什么找不到\app\src\main\java\com\example\led_test文件夹下的类)

F:\OneDrive\Linux\android_project\led_test>javah -encoding UTF-8 -d jni -classpath ./app/src/main/java com.example.led_test.jni_led

指令执行完成后可以发现在jni目录下生成了包名加类名的头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_led_test_jni_led */#ifndef _Included_com_example_led_test_jni_led
#define _Included_com_example_led_test_jni_led
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_example_led_test_jni_led* Method:    Leds_Operation* Signature: (IZ)Ljava/lang/String;*/
JNIEXPORT jstring JNICALL Java_com_example_led_1test_jni_1led_Leds_1Operation(JNIEnv *, jclass, jint, jboolean);#ifdef __cplusplus
}
#endif
#endif

可以发现,头文件中根据jni_led.java中定义的java类接口生成了JNI接口函数,我们要实现这个接口函数。

然后在JNI下创建com_example_led_test_jni_led.c文件

在com_example_led_test_jni_led.c中,我们将头文件中的接口函数据复制过来,然后使用linux API操作linux设备文件

//
// Created by shiyu on 2019/8/17.
//#include<jni.h>
#include<stdio.h>
#include <fcntl.h>
#include <linux/ioctl.h>
//导入我们创建的头文件
#include "com_example_led_test_jni_led.h"#define DEVICE_NAME		"/dev/leds"JNIEXPORT jstring JNICALL Java_com_example_led_JNITest_Leds_1Operation(JNIEnv *env, jclass obj, jint ledsNum, jboolean status){int leds_fd = 0;leds_fd = open(DEVICE_NAME, O_RDWR);  //打开设备节点if (leds_fd == -1) {return 1;}switch (ledsNum) {case 0:if (status)ioctl(leds_fd, 0, 0);elseioctl(leds_fd, 1, 0);break;case 1:if (status)ioctl(leds_fd, 0, 1);elseioctl(leds_fd, 1, 1);break;defautl :break;}close(leds_fd);return 0;  //操作成功返回0
}

在jni下创建一个Android.mk文件


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE := jni_led
LOCAL_SRC_FILES := com_example_led_test_jni_led.c
include $(BUILD_SHARED_LIBRARY)

这时指定了生成库的名字和源文件,再新建一个Application.mk文件

APP_ABI := all

安装NDK工具集后,进入jni目录使用ndk-build命令将JNI接口程序编译成库文件

在libs目录下生成了各种平台的库文件

为了让项目能够找到我们的生成的库,在 build.gradle 文件夹的 android 下添加:

sourceSets {main() {jniLibs.srcDirs = ['../libs']jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程}}

然后在jni_led.java中加载生成的库文件

package com.example.led_test;public class jni_led {static {System.loadLibrary("jni_led");  //加载生成的.so文件}public native static String Leds_Operation(int ledNum, boolean status); //操作接口
}

接下来我们编写android应用程序利用Leds_Operation接口控制LED灯

4.编写android应用程序

打开工程目录下的activity_main.xml文件,添加4个button,并指写button的onClick回调函数

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=""xmlns:app=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TableLayoutandroid:id="@+id/TableLayout2"android:layout_width="fill_parent"android:layout_height="wrap_content"android:collapseColumns="4" ><TableRow><Buttonandroid:id="@+id/button_led3off"android:layout_width="200dp"android:layout_height="200dp"android:onClick="led3_off_click"android:text="led3_off"tools:layout_editor_absoluteX="228dp"tools:layout_editor_absoluteY="186dp" /><Buttonandroid:id="@+id/button_led3on"android:layout_width="200dp"android:layout_height="200dp"android:onClick="led3_on_click"android:text="led3_on"tools:layout_editor_absoluteX="98dp"tools:layout_editor_absoluteY="186dp" /><Buttonandroid:id="@+id/button_led2off"android:layout_width="200dp"android:layout_height="200dp"android:onClick="led2_on_click"android:text="led2_off"tools:layout_editor_absoluteX="228dp"tools:layout_editor_absoluteY="100dp" /><Buttonandroid:id="@+id/button_led2on"android:layout_width="200dp"android:layout_height="200dp"android:onClick="led2_off_click"android:text="led2_on"tools:layout_editor_absoluteX="98dp"tools:layout_editor_absoluteY="100dp" /></TableRow></TableLayout></androidx.constraintlayout.widget.ConstraintLayout>

我们为4个按键指定了4个回调函数据,接下来我们在MainActivity.java中实现这4个回调函数

package com.example.led_test;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void led2_on_click( View view ){jni_led.Leds_Operation(0, false);}public void led2_off_click( View view ){jni_led.Leds_Operation(0, true);}public void led3_on_click( View view ){jni_led.Leds_Operation(1, false);}public void led3_off_click( View view ){jni_led.Leds_Operation(1, true);}
}

如上,我们实现了这4个回调函数,调用jni_led库中的Leds_Operation函数,Leds_Operation会调用Java_com_example_led_JNITest_Leds_1Operation函数,这样就实现了android应用程序调用linux驱动接口。

连接开发板,编译运行。

 

 

更多推荐

android驱动学习1

本文发布于:2024-03-12 01:29:40,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1730386.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:android

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!