前回、フルカラーLEDで電子ホタルを作る記事を書きました。今回は、以前作った温度計とこれを組み合わせた温度によって色が変わるLEDを作ります。
温度をRGBに対応させる
以前作った温度計では、AD変換を使って温度を取得しました。ここではnowTemp()関数を使いました。
unsigned int adconvAX() //サーミスタの電圧を10bitで取得する関数
{
ADCON0bits.CHS = 0;
ADON = 1; //AD変換ON
__delay_us(20);
GO = 1; //AD変換待ち
while(GO); //AD変換終了まで待機
return (ADRESH<<8) + ADRESL;
}
double nowTemp(){ //現在の温度を返す関数
const double BCONST = 3500;
const double T0 = 298; //K
const double RESIST = 200000; //Ω
const double RESIST0 = 200000; //Ω
double AXresist = 0; //サーミスタの抵抗値Rx
double ADvalue; //AD変換された値の格納用
double ReciproTmp; //温度の逆数(ケルビン単位)
double tmp; //温度(℃)
for(int i=0;i<50;i++){ //ADvalueを50回積算
ADvalue += adconvAX();
}
ADvalue = ADvalue/51; //50で割って平均値を算出
AXresist = RESIST * (1024/ADvalue - 1); //サーミスタの抵抗値算出
ReciproTmp = log(AXresist / RESIST0) / BCONST + 1 / T0; //温度の逆数算出(K)
tmp = 1 / ReciproTmp - 273.15; //温度の算出
return tmp;
}
この関数を使えば、温度が℃単位で取得できます。この値をRGBLEDに反映させてみましょう。
RGB関数に温度を組み込む
まず、温度によってどのように色を変えるかを考えなければなりません。私のイメージでは、温度が高くなると赤く、低いと青くなるイメージがあります。
では、前回のRGBLED電子ホタルで作ったfireFly()関数にこれを当てはめてみましょう。
int main(void){
PICinit(); //PICを初期化
while(1){
int tmpnow = nowTemp();
int r = 0;
int g = tmpnow*2; //緑色の強度は温度の2倍に比例
int b = 0;
if(tmpnow<24){ //24℃以下の場合
b = 255; //青は最大出力、赤は出力なし
r = 0;
}else{
b = 255/(tmpnow-23); //青は温度に反比例
r = (tmpnow-24)*20; //赤は温度の20倍に比例
}
fireFly(r,g,b); //電子ホタル部分
}
return 0;
}
まず、始めにtmpnowに現在の温度を代入しています。その後、r,g,bを定義しています。緑色は温度の2倍になるように設定しました。
24℃以下では、寒いので青と緑のみ点灯します。それ以上では青の強度は温度に反比例して減少します。同様に赤は温度の20倍に比例して増加します。
これをグラフで表すと以下のようになります。
温度がだんだん高くなるにつれて、赤が多くなり青が少なくなっています!この計算部分は好きなように調節して、理想の光りかたにしてください。(24℃以下の部分を15℃以下などにするとより実用的です。)
回路図
RB0 ~ RB2にそれぞれR,G,Bを割り当てています。また、AN0にサーミスタを接続しています。
完成プログラム
// PIC16F1938 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable (All VCAP pin functionality is disabled)
#pragma config PLLEN = OFF // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#define LCD_ADD 0x7C
#define Bconst 3500
#define _XTAL_FREQ 8000000
#define RedLED RB0
#define GreenLED RB1
#define BlueLED RB2
unsigned int adconvAX() //サーミスタの電圧を10bitで取得する関数
{
ADCON0bits.CHS = 0;
ADON = 1; //AD変換ON
__delay_us(20);
GO = 1; //AD変換待ち
while(GO); //AD変換終了まで待機
return (ADRESH<<8) + ADRESL;
}
double nowTemp(){ //現在の温度を返す関数
const double BCONST = 3500;
const double T0 = 298; //K
const double RESIST = 200000; //Ω
const double RESIST0 = 200000; //Ω
double AXresist = 0; //サーミスタの抵抗値Rx
double ADvalue; //AD変換された値の格納用
double ReciproTmp; //温度の逆数(ケルビン単位)
double tmp; //温度(℃)
for(int i=0;i<50;i++){ //ADvalueを50回積算
ADvalue += adconvAX();
}
ADvalue = ADvalue/51; //50で割って平均値を算出
AXresist = RESIST * (1024/ADvalue - 1); //サーミスタの抵抗値算出
ReciproTmp = log(AXresist / RESIST0) / BCONST + 1 / T0; //温度の逆数算出(K)
tmp = 1 / ReciproTmp - 273.15; //温度の算出
return tmp;
}
void PICinit(){
OSCCON = 0b01110000; //8MHz
ADCS2 = 1;
ADCS1 = 0;
ADCS0 = 1;
ADFM = 1;
ADNREF = 0;
ADCON1bits.ADPREF = 0;
ANSELA = 0b00000011;
ANSELB = 0b00000000;
TRISA = 0b00000011;
TRISB = 0b00000000;
TRISC = 0b00011000;
PORTA = 0b00000000; //2進数で書いた場合
PORTB = 0x00; //16進数で書いた場合
PORTC = 0; //10進数で書いた場合
}
void rgbLED(unsigned int rduty,unsigned int gduty,unsigned int bduty,unsigned int duty){
int i=0;
rduty = rduty*duty/256;
gduty = gduty*duty/256;
bduty = bduty*duty/256;
for(i=1;i<256;i++){
if(i<rduty){
RedLED = 1; //赤色LEDをオン
}else{
RedLED = 0; //LEDをオフ
}
if(i<gduty){
GreenLED = 1; //緑色LEDをオン
}else{
GreenLED = 0; //LEDをオフ
}
if(i<bduty){
BlueLED = 1; //青色LEDをオン
}else{
BlueLED = 0; //LEDをオフ
}
__delay_us(1);
}
}
void fireFly(unsigned int r,unsigned int g,unsigned int b){
int duty = 0;
for(duty;duty<256;duty++){
rgbLED(r,g,b,duty);
}
for(duty;duty>0;duty--){
rgbLED(r,g,b,duty);
}
}
int main(void){
PICinit(); //PICを初期化
while(1){
int tmpnow = nowTemp();
int r = 0;
int g = tmpnow*2; //緑色の強度は温度の2倍に比例
int b = 0;
if(tmpnow<24){ //24℃以下の場合
b = 255; //青は最大出力、赤は出力なし
r = 0;
}else{
b = 255/(tmpnow-23); //青は温度に反比例
r = (tmpnow-24)*20; //赤は温度の20倍に比例
}
fireFly(r,g,b); //電子ホタル部分
}
return 0;
}
上記のプログラムをコピペして回路に書き込めば同様の結果が得られると思います。今回はデモとして温度変化点を24℃にしましたが、15℃くらいにすると面白いかもです(冬なら寝る前はオレンジ色だったのが、朝起きたら青色になってた等)。
ピンバック: 完全初心者のための基板製作入門(EAGLE・FusionPCB)