Android之在GEC210板上點燈

要用Android控制自定義的硬件,如何實現呢?用JNI即可。

1、準備工作

好瞭,先做些準備工作。準備工作無非就是搭建下環境,下載些東西。請看些鏈接。點我點我!

 

2、led驅動

照理說,點燈的程序,我不應該貼出來的,但是,考慮到有同學做Android沒學過驅動,我就貼出來,僅供參考哈:

[cpp]  

#include  

#include  

#include  

#include  

#include  

#include  

#include  

#include  

#include  

#include  

  

#include  

#include  

#include  

  

  

#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也附出來瞭:

[plain]  

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

[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

[cpp]  

#include  

  

#include  

#include  

#include  

#include  

#include  

  

#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

[plain]  

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

[plain] 

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

 

過會會把源代碼附上。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *