AVR · Embedded System

IR remote receiver with ATtiny2313

Xin chào, chắc hẳn chúng ta đều biết cái remote, hãy ứng dụng IR remote để điều khiển các thiết bị điện trong nhà nào!

1 – CHUẨN BỊ

  • MCU ATtiny2313
  • IR receiver TSOP4838
  • IR remote với protocol NEC.
  • vài con LED, trở 330 và dây dẫn.

2 – PROTOCOL NEC

Dữ liệu được mã hóa bởi Pulse Distance Protocol (PDP). Mỗi bit đều được bắt đầu bởi một xung dài 560us (560us-long 38kHz burst) và theo sau bởi một khoảng pause. Bit 0 có tổng độ dài 1,12ms, bit 1 là 2,25ms. Mỗi chuỗi dữ liệu được bắt đầu bởi 9ms burst (AGC pulse) và 4,5ms-pause.

nec

Gói dữ liệu gửi đi gồm 32 bit (16 bit command và 16 bit address)

dataformat

Chú ý rằng dữ liệu được gửi đi với LSB-first, do đó chúng ta sẽ nhận được như sau:

transformat

Note that the address and command data is sent with the least-significant bit transmitted first. The data comprises an 8-bit address, after which a complementary 8-bit address is sent. This is essentially the opposite bit of the address that’s sent. So for every ‘0’ bit that’s sent in the address, a ‘1’ will be sent in the complementary address. Similarly, for every 1 that’s sent in the address, a 0 will be sent in the complementary address. The command bits are also resent in complementary form.

The complementary address and command bytes are sent so that they can be compared to detect errors. If the complementary data value received doesn’t match the complement of the data value received, the signal has been corrupted somehow (eg, due to interference). Alternatively, the received data may not be PDP protocol data, which means that the signal is being sent by a different hand-held remote.

Sau khi truyền xong 32 bit, gói dữ liệu kết thúc với 560us burst. Nếu tiếp tục giữ nút trên remote, repeat frame sẽ được gửi đi, gồm 9ms burst, theo sau bởi 2,25ms pause và kết thúc bởi 560us burst.

3 – NGUYÊN LÝ HOẠT ĐỘNG

Chúng ta sẽ sử dụng Timer/Counter0 ở ATtiny2313 để đo khoảng thời gian giữa các Falling-edge interrupt. Timer0 hoạt động ở 1MHz (tần số mặc định của ATtiny2313), có prescale = 64, tương ứng với 1 xung = 64us.

Ở trạng thái bình thường, output của TSOP4838 là HIGH, khi phát hiện được 38kHz carrier pulse, output chuyển thành LOW. Dựa vào đặc điểm này chúng ta sẽ sử dụng Falling-edge interrupt trên chân PD2 để đo độ rộng xung.

Chuyển đổi:

Trong thực tế, độ rộng xung tín hiệu không bao giờ chính xác tuyệt đối, do đó chúng ta sẽ sử dụng sai số để dễ dàng phân biệt các tín hiệu.

AGC – 13,5ms = 211 xung [194…228]
Repeat frame – 11,25ms = 176 xung [159…193]
Bit 1 – 2,25ms = 35 xung [26…44]
Bit 0 – 1,12ms = 18 xung

Schematic (not full):
schematic

3D model:

3dmodel
Code cho ATtiny2313:

#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile uint8_t NextBit;
volatile uint32_t RecdData;
uint8_t record;

// Demo routine
void ReceivedCode(uint8_t Repeat) {
  	// Check for correct remote control
  	if ((RecdData & 0xFFFF) != 0x7F80) 
		return;
  	// Read key pressed
	if (!Repeat) {
  		switch(RecdData) {
    		case 0xED127F80: PORTB = 0; break;
    		case 0xE11E7F80: PORTB = record; break;
			case 0xFE017F80: PORTB ^= (1 << PB0); record = PORTB; break;
			case 0xFD027F80: PORTB ^= (1 << PB1); record = PORTB; break;
			case 0xFC037F80: PORTB ^= (1 << PB2); record = PORTB; break;
    		case 0xFA057F80: PORTB ^= (1 << PB3); record = PORTB; break;
    		case 0xF8077F80: PORTB ^= (1 << PB4); record = PORTB; break;
    		case 0xF7087F80: PORTB ^= (1 << PB5); record = PORTB; break;
			case 0xF6097F80: PORTB ^= (1 << PB6); record = PORTB; break;
			case 0xE41B7F80: PORTB ^= (1 << PB7); record = PORTB; break;
    		default: break;
  		}
	}	
}


// Interrupt service routine - called on every falling edge of PD2
ISR(INT0_vect) {
  	int Time = TCNT0;
  	int Overflow = TIFR & (1 << TOV0);
  	// Keep looking for AGC pulse and gap
  	if (NextBit == 32) {
    	if ((Time >= 194) && (Time <= 228) && (Overflow == 0)) {
      		RecdData = 0; 
			NextBit = 0;
    	} 
		else if ((Time >= 159) && (Time <= 193) && (Overflow == 0)) 
			ReceivedCode(1);
  	} 
	// Data bit
	else {
    	if ((Time > 44) || (Overflow != 0)) 
			NextBit = 32; // Invalid - restart
    	else {
      		if (Time > 26) 
				RecdData = RecdData | ((unsigned long) 1<<NextBit);
      		if (NextBit == 31) 
				ReceivedCode(0);
      		NextBit++;
    	}
  	}
  	TCNT0 = 0;             // Clear counter
  	TIFR = 1 << TOV0;      // Clear overflow
  	EIFR = 1 << INTF0;     // Clear INT0 flag
}

  
int main() {
	// GPIO configure
  	DDRD &= ~(1 << PD2); // PD2 as input + pull-up resistor
  	PORTD = (1 << PD2);
	DDRB = 0xFF;

  	// Set up Timer/Counter0 (assumes 1MHz clock)
  	TCCR0A = 0;           // No compare matches
  	TCCR0B = 3 << CS00;   // Prescaler = 64
  	// Set up INT0 interrupt on PD2
  	MCUCR = 1 << ISC01;   // Interrupt on falling edge
  	GIMSK = 1 << INT0;    // Enable INT0
  	sei();
  	NextBit = 32;         // Wait for AGC start pulse

  	while (1) {
  	}
}

Chúng ta sử dụng biến uint32_t RecdData để lưu 32 bit dữ liệu và biến NextBit để lưu số lượng bit đã nhận được, biến NextBit cũng được dùng như là index để lưu bit vừa nhận được vào RecdData theo LSB First.

Để nạp code cho ATtiny2313, các bạn tham khảo bài viết này nhé.

Cảm ơn các bạn đã theo dõi bài viết của mình.

Tham khảo:
[1] IR Remote Control Receiver
[2] IR Remote Control Tool (NEC)
[3] Everyday Practical Electronics 12-2016 – 9-Channel Infrared Remote Control.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s