carcon999のブログ

12年間Y!ブログの記載を移行しました。電子工作関連の記事が多いです。

シリアルLEDを使ってみました

先日、スイッチサイエンスさんで取り扱いをはじめたシリアルLEDを購入してみました。

イメージ 1

勿論、フルカラーのLEDはいくつか持っているのですが、マイコン側でPWMして綺麗に表示させようとするとCPUパワーを結構消費したり、接続が面倒だったり、大量に接続するとポートが足りなくなったりいろいろ面倒だと思っていました。

そんな折、リール買いならば1個100円以下で購入できるシリアルLEDがお手軽で良さそうなので使ってみた次第です。
こんな感じにちらつきなく表示することができます。(結構インパクトがあります。)

★静止画
イメージ 2

★動画


また、LEDの明るさをPWMによる256段階で指定することができるのですが、50/256程度の指定でも個人的には十分な明るさです。(逆に255を指定すると、まぶしすぎる。)

購入の際に、ライブラリも提供されているようだし、がじぇるね(GR-SAKURA)でも、簡単に動くよね~。『ポチ!』と注文したのですが、なんと!機種依存のライブラリでした。(購入後に気づく。がーーーん)

そこで、仕方ないので自分で使えるように修正することにします。

まず、シリアルLEDには、どのようなデータを送信する必要があるのでしょうか?
データシートや、スイッチ・サイエンスさんの購入ページを参考にすると以下のタイミングらしいことが分かりました。(間違っていたらごめんなさい。でもこのタイミングで私は動いています。)

■全体
イメージ 3

RGBのパルスデータを24bit分送信後、50us経過するとシリアルで送った値でLEDが点等する仕組みです。
そして、このパルスデータは、400KHz(低速)と800KHz(高速)のどちらかで送信する必要があります。

■400KHzと800KHzのタイミング
イメージ 4

※タイミングですが、ネットで調べてみると微妙に異なるタイミングが出てきます。気になる型は、WS2811で調べてみてください。どれが本当にただしいのかは分かりませんが、私がプログラムしたのは上記です。許容誤差が結構あるので、その範囲で収まっているのでしょう。

■ソフトウェア
私がスクラッチでプログラムしていれば、公開するのですが、もともとのライブラリを修正して使っているので公開して良いものか分からないので、とりあえずポイントだけ公開しておきます。

ポイントとなるのは、
static inline void delayShort(uint32_t num);
の関数になります。

このdelay関数を使って、シリアルのbit送信をライブラリ側では行っています。
がじぇるねの場合、下記のようなコードで良い感じのタイミングが取れました。

static inline void delayShort(uint32_t num)
{
volatile int i = 0;

for(i = 0 ; i < num ; i++){
__asm__("nop" );
}
}

この関数の引数に以下の値を設定するとシリアルの送信に良い感じのタイミングが得られます。
周波数送信値引数に与える値
800kHz1のHi5
800kHz1のLow4
800kHz0のHi2
800kHz0のLow6
400kHz1のHi9
400kHz1のLow10
400kHz0のHi3
400kHz0のLow16

イメージ 5

もう一つポイントがあります。
シリアルでデータを送信する場合に、ポートのHI/LOWを制御しますが、通常の関数を利用してしまうと遅いので、高速にHI/LOWをポート出力するように記述する必要があります。
具体的には以下のようにします。

// これは、P40のポートを意味しています。
#define DIO_PIN (PORT4.PODR.BIT.B0)

// タイミングのDefine(コメントは実測値)
#define DELAY_800_T0H 2 // 360ns
#define DELAY_800_T0L 6 // 820ns
#define DELAY_800_T1H 5 // 710ns
#define DELAY_800_T1L 4 // 600ns
#define DELAY_400_T0H 3 // 476ns
#define DELAY_400_T0L 16 // 2000ns
#define DELAY_400_T1H 9 // 1200ns
#define DELAY_400_T1L 10 // 1300ns

for (int mask = 0x80; mask; mask >>= 1) {
if (pix & mask) {// 1を送信する場合
DIO_PIN =1;
delayShort(DELAY_800_T1H);
DIO_PIN =0;
delayShort(DELAY_800_T1L);
} else { // 0を送信する場合
DIO_PIN =1;
delayShort(DELAY_800_T0H);
DIO_PIN =0;
delayShort(DELAY_800_T0L);
}
}

こんな情報で分かるかな?分かりにくかったらごめんなさーい。

2013/04/10 追加
オシロのキャプチャーを追加します。
項目画像
0の周期1.29usイメージ 6
0のHI期間400nsイメージ 7
1の周期1.38usイメージ 8
1のHI期間730nsイメージ 9
※多少誤差がありますがまあ、こんな感じです。