# IrDA 拷貝器
## 目的:
希望能透過直接抓取irda的原始資料拷貝任何藉由irda通訊的設備。
## 硬體需求
1. arduino nano(atmega328)
2. VS 1838B
3. 940nm 波長紅外線發射器
**接線:**

## 軟體功能
功能說明:
將**pin12** pull low可以設定為掃描模式,預設可以掃描三組訊號,每掃描完一組led會閃兩下。完成掃描會紀錄到eeprom,之後進入command mode之後可以針對輸入的順序依序(依照預定的掃描按鍵數依序從數字"1"開始 ex:數量為3->(1,2,3))從**Serial Monitor**輸入對應的數字隨即會送出掃到的訊號。
```cpp=
//------------------------------------------------------------------------------
// Include the IRremote library header
//
#include <EEPROM.h>
#include <IRremote.h>
//------------------------------------------------------------------------------
// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838)
//
#if defined(ESP32)
int IR_RECEIVE_PIN = 15;
#else
int IR_RECEIVE_PIN = 11;
#endif
IRrecv IrReceiver(IR_RECEIVE_PIN);
IRsend IrSender;
#define sample_cnt 4
#define atmega168
#define search_cmd 0
#define do_cmd 1
#define button_cnt 5
unsigned int count = 0;
uint16_t cmd_length = 0;
uint16_t eeprom_addr = 0;
uint16_t rawData[37] = {8350, 4200, 500, 550, 500, 1550, 500, 550, 500, 1600,
500, 550, 500, 550, 500, 550, 500, 500, 500, 4200,
500, 1600, 500, 550, 500, 1600, 500, 550, 500, 550,
500, 500, 500, 550, 500, 550, 500};
uint16_t raw[button_cnt][50];
uint16_t raw_tmp[50];
int raw_leng[button_cnt] = {0};
int mode = 0;
int addr = 0;
int cmd_cnt = 0;
void clean_eeprom() {
for (int i = 0; i < EEPROM.length(); i++) {
EEPROM.write(i, 0);
}
}
void write_eeprom(int addr, uint16_t dat[], int num) {
byte *dat_l = (byte *)&dat[0];
int addr_local = addr;
// Serial.println("-----");
for (int i = 0; i < num; i++) {
EEPROM.write(addr_local, dat[i] >> 8);
EEPROM.write(addr_local + 1, dat[i] & 0x00ff);
// if (i < num) {
// Serial.print(dat[i] >> 8, DEC);
// Serial.print(" , ");
// Serial.println(dat[i] & 0x00ff, DEC);
// }
addr_local += 2;
}
// Serial.println("-----");
}
void read_eeprom(int addr, uint16_t dat[], int num) {
int addr_local = addr;
for (int i = 0; i < num; i++) {
dat[i] = (EEPROM.read(addr_local) << 8) | EEPROM.read(addr_local + 1);
addr_local += 2;
}
}
void command() {
Serial.print("enter max button command instruction number:");
Serial.println(button_cnt, DEC);
while (cmd_cnt == 0) {
if (Serial.available() > 0) {
cmd_cnt = Serial.read();
Serial.print("mode_cnt:");
Serial.println(cmd_cnt - 49 + 1, DEC);
Serial.println("----------");
Serial.println("Please begin pressing the button you want to record");
}
}
EEPROM.write(eeprom_addr, (cmd_cnt - 48) >> 8);
EEPROM.write(eeprom_addr + 1, (cmd_cnt - 48) & 0x00ff);
eeprom_addr += 2;
IrReceiver.resume();
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(12, INPUT);
Serial.begin(115200); // Status message will be sent to PC at 9600 baud
IrReceiver.enableIRIn(); // Start the receiver
mode = digitalRead(12);
// Serial.println(IR_RECEIVE_PIN);
// Serial.println("-----");
// Serial.println(sizeof(uint16_t), DEC);
// Serial.println(sizeof(byte), DEC);
// eeprom_test();
// Serial.println("-----");
if (mode == search_cmd) {
clean_eeprom();
Serial.println("search_cmd");
blink();
Serial.println("Try The Click IR Device");
cmd_leng_detect();
command();
sample(cmd_cnt - 48);
Serial.println("Search_cmd finished!!");
while (1) {
}
// mode = do_cmd;
} else {
// Serial.println("1.--------");
// Serial.println(eeprom_addr, DEC);
cmd_length = (EEPROM.read(eeprom_addr) << 8) | EEPROM.read(eeprom_addr + 1);
// Serial.println(cmd_length, DEC);
eeprom_addr += 2;
// Serial.println(eeprom_addr, DEC);
cmd_cnt = (EEPROM.read(eeprom_addr) << 8) | EEPROM.read(eeprom_addr + 1);
// Serial.println(cmd_cnt, DEC);
eeprom_addr += 2;
// Serial.println(eeprom_addr, DEC);
Serial.print("Recorded command number:");
Serial.println(cmd_cnt, DEC);
Serial.println("Command Start From 1");
for (int i = 0; i < cmd_cnt; i++) {
read_eeprom(eeprom_addr, raw[i], cmd_length);
eeprom_addr += cmd_length * 2;
}
// read_eeprom(eeprom_addr, raw[0], cmd_length);
// eeprom_addr += cmd_length * 2;
// Serial.println(eeprom_addr, DEC);
// read_eeprom(eeprom_addr, raw[1], cmd_length);
// eeprom_addr += cmd_length * 2;
// Serial.println(eeprom_addr, DEC);
// read_eeprom(eeprom_addr, raw[2], cmd_length);
// Serial.println(eeprom_addr, DEC);
// Serial.println(cmd_length, DEC);
// Serial.println("2.--------");
}
}
int eeprom_test() {
uint16_t dat_w[10] = {1, 2, 4, 8, 10, 12, 14, 16, 18, 20};
uint16_t dat_r1[10] = {0};
uint16_t dat_r2[10] = {0};
write_eeprom(0, dat_w, 10);
read_eeprom(0, dat_r1, 10);
int cmp = memcmp(dat_w, dat_r1, sizeof(uint16_t) * 10);
if (!cmp) {
Serial.println("EEPROM test ok\n");
} else {
Serial.println("EEPROM test fail\n");
}
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpInfo() {
// Check if the buffer overflowed
if (IrReceiver.results.overflow) {
Serial.println(
"IR code too long. Edit IRremoteInt.h and increase RAW_BUFFER_LENGTH");
return;
}
IrReceiver.printResultShort(&Serial);
Serial.print(" (");
Serial.print(IrReceiver.results.bits, DEC);
Serial.println(" bits)");
}
//+=============================================================================
// The repeating section of the code
//
void blink() {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
void cmd_leng_detect() {
while (!cmd_length) {
if (IrReceiver.decode()) { // Grab an IR code
cmd_length = IrReceiver.results.rawlen - 1;
EEPROM.write(eeprom_addr, cmd_length >> 8);
EEPROM.write(eeprom_addr + 1, cmd_length & 0x00ff);
eeprom_addr += 2;
Serial.print("IR Length is:");
Serial.println(cmd_length, DEC);
blink();
}
}
IrReceiver.resume();
}
void sample(int cnt) {
int cmd_cnt_l = 0;
while (cnt > 0) {
if (IrReceiver.decode()) { // Grab an IR code
unsigned int i;
Serial.print("button ");
Serial.print(cmd_cnt_l + 1, DEC);
Serial.print(":");
for (i = 1; i < IrReceiver.results.rawlen; i++) {
raw[cmd_cnt_l][i - 1] = IrReceiver.results.rawbuf[i] * MICROS_PER_TICK;
raw_tmp[i - 1] = IrReceiver.results.rawbuf[i] * MICROS_PER_TICK;
// Serial.print(raw[cnt-1][i - 1], DEC);
// Serial.print(",");
// Serial.println(IrReceiver.results.rawbuf[i] * MICROS_PER_TICK, DEC);
// Serial.print("--");
}
// Serial.println("");
// IrReceiver.printIRResultAsCVariables(&Serial); // Output
// address and data as source code variables
// IrReceiver.printIRResultAsPronto(&Serial);
// Serial.println(); // 2 blank lines between entries
// Serial.println();
delay(2000);
IrReceiver.resume(); // Prepare for the next value
write_eeprom(eeprom_addr, raw_tmp, cmd_length);
eeprom_addr += cmd_length * 2;
blink();
Serial.println("sample finisheded");
raw_leng[cmd_cnt_l] = IrReceiver.results.rawlen;
cmd_cnt_l++;
cnt--;
}
}
// show the size of each ir command
// Serial.println("-----");
// for (int i = 0; i < cmd_cnt_l; i++) {
// Serial.println(raw_leng[i], DEC);
// }
// Serial.println("-----");
Serial.println("all sample process finisheded");
}
void loop() {
int khz = 38; // 38kHz carrier frequency for the NEC protocol
if (mode == search_cmd) {
Serial.println("search_cmd");
} else if (mode == do_cmd) {
int cmd = 0;
if (Serial.available() > 0) {
Serial.println("do_cmd");
cmd = Serial.read();
Serial.print("command:");
Serial.println(cmd - 49 + 1, DEC);
}
if (cmd != 0) {
IrSender.sendRaw(raw[cmd - 49],
sizeof(raw[cmd - 49]) / sizeof(raw[cmd - 49][0]),
khz); // Note the approach used to automatically
// calculate the size of the array.
// IrSender.sendRaw(rawData, sizeof(rawData) / sizeof(rawData[0]),
// khz); // Note the approach used to automatically calculate the
// size of the array.
Serial.println("IrSender command 1 finished");
}
}
}
```
## 遇到問題:
1. 每個紅外線協定送的字串長度不一樣,如果陣列宣告過大會造成系統執行不穩定。調整為通用型的話可以嘗試兩種方法:
1.1. 宣告一個相當長的陣列,但對於儲存空間有限的arduino不實際。
1.2. 將字串記憶體的長度調整為動態宣告(malloc)。
參考資料:
[1.2 顯示紅外線協定種類](http://coopermaa2nd.blogspot.com/2011/03/12.html)
[2.1 發射紅外線訊號](http://coopermaa2nd.blogspot.com/2011/03/21.html)
[自製紅外線遙控器](http://pizgchen.blogspot.com/2016/11/blog-post_25.html)
[github line 532](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/irReceive.cpp)
###### tags: `arduino` `irda`