Android 下led 的控制

首先说一下我的开发环境,硬件环境开发板使用的是全志的CQA83T板子,Android开发是windows下的eclipse。关于Android下控制led,主要有两大部分,一是Android程序,二是Linux驱动开发。Android部分的开发肯定要使用Android ndk,jni编程,通过jni来调用Linux下的C函数从而控制led设备。关于ndk的安装,和简单使用我在另外的博客里面已经写了,有兴趣的可以自己看看。这篇博客住要是讲一下Android部分的开发,这里默认led驱动正常。

先看一下我的工程目录,如下图:

红色是我们工程的所有文件,后面打对勾是我们需要编辑的文件。

第一步:java部分文件编辑,这部分主要三个文件,布局文件activity_main.xml、逻辑控制文件MainActivity.java、led控制封装类A83TLED.java三个文件。

(1)布局文件activity_main.xml

布局文件没什么可讲的,就是一列按钮,文件内容如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/device_open_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="device_open"/>

    <Button
        android:id="@+id/led1_on_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="led1_on"/>

    <Button
        android:id="@+id/led1_off_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="led1_off"/>

    <Button
        android:id="@+id/led2_on_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="led2_on"/>

    <Button
        android:id="@+id/led2_off_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="led2_off"/>

    <Button
        android:id="@+id/beep_on_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="beep_on"/>

    <Button
        android:id="@+id/beep_off_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="beep_off"/>

     <Button
        android:id="@+id/device_close_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="device_close"/>

</LinearLayout>

实际显示的布局图如下:

虽然说没什么讲的,还是说一下每个按钮的作用吧。

device_open:设备打开按钮,在Linux下一切皆文件,想要操作led,首先要打开led设备。

led1_on:打开1号led

led1_off:关闭1号led

led2_on:打开2号led

led2_off:关闭2号led

beep_on:打开蜂鸣器,这里说一下,蜂鸣器的控制和led一样,开关信号,单引脚,即是只需要控制引脚的输出电平是0或1即可。所以驱动和led写在一起。

beep_off:关闭蜂鸣器

device_close:关闭设备。

(2)看一下A83TLED.java这个文件。这个文件主要是对本地方进行声明,封装了几个控制函数,以及加载本地库。

文件内容如下:

package com.coban.a83tled;

import java.io.IOException;

import android.util.Log;

public class A83TLed {
	private static final String TAG = "A83TLed";
	private int ret;

	public A83TLed(String path) throws SecurityException, IOException{
		ret = open_led_device(path);
		if (ret < -1) {
			Log.e(TAG, "native open returns null");
			throw new IOException();
		}
	}

	//打开设备
	public void open_led(){
		ret = open_led_device("/dev/led");
		if (ret < -1) {
			Log.e(TAG, "native open returns null");
		}
	}

	//打开led
	public void on_led(int num){
		ioctl_led(num,1);
	}

	//关闭led
	public void off_led(int num){
		ioctl_led(num,0);
	}

	//关闭设备
	public void close_led(){
		close_led_device();
	}

	// JNI声明本地函数
	private native static int open_led_device(String path);
	private native void ioctl_led(int i, int j);
	private native void close_led_device();
	
<span style="white-space:pre">	</span>//加载本地库
	static{
		System.loadLibrary("a83tled");
	}

}

文件很简单,首先是类的构造,类的方法,JNI本地函数声明,加载本地库。在类声明时就打开了设备,当然也提供了打开设备的方法open_led(),既然提供了打开设备

那对应的也提供了关闭设备函数close_led(),另外提供了led的打开on_led()和关闭off_led()方法。这些方法都是调用了jni函数,而jni又调用Linux函数。这个文件就是这样了。

(3)下面来看一下控制逻辑文件MainActivity.java文件。这个文件主要是提供控制逻辑,直接面向使用者。

文件内容如下:

package com.coban.a83tled;

import java.io.IOException;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	private Button led1On = null;
	private Button led1Off = null;
	private Button led2On = null;
	private Button led2Off = null;
	private Button beepOn = null;
	private Button beepOff = null;

	private Button deviceOpen = null;
	private Button deviceClose = null;

	private A83TLed a83tLed = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        try {
			a83tLed = new A83TLed("/dev/led");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

        initLayout();
        btnListener();

    }

    //初始化界面
    private void initLayout(){
    	led1On = (Button)this.findViewById(R.id.led1_on_btn);
    	led1Off = (Button)this.findViewById(R.id.led1_off_btn);
    	led2On = (Button)this.findViewById(R.id.led2_on_btn);
    	led2Off = (Button)this.findViewById(R.id.led2_off_btn);
    	beepOn = (Button)this.findViewById(R.id.beep_on_btn);
    	beepOff = (Button)this.findViewById(R.id.beep_off_btn);

    	deviceOpen = (Button)this.findViewById(R.id.device_open_btn);
    	deviceClose = (Button)this.findViewById(R.id.device_close_btn);
    }

    //按钮监听
    private void btnListener(){

    	led1On.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.on_led(1);
			}
		});

    	led1Off.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.off_led(1);
			}
		});

    	led2On.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.on_led(2);
			}
		});

    	led2Off.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.off_led(2);
			}
		});

    	beepOn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.on_led(3);
			}
		});

    	beepOff.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.off_led(3);
			}
		});

    	deviceOpen.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.open_led();			}
		});

    	deviceClose.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				a83tLed.close_led();
			}
		});

    }

    @Override
    protected void onDestroy() {
    	// TODO Auto-generated method stub
    	super.onDestroy();
    	a83tLed.close_led();
    }

}

这里主要就是对按钮的初始化和监听,然后调用类A83TLed里的方法实现控制。

这样java文件就编写完了。

第二步:生成jni头文件

上面一步,把java文件的编辑完成了,然后我们要生成头文件了。

(1)在工程目录下新建jni文件夹。

(2)使用dos窗口进入工程目录下面,使用javah命令生成自动生成头文件。具体命令如下

javah -classpath src -d jni com.coban.a83tled.A83TLed

然后你会在jni文件夹下找到生成的头文件com_coban_a83tled_A83TLed.h

有关操作我在另一篇博客里面都有详细说明,http://blog.csdn.net/dingfengen/article/details/51604877

那我们来看一下头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_coban_a83tled_A83TLed */

#ifndef _Included_com_coban_a83tled_A83TLed
#define _Included_com_coban_a83tled_A83TLed
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_coban_a83tled_A83TLed
 * Method:    open_led_device
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_coban_a83tled_A83TLed_open_1led_1device
  (JNIEnv *, jclass, jstring);

/*
 * Class:     com_coban_a83tled_A83TLed
 * Method:    ioctl_led
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_com_coban_a83tled_A83TLed_ioctl_1led
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_coban_a83tled_A83TLed
 * Method:    close_led_device
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_coban_a83tled_A83TLed_close_1led_1device
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

主要包含的就是本地函数声明。

第三步:本地C或C++文件的编辑。这里主要是俩文件,一个是a83tled.c,另一个是Android.mk。最后生成的so库的全名是liba83tled.so,这个名字和c文件名保持一致。

以及前面java里加载的库名,也是这个文件名。这一点我曾经出过错误,在此也提醒一下大家。首先在jni文件夹下创建a83tled.c和Android.mk文件。

先看a83tled.c这个文件的内容:

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>

#include "android/log.h"

static const char *TAG = "a83tled";
static int fd = -1;

#define IOCTL_SET_ON 1
#define IOCTL_SETOFF 0

#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)

JNIEXPORT jint JNICALL Java_com_coban_a83tled_A83TLed_open_1led_1device (JNIEnv *env, jclass thiz, jstring path)
{
	jboolean iscopy;
	const char *path_utf = (*env)->GetStringUTFChars(env, path, &iscopy);
	LOGD("Opening %s",path_utf);
	fd = open("/dev/led",O_WRONLY,0777);
	LOGD("open fd = %d",fd);

	(*env)->ReleaseStringUTFChars(env, path, path_utf);

	if(fd < -1)
	{
		LOGE("Cannot open port");
		/* TODO: throw an exception */
		return NULL;
	}

	return fd;

}

JNIEXPORT void JNICALL Java_com_coban_a83tled_A83TLed_ioctl_1led (JNIEnv *env, jobject thiz, jint i, jint j)
{
	if(fd > -1)
	{
		if(1 == j)
		{
			ioctl(fd,IOCTL_SET_ON,i);
		}
		else
		{
			ioctl(fd,IOCTL_SETOFF,i);
		}
	}
}

JNIEXPORT void JNICALL Java_com_coban_a83tled_A83TLed_close_1led_1device(JNIEnv *env, jobject thiz)
{
	if(fd > -1)
	{
		close(fd);
	}
}

这个文件主要是实现了头文件里声明的函数。对熟悉Linux编程的朋友应该很简单了,就是用ioctl函数控制led的亮和灭,用文件操作函数,打开和关闭设备。就不再具体细

说了。

下面再看一下Android.mk文件,其内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

TARGET_PLATFORM := android-3
LOCAL_MODULE    := a83tled
LOCAL_SRC_FILES := a83tled.c
LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)

这个Androd.mk文件不长,下面我们来简单解释下:

LOCAL_PATH := $(call my-dir)

一个Android.mk 文件首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即

包含Android.mk file文件的目录)。

include $( CLEAR_VARS)

CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES,

等等...), 除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

TARGET_PLATFORM := android-3

TARGET_PLATFORM是Android.mk 解析的时候,目标 Android 平台的名字, 其中,android-3
-> Official Android 1.5 system images

android-4 -> Official Android 1.6 system images , android-5 -> Official Android 2.0 system images

LOCAL_MODULE := a83tled

  编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意:编译

系统会自动产生合适的前缀和后缀,换句话说,一个被命名为‘a83tled‘的共享库模块,将会生成‘liba83tled.so‘文件。

  重要注意事项:如果你把库命名为‘liba83tled’,编译系统将不会添加任何的lib前缀,也会生成 ‘liba83tled.so‘,这是为了支持来源于Android平台的源代码的Android.mk文件,如果你确实需要这么做的话。

LOCAL_SRC_FILES :=
a83tled.c

  LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;

仅仅列出直接传递给编译器的源代码文件就好。

  注意,默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)

<span style="background-color: rgb(255, 255, 255);">     LOCAL_LDLIBS    := -llog</span>

LOCAL_LDLIBS:  编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀传递指定库的名字是有用的。

include $(BUILD_SHARED_LIBRARY)

  BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用‘include $(CLEAR_VARS)‘以来,定义在LOCAL_XXX变量中的所有信息,

并且决定编译什么,如何正确地去做。还有 BUILD_STATIC_LIBRARY变量表示生成静态库:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。

第四步,就是编译了。

首先:再工程目录中,右键点击工程名 --> Android tools --> Add Native Support  来添加ndk支持,会出现如下界面:

然后是编译,点击工具栏里的锤子图标,如下图:

如果没有错误,下载到开发板测试。如下图,

我的这里没有错误。

简单总结一下,这里我比他们给的例程里面多了一个打开设备函数,在java层。这个程序的执行过程是这样的,界面按钮(xml文件) --> 逻辑控制层(MainActivity.java) --> java实际调用层(A83TLed.java) --> jni层(a83tled.c) --> linux应用层 --> linux底层驱动。

这里参考了如下连接:

http://blog.csdn.net/ly131420/article/details/9619269

http://www.cnblogs.com/devinzhang/archive/2012/02/29/2373729.html

特此感谢。

时间: 2024-08-08 03:33:18

Android 下led 的控制的相关文章

Android开发学习---android下的数据持久化,保存数据到rom文件,android_data目录下文件访问的权限控制

一.需求 做一个类似QQ登录似的app,将数据写到ROM文件里,并对数据进行回显. 二.截图 登录界面: 文件浏览器,查看文件的保存路径:/data/data/com.amos.datasave/files/LoginTest.txt------/data/data/(包名)/files/(文件名) 导出的文件内容: 三.实现代码 新建一个Android 工程.这里我选择的是2.1即API 7,进行开发的,其它都是默认下一步下一步即可. /datasave/res/layout/activity

浅析android下如何通过jni监控wifi网络连接、dhcpcd执行和power电源控制

浅析android下如何通过jni监控wifi网络连接.dhcpcd执行和power电源控制 =============================================================================================================libs/android_runtime/android_net_wifi_Wifi.cpp部分jni接口static JNINativeMethod gWifiMethods[] = {

基于TINY4412的Andorid开发-------简单的LED灯控制【转】

本文转载自:http://www.cnblogs.com/pengdonglin137/p/3857724.html 基于TINY4412的Andorid开发-------简单的LED灯控制 阅读目录(Content) 一.编写驱动程序 二.编写代码测试驱动程序 三.编写HAL代码 四.编写Framework代码 五.编写JNI代码 六.编写App 参考资料: <Andriod系统源代码情景分析> <嵌入式Linux系统开发完全手册_基于4412_上册> 作者:彭东林 邮箱:[em

自己动手写最简单的Android驱动---LED驱动的编写【转】

本文转载自:http://blog.csdn.net/k_linux_man/article/details/7023824 转载注明出处,作者:K_Linux_Man, 薛凯 山东中医药大学,给文章内容引入个人毕业设计. 开发平台:farsight s5pc100-a 内核:linux2.6.29 环境搭配:有博文介绍 开发环境:Ubuntu .Eclipse 首先强调一下要点: 1.编写Android驱动时,首先先要完成Linux驱动,因为android驱动其实是在linux驱动基础之上完成

无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)

1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.demo1" /> 上面targetPackage指定的包要和应用的package相同. (2)在清单文件中ap

【原创:参赛作品】窥视懒人的秘密---android下拉刷新开启手势的新纪元

小飒的成长史原创作品:窥视懒人的秘密---android下拉刷新开启手势的新纪元转载请注明出处 *****************************************************************        前言:窥视懒人那些不为人知的秘密 ***************************************************************** 作为一个程序员,哪有不勤奋的道理,当我们都在为技术奋不顾身的时候.偏偏懒人创造了世界. 有的

2、按下按键S1控制LED1.LED2.LED3实现跑马灯效果(CC2540开发寄存器设置)

按下按键S1控制LED1.LED2.LED3实现跑马灯效果 1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 作 者: Amo [ www.amoMcu.com 阿莫单片机] 4 * 修 订: 2014-04-08 5 * 版 本: 1.0 6 * 描 述: 按下按键S1控制LED1.LED2.LED3实现跑马灯效果 7 ***********

Java反射机制的原理及在Android下的简单应用

花了几天时间,研究了一下Java的反射机制.在这里总结一下这几天学习的成果,一来分享自己的学习过程和在学习中遇到的问题,二来是给像我一样不太了解Java反射机制的同学做一个简单的介绍.在文章后面会链接一个Android反射机制的应用程序. 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述

OK6410基于SD卡的裸机开发-LED灯控制

在上一篇文章中提到SD卡的裸机开发环境的搭建以及OK6410的启动设置,这章开始进入LED灯的闪烁控制. 1.首先打开OK6410的开发板原理图,找到LED等控制的原理图部分,如下图1所示. 图1 LED灯控制原理图 由图1可知,控制LED灯的CPU管脚为NLED1~NLED4,NLED1~NLED4对应的CPU管脚名称为GPM0~GPM3(CPU原理图未给出). 2.编写程序LED.s,下面直接给出LED.s的源码. .globl _start _start: /* 硬件相关的设置 */ ld