[BC19-01] LEDキャンドル

ブレッドボードチャレンジ2019-01 [BC19-01]LEDキャンドル

マイコン1個にLED1個という、これ以上簡単なものは考えられない最小限の構成。

LEDがロウソクのようにゆらゆらっと光る

電池を入れると8時間光って16時間消える周期で繰り返す。

BC19-01の解説用PDF

00-bc19-01-candletimer-12f1822.pdf

部品

ミニブレッドボード BB-601(白)[BB-601(White)]

PICマイコンPIC12F1822-I/P [PIC12F1822-I/P]

5mmウォームホワイト・キャンドル色LED OSM2DK5111A-UV (5個入)[OSM2DK5111A-UV]

(VFが2.9V程度のものなら、どんなLEDでも良い)

電池ボックス 単3×2本 Bスナップ・背中合わせ [BH-322-1B]

バッテリースナップ(電池スナップ・Bスナップ) 縦型 カバー付 [SBS-IR-1/150mm]

ブレッドボードとパターン互換のユニバーサル基板を小さく切ったものを使うと回路が小型化できて、LaQに組み込むことも可能。

(ユニバーサル基板で作るときに追加する部品)

片面ユニバーサル基板(ブレッドボード配線パターンタイプ) Dタイプ(47x36mm) ガラスコンポジット [AE-DB1]

ICソケット ( 8P) (10個入)[2227-08-03]

ピンソケット(メス) 1x4(4P) [FH-1x4SG/RH]

ピンソケット(メス) 1x2(2P)[FH-1x2SG/RH]

回路図

ファームウェア(ソースコード)

XC8 Compiler対応(文字Code :UTF-8)

/*
 * File:   ledcandle_12f1822.c
 * Author: kaimu
 *
 * Created on April 13, 2019, 5:48 PM
 */

/*
 * Output
 *  CCP1 (RA2) [PIN5] : LED
 */

#include <xc.h>
#include <stdint.h>

////// ここから、プログラミングのためのデータや関数を定義する /////


#pragma config FOSC     = INTOSC   // 内部クロック使用。
#pragma config WDTE     = OFF      // ウォッチドッグタイマなし。
#pragma config PWRTE    = ON       // 64ms後にプログラム開始。
#pragma config MCLRE    = OFF      // 外部リセットなし。RA3は入力ピン。
#pragma config CP       = OFF      // コード保護なし。
#pragma config CPD      = OFF      // データ保護なし。
#pragma config BOREN    = ON       // 電源電圧低下時のリセットあり。
#pragma config CLKOUTEN = OFF      // クロック出力不可。
#pragma config IESO     = OFF      // 内部外部クロックなし。
#pragma config FCMEN    = OFF      // FCMなし。


// 動作設定その2
// Configuration 2
#pragma config WRT    = OFF        // 書き込み保護なし。
#pragma config PLLEN  = OFF        // PLLなし。
#pragma config STVREN = ON         // スタックオーバー/アンダーフローでリセット。
#pragma config BORV   = LO         // 電源電圧低下監視閾値はLowモード
#pragma config LVP    = OFF        // 低電圧プログラムなし。


// LED点滅設定
#define LED_BLINK_PERIOD_MIN 50 // LEDが点滅する周期の最小値(20-100)
#define TIME_LIMIT 50

// I/Oポートの定義 (LEDを接続するポートが変わった時はここを変更する)
#define PORT_LED_1 RA2
#define TRISA_LED_1 TRISA2

#define ledOn() (PORT_LED_1 = 1)
#define ledOff() (PORT_LED_1 = 0)
#define led() (PORT_LED_1 ^= 1)

void wait(volatile uint32_t t)
// Delay
{
    while (t-- > 0) NOP();
}

void initIo(void) {
    //OSCCON = 0b01111010; // PLL disable, 16MHz internal clock
    // OSCCON = 0b01100010; // PLL disable, 8MHz internal clock
    OSCCON = 0b01101010; // PLL disable, 4MHz internal clock
    //OSCCON = 0b01011010; // PLL disable, 1MHz internal clock
    //OSCCON = 0b00111010; // PLL disable, 500kHz internal clock
    INTEDG = 0; // Interrupt on falling edge of RB0/INT pin
    INTE = 1; // External Interrupt Enable
    GIE = 1; //Interrupt Enable
    ANSELA = 0b00000000; //ALL digital port
    CM1CON0 = 0x00; //Comparator disable
    TRISA = 0b00001001; //I/O Direction. RA1-2,4-5 : output, RA0,3 : Input
    LATA = 0b00000000; // PORTA Latch Settings
}

void initPwm(void) {
    //Timer2 settings for PWM standard mode
    PR2 = 0; // PWM Period = [(PR2) +1 ]*4*(1/FOSC)*(Timer2 Prescale value)
    T2CON = 0b00000010; //00 = Prescaler is 1, 01 = Prescaler is 4,
    // 10 = Prescaler is 16,  11 = Prescaler is 64

    APFCON &= ~(1 << CCP1SEL); //CCP1 function is on RA2
    //CCP1SEL = 1;//CCP1 function is on RA5
    CCP1CON = 0b00001100; //PWM mode: P1A, P1C active-high; P1B, P1D active-high
    CCPR1L = 64; // PWM Duty Cycle (CCPR1L:CCP1CON<5:4>)*(1/FOSC)*(TMR2 Prescale Value)
    //Start PWM
    TMR2 = 0;
    TMR2ON = 1;
}

void stopPwm(void) {
    CCP1ASE = 1;
    TMR2ON = 0;
}

void startPwm(void) {
    CCP1ASE = 0;
    TMR2ON = 1;
}

void pwmPulseWidth(uint8_t value) {
    CCPR1L = value;
}

volatile uint32_t TimerCounter; // Counter of Timer Interrupt
#define T0UNIT 15UL // TimerCounter at 1 sec.

void initTimer0(void)
//Initialize Timer 0
// count up every 256*256us = 65536us = 65.536ms (clock 4/4=1MHz, prescaler 1:256
// if you want t[s] timer, TimerCount <= t / 0.065536
{
    TMR0IF = 0; // interrupt flag clear
    TimerCounter = 0; // Timer Interrupt Counter clear
    OPTION_REG = 0b11010111; // Timer0 Internal clock, Prescaler 1:256
    // Timer0 Interrupt occured every 65.536ms
    TMR0IE = 1; // enable Timer0 interrupt
    GIE = 1; // enable interrupt
}

void __interrupt() intr(void)
// Interrupt processing function
{
    if (INTF == 1) {
        INTF = 0;
    }
    if (TMR0IF == 1) {
        TMR0IF = 0; //Clear TMR0 Interrupt flag
        TimerCounter++;
    }

}

void initialize(void) {
    initIo();
    initPwm();
    initTimer0();
}

void ledoff(void) {
    ledOff();
}

void ledon(void) {
    ledOn();
}

void waittimeout(uint32_t timeLimit) {
    uint32_t timeLimitCount = timeLimit * T0UNIT; // 時間切れまでのカウント数
    TimerCounter = 0; // タイマのリセット。計時開始。
    timeLimitCount = T0UNIT * timeLimit;
    while (TimerCounter < timeLimitCount) {
        //制限時間になるまでの処理
    }
}

void starttimer0() {
    TimerCounter = 0; // タイマのリセット。計時開始。
}

int8_t istimeout0(uint32_t timeLimit)
//指定時間に達していなければ、0xffを返し、指定時間に達していたら0x0を返す。
{
    uint8_t retvalue;
    if (TimerCounter < T0UNIT * timeLimit) {
        retvalue = 0xff;
    } else {
        retvalue = 0x00;
    }
    return retvalue;
}

////// ここまで、プログラミングのためのデータや関数を定義する /////

////// この後のmain(void) { から }までの間に、プログラムが書ける。 /////

void main(void) {
    uint8_t pulsewidtharray[] = {0x40, 0x28, 0x3f, 0x1f, 0x2a, 0x30, 0x40, 0x38, 0x30, 0x3a, 0x2f, 0x30}; // pwm Pulse width array
    uint8_t npwa = 12; // number of pwm pulsewidth array
    uint8_t pwaindex = 1; // pulse width array index
    uint8_t pulsewidth; // current pulsewidth
    uint32_t ledontime = 28800; // 点灯時間28800sec.(8h)
    uint32_t ledofftime = 57600; //  消灯時間5sec.(16h)


    initialize(); //システムの初期化
    stopPwm();
    ledoff(); //LEDを消す


    while (1) { //無限ループ。次の}までの間を無限回繰り返す。

        starttimer0(); // タイマを開始
        startPwm();

        PR2 = 50;

        while (istimeout0(ledontime)) {
            pulsewidth = pulsewidtharray[pwaindex];
            for (uint8_t i = pulsewidth / 8; i < pulsewidth; i++) {
                pwmPulseWidth(i);
                wait(2000);
            }
            for (uint8_t i = pulsewidth; i > pulsewidth / 8; i--) {
                pwmPulseWidth(i);
                wait(2000);
            }

            if (pwaindex > 0) {
                pwaindex--;
            } else {
                pwaindex = npwa - 1;
            }

        }

        //消灯時間の間LEDを消灯する
        stopPwm();
        ledoff();
        starttimer0();
        while (istimeout0(ledofftime));

    }
}

////// この上の } より上にプログラムが書ける。 /////