"Embedded Space"

Think − Do − Learn − Share







การแปลงสัญญาณ IR จากรีโมทคอนโทรลของเครื่องปรับอากาศให้เป็นข้อมูลดิจิทัล

โดยทั่วไป ในการติดตั้งและใช้งานเครื่องปรับอากาศ มักจะมาพร้อมกับอุปกรณ์รีโมทคอนโทรล (Remote Control) สำหรับผู้ใช้ อุปกรณ์ประเภทนี้ ส่งสัญญาณด้วยแสงอินฟราเรด (Infrared) เพื่อเปิด-ปิด หรือปรับค่าอุณหภูมิได้

บทความนี้จะกล่าวถึง ตัวอย่างการรับและแปลงสัญญาณแสงอินฟราเรด จากรีโมทคอนโทรลของเครื่องปรับอากาศ ให้เป็นข้อมูลดิจิทัล และสามารถนำมาสร้างเป็นอุปกรณ์รีโมทได้ โดยใช้บอร์ดไมโครคอนโทรลเลอร์ อย่างเช่น Arduino ร่วมกับวงจร IR LED เป็นตัวส่ง

รูปแสดงตัวอย่างเครื่องปรับอากาศของ York สำหรับการทดลอง รูปแสดงตัวอย่างรีโมทคอนโทรลสำหรับเครื่องปรับอากาศ

ในการทดลอง ได้เลือกใช้ตัวรับแสงอินฟราเรด (IR Receiver) ซึ่งเป็นไอซีTSOP4838 ของบริษัท Vishay Semiconductor และใช้ได้กับแสงอินฟราเรดแบบคลื่นพาหะความถี่ 38kHz (carrier frequency) ตัวไอซีมี 3 ขา โดยที่ ขา 1 เป็น Vout (สัญญาณดิจิทัล-เอาต์พุต), ขา 2 เป็น Gnd, และขา 3 เป็น VCC (แรงดันไฟเลี้ยง) ซึ่งใช้แรงดันไฟเลี้ยง +5V เช่น จากบอร์ด Arduino ... ขา Vout (หรือ OUT) ของไอซี TSOP4838 จะนำไปต่อเข้ากับขา D3 ของบอร์ด Leonardo หรือ ขา D2 ของบอร์ด Arduino Uno ซึ่งตรงกับ External Interrupt หมายเลข 0


รูปแสดงตำแหน่งและหมายเลขขาของไอซี TSOP4838

Arduino Sketch [IR Receiver / Sniffer]

โค้ด Arduino ตัวอย่างแรกนี้ จะใช้สำหรับการรับสัญญาณอินฟราเรดจากวงจรตัวรับและแปลงให้เป็นข้อมูลเชิงเวลาและลำดับของข้อมูลบิต พฤติกรรมการทำงานของโค้ดโดยสรุปมีดังนี้ ถ้ามีการเปลี่ยนแปลงสถานะลอจิกของอินพุต-ดิจิทัล (D3 สำหรับ Leonardo หรือ D2 สำหรับ Arduino Uno) เช่น เมื่อมีการกดปุ่มที่รีโมทคอนโทรล (ตัวส่งจะส่งสัญญาณออกมา) และตัวรับได้รับสัญญาณ จะทำให้เกิดอินเทอรัพท์ (External Interrupt 0) และฟังก์ชันสำหรับ ISR จะทำหน้าที่อ่านค่าเวลาของ Arduino ในขณะนั้น และบันทึกเก็บไว้ ข้อมูลเหล่านี้จะถูกนำมาแสดงออกทาง Serial และแปลงข้อมูลเหล่านั้นให้เป็นลำดับของบิต 0 หรือ 1 และข้อมูลที่เป็นลำดับของบิต 0 / 1 เหล่านี้ แตกต่างกันขึ้นอยู่กับปุ่มของรีโมทที่ถูกกด

การแยกแยะว่า ข้อมูลที่ได้มานั้น เป็นบิต 0 หรือ บิต 1 จะดูได้จากความกว้างของสัญญาณ Pulse ของช่วงที่เป็น HIGH (ในโค้ดมีการกำหนดเป็นพารามิเตอร์ไว้ในหน่วยเป็นไมโครวินาที หรือ usec ทั้งนี้ก็ขึ้นอยู่กับอุปกรณ์รีโมทคอนโทรลแต่ละรุ่น)

ในการสาธิตการทำงาน ได้ทดลองรับสัญญาณจากรีโมทคอนโทรลของเครื่องปรับอากาศ York แบบติดผนัง (Cooling Capacity 12638 Btu/h) โดยทดลองกดปุ่มต่างๆ เช่น ปุ่มเปิด/ปิด (On/Off) ปุ่มเพิ่มหรือลดอุณหภูมิ และปุ่มเลือกปรับความแรงของพัดลม (Fan) เป็นต้น

ข้อมูลที่ได้จะถูกนำไปใช้ในการสร้างรีโมทคอนโทรล โดยใช้บอร์ด Arduino เพื่อเลียนแบบการทำงาน (บางส่วน) ของรีโมทสำหรับเครื่องปรับอากาศรุ่นดังกล่าว และเมื่อนำไปทดลองสามารถเปิด-ปิดและตั้งค่าอุณหภูมิสำหรับเครื่องปรับอากาศได้

//////////////////////////////////////////////////////////////
// Author: RSP @KMUTNB
// Date: 2013-11-04
// Board: Arduino with ATmega168/328P or Leonardo
// Arduino IDE: version 1.0.5
// This Arduino sketch show how to sniff an IR signal 
// from a remote control.

// bit timing parameters (in usec)
#define BIT1_HIGH_MIN  1100
#define BIT1_HIGH_MAX  1250
#define BIT0_HIGH_MIN  440
#define BIT0_HIGH_MAX  650
#define BIT_LOW_MIN    500
#define BIT_LOW_MAX    650

// Select Pin 2 for Arduino Uno or Pin 3 for Leonardo !!!
const byte EINT0_PIN = 3; // External interrupt 0 pin 

volatile int flag = 0;
volatile uint32_t tL = 0, tH = 0;

// global variables
int start = 0, index = 0;
uint32_t tF = 0;

#define BUF_SIZE 640
uint16_t buf[ BUF_SIZE+1 ];

void setup() {
  Serial.begin( 115200 );
  attachInterrupt( 0, eint0_isr, CHANGE );  // use EINT0
  while (!Serial) ;
  if ( digitalRead( EINT0_PIN ) != HIGH ) {
    Serial.println( "Error: IR input should be HIGH!" );
  }
  tF = tL = tH = micros();
  flag = 0;
  index = start = 0;
}

void showBitSequence( uint16_t time_values[], int len ) {
  uint16_t t;
  char ch;
  for (int i=0; i < len; i+=2) {
     t = time_values[i];
     if ( t >= BIT1_HIGH_MIN && t < BIT1_HIGH_MAX ) 
        ch = '1'; // bit 1
     else if ( t >= BIT0_HIGH_MIN && t < BIT0_HIGH_MAX ) 
        ch = '0'; // bit 0
     else
        ch = '?'; // unknown bit
     if ( i+1 < len )
       t = time_values[i+1];
     else
       t = 0;
     if ( t >= BIT_LOW_MIN && t < BIT_LOW_MAX ) 
        Serial.print( ch ); 
     else
        Serial.print( '-' ); 
     Serial.print( ',' );
  }
  Serial.println( "" );
}

void loop() {
  boolean dump = (micros() - tF) > 500000;
  if ( dump && index < 8 ) {  // too short sequence
     index = 0; // clear buffer
  }
  else if ( dump || (index == BUF_SIZE) ) {
    for (int i=0; i < index; i++) {
       Serial.print( buf[i] );
       if (buf[i] >= 2000) Serial.print( '*' );
       Serial.print( (i+1==index) ? '\n' : ',' );
    }
    Serial.println( index );
    showBitSequence( buf, index );
    index = 0;
  }

  if ( flag ) {
     uint16_t dT;
     if (flag==1) // HIGH  
        dT = (uint16_t)(tL-tH);
     else // LOW 
        dT = (uint16_t)(tH-tL);
     dT = 5*(dT/5); // 5usec resolution
     
     if (start) { // start capture
        buf[index++] = dT;
     }
     else if ( !start && (dT < 5000) && (flag == 2) ) { // found start bit
        start = 1;
     } 
     tF = micros();
     flag = 0; // clear flag
  }
}

void eint0_isr() { // ISR for Ext. Interrupt 0
  uint32_t t = micros();
  if ( digitalRead( EINT0_PIN ) ) { // HIGH
    tH = t;
    flag = 2;
  } else { // LOW
    tL = t;
    flag = 1;
  }
}
///////////////////////////////////////////////////////////////


รูปแสดงการต่อวงจรตัวรับบนเบรดบอร์ด + Arduino (Leonardo)


รูปแสดงข้อมูลจาก Arduino เมื่อได้รับสัญญาณและแปลงเป็นข้อมูลหลังจากมีการกดปุ่มต่างๆของรีโมท

Arduino Sketch [IR Sender]

หลังจากได้ข้อมูลเกี่ยวกับลำดับของบิต และความกว้างของช่วง HIGH และช่วง LOW ของแต่ละบิตมาแล้ว จะนำมาเขียนโค้ดเพื่อทดลองสร้างรีโมทโดยใช้บอร์ด Arduino + วงจร IR LED เป็นตัวส่งสัญญาณแสงอินฟราเรด (เอาต์พุตขา D5) และมีวงจรปุ่มกด (อินพุตขา D6)

พฤติกรรมการทำงานของโค้ดมีดังนี้ เมื่อมีการกดปุ่มหนึ่งครั้ง Arduino จะส่งข้อมูลของคำสั่งออกไปตามลำดับ เริ่มต้นด้วยคำสั่งเปิดเครื่อง (Power On) ถ้ากดปุ่มครั้งต่อไป จะเป็นคำสั่งตั้งค่าอุณหภูมิ 25, 26, 27 และ 28 องศาเซลเซียส ไปจนถึงคำสั่งปิดเครื่อง (Power Off) เป็นคำสั่งสุดท้าย แต่ถ้ากดปุ่มอีก ก็จะวนซ้ำรอบใหม่ ในการทดลองให้หันหลอด IR LED ไปยังทิศทางตัวรับของเครื่องปรับอากาศ กดปุ่มแล้วปล่อยหนึ่งครั้งแล้วสังเกตการเปลี่ยนแปลง

// Author: RSP @KMUTNB
// Date: 2013-11-04
// Board: Arduino with ATmega168/328P or Leonardo
// Arduino IDE: version 1.0.5

// This code is written for demonstration purposes
// and may not be highly optimized.

///////////////////////////////////////////////////////////////////////
const byte BUTTON_PIN = 6; // input push button
const byte IR_LED_PIN = 5; // control pin for IR LED

void setup() {
  pinMode( IR_LED_PIN, OUTPUT );
  pinMode( BUTTON_PIN, INPUT );
  digitalWrite( BUTTON_PIN, HIGH ); // enable pull-up
  Serial.begin( 115200 );
  while (!Serial) ;
  Serial.println("Ready...");
}

const byte CODE_POWER_ON[] = {
  1,1,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,
  1,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,
  255
};

const byte CODE_POWER_OFF[] = {
  1,1,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,
  1,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,
  255
};

const byte CODE_25_DEG[] = {
  1,1,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,
  0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,
  255
};

const byte CODE_26_DEG[] = {
  1,1,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,
  1,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,
  255
};

const byte CODE_27_DEG[] = {
  1,1,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,
  0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,
  255
};

const byte CODE_28_DEG[] = {
  1,1,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,
  1,1,0,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,
  255
};

void burst( int cycles ) {
  cli(); // turn off global interrupt
  for( uint32_t i=0; i < cycles; i++ ) {
     digitalWrite( IR_LED_PIN, HIGH );
     delayMicroseconds( 7 ); 
     digitalWrite( IR_LED_PIN, LOW );
     delayMicroseconds( 8 ); // may adjust this value to change the frequency
  }
  sei(); // turn on global interrupt
}

const char *CODE_NAMES[6] = {
  "Power On", "25 deg.", "26 deg.", "27 deg.", "28 deg.", "Power Off"
};

const byte *CODE_LIST[6] = {
  CODE_POWER_ON, CODE_25_DEG, CODE_26_DEG, CODE_27_DEG, CODE_28_DEG, CODE_POWER_OFF
};

void loop() {
  static byte code_index = 0;
  if ( digitalRead( BUTTON_PIN ) == LOW ) { // button pressed
    uint16_t i = 0;
    byte b;
    const byte *code = CODE_LIST[ code_index ];
    Serial.println( CODE_NAMES[ code_index] );
    code_index = (code_index+1) % 6;

    // send start bit
    burst( 143 ); // LOW: approx. 3800 usec 
    delayMicroseconds( 1460 ); // HIGH: approx 1460 usec

    burst( 20 ); // LOW: approx. 540 usec
    while (true) {
      b = code[ i ]; // get next bit from the code sequence
      if (b == 255) break; // end of bit sequence
      delayMicroseconds( (b==1) ? 1150 : 560 ); // HIGH
      burst( 20 ); // LOW: approx. 540 usec 
      i++;
    }
    while ( digitalRead(BUTTON_PIN) != HIGH ) ; // wait for button release
  }
  delay(10);
}
///////////////////////////////////////////////////////////////////////


รูปแสดงการต่อวงจรตัวส่งบนเบรดบอร์ด + Arduino (Pro Micro)

รูปแสดงสัญญาณเอาต์พุตที่ขา D5 ของ Arduino
(วัดสัญญาณด้วยออสซิลโลสโคป)
รูปแสดงสัญญาณเอาต์พุตที่ขา D5 เมื่อขยายในแกนเวลา
(ช่วง Burst ซึ่งมีความถี่ประมาณ 38kHz)

ถ้าสามารถใช้บอร์ด Arduino เป็นอุปกรณ์รีโมทสำหรับเครื่องปรับอากาศได้ จะนำไปสู่การประยุกต์ใช้งานต่อไป เช่น ใช้งานร่วมกับเซนเซอร์ตรวจจับการเคลื่อนไหวของผู้ใช้ การปรับอุณหภูมิห้องตามเงื่อนไขที่กำหนด หรือควบคุมผ่านอินเทอร์เน็ต เป็นต้น


แก้ไขครั้งล่าสุด (Last Update): 4 Nov. 2013


เผยแพร่ภายใต้ลิขสิทธิ์ / This work is licensed under: Creative Commons Attribution-NonCommercial 3.0 Unported

บทความ (Articles)


>> [ถัดไป] →| [หน้าสุดท้าย]

จากทั้งหมด 90 บทความ

ย้อนกลับ [back]

ห้องปฏิบัติการระบบสมองกลฝังตัว สาขาวิศวกรรมคอมพิวเตอร์ (CprE)
ภาควิชาวิศวกรรมไฟฟ้าและคอมพิวเตอร์ (ECE) คณะวิศวกรรมศาสตร์
มหาวิทยาลัยเทคโนโลยีพระจอมเกล้าพระนครเหนือ (KMUTNB)