2012年11月14日 星期三

8 顆 LED 霹靂燈

說明

這個實驗是使用 Microchip APP-EDF11-1 開發板完成一個 8 顆 LED 的霹靂燈。
8 顆 LED 的霹靂燈

 

電路圖

貼出此次實驗在 APP-EDF11-1 開發板用到的相關電路。

OSC 電路

板上放了一顆 12MHz 的石英晶體振盪器。
clip_image001

MCLR Reset 電路

當 BT1 按下去,/MCLR 接地會讓 MCU Reset。
clip_image002

LED 電路

由 8 顆綠色的 LED 搭配限流電阻接到地,MCU 控制 LED 的陽極,所以 MCU 只要對 RD 任一腳位送 1,都會讓對應的 LED 發亮。
clip_image003

程式碼

目前有 7 種特效,分別為「左右來回」、「向左」、「向右」、「向內再向外 」、「數字累加及遞減」、「向左對齊」、「向右對齊 」等模式。
編譯環境:
  • MPLAB X IDE v1.30
  • C18 v3.40
完整專案檔下載:Pili_LED.zip (6 KB)
檔案:main.c
主程式,從狀態 1~7 循環切換,可額外設定每個功能跑的次數及每個狀態延遲的時間。
#include "main.h"
#include "ConfigurationBits.h"

#define DEMO_FUNS    7       // 功能數量
#define DEMO_COUNT   6       // 每個功能跑的次數
#define DEMO_DELAY   50      // 每個狀態延遲時間

unsigned char fun = 1, count = 0;
unsigned char dir = 0, n = 0;

void main(void)
{
    InitIO();
    
    while (1) {
        switch (fun) {
            case 1:        Pili_1();    break;
            case 2:        Pili_2(0);   break;
            case 3:        Pili_2(1);   break;
            case 4:        Pili_3();    break;
            case 5:        Pili_4();    break;
            case 6:        Pili_5(0);   break;
            case 7:        Pili_5(1);   break;
        }
        
        // Next demo function
        if (count >= DEMO_COUNT) {
            if (++fun > DEMO_FUNS) {
                fun = 1;
            }
            ResetState();
        }
    }
}

PIC18F67J50 若有啟動 PLL, 在執行前必須等待致少 2ms 時間 初始設定 PORTD 全部設為輸出,點亮 bit0 的 LED。
void InitIO(void)
{
    // On the PIC18F87J50 Family of USB microcontrollers, the PLL will not power up and be enabled
    // by default, even if a PLL enabled oscillator configuration is selected (such as HS+PLL).
    {
        int pll_startup_counter = 27000;    // 27000 x 0.083us ~= 2.241 ms
        OSCTUNEbits.PLLEN = 1;  //Enable the PLL and wait 2+ms until the PLL locks before enabling USB module
        while(pll_startup_counter--);
    }

    LATD = 0x01;
    TRISD = 0x00;        // Initializee all PORTD(LED) as input pin
    
    RCONbits.IPEN = 0;
    INTCONbits.GIEH = 0;
    INTCONbits.GIEL = 0;
}

當切換到下一個功能時,重設變數
void ResetState(void)
{
    count = 0;
    dir = 0;
    n = 0;
}

特效功能函數
// 左右來回
void Pili_1(void) 
{
    if (n == 0) {
        LATD = (dir ? 0x80 : 0x01);
        //DelayMs(DEMO_DELAY);
    } else {
        (dir == 0) ? (LATD <<= 1) : (LATD >>= 1);
    }
        
    DelayMs(DEMO_DELAY);
    
    if (++n == 8) {
        if (dir == 1) count++;
        dir ^= 1;
        n = 0;
    }
}

// 向左 或 向右
void Pili_2(unsigned char dir) 
{
    if (n == 0) {
        LATD = (dir ? 0x80 : 0x01);
    } else {
        (dir == 0) ? (LATD <<= 1) : (LATD >>= 1);
    }
    
    DelayMs(DEMO_DELAY);
    
    if (++n == 8) {
        count++;
        n = 0;
    }
}

// 向內再向外
void Pili_3(void) 
{
    if (n == 0) {
        LATD = (dir ? 0x18 : 0x81);
    } else {
        if (dir == 0)
            LATD = ((PORTD & 0xF0) >> 1) | ((PORTD & 0x0F) << 1);
        else
            LATD = ((PORTD & 0xF0) << 1) | ((PORTD & 0x0F) >> 1);
    }
    
    DelayMs(DEMO_DELAY);
    
    if ((++n % 4) == 0) {
        dir ^= 1;
        if (n == 8) {
            count++;
            n = 0;
        }
    }
}

// 數字累加及遞減
// 2012-11-14 修正數字遞減 Demo 跳過的問題
void Pili_4(void) 
{
    if (n == 0) {
        LATD = 0x01;
        n++;
    } else {
        (dir == 0) ? (LATD++) : (LATD--);
    }
        
    DelayMs(DEMO_DELAY);
    
    Bingo(LATD);
    
    if (LATD == 0x00 || LATD == 0xFF) {
        dir ^= 1;
        if (LATD == 0) {
            count += DEMO_COUNT;
            n = 0;
        }
    }
}

// 向左或向右對齊
void Pili_5(unsigned char dir)
{
    static unsigned char data = 0x00, temp, round = 0;
    if (n == 0) {
        temp = (dir ? 0x80 : 0x01);
    } else {
        (dir == 0) ? (temp <<= 1) : (temp >>= 1);
    }
        
    LATD = (data | temp);
    DelayMs(DEMO_DELAY);
    n++;
    
    if (round + n == 8) {
        data |= temp;
        round++;
        n = 0;
    }
    
    Bingo(LATD);
    
    if (LATD == 0xFF) {
        count += DEMO_COUNT;
        data = 0x00;
        round = n = 0;
    }
}

某些特效累積到 0xFF 或遞減到 0x00 則呼叫此函數
void Bingo(unsigned char value)
{
    int i;
    
    switch (value) {
        case 0x00:
            DelayMs(DEMO_DELAY);
            DelayMs(DEMO_DELAY);
            break;
        
        case 0xFF:
            for (i = 0; i < 3; i++) {
                DelayMs(DEMO_DELAY);
                DelayMs(DEMO_DELAY);
                LATD = 0x00;
                DelayMs(DEMO_DELAY);
                DelayMs(DEMO_DELAY);
                LATD = 0xFF;
            }
            break;
    }
}

時間延遲 (單位:ms)
// Delay ? ms
void DelayMs(unsigned int ms)
{
    unsigned int i;
    for (i = 0; i < ms; i++)
        Delay1KTCYx(12);    // 12 x 0.083us = ~ 1 ms
}

 


參考資料







12 則留言:

  1. 2012-11-14 修正數字遞減 Demo 跳過的問題

    回覆刪除
  2. 請問可以把這程式編譯成18f4520用的嗎?

    回覆刪除
  3. 如果只是單純的學習用途都可以, 這是C語言,調整一下應該就可以用了, 如:Configuration Bits 設定

    回覆刪除
  4. 那請問要怎麼改可以講明確一點嗎目前我只知道HS

    回覆刪除
    回覆
    1. 因為不知道你的振盪器是多少, 我手邊也沒有此顆 IC, 在這裏假設你是使用 MCU 內部的 8MHz 高速 OSC, 不使用 PLL (PLL 依你的需求, 可將 clock 拉到 8MHz x 4 = 32 MHz)。
      因為 OSC 已改成 8MHz, 所以一個指令週期變成 4 / 8MHz = 0.5us, 請依底下修改

      =====[ ConfigurationBits.h ]=====
      將 ConfigurationBits.h 的設定換成底下內容 (相關設定請參考 C18 的 doc\hlpPIC18ConfigSet.chm 文件)
      #pragma config OSC = INTIO67 // Internal oscillator block, port function on RA6 and RA7
      #pragma config BOREN = OFF // Brown-out Reset disabled in hardware and software
      #pragma config WDT = OFF // WDT disabled (control is placed on the SWDTEN bit)
      #pragma config MCLRE = ON // MCLR pin enabled; RE3 input pin disabled

      =====[ main.c ]=====
      函式 InitIO 內的第一個大括號程式碼, 以底下置換掉
      OSCCON = 0x01110011; // INTOSC 8 MHz as system clock
      OSCTUNEbits.PLLEN = 0; // PLL disabled

      函式 DelayMs 的 Delay 改成底下
      Delay1KTCYx(2); // 2k x 0.5us = ~ 1 ms


      ~~~祝你成功~~~

      刪除
  5. 請問如果只要讓八顆LED閃爍的話如何寫會比較迅速方便?? 謝謝!!

    回覆刪除
    回覆
    1. hi, 你好
      我的做法會直接呼叫 Bingo(0xFF)

      刪除
    2. for(;;) /* main event loop */
      {

      if(led_index == 0x03)
      led_index = 0x20;
      else
      led_index = led_index << 1 ;
      led_index = !led_index;
      outputByte(led_index); //LED狀態
      outputControl(0x20); //LATCH
      outputControl(0x0);

      _delay_ms(500);

      }
      return 0;

      我的主要程式是這個!! 但是有一個題目是說要交替亮與暗變成是4顆暗4顆亮!!這樣的話要怎麼修改!!謝謝你

      刪除
  6. 完整專案檔下載:Pili_LED.zip (6 KB)無法下載,是否願意分享,謝謝!!! kevin.122759@yahoo.com.tw

    回覆刪除
    回覆
    1. Hi le kevin, 連結已更新了, 可以下載了

      刪除
  7. #include
    #include

    請問main.h中的這兩個.h檔該從哪裡取得呢?

    謝謝

    回覆刪除