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
}

 


參考資料


8 則留言:

  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顆亮!!這樣的話要怎麼修改!!謝謝你

      刪除