Android 驱动编写LED-NDK程序

针对"Android 驱动编写LED-NDK程序",下面是详细的攻略过程:

1. 准备工作

开发过程中需要的一些准备工作:

(1)Android驱动编写LED开发板

正常情况下,开发板上都会有LED指示灯,我们可以通过控制这些指示灯达到验证驱动是否正常执行的效果。

(2)NDK

NDK 是一个让你用 C 或 C++ 来构建 Android 应用的工具集。通常情况下,NDK会集成在Android Studio中,我们不需要进行相应的下载安装。如果不存在,使用Android Studio自带的SDK Manager,安装NDK对应版本即可。

2. 搭建开发环境

(1)创建Android工程文件

首先,在Android Studio中创建一个新的 Native Activity 工程,选择 C++。如果不知道如何创建,可以参考 Android 官方文档:创建 Android 项目

(2)建立jni目录

\"jni\"目录是一个特殊的目录,用于存放我们编写的 C/C++ 源代码,将其放至位于\"app/src/main/"\"下。

(3)编写led.c驱动程序文件

此处我们提供两个示例:c_led_dev 和 c_gpio_led_dev,用于验证LED是否开启。

// c_led_dev.c示例

#include <linux/fs.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/delay.h>

#include <asm/gpio.h>
#include <asm/uaccess.h>

MODULE_AUTHOR("luojing3");
MODULE_LICENSE("GPL");

#define LED_DEV_NAME "c_led_dev"

static int c_gpio_led_open(struct inode *inode, struct file *file) {
    printk("c_gpio_led_dev c_gpio_led_open!\n");
    return 0;
}

static ssize_t c_gpio_led_read(struct file *file,
    char __user *buf, size_t len, loff_t *pos) {
    printk("c_gpio_led_dev c_gpio_led_read!\n");
    return 0;
}

static ssize_t c_gpio_led_write(struct file *file,
    const char __user *buf, size_t len, loff_t *pos) {

    int res;
    char kbuf[6] = {0};

    memset(kbuf, 0, sizeof(kbuf));

    res = copy_from_user(kbuf, buf, len);
    if (res) {
        printk("%s: copy_from_user failed!\n", LED_DEV_NAME);
        return -EFAULT;
    }

    if (strcmp(kbuf, "on") == 0) {
        printk("%s: led on!\n", LED_DEV_NAME);
        gpio_direction_output(12, 1);
    } else if (strcmp(kbuf, "off") == 0) {
        printk("%s: led off!\n", LED_DEV_NAME);
        gpio_direction_output(12, 0);
    } else {
        printk("%s: Unknown Command!\n", LED_DEV_NAME);
        return -EINVAL;
    }

    return len;
}

static int c_gpio_led_release(struct inode *inode, struct file *file) {
    printk("%s: c_gpio_led_release!\n", LED_DEV_NAME);
    return 0;
}

static struct file_operations c_gpio_led_ops = {
    .owner = THIS_MODULE,
    .open = c_gpio_led_open,
    .read = c_gpio_led_read,
    .write = c_gpio_led_write,
    .release = c_gpio_led_release,
};

static void c_register_led_dev(int led_port) {
    gpio_request(led_port, "led");
    gpio_direction_output(led_port, 0);
    gpio_export(led_port, false);
}

static int c_gpio_led_init(void) {
    dev_t devno;
    int res;
    struct device *dev;

    devno = MKDEV(0, 0);

    if (register_chrdev_region(devno, 1, LED_DEV_NAME) < 0) {
        printk("Failed to register_chdev_region!\n");
        return -1;
    }

    c_register_led_dev(12);

    c_gpio_led_dev_major = MAJOR(devno);

    c_led_dev = cdev_alloc();
    c_led_dev->ops = &c_gpio_led_ops;
    c_led_dev->owner = THIS_MODULE;

    res = cdev_add(c_led_dev, devno, 1);
    if (res) {
        printk("Failed to add c_gpio_led_device!\n");
        goto fail_1;
    }

    c_gpio_led_class = class_create(THIS_MODULE, LED_DEV_NAME);
    if (IS_ERR(c_gpio_led_class)) {
        printk("Failed to create class_c_gpio_led_device!\n");
        goto fail_2;
    }

    dev = device_create(c_gpio_led_class, NULL, devno, NULL, LED_DEV_NAME);
    if (IS_ERR(dev)) {
        printk(KERN_ALERT "Failed to create device!\n");
        goto fail_3;
    }

    return 0;

fail_3:
    class_destroy(c_gpio_led_class);
fail_2:
    cdev_del(c_led_dev);
fail_1:
    unregister_chrdev_region(devno, 1);
    return -1;
}

static void c_gpio_led_exit(void) {
    dev_t devno = MKDEV(c_gpio_led_dev_major, 0);

    device_destroy(c_gpio_led_class, devno);
    class_destroy(c_gpio_led_class);
    cdev_del(c_led_dev);
    unregister_chrdev_region(devno, 1);

    gpio_set_value(12, 0);
    gpio_unexport(12);
    gpio_free(12);
}

module_init(c_gpio_led_init);
module_exit(c_gpio_led_exit);
// c_gpio_led_dev.c示例

#include "jni.h"
#include <stdio.h>

JNIEXPORT void JNICALL
Java_com_example_ledtest_MainActivity_nativeLedOn(JNIEnv *env, jobject instance) {

    FILE *fp;
    fp = fopen("/dev/c_led_dev", "w");

    if (fp < 0) {
        printf("open failed!\n");
        return ;
    }

    fprintf(fp, "%s", "on");
    fclose(fp);
}

JNIEXPORT void JNICALL
Java_com_example_ledtest_MainActivity_nativeLedOff(JNIEnv *env, jobject instance) {
    FILE *fp;
    fp = fopen("/dev/c_led_dev", "w");

    if (fp < 0) {
        printf("open failed!\n");
        return ;
    }

    fprintf(fp, "%s", "off");
    fclose(fp);
}

(4)修改Android.mk和Application.mk文件

在\"app/src/main/"\"下,我们需要修改\"Android.mk\"和\"Application.mk\"文件。

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := c_led_dev
LOCAL_SRC_FILES := jni/c_led_dev.c

include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_ABI := all
APP_PLATFORM := android-21

(5)编译测试

执行\"make\"命令进行编译,执行\"ndk-build\"命令进行组合编译并生成相应的so文件和apk文件。

最后在Android设备中进行测试即可。示例中我们可以在MainActivity.java文件的相应按钮(如led on)进行检测,看看是否有输出。

以上为Android 驱动编写LED的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android 驱动编写LED-NDK程序 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • Java实现线性表的链式存储

    实现线性表的链式存储是Java编程中常见的操作之一,下面是完整的攻略: 什么是线性表的链式存储 线性表的链式存储指的是将线性表中的每个元素用一个结点来表示,并将结点之间通过指针链接起来,形成一条“链”的存储结构。每个结点包含两部分信息:数据域和指针域。其中,数据域用来存储具体的元素信息,指针域则用来保存下一个结点的地址。 线性表的链式存储实现步骤 定义结点类…

    other 2023年6月28日
    00
  • mysql 8.0.21免安装版配置方法图文教程

    下面是“mysql 8.0.21免安装版配置方法图文教程”的完整攻略: 1. 下载mysql 8.0.21免安装版 首先,您需要下载mysql 8.0.21的免安装版安装包。您可以在mysql官方网站(https://dev.mysql.com/downloads/mysql)上找到免安装版的下载链接。如果您使用Windows操作系统,建议您下载zip格式的…

    other 2023年6月20日
    00
  • 微博如何查看ip地址归属地?微博查看ip地址归属地教程

    微博如何查看IP地址归属地攻略 如果你想查看微博上某个IP地址的归属地,可以按照以下步骤进行操作: 步骤一:获取IP地址 首先,你需要获取到你想要查询的IP地址。在微博上,你可以通过以下两种方式获取IP地址: 评论区查看:如果你在微博上看到了某个用户的评论,你可以点击该用户的头像或者用户名,进入他们的个人主页。在个人主页中,你可以找到该用户的最近评论,其中可…

    other 2023年7月31日
    00
  • Lua和C++交互 学习记录之四:全局table交互

    Lua和C++交互 学习记录之四:全局table交互 本文是关于Lua和C++交互的学习记录的第四篇,主要介绍如何在Lua与C++之间以全局table的形式进行数据交互。 在之前的文章中,我们已经学习了Lua和C++之间基础的数据类型交互,包括了数值、字符串、数组、函数等。但在实际应用中,更常见的情况是需要将大量的数据以一种结构化的方式进行传输和处理。此时,…

    其他 2023年3月28日
    00
  • c#遍历文件夹下全部文件

    当然,我很乐意为您提供有关“C#遍历文件夹下全部文件”的完整攻略。以下是详细的步骤和两个示例: 1 C#遍历文件夹下全部文件 在C#中,可以使用Directory类和FileInfo类来遍历文件夹下的全部文件。这在需要对文件夹中的所有文件进行操作时非常有用。 2 使用Directory类遍历文件夹下全部文件 以下是使用Directory类遍历文件夹下全部文件…

    other 2023年5月6日
    00
  • Android自定义PopupWindow小案例

    我们开始讲解如何实现一个Android自定义PopupWindow小案例。 前置知识 Android基础知识,包括控件、事件等等 Android Studio开发环境的使用 实现思路 我们要实现的自定义PopupWindow,不同于系统提供的PopupWindow,我们要自定义PopupWindow的背景、动画、内容、位置等,因此需要重写PopupWindo…

    other 2023年6月25日
    00
  • ios11正式版多大 更新升级iOS10正式版需要占用多大内存(附iOS11升级教程)

    iOS 11正式版更新升级攻略 1. iOS 11正式版的大小 iOS 11正式版的大小取决于设备型号和之前安装的iOS版本。以下是一些常见设备的iOS 11正式版大小范例: iPhone 7 Plus:大约1.9GB iPad Pro 9.7英寸:大约2.0GB 请注意,这些数字仅供参考,实际大小可能会有所不同。 2. 升级iOS 10正式版所需的内存空间…

    other 2023年8月1日
    00
  • Spring中Bean的加载与SpringBoot的初始化流程详解

    Spring中Bean的加载 Spring中Bean的加载是指Spring容器在启动时初始化和加载Bean的过程。在Spring中,Bean可以通过XML配置、Java类注解或者混合方式进行定义和配置,而Spring容器则负责将这些Bean实例化、依赖注入并进行管理。 XML配置Bean的加载 在Spring中,XML配置是创建Bean的一种方式。Sprin…

    other 2023年6月20日
    00
合作推广
合作推广
分享本页
返回顶部