วันจันทร์ที่ 23 กรกฎาคม พ.ศ. 2561

ไมโครคอนโทรลเลอร์ 1

DIY - สวิทช์ควบคุมไฟหัวเตียงด้วยไมโครคอนโทรลเลอร์

      ติดตั้งไฟหัวเตียงสำหรับอ่านหนังสือเป็นแผงหลอดแอลอีซึ่งใช้ไฟ 12 โวลต์ 360 มิลลิแอมป์ หรือ 4.3 วัตต์  2 ข้างๆ ละแผง ไฟกลางคืน 12 โวลต์ 220 มิลลิแอมป์ หรือ 2.6 วัตต์ แต่มีวัสดุลดแสงคลุมไว้เพื่อเปลี่ยนสีให้เป็นเหลืองด้วย  แต่เดิมทีผมใช้สวิทช์เลื่อนถูกๆ ธรรมดาทำให้เกิดปัญหาการคลอน แสงไฟจะไม่นิ่ง มีการกระพริบ (flickering effect)  ทำให้ไม่สบายตาอย่างมาก

    แนวทางที่น่าเลือกมี 2 อย่าง คือ เป็นวงจรดิจิตอลอิเล็กทรอนิกส์ หรือ ใช้ MCU (ไมโครคอนโทรลเลอร์ควบคุม) จึงตัดสินใจเลือกใช้ MCU เพราะจะถูกกว่า ขนาดเล็กกว่า และดัดแปลงวงจรง่ายๆ ด้วยโปรแกรม

คุณสมบัติของผลิตภัณฑ์

   -  ควบคุมหลอดไฟฟ้าที่แรงดันสูงสุดสูงสุด 12 โวลต์ กระแสสูงสุด 0.8  แอมป์ กำลังสูงสุด 10 วัตต์ ต่อชุด
   -  ทำงานด้วยสวิทช์เพียง 2 ตัว  
        -  ตัวแรกเป็นตัววนเลือกหลอดไฟ (Select) และตั้งเวลาไฟก่อนนอน (Sleep) 
        -  อีกตัวเอาไว้ปิดไฟในทุกกรณี
      - ควบคุมไฟสว่าง 3 จุด โดยที่ 1 จุดเป็นไฟ

ก่อนนอนสามารถตั้งเวลาไว้ 1 ชั่วโมง หลอดไฟจะวูบสว่างขึ้นและวูบดับ (fade in - fade out) ไม่กระโชกเหมือนเปิดปกติ แต่ละจุดรับแรงดันสูงถึง 12 โวลต์ (สูงได้ถึง 24 โวลต์แต่กระแสสูงสุดจะแปรผันลดลง)  และกระแสสูงสุด 0.8 แอมป์ (10 วัตต์)  

       หมายเหตุ ถ้าต้องการควบคุมกำลังไฟฟ้ามากกว่านี้หรือใช้แรงดันไฟบ้านได้ ให้เปลี่ยนหลอดไฟเป็นรีเลย์ 12 โวลต์แทน (มี  fast recovery diode ต่อ reversr bias คร่อมขาคอยล์ด้วยนะ) ยกเว้นจุดไฟก่อนนอนห้ามเปลี่ยนเพราะมันมีส่วนทำงานแบบ pwm อยู่
     - เมื่อเข้าในโหมดก่อนนอน จะมีหลอดไฟมอนิเตอร์สีแดงสว่างขึ้น (Sleep minitoring) ให้รู้ว่าอยู่ในโหมดตั้งเวลา
     - มีภาค watchdag จะหน้าที่ตั้งระบบในตัวเอง เมื่อเกิดความผิดพลาดในโปรแกรม (แฮงก์จ

การทำงาน ประกอบด้วย 2 ปุ่ม คือ 
         1.  ปุ่ม Select/Sleep  
    - เมื่อกดแต่ละครั้ง หลอดไฟก็จะเปิดวนในลักษณะ หลอด 1  --- >  หลอด 2 --- >  หลอด1 และ หลอด 2  --- >  ไฟก่อนนอน --- >   ดับหมด
    - เมื่อกดแช่นาน ประมาณ 0.3 วินาที จะเข้าโหมด Sleep หลอดไฟ 1และ 2 จะดับ หลอดไฟก่อนนอนเฟดสว่างขึ้นจนเต็มที่ และสว่างนาน 1 ชั่วโมงจากนั้นจะค่อยวูบดับลง ระหว่างนี้จะไม่สามารถกดสวิทช์เลือกไฟได้อีก ยกเว้นกดอีกปุ่ม (Off) ซึ่งทำหน้าที่ดับไฟ

         2.   ปุ่ม Off
    - เอาไว้ดับหลอดไฟ ไม่ว่าจะอยู่โหมดไหน กดปุมนี้จะดับหมด

อุปกรณ์สำคัญ
     MCU ที่ผมเลือกใช้นั้น เป็น PIC เบอร์  12F509 จากบริษัทไมโครชิพ  เนื่องจากมีขนาดเล็กแค่ 8 ขา ง่ายต่อการโปรแกรม ไม่ต้องคอนฟิกมาก เนื่องจากมีแค่ไม่กี่รีจิสเตอร์ ที่สำคัญคือ ราคาถูกและทนทานสูง  โดยที่ 12F509 นั้นมีหน่วยความจำเก็บโปรแกรม 1 กิโลไบต์ มีRAM 41 ไบต์  Digital I/O 6 ขา มีวงจรสร้างสัญญาณนาฬิกาในตัว 4 MHz  แต่ความเร็วทำงานต้องหาร 4 เพราะโครงสร้างแบบ pipeline ตามสถาปัตยกรรมแบบฮาเวิร์ด (RISC)  นั่นคือเหลือ 1 ล้านคำสั่งต่อวินาที ถึงต่อคริสตอลข้างนอกก็เพิ่มความถี่ไม่ได้มากกว่านี้  ไม่มีลูกเล่นใดๆ เช่น พอร์ทอนุกรม  PWM  EEPROM  A/D Comparator  หรือแม้แต่อินเตอร์รัพท์  มีไทม์เมอร์รีจีสเตอร์ 8 บิทแค่ตัวเดียว  มันข้นแค้นจนคุณไม่อยากเชื่อว่ามีคอนโทรลเลอร์แบบนี้มีอยู่ในโลก แต่เพราะการไม่มีอะไรมันเลยเรียบง่าย และมีความเชื่อถือได้สูง ผมจะพยายามใช้มันให้เต็มความสามารถเพื่อให้คุ้มกับเงินมากที่สุด


     หลอดไฟหัวเตียงนั้นผมใช้ของ ROHM รุ่น LBF1048-45DXB จากญี่ปุ่น ต่อกับตัวต้านทาน 2 โอห์ม 3 วัตต์ (1 วัตต์ก็เหลือเฟือแล้ว เพราะกำลังแทบทั้งหมดจะถูกส่งไปที่หลอด)   ให้แสงประมาณ 600 ลูเมนส์ ถือว่าเพียงพอ  (อย่าลิมว่ามันมีมุมสว่างเพียง 120 องศา 1/4 ของหลอดกลมหรือ CFL ทั่วไป ดังนั้นที่พื้นที่เท่ากันมันจะสว่างกว่า 4 เท่าเมื่อเทียบกับหลอดกลมที่ค่าลูเมนส์เท่ากัน)  


     ส่วนไฟนอนหลับนั้นเป็นของ Dominant  รุ่น NPW-RSZ-TU-1 ต่ออนุกรม 3 ดวงอนุกรมกับตัวต้านทาน 12 โอห์ม บนแผงสำเร็จ จริงๆ  แล้วหาหลอด 12 โวลต์ 2-3 วัตต์อะไรก็ได้ อย่างไรก็ตามเรื่องหลอดไฟผมคงไม่เน้นในกระทู้นี้  


วงจรและข้อมูลทั่วไป


การทำงานของวงจร 
          การทำงานนี้ไม่มีอะไร  มี 3 ส่วนหลัก
   1. ส่วนแหล่งจ่ายไฟของวงจร ผมใช้ ไอซี7805 ในการลดแรงดัน 12 โวลต์จากอะแด้ปเตอร์ข้างนอก (อันนี้ไปหาเอาเอง กระแสที่จ่ายต่ำสุดไม่น้อยกว่า 1 แอมป์)  ป้อนพลังงานเข้าบอร์ดควบคุม ถ้าใช้แบบสวิทชิ่งก็จะดีตรงที่ไฟตกเหลือแค่ 100 โวลต์มันก็ยังทำงานปกติ

    2. ส่วนรับอินพุทของ MCU เป็น TACT สวิทช์กดติดปล่อยดับทั่วไป  ต่อกับตัวต้านทาน weak pull up ขนาด 2 กิโลโอห์ม 0.25 วัตต์ จริงๆ ใน MCU ก็มี Weak pull up resistors แต่มันไม่เวิร์ค สู้สัญญาณรบกวนไม่ได้ และตัวโปรแกรมที่ให้มาก็เปิดใช้อยู่

   3. ส่วนควบคุมขาออกของ MCU เพื่อจะไปเปิด-ปิดหลอดไฟ  โดยใช้ทรานซิสเตอร์ 2SD882 เป็นตัวขับกำลังให้แต่ละหลอด และมีตัวต้านทาน 200 โอห์ม  0.25 วัตต์ก็พอเป็นตัวไบอัสขาเบส เพื่อไม่ให้โหลดกระแสซอร์สของ MCU มากเกินไป  อีกจุดหนึ่งคือไฟมอนิเตอร์โหมดไฟก่อนนอน ที่ใช้ตัวต้านทาน 200 โอห์ม 0.25 วัตต์ อนุกรมไว้

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

        อีกจุดหนึ่งคือหลอดแอลอีดีแสดง Power On จะต่อกับอินพุท 12 โวลต์เพื่อโชว์ว่ามีไฟเข้ามาในวงจรหรือไม่ ตัวนี้อนุกรมด้วยตัวต้านทาน 910 โอห์ม (ใช้ 1 กิโลโอห์มก็ได้ แต่อนนั้นผมหาไม่เจอ) 0.25 วัตต์

     หลอด Power On กับ Sleep Monitor นั้น ผมใช้หลอด 2 สีในตัวถังเดียวกัน เพื่อประหยัดการต่อวงจรและ ใช้การมองที่จุดเดียว

      ส่วนแผ่นวงจรผมใช้แบบสำเร็จรูปตัดแต่งลายทางไฟฟ้าตามที่ออกแบบมา  รูปยังไม่ได้ตัดลายเส้นทองแดง
  

โปรแกรมการทำงาน

#include <htc.h>
#include <pic.h>
#define _XTAL_FREQ  4000000     
// int reset, no code protect, watchdog, 4MHz internal clock
__CONFIG(MCLREN & UNPROTECT & WDTEN & INTRC);
void main()
{
    unsigned char   sGPIO;          // GPIO Shadow register
    unsigned char   db_cnt;         // debounce counter
    unsigned char   Lamp;           // Lamp sequence on
    unsigned char   Selected;       // Lamp sequence on
    unsigned char   Dimmer;       
    unsigned char   DimPWM;       
    unsigned char   DimOff;       
    unsigned char   Sel_cnt;       // Check between Lamp or Sleep

unsigned        int    dly;           // Lamp sequence on
    // Initialisation
    OPTION = ~GPPU;                 // enable weak pull-ups
    OPTION = PSA | 0b111;
    GPIO = 0;                       // All LED off
    sGPIO = 0;                      //   update shadow register
    Lamp = 0;
    Selected =1;
    Sel_cnt = 0;
    dly = 0;
    Dimmer = 0;
    DimPWM = 0;
    DimOff = 0;
    TRIS = 0b001100;                // configure GP541 (only) as an output
  // Main loop
    for (;;) {
        // wait until button pressed (GP2 low), debounce by counting:
        for (db_cnt = 0; db_cnt <= 10; db_cnt++) {
            __delay_ms(1);          // sample every 1 ms
            if (GP2 == 1)           // if button up (GP2 high)
            db_cnt = 0;             //   restart count
        }                           // until button down for 10 successive reads

// wait until button released (GP2 high), debounce by counting:
        for (db_cnt = 0; db_cnt <= 10; db_cnt++) {
            __delay_ms(1);          // sample every 1 ms
            if (GP2 == 0) {          // if button down (GP2 low)
            Sel_cnt = Sel_cnt + 1;
            if (Sel_cnt > 250) {
            Selected = 2; Sel_cnt = 254; Lamp = 5;
for (Dimmer == 0 ; Dimmer < 184 ; Dimmer++) {
           DimPWM = Dimmer;       
                 sGPIO =0b001101;
                 GPIO = sGPIO;               // write to GPIO 
          for (DimPWM = DimPWM; DimPWM < 184; DimPWM++) {
                __delay_us(15);          // sample every 1 ms    
              }
           DimPWM = 185 - Dimmer;
                 sGPIO =0b001111;
                 GPIO = sGPIO;               // write to GPIO
for (DimPWM = DimPWM; DimPWM < 184; DimPWM++) {
                __delay_us(15);          // sample every 1 ms    
                   } 
              } 
        }  
            db_cnt = 0;             //   restart count
            }
        }                           // until button up for 10 successive reads

// toggle LED on GP1
        Sel_cnt = 0;
        if (Selected == 1) {
        Lamp = Lamp + 1;
            if (Lamp == 1)
                {sGPIO =0b011100;}
            if (Lamp == 2)                 
                {sGPIO =0b101100;}            
            if (Lamp == 3) 
                {sGPIO =0b111100;}    
            if (Lamp == 4) 
                {sGPIO =0b001110;}        
            if (Lamp > 4) 
                {Lamp = 0; sGPIO =0b001100;}
        Dimmer = 0;
        GPIO = sGPIO;               // write to GPIO
CLRWDT();
        }
        if (Selected == 2) {
        CLRWDT(); 
         for (dly = 0; dly <= 36000; dly++) {
            __delay_ms(100);          // sample every0 100 ms    
            CLRWDT();    
        }    

for (Dimmer == 0 ; Dimmer < 254 ; Dimmer++) {
           DimPWM = Dimmer;       
                 sGPIO =0b00111;
                 GPIO = sGPIO;               // write to GPIO 
          for (DimPWM = DimPWM; DimPWM < 254; DimPWM++) {
                __delay_us(50);          // sample every 1 ms    
              }
DimPWM = 255 - Dimmer;
                 sGPIO =0b00101;
                 GPIO = sGPIO;               // write to GPIO
           for (DimPWM = DimPWM; DimPWM < 254; DimPWM++) {
                __delay_us(50);          // sample every 1 ms    
                   } 
            CLRWDT();
              }
sGPIO =0b001101;
                GPIO = sGPIO;               // write to GPIO
        Selected = 1;    
        SLEEP();        
        }
    }   // Always loop
}

ไม่มีความคิดเห็น:

แสดงความคิดเห็น