Ứng dụng capture giải mã Remote hồng ngoại

Giải mã hồng ngoại, RF cũng có nhiều cách.
Hôm nay mình giới thiệu cách sử dụng bộ Input Capture.
Bộ remote sử dụng là Remote của quạt Vinawind

Đo thử tín hiệu của bộ Remote phát ra

Mỗi nút nhấn có thể được biểu diễn bằng 1 số 12 bit

Code giải mã bằng cách sử dụng Input Capture
Dùng chân P12 để bắt tín hiệu vào

Mã nguồn file IR.h

#ifndef MY_IR_H_
#define MY_IR_H_

#define IR_OFF 0x027E
#define IR_ON_SPEED 0x027D
#define IR_MODE 0x027B
#define IR_TIME 0x0277
#define IR_SWING 0x026F

#include "ms51.h"
#include <stdint.h>

void IR_Init(void);
uint8_t IR_Check(uint32_t *pu32Cmd);

#endif

Mã nguồn file IR.c

#include "myIR.h"

#define IR_IN_VAL P12

#define NUM_BIT 12

#define MIN_LOW 100
#define MAX_LOW 1600
#define LOW_VAL 800
#define MIN_HI 100
#define MAX_HI 1600

static void tim2_init(void);
static void cap_init(void);

#define STATE_IDLE 0
#define STATE_RECEIVE 1
#define STATE_CHECK_BIT_0 2
#define STATE_CHECK_BIT_1 3
#define STATE_DECODE_SUCC 4

typedef void (*pfunc)(void);

void idle_state(void);
void receive_state(void);
void check_bit_0_state(void);
void check_bit_1_state(void);
void decode_succ_state(void);

static pfunc funcSet[] = {
	idle_state,
	receive_state,
	check_bit_0_state,
	check_bit_1_state,
	decode_succ_state
};

static uint8_t u8State = STATE_IDLE;
static uint8_t u8Count = 0;
static uint32_t u32Result = 0;

void idle_state(void)
{
	if (!IR_IN_VAL) {
		u8Count = 0;
		u32Result = 0;
		u8State = STATE_RECEIVE;
	}
}

void receive_state(void)
{
	uint16_t u16Tmp;
	if (IR_IN_VAL) {
		u16Tmp = C0H * 256 + C0L;
		if (u16Tmp < MIN_LOW) {
			u8State = STATE_IDLE;
			return;
		}
		if (u16Tmp > MAX_LOW) {
			u8State = STATE_IDLE;
			return;
		}
		if (u16Tmp > LOW_VAL) {
			u32Result <<= 1;
			++u8Count;
			if (u8Count == NUM_BIT) {
				u8State = STATE_DECODE_SUCC;
				return;
			}
			u8State = STATE_CHECK_BIT_0;
		} else {
			u32Result <<= 1;
			u32Result |= 1;
			++u8Count;
			if (u8Count == NUM_BIT) {
				u8State = STATE_DECODE_SUCC;
				return;
			}			
			u8State = STATE_CHECK_BIT_1;
		}
	}
}

void check_bit_0_state(void)
{
	uint16_t u16Tmp;
	if (!IR_IN_VAL) {
		u16Tmp = C0H * 256 + C0L;
		if (u16Tmp < MIN_HI) {
			u8State = STATE_IDLE;
			return;
		}
		if (u16Tmp > MAX_HI) {
			u8State = STATE_IDLE;
			return;
		}
		if (u16Tmp < LOW_VAL) {
			u8State = STATE_RECEIVE;
		} else {
			u8State = STATE_IDLE;
		}
	}
}

void check_bit_1_state(void)
{
	uint16_t u16Tmp;
	if (!IR_IN_VAL) {
		u16Tmp = C0H * 256 + C0L;
		if (u16Tmp < MIN_HI) {
			u8State = STATE_IDLE;
			return;
		}
		if (u16Tmp > MAX_HI) {
			u8State = STATE_IDLE;
			return;
		}
		if (u16Tmp > LOW_VAL) {
			u8State = STATE_RECEIVE;
		} else {
			u8State = STATE_IDLE;
		}
	}
}

void decode_succ_state(void)
{
	
}

static void tim2_init(void)
{
    /* pre-scalar = 1 / 16*/
    T2MOD &= ~(0x70);
    T2MOD |= (0x20);
    /* auto reload mode */
    CM_RL2 = 0;
	/* auto clear */
	T2MOD |= (1 << 3);
}

static void cap_init(void)
{
	T2MOD |= ((1<<0));
    TR2 = 1;
    CAPCON3 = 0x00;
    CAPCON1 = 0x02;
    CAPCON2 = (1<<4);
    CAPCON0 |= (1<<4);
}

void IR_Init(void)
{
	u8State = STATE_IDLE;
    u32Result = 0;
    u8Count = 0;
    tim2_init();
	cap_init();
}

uint8_t IR_Check(uint32_t *pu32Cmd)
{
	if (TF2) {
		TF2 = 0;
		u8State = STATE_IDLE;
	}
	if (CAPCON0 & (1<<0)) {
		funcSet[u8State]();
		CAPCON0 &= ~(1<<0);
	}
	if (u8State == STATE_DECODE_SUCC) {
		u8State = STATE_IDLE;
		*pu32Cmd = u32Result;
		return 1;
	}
	return 0;
}

Hàm delay sử dụng timer 0 như mã nguồn ở bài viết này
http://vidieukhien.org/ms51fb9ae-mot-so-ham-tao-delay.html

Mã nguồn file main.c

#include "ms51.h"
#include <stdint.h>
#include "myIR.h"
#include "delay.h"

uint32_t u32Cmd;

void main(void)
{
    P1M1 &= ~(1 << 5);
    P1M2 |= (1 << 5);
    P15 = 0;
	
	IR_Init();
	Delay_Init();
	
    while (1) {
		if (IR_Check(&u32Cmd)) {
			switch (u32Cmd) {
			case IR_OFF:
				P15 = 0;
				break;
			case IR_ON_SPEED:
				P15 = 1;
				break;
			}
			Delay_Ms(200);
		}
    }
}

Mỗi khi ấn nút Bật/Tốc độ thì led trên KIT VĐK 1.0 sẽ sáng.
Mỗi khi ấn nút Tắt trên Remote thì led trên KIT VĐK 1.0 sẽ tắt.

Toàn bộ Project:
https://drive.google.com/open?id=1UECUHGP9ED5-YT_zAsxtGeGQE_4cyLZl