赤、緑、青の三色が組み込まれた発光ダイオードを利用し、各色の強さをPICで制御し、フルカラー発光の実験を行います。
近年、青色の発光ダイオードが開発され、赤、青、緑、の色の強さを調節することで、発光ダイオードを用いてフルカラーの発光が可能になりました。ここでは、この発光ダイオードを用いて、超小型プロセッサのプログラムでフルカラーを発光させる実験を行います。
フルカラーLEDとしてOSTA5131A(OptoSupply社)を利用します。一番長い線が共通のカソード(GND)で、上からR(赤)、GND,B(青),G(緑)
の順です。色により発光効率が異なる為、同じ電流を流しても白色にはなりません。許容最大電流は50mAです。
色を設定するには、RGB各LEDの発光強度を調整すればよいのですが、この強度の調整法にPWM: Pulse Width Modulation
があります。この方法は、一定区間の中で通電する割合(時間幅)を変更して平均的な電力を調整する方法です。下図は、25%、50%、75% の電力制御の説明図です。横方向が時間で、立ち上がっている間スイッチをオンにして通電します。
通電幅を0にすればオフ、繰り返し期間と通電期間を同じにすれば、完全オン状態になります。PWM制御は少々荒っぽい手法なので、制御可能な対象は限定されますが
LED の発光強度を調整することは可能です。
PICはハードウエアによるPWM制御も可能ですが、制御可能な信号は1本のみです。ここでは、3本の制御が必要ですから、ソフトウエアでPWMを実現します。1周期の制御は次のようになります。Periodは繰り返し期間で、今回
255 とします。OnPeriod が通電期間で、0から OnPeriod の時刻まで通電することにします。LEDはポートBのB0端子に接続します。
output_high(PIN_B0); Period=0; while(Period<255){ if(Period == OnPeriod) output_low(pin_B0); Period ++; delay_us(10); }
最初、output_high(PIN_B0); でB0端子をオン、Periodを0にします。次に繰り返しの中で、Periodを増し、これが、OnPeriod
になったら、B0端子を0にし通電を停止します。繰り返し周期は、delay_us(10);で定まり、ここでは10μ秒です。
RGBの強さを調整すれば多種の色を出すことができますが、狙った色を出すよう、調整することは困難です。HSVカラーモデルは、H(Hue)を0から360まで変化させると、赤>黄>緑>青緑>青>紫>赤
と回る色の輪を生成できます。Sは色の度合いで1.0のとき最大(鮮やかな色)、0.0のとき最小(白)となります、Vは明るさで1.0のとき一番明るく、0.0のとき黒になります。
このHSVモデルの値(h=0..360、s=0.0..1.0、v=0.0..1.0) から RGBの強さ r,g,b を求めるには次のようなプログラムになります。s,v は少数(float)型変数です。r、g、b は 0..255 の範囲の整数です。
i = (int)(h/60.0); f = h/60.0f -i; p1=(int)(v*(1-s)*255.0); p2=(int)(v*(1-s*f)*255.0); p3=(int)(v*(1-s*(1-f))*255.0); vi=(int)(v*255); if(i==0) {r = vi ;g = p3 ;b = p1;} if(i==1) {r = p2 ;g = vi ;b = p1;} if(i==2) {r = p1 ;g = vi;b = p3;} if(i==3) {r = p1 ;g = p2 ;b = vi;} if(i==4) {r = p3 ;g = p1 ;b = vi;} if(i==5) {r = vi ;g = p1 ;b = p2;}
s,v = 1.0 としてhを0から360まで変化させると、鮮やかな色の変化を見ることができます。下にhueに対する r,g,b の計算値を示します。
hue : red gren blue 0 : 255 0 0 //red 15 : 255 63 0 30 : 255 127 0 45 : 255 191 0 60 : 255 255 0 75 : 191 255 0 90 : 127 255 0 105 : 63 255 0 120 : 0 255 0 //green 135 : 0 255 63 150 : 0 255 127 165 : 0 255 191 180 : 0 255 255 195 : 0 191 255 210 : 0 127 255 225 : 0 63 255 240 : 0 0 255 //blue 255 : 63 0 255 270 : 127 0 255 285 : 191 0 255 300 : 255 0 255 315 : 255 0 191 330 : 255 0 127 345 : 255 0 63
PICは8bit計算機です。PICが1命令で実行できる計算は8bitの加減算だけです。ここで使用するC言語の int 型はunsigned(符号なし)
の 8bitですから表現できる範囲は 0..255 です。255以上の整数を利用するには
long B;
のように、long 型を指定します。これで、16ビットの整数が利用できます。少数の場合は
float C:
のように宣言します。
PICが1命令で実行できる計算は8bitの加減算、シフト、論理演算(AND,OR,NOT)だけです。16bitの加減算や乗除算、少数の計算は8bitの加減算を組み合わせプログラムで行います。人が筆算で計算する場合、10進数1桁単位ですから、これは、4bit程度の演算を組み合わせていることになります。
演算に必要な関数はコンパイラが自動的に付加しています。プログラムのサイズが1200バイトと大きくなっているのは、この演算用の関数が付加されているからです。
回路配線用パッチボード
PIC:16F648
発光ダイオード(OSTA5131A)
抵抗 3本
B0,B1,B2 に LED のRGB 端子を接続します。LED共通のグランド線を電源のグランドバーに接続します。
プログラムを送る込むシリアル通信の部分は省略しています。
PICに電源が入ると、自動的にプログラムを実行開始します。RGB に対応する信号はRB0,RB1,RB2から出力されます。この信号は、色別に時間とともにPWM方式で、電力制御されます。発光ダイオードは、消費電力が少ないので、PICで直接点灯できます。ただし、直結すると、電力超過になりますから、抵抗素子を利用して、流れる電流を制限します。
この抵抗値を変えると、色のカラーバランスが変化します。適当な値を選択して下さい。
発光はかなり強いので、直視すると目が疲れます。紙で遮蔽をすると見やすくなります。
抵抗の値はカラーコードで示します。左から、第1,2,コードで値、第3コードで桁を示します。最後の4桁目は精度の値で、通常金色をしています。金色のリングを右側にしてカラーコードを読みます。各カラーは次の値となります。赤からは、いわゆる虹の色です。
黒:0、茶:1、赤:2、橙:3、黄:4、緑:5、青:6、紫:7、灰:8、白:9
(茶=1),(黒=0),(橙=3),の場合、10kΩ
(橙=3),(灰=8),(茶=1),の場合、380Ω
(赤=2),(紫=7),(茶=1),の場合、270Ω
色を定める変数hを 0..360 まで、順に変化させます。s,vは1.0に固定します。hsvからrgbに変換します。ここで、hは255を超えますから
long 型にする必要があります。
次に、pwm のループに入ります。赤色の場合、ループの入り口で output_high(PIN_B0); により点灯し、ループの値が
rgb の値に達したら output_low(PIN_B0); 消灯します。同じ色を10回繰り返して表示しています。この10の値を変更することで、色の変化する速度を調整できます。
#include <16F873A.h> //FullColor LED 最長:GND red,gnd,blue,green #fuses HS,NOWDT,NOLVP,NOPROTECT,NOBROWNOUT #use delay(clock = 20000000) int j,k; float s=1.0,v=1.0,f; long h; int i,vi; int p1,p2,p3; int r,g,b; void main(){ set_tris_b(0); set_tris_a(0xF); h=0; while(1){ //hsvからrgbへの変換 i = (int)(h/60.0); f = h/60.0f -i; p1=(int)(v*(1-s)*255.0); p2=(int)(v*(1-s*f)*255.0); p3=(int)(v*(1-s*(1-f))*255.0); vi=(int)(v*255); if(i==0) {r = vi ;g = p3 ;b = p1;} if(i==1) {r = p2 ;g = vi ;b = p1;} if(i==2) {r = p1 ;g = vi;b = p3;} if(i==3) {r = p1 ;g = p2 ;b = vi;} if(i==4) {r = p3 ;g = p1 ;b = vi;} if(i==5) {r = vi ;g = p1 ;b = p2;} //PWM loop for(j=0;j<10;j++){ output_high(PIN_B0); output_high(PIN_B1); output_high(PIN_B2); for(k=0;k<255;k++){ if(k==r) output_low(PIN_B0); if(k==g) output_low(PIN_B1); if(k==b) output_low(PIN_B2); } } h=h+1; if(h>=360) h=0; }//while }