Thông báo

Collapse
No announcement yet.

Điều khiển từ xa toàn tập

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Điều khiển từ xa toàn tập

    Nửa đêm đang ngủ ngon phải bò dậy tắt quạt vì lạnh. Bật quạt mãi mà không chạy do nút bấm bị kẹt. Sáng dậy thấy điện vẫn sáng do tối qua ngủ quên không tắt điện.... Đó là những tình huống khó chịu mà ta gặp phải trong cuộc sống hàng ngày.
    Tất cả các lý do trên khiến mình phải bỏ ra 2 tuần để chế ra 1 bộ điều khiển từ xa. Sử dụng vi điều khiển 89C2051 cộng với cái điều khiển TV SONY vứt đi là đã có 1 bộ điều khiển từ xa như ý. Chạy 2 năm nay mà chưa có hỏng hóc gì.
    Ta đi sâu vào điều khiển cái quạt bàn.
    Chức năng của quạt bàn ta thường thấy gồm có:
    - On/Off
    - Hẹn giờ (30', 1h, 2h, 4h)
    - Đổi tốc độ (Số 1, số 2, số 3)
    - Gió liu riu (Nature Wind)

  • #2
    Đây là mạch in đã chạy thử được 3 năm. Hiện vẫn đang chạy thử tiếp. Nếu 10 năm nữa kô vấn đề gì là ok. (chắc lúc đó công nghệ đạt đến mức chỉ nghĩ đến "gió" thôi là quạt đã bật rồi )



    Comment


    • #3
      Điều khiển từ xa phát ra các bit 0 va 1. Tuy nhiên nó không thể đưa lên LED hồng ngoại và phát trực tiếp các bit này được (không phát đi xa được). Vì vậy nó cần phải có 1 sóng mang với tần số khoảng 36KHz (giống như trong Radio ấy).



      Để làm được bộ phát như trên có 2 cách:
      - Tạo ra 1 tần số 36 KHz ổn định làm sóng mang (Dùng NE555)
      (36KHz) AND (Bit 0,1) = Output_Signal
      - Cách 2 đơn giản hơn. Ra chợ mua 1 cái đk về dùng

      Bộ thu là 1 con IC 3 chân(VCC--GND--OUTPUT). Nó có nhiệm vụ nhận tín hiệu hồng ngoại yếu ớt từ đk phát ra, khuyêch đại tín hiệu, tách sóng mang để lọc ra những bít 0 và 1.



      Mỗi 1 lần phát, đk sẽ phát đi 1 chuỗi các bít 0 và 1. IC nhận cũng sẽ nhận đúng số lượng và đúng thứ tự các bit này.



      Sau khi nhân được chuỗi các bit, nhiệm vụ của người lập trình là giải mã chuỗi bit này.
      Mỗi loại đktx sẽ tuân theo 1 chuẩn mã khác nhau (RC5 là 1 chuẩn phổ biến).
      Trong chuỗi bit đó người ta sẽ phân ra làm 2 phần:
      - phần 1 là địa chỉ để phân biệt các thiết bị khác nhau(cùng là hãng SONY nhưng đktx của TV không làm ảnh hưởng đến đầu DVD chẳng hạn)
      - phần 2 là phần lệnh (lúc này sẽ chỉ rõ lệnh phát ra là gì khi ta ấn nút trên đk)



      Cuối cùng dựa vào lệnh đã nhận. Ta chỉ việc sử dụng thôi. Ví dụ ấn nút số 1 trên đktx thì sẽ nhận được số 1, ta bật cái quạt. Ấn số 2 ta nhận đc số 2, ta bật cái bóng điện v.v..

      Comment


      • #4
        Đây là chuẩn SIRC mà đktx SONY sử dụng (ở đây mình sử dụng bộ mã 12 bits)




        Comment


        • #5
          Phần cứng đã xong, kiến thức đã đủ. Bây giờ là ngồi vào máy tính và lâp trình thôi.

          Công việc đầu tiên của lập trình là làm sao để thu được 12 bit mà đktx đã phát đi. Chân OUTPUT của con IR receiver nối với chân ngắt ngoài INT0 của 89C2051.
          Khi có ngăt ngoài xảy ra (tức là đã có tín hiệu phát ra từ bộ đktx) chương trình sẽ dừng các việc đang làm và nhảy vào trình phục vụ ngắt.
          Chương trình ngắt sẽ làm gì?
          - Việc đầu tiên khi nhảy vào ngắt là chờ cho bit START về 0
          - Đọc bít ngay sau đó
          - Lưu vào vị trí bit đầu tiên của 2 byte (2 byte nằm trong 1 biến: int receiver
          - Dịch bít này sang trái 1 lần
          - Đọc bít tiếp theo......
          - Nhận đủ 12 bit
          - Lọc ra 7 bit đầu để lấy ra lệnh (tức là đktx vừa bấm nút nào?)
          - Tra trong bảng lệnh để thực hiện 1 công việc nào đó

          Comment


          • #6
            Đây là đoạn chương trình ngắt INT0

            Comment


            • #7
              Tiếp về điều khiển từ xa nào.
              Hôm nay post tiếp cho anh em mạch và code
              Trong mạch sử dụng các linh kiện chính sau:
              Vi điều khiển 89C2051
              Cách ly quang MOC3020 (3,5k/con)
              Triac MAC97A6 đóng mở dòng điện cho các cuộn dây
              Còn những linh kiện khác anh em chắc nhìn quen rồi



              Mạch này làm xong, hàn linh kiện, nạp code cho chip là chạy liền
              Code và mạch sẽ gửi sau

              Comment


              • #8
                Anh em nếu làm thì chú ý khi hàn con MAC97A6, nhớ hàn theo đúng chân MT1 và MT2. Trước tôi tưởng 2 chân này như nhau, nhưng hàn đảo đầu đi thì bị cháy.
                Ngoài ra, nếu cẩn thận hơn, giữa chân MT1 và MT2 anh em nên làm thêm cái dập xung cho cuộn dây.
                Mắc (tụ nối tiếp trở) // MT1 và MT2
                Tụ gốm 103 2KV
                Trở 2W 390 ôm

                Comment


                • #9
                  Còn đây là code

                  //*****************************
                  // for Sony remote only

                  //*****************************

                  #include <AT89x051.H>
                  //#include <intrins.H>

                  #define pow P3_1 // in
                  #define speed P3_0 // in
                  #define timer P3_3 // in
                  #define nature P3_4 // in

                  #define power_IR 212 // IR receiver
                  #define speed_IR 142 // IR receiver
                  #define timer_IR 210 // IR receiver
                  #define nature_IR 244 // IR receiver

                  #define speed3 P1_0 //out triac
                  #define speed2 P1_1 //out triac
                  #define speed1 P1_2 //out triac

                  #define timer1 P1_4 //timer out led
                  #define timer2 P1_5 //timer out led
                  #define timer3 P1_6 //timer out led
                  #define timer4 P1_7 //timer out led

                  #define alarm P1_3 //loa chip out

                  unsigned char tocdo,hengio,kt_hengio,power;
                  unsigned char tick,wind,anti_vib,enable_IR;
                  unsigned int tick1,tick2,current_time,wind_time,time_off;
                  unsigned char rev_IR,save_rev;



                  void chip() //tao am thanh 2KHz
                  {
                  unsigned int i,m;
                  for(m=0;m<250;m++)
                  {
                  alarm=0;
                  for(i=0;i<20;i++)
                  {;}
                  alarm=1;
                  for(i=0;i<20;i++)
                  {;}
                  }
                  }



                  void timer1_ISR (void) interrupt 3
                  {
                  tick1++; tick2++; //100 us
                  }



                  void external_ISR (void) interrupt 0
                  {
                  tick2=0;
                  rev_IR = 0x01;
                  bit_1:
                  if(rev_IR >= 128) {save_rev = rev_IR; goto end_rev;}
                  while((P3_2 == 0)&&(tick2<250)) {;}
                  bit_0:
                  if(rev_IR >= 128) {save_rev = rev_IR; goto end_rev;}
                  while((P3_2 == 1)&&(tick2<250)) {;}
                  tick1=0;
                  while(tick1<7) {;}
                  if(P3_2 == 0) {rev_IR <<= 1; rev_IR |= 0x01; goto bit_1;}
                  if(P3_2 == 1) {rev_IR <<= 1; rev_IR |= 0x00; goto bit_0;}
                  end_rev:
                  //tick1=0;
                  //while(tick1<70) {;}
                  //_nop_();
                  EX0=0; //chi lay 7 bit lenh, bo qua 5 bit dia chi
                  }


                  void timer0_ISR (void) interrupt 1
                  {
                  // with xtal 12.000MHz
                  // 3CAF(15535) - 50ms
                  // D8EF(55535) - 10ms

                  // with xtal 11.0592 MHz
                  // DC05 - 10ms
                  // FC17(64535) - 1ms
                  // FE0B(65035) - 0.5ms
                  // FF37(65335) - 0.2ms

                  TH0 = 0xDC;
                  TL0 = 0x05;
                  tick++;
                  anti_vib++;
                  enable_IR++;
                  if (tick >= 100) // 1 sec
                  {
                  current_time++;
                  wind_time++;
                  tick = 0;
                  }
                  }


                  void main (void)
                  {//-------------------------

                  // init system
                  TMOD = 0x21; // (TMOD: 0010 0001) Timer_1 8 bits auto reload. Timer_0 16 bits
                  TH1 = 255-100;
                  TL1 = TH1;
                  ET0 = 1; // Enable Timer 0 Interrupt
                  ET1 = 1; // Enable Timer 1 Interrupt
                  // EX0 = 1; // Enable External 0 Interrupt
                  EA = 1; // Global Interrupt Enable
                  PT1 = 1; // Priority timer_1
                  TR0 = 1; // Start Timer 0
                  TR1 = 1; // Start timer 1
                  P1 = 0x00; // set P1 lam dau ra
                  P3 = 0xff; // set P3 lam dau vao

                  save_rev=0xff;
                  //enable_IR=0;

                  // main loop
                  while(1)
                  {//*
                  kt_hengio=0;
                  hengio=0;
                  wind=0;
                  power=0;
                  tocdo=1;
                  speed1=speed2=speed3=1;
                  timer1=timer2=timer3=timer4=1;
                  alarm=0;
                  EX0 = 1; // Enable External 0 Interrupt

                  //********** ENABLE IR INTERRUPT AGAIN *************
                  // while(enable_IR > 100)
                  // { EX0=1; enable_IR=0; }
                  //**************************************************



                  //**************** POWER ON ************************
                  if((!pow) || (save_rev==power_IR)) // nut on/off duoc an lan dau
                  {
                  chip();
                  speed1=0; // speed1 is defauled
                  power++;
                  while(!pow) {;}
                  anti_vib=0;
                  while(anti_vib<20)
                  {;}
                  save_rev=0xff;
                  EX0=1;
                  }
                  //*************************************************



                  //**************************************************
                  //**************************************************
                  while(power)
                  {//**



                  //******************* POWER OFF ************************
                  if((!pow) || (save_rev==power_IR)) // nut on/off duoc an lan tiep theo
                  {
                  chip();
                  chip();
                  chip();
                  power--;
                  while(!pow) {;} //anti vibration contact
                  anti_vib=0;
                  while(anti_vib<20)
                  {;}
                  save_rev=0xff;
                  EX0=1;

                  }
                  //**************************************************



                  //******************** SPEED ************************
                  if((!speed) || (save_rev==speed_IR)) // button speed
                  {///***
                  chip();
                  tocdo++;
                  if(tocdo > 3)
                  { tocdo=1;}
                  dungimi:switch(tocdo)
                  {////
                  case 1: speed1=0; speed2=1; speed3=1;
                  break;
                  case 2: speed1=1; speed2=0; speed3=1;
                  break;
                  case 3: speed1=1; speed2=1; speed3=0;
                  break;
                  }////
                  while(!speed) {;}
                  anti_vib=0;
                  while(anti_vib<20)
                  {;}
                  save_rev=0xff;
                  EX0=1;

                  }///***
                  //**************************************************



                  //********** ENABLE IR INTERRUPT AGAIN *************
                  while(enable_IR > 100)
                  { EX0=1; enable_IR=0; }
                  //**************************************************




                  //****************** CHECK TIMER *******************
                  if(kt_hengio == 1)
                  {
                  if(current_time > time_off)
                  { chip(); chip(); chip(); power--; goto off; }
                  }
                  //**************************************************




                  //******************* TIMER ************************
                  if((!timer) || (save_rev==timer_IR)) //timer function
                  {
                  chip();
                  kt_hengio=1;
                  current_time=0;
                  hengio++;
                  if(hengio > 4)
                  { hengio=0; }

                  switch(hengio)
                  {
                  case 0: kt_hengio=0;
                  timer1=1; timer2=1; timer3=1; timer4=1; break;
                  case 1: time_off=1800; // 30 minutes
                  timer1=0; timer2=1; timer3=1; timer4=1; break;
                  case 2: time_off=3600; // 1 hour
                  timer1=1; timer2=0; timer3=1; timer4=1; break;
                  case 3: time_off=7200; // 2 hours
                  timer1=1; timer2=1; timer3=0; timer4=1; break;
                  case 4: time_off=14400; // 4 hours
                  timer1=1; timer2=1; timer3=1; timer4=0; break;
                  }

                  while(!timer) {;}
                  anti_vib=0;
                  while(anti_vib<20)
                  {;}
                  save_rev=0xff;
                  EX0=1;

                  }
                  //************************************************** **




                  //******************** NATURE ************************
                  if((!nature) || (save_rev==nature_IR)) // nature wind function
                  {
                  chip();
                  wind++;
                  if(wind>1)
                  {
                  wind=0;
                  goto dungimi; // return speed after turn-off nature wind function
                  }
                  while(!nature) {;}
                  anti_vib=0;
                  while(anti_vib<20)
                  {;}
                  save_rev=0xff;
                  EX0=1;

                  }
                  //**************************************************




                  //**************************************************
                  if(wind) // if nature wind function is turned-on
                  {
                  switch(tocdo)
                  {
                  case 1: if(wind_time>5)
                  {speed1 =~ speed1; wind_time=0;}
                  break;
                  case 2: if(wind_time>10)
                  { speed2 =1;
                  anti_vib=0;
                  while(anti_vib<5)
                  {;}
                  speed1=0;
                  wind_time=0;}
                  if(wind_time>7)
                  { anti_vib=0;
                  while(anti_vib<5)
                  {;}
                  speed2=0;}
                  if(wind_time>3)
                  { anti_vib=0;
                  while(anti_vib<5)
                  {;}
                  speed1=1;}
                  break;

                  case 3: if( wind_time>10)
                  { speed3 =1;
                  speed1 =1;
                  anti_vib=0;
                  while(anti_vib<5)
                  {;}
                  speed2 =0; //chuyen sang so 2
                  wind_time=0;

                  }
                  if(wind_time>7)
                  { speed3 =1;
                  speed2 =1;
                  anti_vib=0;
                  while(anti_vib<5)
                  {;}
                  speed1=0; //chuyen sang so 1
                  goto exit;
                  }
                  if(wind_time>3)
                  { speed1 =1;
                  speed2 =1;
                  anti_vib=0;
                  while(anti_vib<5)
                  {;}
                  speed3 =0; //chuyen sang so 3
                  }
                  exit: break;

                  }
                  }
                  //**************************************************


                  }//**

                  //**************************************************
                  //**************************************************


                  off:
                  alarm=0;

                  }//* end while()

                  }//------------------end

                  Comment


                  • #10
                    Đây là mạch dùng điện 220VAC (không cần biến áp). Có switch gạt để đặt địa chỉ cho thiết bị

                    Comment


                    • #11
                      Đây là mạch vẽ bằng Protel99SE

                      http://www.mediafire.com/?nnynyyn4thz

                      -------------------------------------------------------------------

                      Đây là mạch vẽ bằng Protel DXP

                      http://www.mediafire.com/?zde5n2jn0od

                      Comment


                      • #12
                        Đây là code viết bằng KeilC

                        http://www.mediafire.com/file/gzknqy...emote Sony.rar

                        Comment


                        • #13
                          thank bạn nhiều! Đang ngâm cú về dktx dùng hồng ngoại này. Trước giờ mình chỉ làm dùng cặp IC 48/49. Bạn cho mình hỏi: mấy cái mã code của cái remote sony ở trên là chỉ dành cho dktc của sony phải không bạn? Mình có cái remote bất kỳ có thể dùng dc không?

                          Comment


                          • #14
                            Có nhiều mã code dành cho đktx. Mỗi một hãng hay một nhóm các hãng điện tử sẽ dùng 1 loại mã nào đó. Vì thế khi sử dụng đktx loại nào thì phải tra trên mạng về mã của loại đó. Sau đó thay đổi lại các mã được định nghĩa (#define) ở trên đầu của đoạn code

                            Cách khác để tra mã của 1 loại đktx nào đó là dùng oscilloscope để soi.

                            Comment


                            • #15
                              Giải thích thêm về đoạn chương trình ngắt để giải mã code

                              Trước hết xem lại phần frame timing



                              Khi truyền, đktx sẽ phát ra các bit có frame timing như sau
                              - bit START gồm 4T mức "1", mỗi T là 600uS
                              - bit 0 gồm 2T: 1T mức "0" và 1T mức "1"
                              - bit 1 gồm 3T: 1T mức "0" và 2T mức "1"

                              Khi nhận, mắt nhận hồng ngoại sẽ đảo dấu các bit. Nguyên nhân của việc phải đảu dấu là vì: chân OUT của mắt nhận nối với chân ngắt ngoài INT0 của vđk. Do vậy, khi bit START được phát ra (mức 1) thì vđk sẽ nhận được mức 0 (mức 0 là mức tác động của ngắt ngoài) báo cho vđk biết để bắt đầu quá trình giải mã. Frame timing như sau



                              - bit START gồm 4T mức "0", mỗi T là 600uS
                              - bit 0 gồm 2T: 1T mức "1" và 1T mức "0"
                              - bit 1 gồm 3T: 1T mức "1" và 2T mức "0"

                              Dựa vào frame timing nhận, ta có thể tiến hành lấy mẫu chân P3_2 để xác định được đâu là bit 0 và đâu là bit 1 (từ đây ta chỉ quan tâm đến frame timing nhận thôi)

                              Chú ý rằng dù bit "0" hay bit "1" thì đều có 1T ở đầu là mức "1". ta tạm gọi 1T đặc biệt này là "X"

                              tick2=0; while(tick2<250) {;} // là tạo ra 1 trễ, mỗi khi hết 100uS thì tick1 và tick2 tăng lên 1 (xem đoạn gắt timer1). Như vậy đoạn này tạo ra (100*250 uS)


                              ------------------------------------------------------------------------------------
                              void external_ISR (void) interrupt 0
                              {
                              tick2=0; //bắt đầu tính trễ
                              rev_IR = 0x01; // rev_IR = 000 0001 giá trị khởi tạo ban đầu cho rev_IR


                              bit_1:
                              if(rev_IR >= 128) {save_rev = rev_IR; goto end_rev;} // Nếu đã nhận đủ 7 bit thì thoát
                              while( (P3_2 == 0)&&(tick2<250)) {;}
                              // Chờ cho hết bit START (P3_2 về "1"). Nếu vì lý do nào đó, P3_2 không về "1" thì sau (100*250)uS sẽ thoát, nếu không chương trình sẽ bị treo ở đây.


                              bit_0:
                              if(rev_IR >= 128) {save_rev = rev_IR; goto end_rev;} // Nếu đã nhận đủ 7 bit thì thoát
                              while( (P3_2 == 1)&&(tick2<250)) {;}
                              // Chờ cho "X" về "0" và bắt đầu lấy mẫu ở chân P3_2 (đọc bit)


                              tick1=0;
                              while(tick1<7) {;} //tạo trễ 700uS
                              if(P3_2 == 0) {rev_IR <<= 1; rev_IR |= 0x01; goto bit_1;} // bit_x = 1

                              //Nếu chân P3_2 = 0 tức là nhận được bit "1". Nếu nhận được bit 1, ta phải chờ cho P3_2 về "1" rồi chờ tiếp cho P3_2 về "0" rồi mới đọc bit tiếp theo, chính vì thế mới "goto bit_1" (xem ảnh dưới)


                              if(P3_2 == 1) {rev_IR <<= 1; rev_IR |= 0x00; goto bit_0;} // bit_x = 0

                              //Nếu chân P3_2 = 1 tức là nhận được bit "0". Nếu nhận được bit 0, ta chỉ phải chờ cho P3_2 về "0" rồi mới đọc bit tiếp theo, chính vì thế mới "goto bit_0" (xem ảnh dưới)




                              /*
                              | MSB LSB |
                              --------------------------------------------------
                              rev_IR = 0 0 0 0 0 0 0 1
                              rev_IR = 0 0 0 0 0 0 1 bit1
                              rev_IR = 0 0 0 0 0 1 bit1 bit2
                              rev_IR = 0 0 0 0 1 bit1 bit2 bit3
                              rev_IR = 0 0 0 1 bit1 bit2 bit3 bit4
                              rev_IR = 0 0 1 bit1 bit2 bit3 bit4 bit5
                              rev_IR = 0 1 bit1 bit2 bit3 bit4 bit5 bit6
                              rev_IR = 1 bit1 bit2 bit3 bit4 bit5 bit6 bit7 (rev_IR >= 128 ; stop INT0 va thoat)
                              */

                              end_rev:
                              EX0=0; //chi lay 7 bit command, bo qua 5 bit address
                              }
                              Last edited by dungimi43; 16-04-2010, 14:31.

                              Comment

                              Về tác giả

                              Collapse

                              dungimi43 Tìm hiểu thêm về dungimi43

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X