使用Arduino錄製與播放遙控器的紅外信號

使用的材料有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
	}
}


如果做成互聯網形的,只需加一個WIFI模塊,使用Socket,利用arduino的串口進行通信。

服務端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();
		}
	}

}



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