遥控器这个东东,我看它就不顺眼:丑陋,速率低,还不通用。不过它也有自己的优点:功耗低,实现简单,成本低。可以想象的,目前的红外遥控器,是不能满足未来智能电视的需求。虽然我不知道智能电视长什么样,我还是固执地以为,蓝牙,或者WiFi遥控器,才是五年之后的主流。

除了做遥控器之外,蓝牙wifi还将为电视建起一条高速公路,这条公路通往手机,电视和用户本身。其实智能手机成功的原因也仅此而已。电视上简单地增加一个通用无线高速接口可以大大丰富开发者的想象空间,如,在电视上外放音乐,做成数码相框等等。

不过目前我只对android万能遥控器感兴趣。因为这是android入门的绝好题目。

市面上的单片机万能红外遥控器,已经很便宜很方便了,一般不外乎两种实现方式:

1.将市面上的所有遥控器的键控码字记录下来,然后按住某个按键,比如“vol

+”按键,遥控器按型号去逐一搜索,当电视作出音量增加的反应时,此时的软件所调用的型号就对应电视的型号,然后,一切都好办了。

2.让遥控器具有学习功能。让万能遥控器分别去学习家里的各个遥控器的按键。

第一种方式当然是最方便的,但是工作量太大,设计的知识点却比第二种少,不太适合学习。这里用第二种方式。

我将分别接收我、家里三个遥控器的各个按键,然后记录在xml文件里。遥控时android应用程序通过JNI去调用GPIO的驱动,设置GPIO的输出值,通过一个三极管去驱动红外发光二极管,实现遥控的目的。

这里涉及到得主要知识点有:

1.开发环境的搭建,包括android开发板的设置,Eclipse开发环境的设置,ndk(cygwin)开发环境的搭建,自然,还有硬件环境的搭建(就是一个简单的三极管和一个红外二极管)。

2.JNI的调用。

3.GPIO中断处理。

4.定时中断处理。

5.dom4j的使用。

后期的遥控器还可以通过网络来控制,自然要实现蓝牙或WiFi功能。这里的知识点更多,够我学习个大半年的。呵呵。这个做完,估计android算是入门了。

下面的代码是我已经实现的部分。已经能够控制我家电视的“音量+”功能了。

JNI代码(当然,抄人家的,然后改的,呵呵。参考:赖玉平(Peter Lai)aulyp@163.com写的《Android通过JNI调用驱动程序(完全解析实例) 》):

#include 
#include 
#include 
#include 
//----for output the debug log message
#include 
#define LOG_TAG "vib-jni"
#define LOGI(...)
__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR
,LOG_TAG,__VA_ARGS__)
#define DEVICE_NAME "/dev/leds"
#define VIB_ON 1
#define VIB_OFF 0
#define usPrambleH 4500 //(TC9028、TC9012、TC9243)
#define usPrambleL 4500
#define usH 250
#define usL0 1850
#define usL1 800
//0:h->250us,l->1850us
//1:h->250us,1->800us
int fd;
jstring Java_com_auly_control_vibClass_stringFromJNI( JNIEnv*
env,jobject thiz )
{
return
(*env)->NewStringUTF(env, "Hello from JNI--Peter for
vib!");
}
jint Java_com_auly_control_vibClass_Init( JNIEnv* env )
{
LOGE("vibClass_Init() /n");
fd = open("/dev/leds0", O_RDONLY);
if (fd < 0)
{
fd = open("/dev/leds",
O_RDONLY);
//LOGE("vibClass_Init()->
fd = %d /n",fd);
if(fd == -1){
LOGE("when
open device %s error /n ",DEVICE_NAME);
return
0;
}
}
return 1;
}
jint Java_com_auly_control_vibClass_IOCTLVIB( JNIEnv* env, jobject
thiz,jint ledID,jint ledState,jboolean WithPramble,jstring
str)
{
int i;
ioctl(fd,1, ledID);//set led IO low.
//My Sharp TV "vol +" is controlled by a 3
bursts signal
//0111111010111011 the 1st burst
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
volatile unsigned int j;
for(j = 0; j < 2700000;
j++);//delay 46ms
//0111100101000101 the 2nd burst
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
volatile unsigned int l;
for(l = 0; l < 2700000;
l++);//delay 46ms
//0111111010111011 the 3rd burst
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL0(ledID);
DataH(ledID);DataL1(ledID);
DataH(ledID);DataL1(ledID);
ioctl(fd,1, ledID);
return 1;
}
jint CycleH(int ledID){//Generate a 38KHz cycle,duty cycle
1/3
volatile unsigned int k;
unsigned int i;
ioctl(fd,0, ledID); //set Led IO high
i=420;
for(k = 0; k < i; k++);
ioctl(fd,1, ledID);
i=840;
for(k = 0; k < i; k++);
return 1;
}
jint CycleL(int ledID){//Generate a 38KHz cycle,duty cycle 0
volatile unsigned int k;
unsigned int i;
ioctl(fd,1, ledID);
i=415;
for(k = 0; k < i; k++);
ioctl(fd,1, ledID);
i=830;
for(k = 0; k < i; k++);
return 1;
}
jint DataH(int ledID){
int i;
int DataHCycleNumber = ceil(usH*38/1000);
//38KHz;
ioctl(fd,1, ledID);
for(i=0;i
CycleH(ledID);
ioctl(fd,1, ledID);
return 1;
}
jint DataL0(int ledID){//delay
volatile unsigned int k;
for(k = 0; k < 108000; k++);
return 1;
}
jint DataL1(int ledID){
volatile unsigned int k;
for(k = 0; k < 46600; k++);
return 1;
}

其中0111111010111011,0111100101000101,0111111010111011这几个值是我用示波器抓的。含义可以参考红外遥控器的编码知识。不过,红外遥控器标准很乱。像我抓的这个连引导码都没有。

然后自然是android.mk了:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := vib-jni
LOCAL_SRC_FILES := vib-jni.c
LOCAL_CFLAGS := -Werror
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

编译后就可以生成libvib-jni.so供调用。

然后是Eclipse下的应用程序:

package com.auly.control;
public class vibClass {
static {
System.loadLibrary("vib-jni");
}
public static native String stringFromJNI();
public static native int Init();
public static native int IOCTLVIB(int
ledID,int ledState,boolean Pramble,String data);
}
之后在适当的地方调用就可以了。
package com.auly.control;
import android.R.string;
import android.widget.TextView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.util.Log;
import android.app.Activity;
import android.os.Bundle;
public class vibrator extends Activity {
public static final int VIB_ON = 1;
public static final int VIB_OFF = 0;
vibClass mvibClass;
@Override
public void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mvibClass = new
vibClass();
vibClass.Init();
final Button btn1 =
(Button)findViewById(R.id.button1);
btn1.setOnClickListener(new
View.OnClickListener()
{
public void
onClick(View v)
{
vibClass.IOCTLVIB(0,VIB_ON,true,"");
}
});
}
}

遗憾的是,我没看到/dev/leds驱动的源码。