rgbLED関数を作る
前回、RGBLED(フルカラーLED)の使い方を学びました。今回は、PICを使って好きな色を出してみます。
pwmを使う
pwmとは、細かいオンオフを繰り返して何かを駆動する技術のことです。これに関しては、PICで電子ホタルを作るで詳しく解説しています。
上記の記事では一つのLEDの明るさをPWMで変えましたが、RGBLEDの3色の明るさを同時に変えるにはどうすればいいのでしょうか。
最も単純な方法は下図のように各色の明るさの割合(duty)を設定し、ループを回してオンオフ判定でしょう。
赤の割合をrduty(red duty)、緑をgduty,青をbdutyとしています。明るさのパーセンテージだと思えば簡単です。この縦線で区切られたブロック内をfor文で回し、i++等でカウントアップします。その値がrduty等よりも大きいかどうかでオンオフを切り替えれば、図のような光らせ方が実現できますね。
このブロックをいくつも繋げることで、長い時間この色を表現できるようになります。
pwmLEDの記事でも説明しましたが、人間の目は騙されやすく、このループを高速で行うと平均された色に見えるのです。上図でいえば、rgb=(40,100,30)の光、つまり少し白の混ざった緑色に見えます。
rgbLED関数を書いてみる
では、このような原理で様々な色を表現する関数を作ってみましょう。赤色LEDのピンに繋がっているPICのピンをRedLED、同様にGreenLED,BlueLEDとすると、
void rgbLED(int rduty,int gduty,int bduty,int time){
int i=0;
int j=0;
for(j=1;j<time;j++){
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(10);
}
}
}
と書けます。一般にrgbは最大値を255とした値で表されるので、iの値を256までカウントアップすることにしました(中のループ文)。引数にはrduty等の光の割合(最大255),どのくらいの時間継続させるかのtimeを入れました。中のループに__delay_us(10)があり、255回ループされるので、time*10(μs)*256秒間この色を光らせることができます。
上記の説明通り、iをカウントアップして、それよりもdutyが大きかったらLEDの点灯を維持、小さくなったらオフにするという構造です。使うときはこのようにします。
rgbLED(200,0,250,100); //紫色(赤と青のLEDが点灯)
rgbLED(100,200,0,100); //オレンジ色(赤と緑のLEDが点灯)
rgbLED(250,150,150,100); //白色
回路組み・実行例
では、RGBLEDを実際にrgbLED関数で駆動してみます。下図のようにブレッドボード上にRGBLEDと抵抗・PICを設置します。
RGBLEDの赤色LEDのピン(端っこで、最も長い脚の隣)に510Ωの抵抗を繋ぎ、それをPIC16F1938のRB0ピンに繋ぎます。同様に緑色LED(右端)→510Ω→RB1、青色LED(右から2番目)→510Ω→RB2。
RGBLEDの長い脚(GND)は電源のGNDに繋ぎましょう(図では青いジャンパワイヤで接続)。
これに、PICにプログラムを書き込むを参考に、PICkit3を接続します。これで回路は完成です!
完成プログラム(例)
例として、下のようなプログラムを書き込んでみます。まずRB0にredLEDを繋げたので、#define RedLED RB0としています。(他のGreenLED等も同様)。こうすることで、LEDを繋ぐピンを変えても#define部分だけ変更すればよくなります。
// 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 <xc.h>
#define _XTAL_FREQ 8000000
#define RedLED RB0
#define GreenLED RB1
#define BlueLED RB2
void PICinit(){
OSCCON = 0b01110000;
ANSELA = 0b00000000;
ANSELB = 0b00000000;
TRISA = 0b00000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
PORTA = 0b00000000; //2進数で書いた場合
PORTB = 0x00; //16進数で書いた場合
PORTC = 0; //10進数で書いた場合
}
void rgbLED(int rduty,int gduty,int bduty,int time){
int i=0;
int j=0;
for(j=1;j<time;j++){
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(10);
}
}
}
int main(void){
PICinit(); //PICを初期化
while(1){
rgbLED(250,100,180,100); //白
rgbLED(0,0,90,100); //青
rgbLED(250,0,50,100); //ローズレッド
}
return 0;
}
このプログラムは、始めに白(少し緑っぽいかもしれません)、青、ローズレッドを出力するものです。もちろん、rgbLED()内のduty比は好きな値にして構いません。これはあくまで一例です。これで、好きな色が出せるようになりましたね!
ピンバック: Wak-tech » RGBLED(フルカラーLED)を使ってみる
ピンバック: Wak-tech » RGBフルカラーLEDで電子ホタルを作る
他のサイトで解らなかったことがとても解りやすくて見やすいです。
例のプログラムでアノードコモンのLEDを使った場合オンオフの1と0を入れ替えた場合RGBの明るさってどう変えるのでしょうか?
いまいちRGBLEDでのプログラムがわかってないので、お教え頂きたいです。
よろしくお願いします。
コメントありがとうございます。そう言っていただけると、時間かけて作った甲斐があります!
アノードコモンの場合は試したことが無いので正直分かりません。ただOUTPUTモードにして、LEDからの電圧をピンに流すのは危険な気がします。やるとすれば、各RGB線の間にトランジスタを挟んでゲート電圧をマイコン側で操作するのがいいと思います。もちろんその分複雑になりますので、カソードコモンをおすすめします…。
返信ありがとうございます。
ちょうど良いサイズのチップLEDがアノードしかなくて質問してしまいました。
サイズ違いでチャレンジして見ます。