Android之在GEC210板上點燈。

又是點燈,沒有錯,學硬件,什麼時候都是從點燈開始的,對不,而且還是用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.");

Makefile也附出來了:

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

那個linux-2.6.35.7是指GEC210板上Android系統的Linux內核版本,而且在PC機的Linux下也要有這個內核的源碼,路徑按Makefile裏面放,也可以改Makefile需要的同學可以自行下載哈。

好了。執行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();

    
}

要在工程目錄下創建jni文件,把下面的文件放進去。

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

}

上面的JNIEXPORT是必須的,void是返回類型,JNICALL也是必須的,後面的Java也是必須的,Java後面跟的就是com.gec.leddemotest.activity包下的LedDemoTestActivity下調用的函數名,把.改爲_就可以了。大概是這意思。在JNI的.c文件中,所以要調用的函數的參數最少是兩個,一個是JNIEnv *env,一個是jobject this.具體有什麼用,大夥們自己上網查一下JNI即可。另外,像int這樣的參數,在JNI裏要寫成jint,雖然int跟jint其實是一樣的,但是JNI格式還是選擇jint比較適合,也就是在JNI的.c中,用到的所有數據類型都可以在上面加個j。當然頭文件要包jni.h才行。


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板上了。享受吧。


過會會把源代碼附上。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章