使用的材料有arduino R3,一個金屬外殼紅外接收頭,一個紅外發射頭,LED指示燈若干,兩個開關,電阻若干
以下爲arduino的代碼,相關注意事項在註釋中已經寫明。
我嘗試過使用delayMicroseconds的方法來發射38KHz的信號,最終不被電視機識別。使用IRremote開源項目的方法更爲合適。它直接改變pin 3的輸出頻率,從而實現模擬遙控器發射。
以下代碼在海信電視上測試成功,先錄製靜音鍵,然後播放,電視機可以正確識別。
/*
使用arduino錄製一個紅外信號,並播放
播放部分使用了IRremote中的實現方法,直接引用了改變pin 3的輸出頻率部分
於2016年2月28日發佈在http://blog.csdn.net/luhanglei
*/
#include <IRremote.h>
//引用Github的一個開源項目
//地址:https://github.com/shirriff/Arduino-IRremote
#define pin_IRreceiver 2 //引用Github的一個開源項目
#define pin_Playing 4 //正在播放指示燈
#define pin_Recording 5 //正在錄製指示燈
#define pin_Record_Button 7 //錄製按鈕
#define pin_Play_Button 8 //播放按鈕
boolean isRecord = false,isPlay = false;
unsigned long res[100]; //記錄脈衝長度的buffer
unsigned long currenttime,t;
int state = HIGH; //紅外接收頭默認狀態下輸出高電平,所以初始化爲高電平,目的是檢測低電平(收到低電平是代表收到了紅外信號)
int loc = 0,loc1=0;//分別記錄信號長度和錄製進度
void setup() {
// 初始化
pinMode(pin_IRreceiver,INPUT);
pinMode(pin_Playing,OUTPUT);
pinMode(pin_Recording,OUTPUT);
pinMode(pin_Record_Button,INPUT);
pinMode(pin_Play_Button,INPUT);
//time部分,引用IRremote中的代碼
// Disable the Timer2 Interrupt (which is used for receiving IR)
TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt
pinMode(TIMER_PWM_PIN, OUTPUT);
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA as top
// CS2 = 000: no prescaling
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
TIMER_CONFIG_KHZ(38);
//串口初始化
Serial.begin(19200);
Serial.println("start");
}
void loop() {
//檢測按鈕是否按下
if(digitalRead(pin_Play_Button)==HIGH) {
isPlay = true;
} else if(digitalRead(pin_Record_Button)==HIGH) {
isRecord = true;
}
//如果處於播放狀態
if(isPlay) {
//串口和指示燈示意播放中
Serial.println("startPlaying");
digitalWrite(pin_Playing,HIGH);
//信號長度
int times = loc;
//播放數組中的信息,由於第0位是高電平(暨沒有收到信號)長度,所以捨去不播放
for(int i =1; i<times; i++) {
if(i&1) {//奇數位爲紅外接收頭低電平=紅外發射頭高電平
light(res[i]);
} else//偶數位爲不發射
custom_delay_usec(res[i]);
}
isPlay = false;
//每次發射中間應該有間隔
delay(900);
//關閉指示燈
digitalWrite(pin_Playing,LOW);
}
//如果處於錄製狀態
if(isRecord) {
//串口和指示燈示意錄製中
Serial.println("startRecording");
digitalWrite(pin_Recording,HIGH);
//等待脈衝信號改變
while(true) {
if(digitalRead(pin_IRreceiver)!=state) {//信號狀態改變
currenttime = micros()-t;//計算時長
t = micros();//記錄起點
state = !state;//狀態改變,下一次檢測相反狀態
res[loc1++]=currenttime;//將結果存入buffer
}
if((micros()-t>100000)&&loc1>1) {//如果超時沒有記錄到新信息,且已經收集到有效信息,則記錄結束
for( int i =1; i<loc1; i++) {//在串口打印輸出的信息,因爲IO很慢很浪費時間,所以放在信息採集完之後進行,否則會很大程度影響採集到的信息的準確度
Serial.print(res[i]);
Serial.print(", ");
}
loc = loc1;
loc1=0;
isRecord = false;
//關閉指示燈
digitalWrite(pin_Recording,LOW);
break;
}
}
}
}
//點亮LED,宏來自IRremote,目的爲將pin 3按照38KHz輸出
void light(int len) {
TIMER_ENABLE_PWM;
custom_delay_usec(len);
TIMER_DISABLE_PWM;
}
//IRremote中的延時方法,比delayMicroseconds()好用。
void custom_delay_usec(unsigned long uSecs) {
if (uSecs > 4) {
unsigned long start = micros();
unsigned long endMicros = start + uSecs - 4;
if (endMicros < start) { // Check if overflow
while ( micros() > start ) {} // wait until overflow
}
while ( micros() < endMicros ) {} // normal wait
}
}
服務端JAVA代碼如下(被註釋掉的部分是讀取數據的代碼,沒被註釋掉的是通過控制檯向arduino發數據):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws UnknownHostException,
IOException {
// TODO 自動生成的方法存根
Socket socket = new Socket("192.168.0.7", 9000);
// InputStream is = socket.getInputStream();
// InputStreamReader isr = new InputStreamReader(is);
// BufferedReader br = new BufferedReader(isr);
// char[] buffer = new char[10];
// int hasRead = 0;
// while (true) {
// hasRead = br.read(buffer);
// if (hasRead != 0)
// for (int i = 0; i < hasRead; i++) {
// System.out.print(buffer[i]);
// }
// }
OutputStream os = socket.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
Scanner input = new Scanner(System.in);
while (true) {
String in = input.nextLine();
osw.write(in);
osw.flush();
}
}
}