又是点灯,没有错,学硬件,什么时候都是从点灯开始的,对不,而且还是用Android应用程序点灯。
要用Android控制自定义的硬件,如何实现呢?用JNI即可。
1、准备工作
好了,先做些准备工作。准备工作无非就是搭建下环境,下载些东西。请看些链接。点我点我!
2、led驱动
照理说,点灯的程序,我不应该贴出来的,但是,考虑到有同学做Android没学过驱动,我就贴出来,仅供参考哈:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <mach/gpio.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> #define DEVICE_NAME "leds" static int led_gpios[] = { S5PV210_GPJ2(0), S5PV210_GPJ2(1), S5PV210_GPJ2(2), S5PV210_GPJ2(3), }; #define LED_NUM ARRAY_SIZE(led_gpios) static long gec210_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { case 0: case 1: if (arg > LED_NUM) { return -EINVAL; } gpio_set_value(led_gpios[arg], !cmd); //printk(DEVICE_NAME": %d %d\n", arg, cmd); break; default: return -EINVAL; } return 0; } static struct file_operations gec210_led_dev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = gec210_leds_ioctl, }; static struct miscdevice gec210_led_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &gec210_led_dev_fops, }; static int __init gec210_led_dev_init(void) { int ret; int i; for (i = 0; i < LED_NUM; i++) { ret = gpio_request(led_gpios[i], "LED"); if (ret) { printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME, led_gpios[i], ret); return ret; } s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT); gpio_set_value(led_gpios[i], 1); } ret = misc_register(&gec210_led_dev); printk(DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit gec210_led_dev_exit(void) { int i; for (i = 0; i < LED_NUM; i++) { gpio_free(led_gpios[i]); } misc_deregister(&gec210_led_dev); } module_init(gec210_led_dev_init); module_exit(gec210_led_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("GEC Inc.");
ifneq ($(KERNELRELEASE),) obj-m :=led_drv.o else module-objs :=led_drv.o KERNELDIR :=/home/gec/linux_kernel/linux-2.6.35.7/ PWD :=$(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif clean: $(RM) *.ko *.mod.c *.mod.o *.o *.order *.symvers *.cmd
好了。执行make,之后,就能得到一个.ko结尾的文件,把这个.ko文件放进GEC210板的文件系统里,怎么放进去?SD卡也可以,网线nfs也可以,串口线也可以。这里不详说。
3、编写Android应用程序
不多说,看代码吧,都是最基本的。2.2版的
LedDemoTestActivity.java
package com.gec.leddemotest.activity; import android.app.Activity; import android.os.Bundle; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.Toast; public class LedDemoTestActivity extends Activity { private RadioGroup radioGroupLed01; private RadioGroup radioGroupLed02; private RadioGroup radioGroupLed03; private RadioGroup radioGroupLed04; static{ System.loadLibrary("leddemotest"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); openRunLed(); radioGroupLed01=(RadioGroup)findViewById(R.id.radioGroupLed01); radioGroupLed01.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub if(checkedId==R.id.chooseLed01_1) { startRunLed(0,1); Toast.makeText(LedDemoTestActivity.this, R.string.led1_on, Toast.LENGTH_LONG).show(); }else if(checkedId==R.id.chooseLed01_2) { startRunLed(0,0); Toast.makeText(LedDemoTestActivity.this, R.string.led1_off, Toast.LENGTH_LONG).show(); } } }); radioGroupLed02=(RadioGroup)findViewById(R.id.radioGroupLed02); radioGroupLed02.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub if(checkedId==R.id.chooseLed02_1) { startRunLed(1,1); Toast.makeText(LedDemoTestActivity.this, R.string.led2_on, Toast.LENGTH_LONG).show(); }else if(checkedId==R.id.chooseLed02_2) { startRunLed(1,0); Toast.makeText(LedDemoTestActivity.this, R.string.led2_off, Toast.LENGTH_LONG).show(); } } }); radioGroupLed03=(RadioGroup)findViewById(R.id.radioGroupLed03); radioGroupLed03.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub if(checkedId==R.id.chooseLed03_1) { startRunLed(2,1); Toast.makeText(LedDemoTestActivity.this, R.string.led3_on, Toast.LENGTH_LONG).show(); }else if(checkedId==R.id.chooseLed03_2) { startRunLed(2,0); Toast.makeText(LedDemoTestActivity.this, R.string.led3_off, Toast.LENGTH_LONG).show(); } } }); radioGroupLed04=(RadioGroup)findViewById(R.id.radioGroupLed04); radioGroupLed04.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(RadioGroup group, int checkedId) { // TODO Auto-generated method stub if(checkedId==R.id.chooseLed04_1) { startRunLed(3,1); Toast.makeText(LedDemoTestActivity.this, R.string.led4_on, Toast.LENGTH_LONG).show(); }else if(checkedId==R.id.chooseLed04_2) { startRunLed(3,0); Toast.makeText(LedDemoTestActivity.this, R.string.led4_off, Toast.LENGTH_LONG).show(); } } }); } protected void onDestroy() { closeRunLed(); } public native void startRunLed(int whichLed,int on); public native void openRunLed(); public native void closeRunLed(); }
appleds.c
#include <android/log.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <jni.h> #define LED_ON 1 #define LED_OFF 0 int fd; JNIEXPORT void JNICALL Java_com_gec_leddemotest_activity_LedDemoTestActivity_openRunLed (JNIEnv *env, jobject this,jint whichLed,jint on) { fd = open("/dev/leds", 0); } JNIEXPORT void JNICALL Java_com_gec_leddemotest_activity_LedDemoTestActivity_startRunLed (JNIEnv *env, jobject this,jint whichLed,jint on) { if (fd < 0) { perror("open device leds"); exit(1); } ioctl(fd, on,whichLed); } JNIEXPORT void JNICALL Java_com_gec_leddemotest_activity_LedDemoTestActivity_closeRunLed (JNIEnv *env, jobject this,jint whichLed,jint on) { close(fd); }
4、编写Android.mk
Android.mk是编译.so文件的重要部分,分别有两个。
下面是JNI文件夹下的Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libleddemotest a LOCAL_SRC_FILES :=appleds.c b LOCAL_C_INCLUDES += \ c $(JNI_H_INCLUDE) LOCAL_PRELINK_MODULE := false include $(BUILD_SHARED_LIBRARY) d
a:生成C 动态库名称libleddemotest(JAVA层就是通过加载此库名称来实现互调)
b:编译C文件
c:加载jni库头文件
d:生成libleddemotest动态库
下面是工程目录下的Android.mk
LOCAL_PATH:= $(call my-dir) a include $(CLEAR_VARS) b LOCAL_SRC_FILES := $(call all-subdir-java-files) c LOCAL_PACKAGE_NAME := LedDemoTest d LOCAL_JNI_SHARED_LIBRARIES := libleddemotest e include $(BUILD_PACKAGE) f include $(LOCAL_PATH)/jni/Android.mk g # Use the folloing include to make our test apk. include $(call all-makefiles-under,$(LOCAL_PATH)) h
a:一个Android.mk文件首先必须定义好LOCAL_PATH,获得当前目录
b:用来初始化Android.mk文件中”LOCAL_XXX”的变量
c:编译Java文件
d:生成Android应用apk文件名称
e:生成Android应用apk文件名称
f:生成Android应用
g:编译jni目录里面的Android.mk文件
h:编译此工程里面所有的Android.mk文件
5、执行ndk-build
在cygwin中执行,用linux命令,进入工程目录,执行ndk-build.
6、将leds设备文件设置权限
用串口线,连接GEC210板,执行insmod XXXX.ko文件,将设备文件装进内核,然后在/dev下会有一个leds的设备文件,
用chmod 777 leds,将leds的设备权限加大,好了。可以将应用程序运行在GEC210板上了。享受吧。
过会会把源代码附上。