[Raspberry Pi]ラズパイでLチカ(6)

2016年6月7日火曜日

RaspberryPi

さぁ、フルカラーLEDで色を変えるぞ!



とおもったんですが。raspbianの4.1.19にはnode.js(version 0.10.29)が搭載されている様子だったので、前回の手動PWMをnodeでやってみる。

(もちろん、PWM用のライブラリは存在するのですが、今回もハンドメイドで)

<< pwm.js >>


var fs = require('fs');





for(var i=0;i<10000;i++){


    fs.writeFileSync('/sys/class/gpio/gpio18/value', 1);


    for(var j=0;j<10;j++){


        fs.writeFileSync('/sys/class/gpio/gpio18/value', 0);


    }


}


実行は


$ node pwm.js


若干、ちらつくが概ねOK。





CでフルカラーLEDのLチカが出来たら、node版も作ってwebインタフェースで色を変えれるようにしてみましょうかね。




さて、ではフルカラーLEDのLチカをやっていきましょう。

まず、gpioの準備から。以前の投稿で、RGBの制御をかけると各色が出せる旨はお話ししました。つまり、Red, Green, Blueのそれぞれの制御が必要なので、出力用のGPIOピンは3つ用意します。



今回はピンの近いところで選んでみました。




<< pinopen.sh >>

#!/bin/bash

for port in 17 18 27

do

 echo $port > /sys/class/gpio/unexport    # 念のため

 echo $port > /sys/class/gpio/export

 echo out > /sys/class/gpio/gpio${port}/direction

 # test

 echo 1 > /sys/class/gpio/gpio${port}/value

 sleep 1

 echo 0 > /sys/class/gpio/gpio${port}/value

done



これを実行するとポートが開いたはずです。

確認してみましょう。



$ gpio readall



(抜粋)


 |  17 |   0 | GPIO. 0 |  OUT | 0 | 11 || 12 | 0 | OUT  | GPIO. 1 | 1   | 18  |




 |  27 |   2 | GPIO. 2 |  OUT | 0 | 13 || 14 |    |          | 0v        |      |       |



GPIO.0〜2(17,18,27)ピンがoutになっていますね。

# 各種ウェブサイトには、PWMの標準は18番ポートと書いてあって、17, 27とかではできないかと思ってたんですが、on/offの入れ替えですからね。Lチカくらいであれば、問題なく動作するようです。



これで前準備は完了です。



今回使用しているのは、このLEDです。



商品説明を抜粋すると、

特徴: 

    サイズ:5ミリメートル(。ピン長さ約25ミリメートル) 

    放出されたカラー:赤/緑/青 

    ピン系列:レッド/コモンカソード(マイナス端子)/緑/青 

    レンズカラー:拡散、 

    光度:4000/8000/5000mcd 

    順方向電圧(V):2.1〜3.4 

    約25度の角度を表示します。 

    電流制限抵抗を追加するためにテストしてください、

    それは、数百~1000ohmのLEDの抵抗を焼損することは非常に容易になります 



    R:波長630-640nm 明るさ1000-1200mcd電圧1.8-2.0V 

    G:波長515-512nm 明るさ3000-5000mcd電圧3.2-3.4V 

    B:波長465-475nm 明るさ2000-3000mcd電圧3.2-3.4V 



と、記載があります。ところどころ日本語がおかしいので、自動翻訳か日本語が母語じゃない方が記述なさっているのかもしれませんが、まぁ、なんとなくわかりますね。

この商品は、これ以外に説明資料が一切ありませんので、ここから読取らなくてはなりません。

mcdはミリ・カンデラ。ミリは1/1000のミリです。ミリメートルとかのアレです。

カンデラは明るさを表す単位ですね。ろうそくの火の明るさが約1カンデラらしいです。

カンデラはラテン語で、キャンドルの語源だとか。

…という前提でLEDの仕様をみると…

最大出力として(R,G,B)=(4000, 8000, 5000)だと推測できます。

Rが一番光らないんですねぇ。

Gが一番光るわけですか。ふむふむ。

順電圧もRだけ低いわけなので、その辺も計算しないといけないはずですが…

まぁ、短時間光らせるのであれば、大きすぎなければ焼けることもないでしょう…

とタカをくくって…こんな感じで書いてみました。



<< fullcolor.c >>





#include <stdio.h>


#include <getopt.h>


#include <sys/types.h>


#include <sys/stat.h>


#include <fcntl.h>


#include <unistd.h>





#define GPIO_PATH "/sys/class/gpio"





void gpio_on(int fd){


        write(fd, "1\n", 2);


}


void gpio_off(int fd){


        write(fd, "0\n", 2);


}


void alloff(int all[3], int ledmax){


        int led;


        for(led = 0; led < ledmax; led++){


                gpio_off(all[led]);


        }


}





int main(void){


        int i, led, next;


        int on, off;


        int on_max = 1;


        int off_max = 20;


        char *buf[] = {"1\n", "0\n"};


        int r = open(GPIO_PATH "/gpio27/value", O_RDWR);


        int g = open(GPIO_PATH "/gpio18/value", O_RDWR);


        int b = open(GPIO_PATH "/gpio17/value", O_RDWR);


        if(r < 0 || g < 0 || b < 0){


                fprintf(stderr, "open failure (%d,%d,%d)", r, g, b);


                goto err;


        }


        int all[3] = { r, g, b };


        int ledmax = sizeof(all)/sizeof(all[0]);


        // single color


        for(led = 0; led < ledmax; led++){


                for(i=0;i<1000*1000;i++){


                        gpio_on(all[led]);


                }


                gpio_off(all[led]);


        }




        // double color


        for(led = 0; led < ledmax; led++){


                next = (led + 1) % 3;


                for(i=0;i<1000*1000 / 2;i++){


                        if((all[led] == r && i%3 == 0)


                        || (all[led] == g && i%5 == 0)


                        || (all[led] == b && i%2 == 0)


                        ){


                                gpio_on(all[led]);


                        }else{


                                gpio_off(all[led]);


                        }


                        if((all[next] == r && i%3 == 0)


                        || (all[next] == g && i%5 == 0)


                        || (all[next] == b && i%2 == 0)


                        ){


                                gpio_on(all[next]);


                        }else{


                                gpio_off(all[next]);


                        }


                }


                alloff(all, ledmax);


        }


        // triple color


        for(i=0;i<1000*1000/3;i++){


                for(led=0;led<ledmax;led++){


                        if((all[led] == r && i%3 == 0)


                        || (all[led] == g && i%5 == 0)


                        || (all[led] == b && i%2 == 0)


                        ){


                                gpio_on(all[led]);


                        }else{


                                gpio_off(all[led]);


                        }


                }


        }





        alloff(all, ledmax);


err:


        if(r > 0) close(r);


        if(g > 0) close(g);


        if(b > 0) close(b);


        return 0;






















































}



前回まででやったPWMの要領で、ループの中での各LEDの点灯回数を変えてやることで輝度を調整しています。




if((all[led] == r && i%3 == 0)


|| (all[led] == g && i%5 == 0)


|| (all[led] == b && i%2 == 0)


){




この部分ですね。





実行するとこんな感じです。







赤、単色




緑・単色




青・単色




赤+緑=黄




緑+青=水色




青+赤=紫



赤+青+緑=白




光の三原色はこんな感じですから、なんとなくOKそうです。



本当は、きちんと計算しないとダメなんですけどね。





Lチカ完了です。