NDK & JNI方式读写Android系统的GPIO
来源:互联网 发布:淘宝上卖的一碗泄油汤 编辑:程序博客网 时间:2024/06/04 19:04
NDK & JNI方式读写Android系统的GPIO
大家都知道Android系统是一种基于Linux的自由及开放源码的操作系统,所以读写GPIO也可以直接用Linux那一套export/unexport方法,本文将介绍如何使用NDK jni方式来读写Android系统的GPIO。
1. 软硬件环境:
- Android Studio
- RK3288 Android开发板
2. Android Studio安装NDK
打开Android Studio 中的SDK Manager,菜单Tools -> Android -> SDK Manager
选中NDK,点击OK就可以安装NDK了,安装时间需要几分钟到十几分钟
3. 创建Android工程
(1) 创建Android工程jnigpio,然后添加一个新的java类GPIOControl.java
代码如下:
public class GPIOControl { static { System.loadLibrary("GPIOControl"); } public final static native int exportGpio(int gpio); public final static native int setGpioDirection(int gpio, int direction); public final static native int readGpioStatus(int gpio); public final static native int writeGpioStatus(int gpio, int value); public final static native int unexportGpio(int gpio);}
(2) Build -> Rebuild Project
(3) 生成jni的头文件
Android Studio Terminal中输入如下命令
cd app/src/main/java/
javah -d ../jni com.zhuang.jnigpio.GPIOControl
生成jni头文件如下图:
(4) jni目录下创建GPIOControl.c程序
代码如下:
//// Created by Gavin Zhuang on 05/12/2017.//#include <jni.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <sys/mman.h>#include <unistd.h>#include <android/log.h>#include "com_zhuang_jnigpio_GPIOControl.h"#define TAG "jni_gpio"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)#define IN 0#define OUT 1#define LOW 0#define HIGH 1#define BUFFER_MAX 3#define DIRECTION_MAX 48/* * Class: com_zhuang_jnigpio_GPIOControl * Method: exportGpio * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_exportGpio(JNIEnv *env, jobject instance, jint gpio){ char buffer[BUFFER_MAX]; int len; int fd; fd = open("/sys/class/gpio/export", O_WRONLY); if (fd < 0) { LOGE("Failed to open export for writing!\n"); return(0); } len = snprintf(buffer, BUFFER_MAX, "%d", gpio); if (write(fd, buffer, len) < 0) { LOGE("Fail to export gpio!\n"); return 0; } close(fd); return 1;}/* * Class: com_zhuang_jnigpio_GPIOControl * Method: setGpioDirection * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_setGpioDirection(JNIEnv *env, jobject instance, jint gpio, jint direction){ static const char dir_str[] = "in\0out"; char path[DIRECTION_MAX]; int fd; snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", gpio); fd = open(path, O_WRONLY); if (fd < 0) { LOGE("failed to open gpio direction for writing!\n"); return 0; } if (write(fd, &dir_str[direction == IN ? 0 : 3], direction == IN ? 2 : 3) < 0) { LOGE("failed to set direction!\n"); return 0; } close(fd); return 1;}/* * Class: com_zhuang_jnigpio_GPIOControl * Method: readGpioStatus * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_readGpioStatus(JNIEnv *env, jobject instance, jint gpio){ char path[DIRECTION_MAX]; char value_str[3]; int fd; snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", gpio); fd = open(path, O_RDONLY); if (fd < 0) { LOGE("failed to open gpio value for reading!\n"); return -1; } if (read(fd, value_str, 3) < 0) { LOGE("failed to read value!\n"); return -1; } close(fd); return (atoi(value_str));}/* * Class: com_zhuang_jnigpio_GPIOControl * Method: writeGpioStatus * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_writeGpioStatus(JNIEnv *env, jobject instance, jint gpio, jint value){ static const char values_str[] = "01"; char path[DIRECTION_MAX]; int fd; snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", gpio); fd = open(path, O_WRONLY); if (fd < 0) { LOGE("failed to open gpio value for writing!\n"); return 0; } if (write(fd, &values_str[value == LOW ? 0 : 1], 1) < 0) { LOGE("failed to write value!\n"); return 0; } close(fd); return 1;}/* * Class: com_zhuang_jnigpio_GPIOControl * Method: unexportGpio * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_unexportGpio(JNIEnv *env, jobject instance, jint gpio){ char buffer[BUFFER_MAX]; int len; int fd; fd = open("/sys/class/gpio/unexport", O_WRONLY); if (fd < 0) { LOGE("Failed to open unexport for writing!\n"); return 0; } len = snprintf(buffer, BUFFER_MAX, "%d", gpio); if (write(fd, buffer, len) < 0) { LOGE("Fail to unexport gpio!"); return 0; } close(fd); return 1;}
(5) 修改项目下的gradle.properties修改app下的build.gradle
在项目下的gradle.properties添加:
android.useDeprecatedNdk=true
在defaultConfig中添加ndk内容:
ndk{ moduleName "GPIOControl" //so文件: lib+moduleName+.so ldLibs "log", "z", "m" // 添加android日志引用 abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的类型 }
(6) Rebuild Project 生成so文件
so文件在app>build>intermediates>ndk>debug>lib>目录下,如图:
(7) 方法调用
// 定义GPIO输入输出方式和高低电平 public final static int GPIO_DIRECTION_IN = 0; public final static int GPIO_DIRECTION_OUT = 1; public final static int GPIO_VALUE_LOW = 0; public final static int GPIO_VALUE_HIGH = 1;
例如,输出高低电平变化信号(如:IO口接LED电路,闪烁发光)
调用流程跟直接linux下文件方式控制gpio类似,先export该管脚,然后设定输入输出方式,最后不用的时候要unexport该管脚。
mStartButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String gpioPinStr = mGPIOEdit.getEditableText().toString(); if (TextUtils.isEmpty(gpioPinStr)){ return; } mStartButton.setEnabled(false); final int gpioPin = Integer.valueOf(gpioPinStr); Thread thread = new Thread(new Runnable() { @Override public void run() { mIsFlashing = true; try { GPIOControl.exportGpio(gpioPin); GPIOControl.setGpioDirection(gpioPin, GPIOControl.GPIO_DIRECTION_OUT); boolean flag = true; while (mIsFlashing){ GPIOControl.writeGpioStatus(gpioPin, flag ? GPIOControl.GPIO_VALUE_HIGH : GPIOControl.GPIO_VALUE_LOW); flag = !flag; Thread.sleep(1000); } GPIOControl.unexportGpio(gpioPin); } catch (Exception ex){ } } }); thread.start(); } });
读取gpio电平状态,按键按下为高电平,松开为低电平,如下是读取该管脚的日志:
12-05 10:09:22.624: W/CallSettingFragment(2551): GpioRead value; 262; 112-05 10:09:22.724: W/CallSettingFragment(2551): GpioRead value; 262; 112-05 10:09:22.824: W/CallSettingFragment(2551): GpioRead value; 262; 112-05 10:09:22.925: W/CallSettingFragment(2551): GpioRead value; 262; 012-05 10:09:23.025: W/CallSettingFragment(2551): GpioRead value; 262; 012-05 10:09:23.126: W/CallSettingFragment(2551): GpioRead value; 262; 012-05 10:09:23.228: W/CallSettingFragment(2551): GpioRead value; 262; 0
注意事项:该控制GPIO需要su权限,可以试着用adb shell去修改 /sys/class/gpio/export 和 /sys/class/gpio/unexport 的读写权限。如:chmod 666 /sys/class/export
- NDK & JNI方式读写Android系统的GPIO
- Android系统JNI的实现方式
- Android系统JNI的实现方式
- Android系统JNI的实现方式
- android JNI (NDK)的故事
- Android JNI和NDK学习(03)--动态方式实现JNI
- Android JNI和NDK学习(02)--静态方式实现JNI
- Android JNI和NDK学习(03)--动态方式实现JNI
- 【转】Android应用程序:(jni方式)控制LED/GPIO
- Android初步学习NDK和JNI开发(命令行的方式)
- Android SDK、NDK、JNI的简单介绍
- JNI和Android NDK的使用
- JNI和Android NDK的使用
- Android-JNI NDK的学习记录
- Android NDK的入门学习Hello JNI
- Android的SDK,NDK以及JNI
- Android的SDK,NDK以及JNI
- Android NDK&&JNI 编译环境的搭建
- C++两个类相互调用
- 自定义动画实现左右摇摆
- 达内课程-FileInputStream/FileOutputStream
- NDK环境搭建
- 遗传学总复习--绪论
- NDK & JNI方式读写Android系统的GPIO
- C# WinForm获取 当前执行程序路径的几种方法
- stm32之定时器中断
- 在Linux环境下安装gcc/g++/gdb/vim,以及进行vim的配置
- 面试题42:翻转单词顺序(句子反转)
- PHP后端接收不到AngularJs中$http.post发送的数据的问题
- php 多维数组转一维数组
- 【转】Android ROM研究---Android build system增加模块
- ie删除文件html