树莓派基于wiringPi库, 编写JNI本地动态库供Java调用

xiaoxiao2021-02-28  58

树莓派基于wiringPi库, 编写JNI本地动态库供Java调用

本文关键字:

RaspberryPIJava JNIwiringPi库

什么是JNI

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。 —— [ WiKi ]

在这之前, RaspberryPi已经提供了Pi4J的java库供使用者来操作RaspberryPi的硬件资源, 因为你可以直接使用这些库。

笔者做这件事情的初衷是想因为一个项目, 想看看Java是如何与本地系统硬件资源交互的. 废话不多少, 直接上操作过程.

本文大致有如下几个步骤:

编写Java类, 定义与本地函数的接口.通过javah生成本地实现函数的头文件.编写本地实现函数.生成”.so”动态库文件.Java程序调用”.so”文件运行.

step1. Java类(JavaRaspberryPi)

这里在Java中定义了一个类, 代码如下:

import java.util.Scanner /* Author: Jony Deng. Email: den.mingxing@163.com Date: 2017/06/08 */ import java.util.Scanner class JavaRaspberryPi { // Define 3 native functions. public native void Hello(); public native void OpenLed(); public native void CloseLed(); static { System.out.println(System.getProperty("java.library.path")); // Load the "libLed.so" library. System.loadLibrary("Led"); } public static void main(String[] args) { JavaRaspberryPi pi = new JavaRaspberryPi(); Scanner sc = new Scanner(System.in); int count = 0; while(true) { System.out.println(""); System.out.println("Pls select ur operation:(" + Integer.toString(count) + ")"); System.out.println("-------------------------"); System.out.println("H/h: hello world."); System.out.println("O/o: open led."); System.out.println("C/c: close led."); System.out.println("E/e: exit application."); String text = sc.nextLine(); if(text.equals("H") || text.equals("h")){ System.out.println("Hello world..."); pi.Hello(); } else if(text.equals("O") || text.equals("o")){ System.out.println("Open led..."); pi.OpenLed(); } else if(text.equals("C") || text.equals("c")){ System.out.println("Close led..."); pi.CloseLed(); } else if(text.equals("E") || text.equals("e")){ System.out.println("Exit java application..."); pi.CloseLed(); } } } }

step2.生成本地实现函数的头文件

javah -jni JavaRaspberryPi.class

通过上述指令后, 用户将得到一个JavaRaspberryPi.h头文件,你需要实现这个头文件内声明的函数的函数体.

注意:值得注意的是: 我们在Java内声明的本地函数接口在此头文件内会变了一个名称, 如果要知道为什么, 请查考JNI的规则定义.

例如: public native void Hello() 在头文件内变成: JINIEXPORT void JNICALL Java_JavaRaspberryPi_Hello(JNIEnv* env, jobject jbt);**。

step3.编写本地实现函数

在这里博主定义了一个”Led.c”文件, 文件内容如下:

```C /* Author: Jony Deng. Email: den.mingxing@163.com Date: 2017/06/08 */ #include <stdio.h> #include <stdlib.h> #include "JavaRaspberryPi.h" #include <wiringPi.h> JINIEXPORT void JNICALL Java_JavaRaspberryPi_Hello(JNIEnv* env, jobject jbt) { printf("+===========================+\n"); printf("| Java native interface |\n"); printf("| Hello world |\n"); printf("+===========================+\n"); } JINIEXPORT void JNICALL Java_JavaRaspberryPi_OpenLed(JNIEnv* env, jobject jbt) { wiringPiSetup(); // set wiringPi module. pinMode(1, OUTPUT); // use physical "pin12", set it as output pin. digitalWrite(1, HIGH); // High signal. delay(20); // 20ms. } JINIEXPORT void JNICALL Java_JavaRaspberryPi_CloseLed(JNIEnv* env, jobject jbt) { wiringPiSetup(); // set wiringPi module. pinMode(1, OUTPUT); // use physical "pin12", set it as output pin. digitalWrite(1, Low); // Low signal. delay(20); // 20ms. }

step4.编译生成动态库.so文件

gcc Led.c -l wiringPi -fPIC -shared -o libLed.so

使用上述指令, 在console内生成动态库, 得到libLed.so.

step5. Java程序调用”.so”文件运行

java JavaRaspberryPi

使用上述指令运行Java程序, 但是在运行过程中会报错. 大概意思就是JVM找不到libLed.so文件, 博主此时查看了java.library.path路径, 博主java的library路径在/usr/lib内, 因此使用指令:

sudo cp libLed.so /usr/lib

OK, 程序可以正常运行了. 尝试输入上面的指令, 可以打开/关闭GPIO. 到此为止, 整个过程结束.


转载请注明原文地址: https://www.6miu.com/read-73751.html

最新回复(0)