[BC17-04] マイコン・センサ・ライト

暗くなると一定時間だけLEDが点灯する賢いライトです。

使用部品

ブレッドボード

PICマイコン PIC12F1822P

カーボン抵抗器 150Ω (茶緑茶金)、100kΩ(茶黒黄金)

LED

バッテリスナップ

電池ボックス(単3×3本用)

回路図

回路図

実体配線図

PICkit3によるマイコンへのプログラム書き込みのための配線

完成品

breadboard

ファームウェア

最初のファームウェア

ファイル名:sensor_light_12f1822.c

XC8 Compiler用

/*
 * LED1 : PIN 7 (RA0) : 1-ON, 0-off
 * 
 * 
 * ANALOG PORT : PIN 3 (AN3) 
 *
 */
#include <xc.h>
#include <stdint.h>
#define ledOn()    (RA0 = 1)
#define ledOff()   (RA0 = 0)
#define led()      (RA0 ^= 1) // LEDを点滅する
// Configuration 1
#pragma config FOSC     = INTOSC   // Internal Clock
#pragma config WDTE     = OFF      // NO Watchdog timer
#pragma config PWRTE    = ON       // Program start at Power on after 64ms
#pragma config MCLRE    = OFF      // No Ext Reset, Enable RA3 input pin
#pragma config CP       = OFF      // No Code protect
#pragma config CPD      = OFF      // No Data Protect
#pragma config BOREN    = ON       // Brown out enable
#pragma config CLKOUTEN = OFF      // CLKOUT as RA4
#pragma config IESO     = OFF      // No Internal External clock
#pragma config FCMEN    = OFF      // No FCM
// Configuration 2
#pragma config WRT    = OFF        // No Write Protect
#pragma config PLLEN  = OFF        // No PLL
#pragma config STVREN = ON         // Reset on Stack over / under flow
#pragma config BORV   = HI         // Watch Voltage drop (2.5V = HI)
#pragma config LVP    = OFF        // No Low Voltage Programming
void wait(volatile uint32_t i)
{
    while (i-- > 0);
}
void initIO(void)
// I/Oポートの初期化
{
     OSCCON     = 0b01110010 ;   // Internal clock 8MHz
     OPTION_REG = 0b00010000 ;   // Weak Pull up Resistor RA4-OFF, others ON
     ANSELA     = 0b00010000 ;   // Analog PORT AN3(RA4)
     TRISA      = 0b00011000 ;   // Input : RA34,    Output: others
     WPUA       = 0b00001000 ;   // Weak pullup : RA3
     PORTA      = 0b00000000 ;   // Initialize PORTA
}
void initAdc8(void)
// A/Dコンバータの初期化
{
    ANSELA = 0b00010000;         //RA4 Analog port, others digital port
    ADCON0 = 0b00001101;    //0:unimp, 00011:AN3, 0:GOnDone, 1:ADC enable
    ADCON1 = 0b01000000;    //0:Left jutified (8bit res.), 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
    CM1CON0 = 0x00;     //Comparator disable
}
uint8_t getAdc8(void)
// 精度8bitでA/D変換
{
    uint8_t d;
    //ADC
    wait(10);
    GO_nDONE = 1;
    while (GO_nDONE);
    d = ADRESH;
    return d;
}
void initTimer0(void)
// タイマの初期化
{
    OPTION_REG &= 0b11111000; // Clear Prescale parameter
    OPTION_REG |= 0b00000111; // Prescaler 1:256
    
    TMR0 = 0; // initialize Timer0
    TMR0IF = 0; // Timer0 interrupt enable
    TMR0IE = 1; // Enable Timer0 Interrupt
    GIE = 1; // Enable Interrupt
}
/*
 * 1 interrupt 
 *   => 1/8 * 4 (instruction exec clock) * 256(prescaler) * 256 = 32768 us ,
 * 1 sec = 1 / 32768e-6 = 30.517 counts   
 */
static volatile unsigned int T0count;
#define TIMER0_1SEC    30
void interrupt InterFunction( void )
// 割り込み関数
{
    // Timer0 Interrupt
    if (TMR0IF == 1) { // Timer0割り込みが発生したとき
        TMR0 = 0;
        T0count++;
        TMR0IF = 0;
    }
}
void main(void) {
    
    int i;
    uint8_t adc_value; // 明るさを表す数値
    
    initIO(); // I/Oポートの初期化
    initAdc8(); // A/Dコンバータの初期化
    initTimer0(); // Timer0の初期化
    // LEDが3回点滅
    for (i = 0; i < 6; i++) {
        led();
        wait(10000);
    }
    ledOff();
    
    while (1) {
        adc_value = getAdc8(); // A/Dコンバータで明るさを検出
        if (adc_value < 220) { // 明るいときは LED消灯
            ledOff();
        } else {
            // 暗いときは60秒間点灯する
            for (T0count = 0 ; T0count < TIMER0_1SEC * 60;  ) {
                ledOn();            
            }
            // 明るくなるまでLEDを消灯して待つ
            while (adc_value >= 220) {
                ledOff();
                adc_value = getAdc8(); // A/Dコンバータで明るさを検出
            }
        }
    }
}

発展したファームウェア

ヘッダファイル: sensor_light.h

/*
 *  sensor light configuration header file
 * 
 * KAIMU 2017/07/09
 * 
 */
#define FIRST_LED_BLINK_COUNT 3  // 最初にLEDが点滅する回数
#define TIMER_SECOND 5         // 暗くなってからLEDが点灯し、消えるまでの時間(秒数)
#define SENSOR_PARAMETER 220 //明るさセンサの感度 数値が大きいほど明るくても反応しやすくなる
#define LED_PWM 5 // LEDの暗く/明るくなる速度 (5~500)
#define BUZ_LENGTH 500 // ブザーのなる長さ
#define BUZ_TONE 50 // ブザーの音の高さ

ソースファイル: led-timer-12f1822.c

/*
 * File:   led-marker-timer-12f1822.c
 * Author: kaimu
 *
 * Created on Jul 9, 2017
 */
/*
 * LED1 : PIN 7 (RA0) : 1-ON, 0-off
 * 
 * Buzzer : PIN 6 (RA1)
 * 
 * ANALOG PORT : PIN 3 (AN3) 
 *
 */
#include <xc.h>
#include <stdint.h>
#include "sensor_light.h"
enum STATUS {ST_STANDBY , ST_TIMER, ST_TIMEOUT} Status; 
#define ledOn()    (RA0 = 1)
#define ledOff()   (RA0 = 0)
#define led()      (RA0 ^= 1) // LEDを点滅する
#define buz()      (RA1 ^= 1) // Buzzerの鳴動
// Configuration 1
#pragma config FOSC     = INTOSC   // Internal Clock
#pragma config WDTE     = OFF      // NO Watchdog timer
#pragma config PWRTE    = ON       // Program start at Power on after 64ms
#pragma config MCLRE    = OFF      // No Ext Reset, Enable RA3 input pin
#pragma config CP       = OFF      // No Code protect
#pragma config CPD      = OFF      // No Data Protect
#pragma config BOREN    = ON       // Brown out enable
#pragma config CLKOUTEN = OFF      // CLKOUT as RA4
#pragma config IESO     = OFF      // No Internal External clock
#pragma config FCMEN    = OFF      // No FCM
// Configuration 2
#pragma config WRT    = OFF        // No Write Protect
#pragma config PLLEN  = OFF        // No PLL
#pragma config STVREN = ON         // Reset on Stack over / under flow
#pragma config BORV   = HI         // Watch Voltage drop (2.5V = HI)
#pragma config LVP    = OFF        // No Low Voltage Programming
void wait(volatile uint32_t i)
{
    while (i-- > 0);
}
void initIO(void)
// I/Oポートの初期化
{
     OSCCON     = 0b01110010 ;   // Internal clock 8MHz
     OPTION_REG = 0b00010000 ;   // Weak Pull up Resistor RA4-OFF, others ON
     ANSELA     = 0b00010000 ;   // Analog PORT AN3(RA4)
     TRISA      = 0b00011000 ;   // Input : RA34,    Output: others
     WPUA       = 0b00001000 ;   // Weak pullup : RA3
     PORTA      = 0b00000000 ;   // Initialize PORTA
}
void initAdc8(void)
// A/Dコンバータの初期化
{
    ANSELA = 0b00010000;         //RA4 Analog port, others digital port
    ADCON0 = 0b00001101;    //0:unimp, 00011:AN3, 0:GOnDone, 1:ADC enable
    ADCON1 = 0b01000000;    //0:Left jutified (8bit res.), 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
    CM1CON0 = 0x00;     //Comparator disable
}
uint8_t getAdc8(void)
// 精度8bitでA/D変換
{
    uint8_t d;
    //ADC
    wait(10);
    GO_nDONE = 1;
    while (GO_nDONE);
    d = ADRESH;
    return d;
}
void initTimer0(void)
// タイマの初期化
{
    OPTION_REG &= 0b11111000; // Clear Prescale parameter
    OPTION_REG |= 0b00000111; // Prescaler 1:256
    
    TMR0 = 0; // initialize Timer0
    TMR0IF = 0; // Timer0 interrupt enable
    TMR0IE = 1; // Enable Timer0 Interrupt
    GIE = 1; // Enable Interrupt
}
/*
 * 1 interrupt 
 *   => 1/8 * 4 (instruction exec clock) * 256(prescaler) * 256 = 32768 us ,
 * 1 sec = 1 / 32768e-6 = 30.517 counts   
 */
static volatile unsigned int T0count;
#define TIMER0_1SEC    30
void interrupt InterFunction( void )
// 割り込み関数
{
    // Timer0 Interrupt
    if (TMR0IF == 1) { // Timer0割り込みが発生したとき
        TMR0 = 0;
        T0count++;
        TMR0IF = 0;
    }
}
void buzzer(int length) {
    int i;
    for (i = 0; i < length; i++) {
        buz();
        wait(BUZ_TONE);
    }
}
void main(void) {
    
    int i;
    uint8_t adc_value; // 明るさを表す数値
    
    initIO(); // I/Oポートの初期化
    initAdc8(); // A/Dコンバータの初期化
    initTimer0(); // タイマの初期化
  
    Status = ST_STANDBY; // 状態はSTANBY状態に設定
    T0count = 0; // 時計をリセット
    
    buzzer(100); //ブザを鳴らす
    
    // 電源投入直後、最初にLEDを点滅
    for (i = 0 ; i < FIRST_LED_BLINK_COUNT; i++) {
        led();
        wait(20000L);
        led();
        wait(20000L);
    }
    ledOff(); 
    
    while (1) {
        switch (Status) { // 状態Statusに応じて切り替え
            case ST_STANDBY : // STANDBY 状態
                adc_value = getAdc8(); // A/Dコンバータで明るさを検出
                if (adc_value < SENSOR_PARAMETER) { // 明るいときは LED消灯
                    ledOff();
                }  else {
                    buzzer(BUZ_LENGTH); // ブザを鳴らす
                    Status = ST_TIMER; // 暗いときはTIMER状態へ移行
                    T0count = 0;
                }
                break;
            case ST_TIMER : // TIMER状態
                for (i = 0; i < 1000; i += LED_PWM) { // LEDが徐々に暗くなる
                    ledOn();
                    wait(1000 - i); // LED点灯時間が1000→990→980→…→20→10と短くなる
                    ledOff();
                    wait(i); // LED消灯時間が0→10→20→…→980→990と長くなる
                }
                for (i = 0; i < 1000; i += LED_PWM) { // LEDが徐々に明るくなる
                    ledOff();
                    wait(1000 - i); // LED消灯時間が1000→990→980→…→20→10と短くなる
                    ledOn();
                    wait(i); // LED点灯時間が0→10→20→…→980→990と長くなる
                }
                adc_value = getAdc8(); // 明るさをチェック
                if (adc_value < SENSOR_PARAMETER) { // 明るいときはLEDを消灯しSTANDBY状態へ
                    ledOff();
                    Status = ST_STANDBY;
                }
                if (T0count > TIMER0_1SEC * TIMER_SECOND) { // TIMER_SECOND 秒経過したら
                    Status = ST_TIMEOUT; // TIMEOUT状態へ
                }
                break;
            case ST_TIMEOUT : // TIMEOUT 状態
                ledOff(); // LED消灯
                adc_value = getAdc8(); // 明るさをチェック
                if (adc_value < SENSOR_PARAMETER) { // 明るいときはLEDを消灯しSTANDBY状態へ
                    Status = ST_STANDBY;
                }
                break;
            default : // 異常なStatus値の場合はSTANDBY状態へ
                Status = ST_STANDBY;
        }
    }
    return;
}