3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WS2812の話題がZRouter.orgのircでもあったので、ちょっといじってみました。

AmazonでWS2812の安いモジュールは中国発送で、クリスマスに間に合わないので、ヤフーショッピングで安いものを購入しました。送料無料で秋葉までの電車代より安かったです。

ESP32ではRMTというOne-Wireをサポートする機構があり、それを使っているようですが、このような機構が無い場合はSPIで処理することもあるようです。

WS2812の仕様を確認してみると300nsくらいの波形が必要になるようです。

SPIはかなり苦戦しているようなので、FTDIのBitBangを使って試してみることにしました。

FreeBSDのmrubyで以前パラレルLCDを処理するのにmruby-ftdiを作ったので、これを使います。

# WS2812 sample script

HI = 0xff
LO = 0x00

class WS2812

  RESET = [LO]
  ZERO = [HI, LO, LO]
  ONE = [HI, HI, LO, LO]

  def initialize(ftdi)
    @f = ftdi
  end

  def send_hex(hex)
    b = []
    for h in hex do
      for n in 0..23 do
        if (h >> (23 - n)) & 1 == 1
          b += ONE
        else
          b += ZERO
        end
      end
    end
    dat = b + [HI]
    @f.write(RESET)
    usleep 200
    @f.write(dat)
  end
end

begin

# FT232H
ftdi = Ftdi.new(0x6014, 0xff)
ftdi.baudrate(9600*20)
ftdi.write([HI])

ws = WS2812.new(ftdi)

# Green, Red, Blue
pat = [0x400000] * 7

ws.send_hex(pat)

end

光りました。これで25mAくらいで、無点灯でも4.5mAくらいでした。

IMG_20251211_161033.jpg

古いFTDIのチップはだめで、USB 2.0のFT232Hでないとだめでした。

ビットの0は3バイト,1が4バイトで送られて、LEDが1つあたり24ビットなのでMAX96バイトで、7つの場合は7倍で672バイトで終端の1バイトを入れると673バイトになります。

8x8のような大きなモジュールを使う場合にはmruby-ftdiのバッファを大きくする必要がありますが、動作は未確認です。

WS2812は送られてくる信号の先頭のGRB(24ビット)を拾って、残りを次のデバイスに渡すことで、複数のデバイスをサポートしているようです。このモジュールでは真ん中が一番最後です。

baudrateはオシロで波形を確認して決めました。

WS2812B_DATA.png

上記のコードでは全ビット同じものがでますが、別々にしてそれぞれWS2812に入れれば8倍の高速化が実現できますね。

やっぱクリスマスは光物がいいですね。

Python先輩にはFTDIのMPSSEを使ったライブラリがあるようですが、わざわざより複雑なMPSSEを使うまでもなく、BitBangで十分だと思います。

おまけ

正月も近いので、ぐるぐる回るアニメーションを作ってみました。

n =  0

loop do
  pat = [0x000000] * n
  pat += [0x400000]
  pat += [0x000000] * (6 - n)
  ws.send_hex(pat)
  n += 1
  n = 0 if n == 6
  usleep 100_000
end

WS2812_3.png

いつもより多く回っております。

こうしても同じように回ります。

n = 0

pat = [0x400000] + [0x000000] * 6
loop do
  ws.send_hex(pat.rotate(-n))
  n += 1
  n = 0 if n == 6
  usleep 100_000
end

こうすると

n = 0

loop do
  pat = [0x400000] * n + [0x000000] * (7 - n)
  ws.send_hex(pat)
  n += 1
  n = 0 if n == 7
  usleep 100_000
end

こうなります。

WS2812_4.png

虹色も試してみました。まずWS2812クラスに以下のメソッドを追加します。ESP32のコードを参考にしました。

  def hsb_to_hex(h, s, b)
    h = h % 360
    s = s / 100.0
    b = b / 100.0

    if s == 0
      gray = (b * 255).to_i
      return [gray, gray, gray]
    end

    h_sector = h / 60.0
    sector = h_sector.to_i
    fraction = h_sector - sector

    tint1 = b * (1 - s)
    tint2 = b * (1 - s * fraction)
    tint3 = b * (1 - s * (1 - fraction))

    r, g, b_rgb = case sector
    when 0
      [b, tint3, tint1]
    when 1
      [tint2, b, tint1]
    when 2
      [tint1, b, tint3]
    when 3
      [tint1, tint2, b]
    when 4
      [tint3, tint1, b]
    else
      [b, tint1, tint2]
    end

    (g * 255).to_i << 16 | (r * 255).to_i << 8 | (b_rgb * 255).to_i
  end

これで表示します。

loop do
  for n in 0..360 do
    pat = [ws.hsb_to_hex(n, 100, 100)] * 7
    ws.send_hex(pat)
    usleep 50_000
  end
end

なんか、あまり綺麗ではありません。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?