Android 通過GPIO 控制LED燈的亮滅,給菜鳥小白用的
開發環境
版本 Android studio 3.5 Gradle 5.4.1
Android 設備環境:
rockchip rk3288
查看GPIO信息
如果不清楚自己的開發板gpio編號對應的是什麼可以查看下這篇文章地址
文章原創地址
我不會jni,所以jni部分是別人的,地址
源碼
代碼部分
jni部分(非原創) 地址
gpio-manager.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_zhongyi_gpiodemo_MainActivity */
#ifndef _Included_com_zhongyi_gpiolibrary_GpioManager
#define _Included_com_zhongyi_gpiolibrary_GpioManager
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_beep_GpioCtr
* Method: exportGpio
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_zhongyi_gpiolibrary_GpioManager_exportGpio
(JNIEnv *, jclass, jint);
/*
* Class: com_example_beep_GpioCtr
* Method: setGpioDirection
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_zhongyi_gpiolibrary_GpioManager_setGpioDirection
(JNIEnv *, jclass, jint, jint);
/*
* Class: com_example_beep_GpioCtr
* Method: readGpioStatus
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_zhongyi_gpiolibrary_GpioManager_readGpioStatus
(JNIEnv *, jclass, jint);
/*
* Class: com_example_beep_GpioCtr
* Method: writeGpioStatus
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_zhongyi_gpiolibrary_GpioManager_writeGpioStatus
(JNIEnv *, jclass, jint, jint);
/*
* Class: com_example_beep_GpioCtr
* Method: unexportGpio
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_zhongyi_gpiolibrary_GpioManager_unexportGpio
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
gpio-manager.cpp
#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 "gpio-manager.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
/**
* 文件所有者是root,所以在操作之前修改文件的權限
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhongyi_gpiolibrary_GpioManager_exportGpio(JNIEnv *env, jclass clazz, jint gpio) {
system("su");
system("sudo");
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);
}
LOGE("sizeof(buffer) : %d", sizeof(buffer));
len = snprintf(buffer, BUFFER_MAX, "%d", gpio);
LOGE("gpio : %d , len : %d, buffer : %s , sizeof(buffer) : %d", gpio, len, buffer, sizeof(buffer));
if (write(fd, buffer, len) < 0) {
LOGE("Fail to export gpio!\n");
return 0;
}
close(fd);
return 1;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhongyi_gpiolibrary_GpioManager_setGpioDirection(JNIEnv *env, jclass clazz, 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);
LOGE("path : %s", path);
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;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhongyi_gpiolibrary_GpioManager_readGpioStatus(JNIEnv *env, jclass clazz, 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;
}
LOGD("fd %d\n", fd);
close(fd);
return (atoi(value_str));
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhongyi_gpiolibrary_GpioManager_writeGpioStatus(JNIEnv *env, jclass clazz, 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);
LOGE("write path: %s\n", path);
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;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_zhongyi_gpiolibrary_GpioManager_unexportGpio(JNIEnv *env, jclass clazz, 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;
}
java部分
命令執行工具CommandExec.java 用於在操作gpio之前,先修改文件的權限。
/**
* 命令行執行工具
*/
public class CommandExec {
private CommandExec() {
}
/**
* 修改gpio下文件的權限,讓他可以使用
* @param ledId gpio 編號
* @return 成功true
*/
public static boolean execRedLed(int ledId) {
return execCommand(String.format("cd /sys/class/gpio/gpio%d/ && chmod 777 value", ledId));
}
/**
* 還原 gpio文件的權限
* @param ledId gpio 編號
* @return 成功 true
*/
public static boolean releaseLed(int ledId) {
return execCommand(String.format("cd /sys/class/gpio/gpio%d/ && chmod 644 value", ledId));
}
public static boolean execCommand(String command) {
boolean status = false;
if (TextUtils.isEmpty(command)) {
return status;
}
try {
Process exec = Runtime.getRuntime().exec("su");
OutputStream outputStream = exec.getOutputStream();
outputStream.write(command.getBytes(Charset.forName("utf-8")));
outputStream.write("\n".getBytes());
outputStream.write("exit\n".getBytes());
outputStream.flush();
int waitFor = exec.waitFor();
Log.e("execCommand", "execCommand command:"+command+";waitFor=" + waitFor);
if (waitFor == 0) {
//chmod succeed
status = true;
}
} catch (Exception e) {
e.printStackTrace();
Log.e("execCommand", "execCommand exception=" + e.getMessage());
return false;
}
return status;
}
}
jni java部分 GpioManager.java 用於調用jni
/**
* 控制gpio
*/
public class GpioManager {
public static int out = 1;
public static int in = 0;
static {
System.loadLibrary("gpio-manager");
}
public static native int exportGpio(int gpio);
public static native int setGpioDirection(int gpio, int direction);
public static native int readGpioStatus(int gpio);
/**
* 修改gpio狀態
* @param gpio
* @param value
* @return
*/
public static native int writeGpioStatus(int gpio, int value);
public static native int unexportGpio(int gpio);
}
調用
static int LED_WHITE = 11;
....
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
execLed(); //使led文件可讀寫
...
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseLed(); //還原led讀寫權限
}
/**
* 讓led可執行
*/
private void execLed() {
CommandExec.execRedLed(LED_WHITE);
CommandExec.execRedLed(LED_RED);
CommandExec.execRedLed(LED_GREEN);
}
/**
* 釋放led燈
*/
private void releaseLed() {
CommandExec.releaseLed(LED_WHITE);
CommandExec.releaseLed(LED_RED);
CommandExec.releaseLed(LED_GREEN);
}
....
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_write:
flag_white = (flag_white == 0 ? 1 : 0); //1 燈亮 0 燈滅
GpioManager.writeGpioStatus(LED_WHITE, flag_white);
((TextView) v).setText(flag_white == 1 ? "白燈亮" : "白燈滅");
break;
}
}