Fork me on GitHub

Android 红外遥控

刚刚放假,老爸就给了我一个任务,让我写个简易的app,用手机红外遥控他公司要用的单片机。之前在JetsonTx2小车的项目里有用过蓝牙和socket通信,还没尝试过红外,研究了一下,发现并不难。整个app两个小时就写好了,当然也没做什么界面的美化,主要还是把精力放在功能的实现上。

Android部分

Android有现成的红外类ConsumerIrManager可以用,代码都很简单,关键在于红外码的解读。

红外的编码格式一般为:引导码+用户编码低8位+用户编码高8位+数据码(8位)+数据码的反码(8位,校验用)

以我老爸的单片机为例:

  • 引导码:9ms的高电平+4.5ms的低电平
  • 用户编码:这个要看你自己的,我们的单片机为00000000 ffffffff
  • 数据码:这个要看你想传什么,以传16为例,就是0001 0110,前4位表示1,后4位表示6
  • 数据码的反码:看名字就知道要干嘛,还是以传16为例,就是1110 1001
  • 载波:38KHz

最后要把10用高低电平表示,在我老爸的单片机上,560ms的高电平+565ms的低电平表示0560ms的高电平+1690ms的低电平表示1

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:stretchColumns="0,1,2">
<TableRow
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="10dp">
<Button
android:id="@+id/send_button45"
android:text="总开关"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#ff0000"
android:textColor="#ffffff"
android:textSize="25dp"/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/send_button0d"
android:text="区号"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
<Button
android:id="@+id/send_button47"
android:text="模式"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
<Button
android:id="@+id/send_button44"
android:text="时间"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/send_button0c"
android:text="统一时间"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
<Button
android:id="@+id/send_button18"
android:text="统一模式"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
<Button
android:id="@+id/send_button16"
android:text="分段定时"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/send_button40"
android:text="+"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
<Button
android:id="@+id/send_button19"
android:text="-"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="30dp"/>
<Button
android:id="@+id/send_button15"
android:text="移位"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"/>
</TableRow>
<TableRow
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/send_button09"
android:text="开机"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"
android:background="#0000ff"
android:textColor="#ffffff"/>
<Button
android:id="@+id/send_button07"
android:text="关机"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"
android:background="#bb0000"
android:textColor="#ffffff"/>
<Button
android:id="@+id/send_button43"
android:text="确认"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="20dp"
android:background="#00aa00"
android:textColor="#ffffff"/>
</TableRow>
</TableLayout>

AndroidManifest.xml

加上这两句:

1
2
3
4
<!-- 红外遥控 -->
<uses-permission android:name="android.permission.TRANSMIT_IR" />
<!-- 仅在支持红外的设备上运行 -->
<uses-feature android:name="android.hardware.ConsumerIrManager" android:required="true" />

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.example.hongwai;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.hardware.ConsumerIrManager;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ConsumerIrTest";
private ConsumerIrManager mCIR;
@SuppressLint("InlinedApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取系统的红外遥控服务
mCIR = (ConsumerIrManager) getSystemService(Context.CONSUMER_IR_SERVICE);
initViewsAndEvents();
}
private void initViewsAndEvents() {
findViewById(R.id.send_button45).setOnClickListener(mSendClickListener45);
//其余类似
}
private static int startH = 9000;
private static int startL = 4500;
private static int high8 = 560;
//0:1125
private static int low0 = 565;
//1:2250
private static int low1 = 1690;
//用户编码高八位
private static String userH = "00000000";
//用户编码低八位
private static String userL = "11111111";
//38kHz
private static int carrierFrequency = 38000;
private static int[] pattern;
private static List<Integer> list = new ArrayList<>();
public static void change(String code) {
int len = code.length();
String part;
for (int i = 0; i < len; i++) {
list.add(high8);
part = code.substring(i, i + 1);
if (part.equals("0"))
list.add(low0);
else
list.add(low1);
}
}
View.OnClickListener mSendClickListener45 = new View.OnClickListener() {
@TargetApi(Build.VERSION_CODES.KITKAT)
public void onClick(View v) {
if (!mCIR.hasIrEmitter()) {
Log.e(TAG, "未找到红外发身器!");
return;
}
list.clear();
//引导码
list.add(startH);
list.add(startL);
//用户编码
change(userH);
change(userL);
//键数据码
change("10100010");
//键数据反码
change("01011101");
//发射时数据少一位
change("1");
int size = list.size();
pattern = new int[size];
for (int i = 0; i < size; i++) {
pattern[i] = list.get(i);
}
mCIR.transmit(carrierFrequency, pattern);
}
};
//其余类似
}

代码写的不好,不同的数据我就硬编码了,没动脑子。。。这里就不全贴出来,用”其余类似“表示了

实际操作中,数据码的传送要左右颠倒,比如16的数据码是00010110,那你就得写成01101000。我不知道为什么要这样,可能是我老爸的单片机接受数据的方式就是这样,开始一直不对,我也是试了几次才发现了这个规律。

还有个坑是发射时数据会少一位,所以我补了一位,这个问题也是仁者见仁,你可能压根遇不到这个问题。

单片机部分

这个咱也不知道是咋写的,咱也不敢问。反正老爸都写好了,用C语言写了一千多行,咱也不想看。

donate the author