android控制gpio实现对小灯读写(一)
来源:互联网 发布:淘宝 大麻暗语 编辑:程序博客网 时间:2024/06/08 07:30
本实验通过GPIO口拉高拉低控制小灯的亮灭,作为刚刚从应用层转framework的小兵,写这篇文章希望对大家的学习有帮助。
什么是GPIO
GPIO,英文全称为General-Purpose IO ports,也就是通用IO口。嵌入式系统中常常有数量众多,但是结构却比较简单的外部设备/电路,对这些设备/电路有的需要CPU为之提供控制手段,有的则需要被CPU用作输入信号。而且,许多这样的设备/电路只要求一位,即只要有开/关两种状态就够了,比如灯亮与灭。对这些设备/电路的控制,使用传统的串行口或并行口都不合适。
所以在微控制器芯片上一般都会提供一个“通用可编程IO接口”,即GPIO。
通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。
内核中生成设备
原理
关于GPIO口字符设备驱动我们要做如下步骤:
1 找到原理图对应的GPIO口并配置它为输出管脚
gpio口配置(不同平台配置不一样)但目的是一样的 设置GPIO口输出,并默认低电平,我们接的是57管脚
<&range 56 1 0x1500>
<&range 57 1 0x1500> 代表57管脚做为gpio口使用,并默认低电平
这个io口寄存器地址:0xe46002e4
但是调试过程中发现
#define gpio_lp 57 gpio_request(gpio_lp,"pos_pwr");gpio_set_value(gpio_lp,1);
GPIO调用request报错,导致GPIO不能用但是换个GPIO口后换个gpio口就不报错了,
这种原因是由于intel的特殊性:gpio在vmm的地方被调用,在kernel下就不能操作它(一般平台这样操作没问题的)
后续,想到了另外一种方法
void __iomem *ldo_mmio_base = ioremap(0xe46002e4, 4);iowrite32(0x1700, ldo_mmio_base); //1700代表设置寄存器(0xe46002e4)为GPIO口,输出为高iowrite32(0x1500, ldo_mmio_base);//1500代表设置寄存器(0xe46002e4)为GPIO口,输出为低
实现了IO口的控制
实现
源代码我放到kenel-3.10/drivers/char下面让系统生成设备节点:/dev/mtgpio,具体需要修改两个地方。
首先进入到kernel-3.10/drivers/char目录,新增文件,我这里命名为lp6735_switch.c ,具体代码如下:
kernel-3.10/drivers/char$ vim lp6735_switch.c
#include <linux/module.h> /* For module specific items */ #include <linux/moduleparam.h> /* For new moduleparam's */ #include <linux/types.h> /* For standard types (like size_t) */ #include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/kernel.h> /* For printk/panic/... */ #include <linux/fs.h> /* For file operations */^M #include <linux/ioport.h> /* For io-port access */ #include <linux/platform_device.h> /* For platform_driver framework */ #include <linux/init.h> /* For __init/__exit/... */ #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ #include <linux/io.h> /* For inb/outb/... */ #include <linux/gpio.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/slab.h> /*kamlloc */ //#include <asm-generic/ioctl.h> //ioctl #define CMD_FLAG 'i' #define led_PWR_ON _IOR(CMD_FLAG,0x00000001,__u32) #define led_PWR_OFF _IOR(CMD_FLAG,0x00000000,__u32) #define gpio_lp 57 static int major =0; static struct classclass *led_class; struct cdev_led { struct cdev cdev; }; struct cdev_led *led_dev; static int led_ioctl(struct file* filp,unsigned int cmd,unsigned long argv) { printk(KERN_INFO "entry kernel.... \n"); printk(KERN_INFO "%d\n", led_PWR_ON); void __iomem *ldo_mmio_base = ioremap(0xe46002e4, 4); switch(cmd) { case led_PWR_ON: { #if 0 gpio_set_value(gpio_lp,1); // printk(KERN_INFO "led on\n"); #endif iowrite32(0x1700, ldo_mmio_base) break; } case led_PWR_OFF: { #if 0 gpio_set_value(gpio_lp,0); printk(KERN_INFO "led off \n"); #endif iowrite32(0x1500, ldo_mmio_base); break; } default: return -EINVAL; } return 0; } //open static int led_open(struct inode* i_node,struct file* filp) { printk(KERN_INFO "larsonzhong open init.... \n"); int err; // larsonzhong Content between #if 0 #endif would comment, because there is no actual device #if 0 err = gpio_request(gpio_lp,"led_pwr"); if(err<0) { printk(KERN_INFO "gpio request faile \n"); return err; } gpio_direction_output(gpio_lp,1); #endif return 0; } //close static void led_close(struct inode* i_node,struct file* filp) { printk(KERN_INFO "larsonzhong close init \n"); // larsonzhong Content between #if 0 #endif would comment, because there is no actual device#if 0 gpio_free(gpio_lp); #endif return ; } /* file operations */ struct file_operations fops={ .owner = THIS_MODULE, .open = led_open, .unlocked_ioctl = led_ioctl, .release= led_close, }; static int __init led_init(void) { printk(KERN_INFO "init .... \n"); dev_t dev_no; int result,err; err = alloc_chrdev_region(&dev_no,0,1,"my_led"); //dynamic request device number if(err<0) { printk(KERN_INFO "ERROR\n"); return err; } major = MAJOR(dev_no); led_dev = kmalloc(sizeof(struct cdev_led),GFP_KERNEL); if(!led_dev) { result = -ENOMEM; goto fail_malloc; } memset(led_dev,0,sizeof(led_dev)); cdev_init(&led_dev->cdev,&fops); led_dev->cdev.owner = THIS_MODULE; result = cdev_add(&led_dev->cdev,dev_no,1); if(result <0) { printk(KERN_INFO "error\n"); goto fail_add; } led_class = class_create(THIS_MODULE,"mtgpio"); //in sys/class create sysfs file device_create(led_class,NULL,MKDEV(major,0),NULL,"mtgpio"); //dynamic create device file /dev/myled return 0; fail_add: kfree(led_dev); fail_malloc: unregister_chrdev_region(dev_no,1); return result; } static void __exit led_exit(void) { dev_t dev_no=MKDEV(major,0); unregister_chrdev_region(dev_no,1); cdev_del(&led_dev->cdev); kfree(led_dev); device_destroy(led_class,dev_no); class_destroy(led_class); printk(KERN_INFO "exit........ \n"); } module_init(led_init); module_exit(led_exit); MODULE_AUTHOR("larsonzhong@gmail.com"); MODULE_DESCRIPTION("control_led_power"); MODULE_LICENSE("GPL");
保存退出,然后我们还需要修改一个文件,就是同级目录下的makefile文件。
在kernel-3.10/drivers/char$ vim Makefile 里面新增一段:
+obj-y += lp6735_switch.o
具体代码,因为csd对一些特俗符号作了处理,只能传图:
这样加入lp6735_switch.c并修改Makefile后固件生成就会在 /dev/ 下生成节点 /dev/mtgpio
要让这个节点让别人可读写,还必须修改节点的系统所有者以及他的权限,这个步骤我们一版在 init.rc中进行
我的代码是system/core/rootdir/init.rc
... # added by larsonzhong@163.com change my devices mqgpio chown system system /dev/mtgpio chmod 0766 /dev/mtgpio ...
开始实验
我们假设我们要用的小灯的设备是dev/mtgpio##Jni头文件
新建一个安卓工程,然后新建类,我这里是GpioLED.java。
public class GpioLED { //控制LED上电 public native static void ledPowerOn(); // 控制LED下电 public native static void ledPowerOff(); }
生成头文件
方法1:简单粗暴
使用javah生成,请注意java环境已经搭建好(包括环境配置classpath配置)。
进入到源码下的bin目录下的classes目录,使用javah -jni 包名.类名,我这里是javah -jni com.coban.ledsimple.LEDGpio
我们再目录下就能看到头文件,打开头文件。把里面的声明copy出来。
方法2:更便捷
点击编译按钮旁边带工具箱的编译按钮旁边的小三角,弹出下拉列表,点击External Tools Configurations,弹出了一个对话框,
我们选中Program然后点击上面的新建按钮。然后如下填写:
Main卡: Name:javah Location:选择javah所在目录。我的是C:\Program Files\Java\jdk1.8.0_102\bin\javah.exe Working Diractory:点击variables按钮弹出列表,选择project_loc确定,然后再后面加上\src,我的结果是${project_loc}\src Arguments:-classpath ${project_loc}\bin\classes -d ${project_loc}\jni -jni ${java_type_name}Refresh卡: 勾选 refresh Resource upon completionCommon卡: 勾选 External Tools 然后点击apply
jni实现
新建c文件和mk文件。如果你使用的是eclipse并且配置了ndk(注意不仅在eclipse要配置ndk,在环境变量也要配置)否则可能出现Unable to launch cygpath. Is Cygwin on the path?] 错误。
右击Project->Android Tools->Add Native Support
然后你会看到工程目录下多了一个文件夹和两个文件,我们把刚刚copy的头文件声明粘贴过来。
我这里的代码实现是这样的:ledcontrol.c
#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<errno.h>#include<unistd.h>#include<sys/ioctl.h>#include<jni.h> // 一定要包含此文件#include<string.h>#include<sys/types.h>#include<sys/stat.h>#include <android/log.h>//驱动里的命令码.#define CMD_FLAG 'i'#define LED_ON _IOR(CMD_FLAG,0x00000001,__u32)#define LED_OFF _IOR(CMD_FLAG,0x00000000,__u32)#define DEVICE_NAME "/dev/mtgpio"int fd;static const char *TAG="012";#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)/* * Class: Linuxc* Method: openled* Signature: ()I*/JNIEXPORT void JNICALL Java_com_coban_ledsimple_LEDGpio_ledPowerOn(JNIEnv* env, jclass mc){ LOGI("POWER ON BY LARSON"); LOGI("LED_ON:%d LED_OFF:%d",LED_ON,LED_OFF); fd=open(DEVICE_NAME,O_RDWR); if(fd<0) { LOGI("don't open dev"); } else { ioctl(fd,LED_ON,NULL) ; LOGI("open success"); }}/* * Class: Linuxc* Method: clsoeled* Signature: ()V*/JNIEXPORT void JNICALL Java_com_coban_ledsimple_LEDGpio_ledPowerOff(JNIEnv* env, jclass mc){ LOGI("POWER Off BY LARSON"); ioctl(fd,LED_OFF,NULL) ; close(fd);}
请注意,这里我用到了日志和一些其他的头文件,我们需要把相关的库包含进来。修改Android.mk
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_LDLIBS := -lm -llog LOCAL_MODULE := ledcontrolLOCAL_SRC_FILES := ledcontrol.cinclude $(BUILD_SHARED_LIBRARY)
要注意的是LOCAL_LDLIBS := -lm -llog 不要添加在include $(CLEAR_VARS)的前面,否则会被清掉,导致无效。
Application.mkAPP_ABI := all
这里的意思是编译所有平台的so文件,如果想指定某个编译
APP_ABI := armeabi armeabi-v7a x86
中间用空格隔开
生成so文件
我们直接把软件往设备上推或者build一把。会在工程目录下看到多出了一个obj文件夹,
而且在libs下多出了好几个文件夹,这些文件夹对应不同的平台。
APP实现
这里我就直接贴代码了
HelloJniLED.java
package com.example.hellojni;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;public class HelloJniLED extends Activity { private Button power_on; private Button power_off; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); power_on = (Button) findViewById(R.id.power_on); power_off = (Button) findViewById(R.id.power_off); power_on.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("012", "power_on by android\n"); LEDGpio.ledPowerOn(); } }); power_off.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d("012", "power_off by android\n"); LEDGpio.ledPowerOff(); } }); }}
LEDGpio.java
package com.coban.ledsimple;import android.util.Log;public class LEDGpio { static { try { Log.i("012", "try to load ledcontrol.so"); System.loadLibrary("ledcontrol"); } catch (UnsatisfiedLinkError ule) { Log.e("012", "WARNING: Could not load ledcontrol.so"); } } public native static void ledPowerOn(); public native static void ledPowerOff();}
布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/position" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text=" power control " android:textColor="#ff0000" android:textSize="25sp" /> <Button android:id="@+id/power_on" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/position" android:layout_centerHorizontal="true" android:layout_toLeftOf="@+id/position" android:text="power_on" android:textSize="18sp" /> <Button android:id="@+id/power_off" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/position" android:layout_toRightOf="@+id/position" android:text="power_off" android:textSize="18sp" /></RelativeLayout>
- android控制gpio实现对小灯读写(一)
- Android 驱动 (一) GPIO
- 控制GPIO, 点亮led,实现跑马灯
- mtk android ,gpio控制
- python实现对excel表的读写操作(一)
- 用C#控制TQ2440开发板上的LED小灯(C# GPIO学习笔记)
- 用C#控制TQ2440开发板上的LED小灯(C# GPIO学习笔记)
- arm的GPIO控制(流水灯)
- 通过API实现C#对硬件的控制(一)
- 通过API实现C#对硬件的控制(一)
- 通过API实现C#对硬件的控制(一)
- 通过API实现C#对硬件的控制(一)
- 通过API实现C#对硬件的控制(一)
- 通过API实现C#对硬件的控制(一)
- BBB(一):三种方式控制GPIO
- android 用户空间控制gpio
- android 上层如何控制GPIO
- Android Things入门-控制GPIO
- 使用STS ,启动Tomcat时,报错Multiple xxxxxx
- LeetCode25. Reverse Nodes in k-Group
- 欢迎使用CSDN-markdown编辑器
- 圆周角和圆心角的关系探究
- grep、resgrep、jgrep使用,以及源码编译
- android控制gpio实现对小灯读写(一)
- Hbase原理、基本概念、基本架构
- Hibernate中openSession()与getCurrentSession()的区别与联系
- 雪城大学信息安全讲义 4.3~4.4
- modelsim 保存仿真结果(波形文件)
- kindeditor获取内容
- Python格式化字符串的方法
- Java语言基础面试题及答案
- SM951 linux centos fio 速度测试