# IrDA 拷貝器 ## 目的: 希望能透過直接抓取irda的原始資料拷貝任何藉由irda通訊的設備。 ## 硬體需求 1. arduino nano(atmega328) 2. VS 1838B 3. 940nm 波長紅外線發射器 **接線:** ![](https://i.imgur.com/ntmlTpT.png) ## 軟體功能 功能說明: 將**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`