Module điều khiển RF 315MHz học lệnh

Module điều khiển RF 315MHz học lệnh với MP430

Thành phần chính mạch gồm

Chức năng của mạch

Thông số của mạch

Nguyên lý hoạt động

Khuyến cáo: nên chạy chế độ xóa dữ liệu trước khi muốn thay đổi thiết lập để tránh lỗi.

Đo tín hiệu điều khiển từ Remote

Để có thể giải mã được những gì mà tay phát truyền đi, tôi sẽ coi xem tín hiệu thu được từ module thu thông qua phần mềm Audacity (Sử dụng card âm thanh làm Oscilloscope tạm vì ở nhà tôi không có máy đo)

Tiến hành đo tín hiệu đối với từng phím bấm trên tay phát. Tín hiệu thu được như dưới đây:

Dữ liệu thu được tại đầu ra của module thu RF 315MHz

MCU sẽ đếm độ rộng xung tín hiệu và giải mã tín hiệu đó về dạng nhị phân để xử lý. Bit đồng bộ sẽ được thêm vào khung truyền nhằm đồng bộ hóa quá trình mã hóa và giải mã. MCU sẽ dựa vào bit này để nhận ra 1 khung truyền.

Trong chế độ học lệnh, dữ liệu sau giải mã được lưu lại vào bộ nhớ và sử dụng lại để so khớp trong chế độ chạy bình thường.

Trên thị trường hiện này, các tay phát sử dụng đa số các loại chip mã hóa như: SC2262, PT2262… và sử dụng mạch dao động nội (Được cấu hình thông qua 1 điện trở) khác nhau dẫn đến độ rộng xung khác nhau. Cộng thêm là phương thức điều chế. Vì vậy cần nghiên cứu kỹ phần này để viết chương trình tốt hơn.

Như hình dưới, có thể đo sơ qua được 1 bit rộng cỡ 21 đoạn mẫu, trong khi chương trình được cấu hình lấy mẫu với tần số 44.1KHz

21/44100 = 476us

Độ rộng xung ứng với 1 bit

Căn cứ vào giá trị này để tính thời gian timer lấy mẫu tín hiệu cho MCU.

Sơ đồ nguyên lý

Sơ đồ nguyên lý

Mạch thật

Module thực tế

Mã nguồn

IDE tôi sử dụng là IAR. Do không có thời gian phát triển thêm nên hiện tại code còn hạn chế. :)

Mã nguồn:

/*
MSP430 Project:
BO DIEU KHIEN TU XA HOC LENH RF 315MHz
MCU: MSP430

Author: TrungThanh
Website: thanhnt.com

DESCRIPTION:
Chuong trinh su dung 1 port duy nhat
- 2 Led thong bao
- 4 port dieu khien Relay
- 1 Button
- 1 Chan nhan tin hieu RF
Chuong trinh VDK cho phep giai ma, luu tru, dieu khien relay tu bo dieu khien co su dung chip
ma hoa dong 2262-2264.
Luu du lieu khi bi mat dien, reset.
Cau hinh tu do.
Phuc hoi trang thai cuoi truoc khi mat dien bang cach luu gia tri thanh ghi P1OUT (8bit ~ 1byte) vao flash.

Button:
- Nhan 1.5s (Blink Red Led 1 time) => Confirm manual setup
- Nhan 2.5s (Blink Red Led 2 times) => Setup Mode
- Nhan 5s (Blink Red Led 5 times) => Clear all command, memory (Reset all to default)

HARDWARE:
RF 315Mhz
- Nguon 5V

Button
- Tro treo len Vcc 4.7k

Power Down detector
- treo 1 tro 4.7k len truoc diod noi vao Vcc

Relay
- Cathode chung

Flash
- Moi gia tri Command co do rong 24bit => luu thanh 4byte
  => luu 16byte trong SegmentD.


ChangeLog:
30/8/2014 - Release (Ko luu trang thai truoc khi mat dien)
31/8/2014 - Release (Luu trang thai truoc khi mat dien) - Loi bi xoa het flash khi trang thai cuoi cung ko co relay nao bat.
3/12/2014 - Final
*/
#include <msp430g2452.h>
#include "Flash.h"

#define set |=
#define clr &=~
#define tgl ^=

#define SETTING 1
#define RUNNING 2

#define RF_RECEIVE_PORT BIT1
#define BUTTON_MENU BIT7
#define LED_RED BIT6
#define PW_LOSS BIT0
#define RELAY_1 BIT5
#define RELAY_2 BIT4
#define RELAY_3 BIT3
#define RELAY_4 BIT2

unsigned char BitCounter, LastState;
unsigned char Buffer[32], Byte_read;
volatile unsigned long RFCode, Command[4];
static unsigned char Scene = RUNNING;
unsigned int TACounter = 0, Setting_Button = 0, i, j;

void Blink_Led(unsigned int solan, unsigned char Port);
int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

  if (CALBC1_1MHZ==0xFF)                    // If calibration constant erased
  {
    while(1);                               // do not load, trap CPU!!
  }
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
  DCOCTL = CALDCO_1MHZ;

  Init_Flash(); //Initial Read - Write Flash
  
  P1DIR set (LED_RED + RELAY_1 + RELAY_2 + RELAY_3 + RELAY_4);
  P1OUT clr (LED_RED + RELAY_1 + RELAY_2 + RELAY_3 + RELAY_4);
  
  // Configure Port Pins
  P1DIR clr RF_RECEIVE_PORT; //Set P1.3 input
  P1REN clr RF_RECEIVE_PORT;
  P1IE set RF_RECEIVE_PORT; //Enable interrupt in p1.3
  P1IES clr RF_RECEIVE_PORT; //P1IES clr BIT3; -> Detect rising pulse(L2H) ||| P1IES |= BIT3; -> Detect falling pulse (H2L)
  P1IFG clr RF_RECEIVE_PORT; //Clear Interrupt flag
  
  //Setup Menu Button
  P1IES set BUTTON_MENU;
  P1IFG clr BUTTON_MENU;
  P1IE set BUTTON_MENU;

  //Setup Power Down interrupt
  P1DIR clr PW_LOSS;
  P1IES set PW_LOSS;
  P1IFG clr PW_LOSS;
  P1IE set PW_LOSS;
  P1OUT clr PW_LOSS;
  
  //Prepare value for Command from Flash
  for(i = 0; i < 4; i++)
  {
    for(j = 0; j < 4; j++)
    {
      Flash_Read_Byte(SegmentD, &Byte_read, (3-j) + i*4);
      Command[i] |= Byte_read;
      if(j<3) Command[i]<<=8;
    }
  }
  Flash_Read_Byte(SegmentD, &LastState, 20);
  if(LastState < 255 && LastState > 0) {
    LastState clr (LED_RED | PW_LOSS | BUTTON_MENU | RF_RECEIVE_PORT);
    P1OUT set LastState;
    Blink_Led(3, LED_RED);
  }
  LastState = 0;
  
  // Configure Timer
  TA0CTL = TASSEL_2 + MC_1; //Source clock from DCO, up mode
  TA0CCR0 = 50000; //Dem cho thanh ghi TAR
  TA0CCR1 = 15000; //Thoi gian lay mau Timer
  
  __bis_SR_register(LPM0_bits + GIE);
}

// interrup port 1.3
#pragma vector = PORT1_VECTOR
__interrupt void port1_isr(void)
{
  if((P1IFG & BUTTON_MENU) == BUTTON_MENU)
  {
    WDTCTL = WDT_MDLY_0_5;
    IE1 |= WDTIE;                       // Enable WDT interrupt
    P1IFG clr BUTTON_MENU;
    return;
  }
  if((P1IFG & PW_LOSS) == PW_LOSS) //Power down interrupt
  {
    if( !((P1OUT&RELAY_1) | (P1OUT&RELAY_2) | (P1OUT&RELAY_3) | (P1OUT&RELAY_4)) )
    {P1IFG clr PW_LOSS;
    P1OUT set LED_RED;
    LastState = 0x00;
    Flash_Write_Byte(SegmentD, LastState, 20);
    return;}
    else
    {
      P1OUT set LED_RED;
      LastState = P1OUT;
      Flash_Write_Byte(SegmentD, LastState, 20); //Save to SegmentD
    }
    P1IFG clr PW_LOSS;
    return;
  }
  if(TAR>13000) //Filter
  {
    TAR = 0;
    TA0CCTL1 = CCIE; //Enable Timer interrupt
    BitCounter = 0;
  }
  else if(BitCounter < 100) //Limit the pulse
  {
    Buffer[BitCounter] = TAR;
    TAR = 0;
    BitCounter++;
  }
  P1IFG clr RF_RECEIVE_PORT; //Clear Interrupt Flag
  P1IFG clr BUTTON_MENU;
  P1IFG clr PW_LOSS;
}

//timer interrupt
#pragma vector=WDT_VECTOR  
__interrupt void watchdog_timer(void)
{
  if(!(P1IN & BUTTON_MENU))
  {
    TACounter++;
    if(TACounter == 2000) //Stop Setting manual port
    {
      Blink_Led(1, LED_RED);
      Setting_Button = 0;
      Scene = RUNNING;
    }
    if(TACounter == 5000) //Start Setting Mode
    {
      Blink_Led(2, LED_RED);
      Scene = SETTING;
    }
    else if(TACounter > 10000) //Clear command memory
    {
      Blink_Led(5, LED_RED);
      TACounter = 0;
      for(int i = 0; i < 6; i++)
      {
        Command[i] = 0;
      }
      P1OUT clr (LED_RED + RELAY_1 + RELAY_2 + RELAY_3 + RELAY_4);
      Flash_Clear_All(SegmentD);
      Scene = RUNNING;
      IE1 clr WDTIE;
      WDTCTL = WDTPW + WDTHOLD;
    }
  }
  else {TACounter = 0; IE1 clr WDTIE; WDTCTL = WDTPW + WDTHOLD; }
}

//timer interrupt
#pragma vector=TIMER0_A1_VECTOR
__interrupt void Timer0_A1(void)
{
  unsigned int average, max = 0, min = 1000;
  
  //Start processing
  P1IE clr RF_RECEIVE_PORT;
  TA0CCTL1 clr CCIE;
  //Check frame correctly
  if(BitCounter < 24 || BitCounter > 32) {P1IE set RF_RECEIVE_PORT; return;}
  //====Valid -> Process====
  for(i = 1; i < BitCounter; i++) //Find Max pulse and Min pulse
  {
    if(Buffer[i] > max) max = Buffer[i];
    if(Buffer[i] < min) min = Buffer[i];
  }
  
  if(Buffer[0] < max) {P1IE set RF_RECEIVE_PORT; return;} //Invalid Frame
  
  average = (max + min) / 2;
  
  RFCode = 0;
  for(i = 0; i < BitCounter; i++) //Store RF code to variable
  {
    RFCode <<= 1;
    if(Buffer[i] > average) RFCode++;
  }
  //Now, RF code is store in RFCode variable
  //----------------------------------------
    if(Scene == RUNNING) //Running
  {
    if(Command[0] == RFCode) P1OUT tgl RELAY_1;
    if(Command[1] == RFCode) P1OUT tgl RELAY_2;
    if(Command[2] == RFCode) P1OUT tgl RELAY_3;
    if(Command[3] == RFCode) P1OUT tgl RELAY_4;
  }
  else if(Scene == SETTING && Setting_Button >= 0) //Setting
  {
    Command[Setting_Button] = RFCode; //Set RFCode to Command

    for(i=0; i<4; i++) //Save RFCode to Flash (Segment D)
    {
      Byte_read = RFCode >> i*8;
      Flash_Write_Byte(SegmentD, Byte_read, i + Setting_Button*4);
    }

    if(++Setting_Button > 3) {Scene = RUNNING; Setting_Button = 0;} //If all set, Start RUNNING
  }

  __delay_cycles(500000); //Debound the button on remote
  //========================
  P1IE set RF_RECEIVE_PORT;
}

void Blink_Led(unsigned int solan, unsigned char Port)
{
  for(int a = 0; a < solan; a++)
  {
    P1OUT set Port;
    __delay_cycles(100000);
    P1OUT clr Port;
    __delay_cycles(200000);
  }
}

Tải về toàn bộ project

Project RF315MHz - MSP430