周囲が暗くなると光り始めるLEDマーカーは、トランジスタやICを使った発振回路とフォトトランジスタを組み合わせることで簡単に作れる。
しかし、マイコンを使うと、暗くなったら1分間だけ光ってから消えるとか、消える前に次第に点滅間隔が短くなっていくといった細かい制御ができるようになる。
ここでは、PICマイコンを使った、ちょっと賢いLEDマーカーを紹介する。
マイコン Microchip PIC12F1822
ICソケット 8ピン用
カーボン抵抗器 1/4W 150Ω(茶緑茶金)、100kΩ(茶黒黄金)、0Ω(黒・ジャンパ線として使用)
積層セラミックコンデンサ 0.1uF (104)
LED Φ5mm、Vf1.9〜3V程度のもの
ユニバーサル基板 Sunhayato ICB-91
または
矢島製作所 片面ユニバーサル基板(ブレッドボード配線パターンタイプ)
Dタイプ(47x36mm) ガラスコンポジット AE-DB1
フォトトランジスタ NJL7502L
電池ボックス 単3×3本用 バッテリースナップタイプ
バッテリースナップ
スペーサ、皿ネジ類
Rev.2→
[0]電源ON
↓
[1]STNDBY状態
LED消灯
(暗くなったら[2]へ)
↓
[2]TIMER状態
LED点滅(だんだん点滅間隔が短くなる)
(1分経過後[3]へ)(明るくなったら[1]へ↑)
↓
[3]TIMEOUT状態
LED消灯
(明るくなったら[1]へ↑)
※MPLAB X IDEとPIC kit3を使ったマイコンへのプログラム書き込み方法は、how2usepickit3.pdfを参照。
/*
* File: led-marker-timer-12f1822.c
* Author: kaimu
*
* Created on May 1, 2016, 2:33 PM
*/
/*
* LED1 : PIN 7 (RA0) : 1-ON, 0-off
* ANALOG PORT : PIN 3 (AN3)
*
*/
#include <xc.h>
#include <stdint.h>
enum STATUS {ST_STANDBY , ST_TIMER, ST_TIMEOUT} Status;
#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) {
uint8_t adc_value; // 明るさを表す数値
initIO(); // I/Oポートの初期化
initAdc8(); // A/Dコンバータの初期化
initTimer0(); // タイマの初期化
Status = ST_STANDBY; // 状態はSTANBY状態に設定
T0count = 0; // 時計をリセット
while (1) {
switch (Status) { // 状態Statusに応じて切り替え
case ST_STANDBY : // STANDBY 状態
adc_value = getAdc8(); // A/Dコンバータで明るさを検出
if (adc_value < 220) { // 明るいときは LED消灯
ledOff();
} else {
Status = ST_TIMER; // 暗いときはTIMER状態へ移行
T0count = 0;
}
break;
case ST_TIMER : // TIMER状態
led();
wait(185000L - T0count * 100L); // 点滅間隔が徐々に短くなる
adc_value = getAdc8(); // 明るさをチェック
if (adc_value < 220) { // 明るいときはLEDを消灯しSTANDBY状態へ
ledOff();
Status = ST_STANDBY;
}
if (T0count > TIMER0_1SEC * 60) { // 60秒経過したら
Status = ST_TIMEOUT; // TIMEOUT状態へ
}
break;
case ST_TIMEOUT : // TIMEOUT 状態
ledOff(); // LED消灯
adc_value = getAdc8(); // 明るさをチェック
if (adc_value < 220) { // 明るいときはLEDを消灯しSTANDBY状態へ
Status = ST_STANDBY;
}
break;
default : // 異常なStatus値の場合はSTANDBY状態へ
Status = ST_STANDBY;
}
}
return;
}