3色LEDマーカー2019
周囲が暗くなると、LEDが点滅する回路を、100円均一ショップで買ったプラスチックケースに入れてみた。
使用部品
使用部品
・PICマイコン PIC12F1822-I/P
・ICソケット 8PIN
・LED φ5mm 3個
・カーボン抵抗器 51Ω 3個、100kΩ
・フォトトランジスタ NJL7502L
・積層セラミックコンデンサ 0.1uF
・ユニバーサル基板 AE-DB1 片面ユニバーサル基板(ブレッドボード配線パターンタイプ) Dタイプ(47×36mm) ガラスコンポジット
・電池ボックス(単3形×1本用リード線付)2個
・ワイドクリアケース(2段) 直径73mmx高さ72mm
・配線材
回路図
基板部品配置パタン(例)
ファームウェア
ファームウェア
(XC8 ソースコード)
/*
* File: led-marker-2019.c
* Author: kaimu
*
* Created on September 22, 2019, 5:57 PM
*/
/*
* Input
* RA4/AN3 (PIN2) : photo transistor, bright:0, dark:1
* Output
* RA0 [PIN7] : LED0 , active Low
* RA1 [PIN6] : LED1 , active Low
* RA2 [PIN5] : LED2 , active Low
*/
#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 // 低電圧プログラムなし。
// I/Oポートの定義 (LEDを接続するポートが変わった時はここを変更する)
#define PORT_LED_0 RA0
#define TRISA_LED_0 TRISA0
#define PORT_LED_1 RA1
#define TRISA_LED_1 TRISA1
#define PORT_LED_2 RA2
#define TRISA_LED_2 TRISA2
// A/D変換用I/Oポートの設定定義
#define PORT_ADC ANSA4
#define TRISA_ADC TRISA4
#define PORT_NO_ADC 3
#define led0on() (PORT_LED_0 = 0)
#define led0off() (PORT_LED_0 = 1)
#define led0() (PORT_LED_0 ^= 1)
#define led1on() (PORT_LED_1 = 0)
#define led1off() (PORT_LED_1 = 1)
#define led1() (PORT_LED_1 ^= 1)
#define led2on() (PORT_LED_2 = 0)
#define led2off() (PORT_LED_2 = 1)
#define led2() (PORT_LED_2 ^= 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 = 0b00001000; //I/O Direction. RA0-2,4-5 : output, RA3 : Input
//OPTION_REGbits.nWPUEN = 1; //// weak pull-up disable
//WPUA = 0b00000000; // weak pull-up disable
OPTION_REGbits.nWPUEN = 0; //// weak pull-up enable
WPUA = 0b00001000; // weak pull-up 3 enable
LATA = 0b00000000; // PORTA Latch Settings
}
// A/D変換関数
void initAdc(void) {
PORT_ADC = 1; // PORT_ADCで定義されたポートをアナログポートにする。
TRISA_ADC = 1; // A/D変換端子を入力モードにする。
ADCON0 = 0b00000001 | (PORT_NO_ADC << 2); //AD変換を有効化。
ADCON1 = 0b01000000; // 0:(ADFM=0)精度10bit, 100:Fosc/4 ,0:Reserved, 00:AVDD=VREF
CM1CON0 = 0x00; //コンパレータを無効化。
}
uint16_t getAdc(void)
// A/D変換した値を得る。
// 戻り値: A/D 変換されたアナログ信号の大きさ(0〜1023)
{
uint16_t adcvalue;
//ADC
wait(10);
GO_nDONE = 1;
while (GO_nDONE);
adcvalue = ADRESH << 2 | ADRESL >> 6;
return adcvalue;
}
int8_t isdark(void)
// 光センサの出力から、「暗い」かどうか判断する。
// 戻り値; 「暗い」と判断したとき -1
// それ以外 0
{
uint16_t photo; // 光センサの出力値
int8_t result; // 戻り値
uint16_t darkness_threshold = 900; //「暗い」と判断する閾値
photo = getAdc(); // 光センサの出力をA/D変換
if (photo > darkness_threshold) { //「暗い」とき
result = -1;
} else { // 「明るい」とき
result = 0;
}
return result;
}
// Timer0 制御関数
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 = 0b01010111; // Timer0 Internal clock, Prescaler 1:256
OPTION_REG &= 0b11000000; // Masking Timer0 bits
OPTION_REG |= 0b00010111; // Timer0 Internal clock, Prescaler 1:256
// Timer0 Interrupt occured every 65.536ms
TMR0IE = 1; // enable Timer0 interrupt
GIE = 1; // enable interrupt
}
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;
}
void __interrupt() intr(void)
// Interrupt processing function
{
if (INTF == 1) {
INTF = 0;
}
if (TMR0IF == 1) {
TMR0IF = 0; //Clear TMR0 Interrupt flag
TimerCounter++;
}
}
void main(void) {
initIo(); // I/O port初期化
initTimer0(); // Timer0 初期化
initAdc(); // A-D convertor 初期化
led0off(); //LED0を消す
led1off(); //LED1を消す
led2off(); //LED2を消す
while (1) { //無限ループ。次の}までの間を無限回繰り返す。
if (isdark()) {
led0on();
wait(5000);
led0off();
wait(5000);
led1on();
wait(5000);
led1off();
wait(5000);
led2on();
wait(5000);
led2off();
wait(5000);
} else {
led0off();
led1off();
led2off();
}
}
}