常夜灯(フルカラーLED)
概要
秋月電子で大型フルカラーLED(35mA)が安価(200円)で販売していましたので、早速購入し“常夜灯”なるものを作成してみました。
<仕様>
- 暗くなると自動的に点灯すること。点灯する暗さのレベルが調整できること。
- RGB各々のLEDは10段階で明るさが変わること。つまり1000色(10×10×10)に変化できること。
- 音も出せること。これは泥棒避けの為です。
動作原理
暗さの検出は、CDS(Cadmium sulphide cell)を利用しました。
今回は、暗くなると電圧が下がるようにCDSと抵抗を接続しました。

点灯する暗さのレベルは、通常はボリュームを使用して調整するのですが、少し趣向を凝らしてみました。
起動時の暗さを記憶し、それを点灯するレベルとします。
つまり、点灯してほしい暗さで起動してあげればよいことになります。
尚、起動時だけでなくSWを押すことによって、このレベル(その時の暗さ)を再設定することも出来ます。
RGB各々のLEDを10段階の明るさに切り替えることが出来るようにするために、PWM方式を採用しました。
LEDが1個だけであれば、PICが内臓しているPWMモジュールを使用するのですが、今回はRGBと3つのLEDがあるのでこのモジュールは使えません。
そこでタイマー割り込みを駆使して実現してみました。
- タイマー割り込みの周期は、約0.1msec(正確には128μsec)とします。
- LEDの明るさを10段階としましたので、PWMの周期は、1msec(0.1msec×10)とします。
- PWMのデューティサイクル【duty cycle】は、RGBの各LED毎に変えます。(これで明るさが変わります)
- 各LEDのデューティサイクルは、0~9の乱数を発生させ、その値を設定します。
<乱数で0~9を発生させる方法>
- mikroCが提供している関数(rand)は、0~32767を返します。
- これを利用して、0~9を得るには次のようにします。
cnt = (((double)rand()) / 32768.0) * 10.0;
音を出すために内臓モジュールのPWMを使用しました。
音の周波数は、500Hz、1KHz、2KHz、4KHz、8KHzと変化(100msec単位)させて見ました。
これはPWMの関数が用意されているのでとても簡単に出来ます。
回路図
ソースコード
- NigthLight.c
//********************************************************************** #define ledR GPIO.F0 #define ledG GPIO.F4 #define ledB GPIO.F5 #define SWITCH GPIO.F3 //********************************************************************** static unsigned char led_cnt, ledR_cnt, ledG_cnt, ledB_cnt; void interrupt(){ if (INTCON.T0IF == 1) { INTCON.T0IF = 0; GPIO.F1 = ~GPIO.F1; // if ((led_cnt <= ledR_cnt) && (ledR_cnt != 0)) ledR = 0; else ledR = 1; // if ((led_cnt <= ledG_cnt) && (ledG_cnt != 0)) ledG = 0; else ledG = 1; // if ((led_cnt <= ledB_cnt) && (ledB_cnt != 0)) ledB = 0; else ledB = 1; // if (led_cnt < 9) led_cnt++; else led_cnt = 0; } if (PIR1.TMR1IF == 1) { PIR1.TMR1IF = 0; } } //********************************************************************** void Pwm_Change_DutyEx(unsigned int duty_ratio) { CCPR1L = duty_ratio >> 2; CCP1CON.F6 = duty_ratio & 0b00000001; CCP1CON.F7 = (duty_ratio & 0b00000010) >> 1; } //********************************************************************** void buzzer() { Pwm_Init(500); Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Start(); Delay_ms(100); Pwm_Stop(); // Pwm_Init(1000); Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Start(); Delay_ms(100); Pwm_Stop(); // Pwm_Init(2000); Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Start(); Delay_ms(100); Pwm_Stop(); // Pwm_Init(4000); Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Start(); Delay_ms(100); Pwm_Stop(); // Pwm_Init(8000); Pwm_Change_DutyEx((PR2 * 4) / 2); Pwm_Start(); Delay_ms(100); Pwm_Stop(); } //********************************************************************** void main() { unsigned char cntR, cntG, cntB; unsigned int tmp, ref; OSCCON = 0b01110000; // クロックは8Mhz CMCON0 = 0b00000111; // コンパレータは使用しない。 ANSEL = 0b00000010; // AN1を使用する。 TRISIO = 0b00001010; GPIO = 0b00000000; OPTION_REG = 0b10000000; // INTCON.T0IE = 1; INTCON.T0IF = 0; OPTION_REG.T0CS = 0; OPTION_REG.PSA = 1; OPTION_REG.PS0 = 0; OPTION_REG.PS1 = 0; OPTION_REG.PS2 = 0; // led_cnt = 0; ledR_cnt = 0; ledG_cnt = 0; ledB_cnt = 0; // INTCON.PEIE = 1; // これ以降の処理で割り込みを許可する。 INTCON.GIE = 1; // これ以降の処理で割り込みを許可する。 // ref = Adc_Read(1); while (1) { if (SWITCH == 0) { ref = Adc_Read(1); } if (Adc_Read(1) > ref) { ledR_cnt = 0; ledG_cnt = 0; ledB_cnt = 0; continue; } tmp = rand(); ledR_cnt = (((double)tmp) / 32768.0) * 10.0; tmp = rand(); ledG_cnt = (((double)tmp) / 32768.0) * 10.0; tmp = rand(); ledB_cnt = (((double)tmp) / 32768.0) * 10.0; buzzer(); Delay_ms(1000); } } //**********************************************************************
















