シフトレジスタ(74HC595) を使って、複数の LED を制御してみる


## 使ったもの

- Raspberry Pi TypeB
- 外部接続用のPC(Mac)
- シフトレジスタ(74HC595)
- LED5本(5個しか無かった...)
- 抵抗8本
- ブレッドボード

## シフトレジスタって何?

- シリアル → パラレル変換や、その逆を行う回路
- 例えば、RaspberryPi で、8個のLEDを個別にチカらせたい場合、何も考えないと、GPIOのピンを8個使うことになる
- けど、シフトレジスタ(シリアル → パラレル変換)を使えば、1つの出力からのデータ(シリアル)を複数の出力(パラレル)に変換できる
- パラレル → シリアル変換ならば、複数の入力を1つの入力に変換できる

## シフトレジスタ(74HC595)の使い方

以下のPin Assignment について解説

- http://html.alldatasheet.com/html-pdf/214419/TOSHIBA/TC74HC595AP_07/301/1/TC74HC595AP_07.html

### 各ピンの意味

- SI : シリアルデータを入れる所
- SCK : シフトレジスタクロック
- RCK : ラッチクロック
- QA〜QH : 出力先(8個)
- Vcc : 電源接続(5V)
- GND : グラウンドに接続
- G : Hiにすると、QA〜QHがハイインピーダンス状態(切断状態)になる
今回は未使用なので、GNDに接続
- SCLR : リセットクロック(Loにするとシフトレジスタをリセットする)
今回は未使用なので、Vccに接続
- QH' : 別の74HC595につなげることで、16ビット、24ビットと、拡張できる

### 使い方

1. SI に1ビットのデータを入れる(Lo or Hi)
1. SCK を Hi にすると、データの入力先が次のアドレスに移動する
1. SI に次のアドレスのデータを入れる
1. 8ビット分データを入れたら、RCK を Hi にする
1. 各出力先から、SIに入力した8ビット分のデータが出力される

### 配線

- SI(17)、SCK(27)、RCK(22) を GPIO に接続
- QA〜QHに、発光ダイオードと、抵抗を接続
- Vcc、SCLR を Vcc に接続
- GND、G を GND に接続

こんなかんじ

<img src="https://24.media.tumblr.com/b34633f151b0a1ef842351dafeaf4118/tumblr_mznez9eobq1qz56lho1_500.jpg">

## Raspberry Pi 側の実装

### gem pi_piper のインストール

pi_piper は、ruby から GPIO へのアクセスを楽にしてくれる gem


```shell-session
$ sudo apt-get install ruby-dev 
$ sudo gem install pi_piper
$ gem list --local

*** LOCAL GEMS ***

ffi (1.9.3)
pi_piper (1.3.2)
```

### ruby の実装

1個ずつLEDを光らせてみる

```rb
require 'pi_piper'

$pins = {
  :ser => PiPiper::Pin.new(:pin => 17, :direction => :out), # シリアルデータ
  :sck => PiPiper::Pin.new(:pin => 27, :direction => :out), # シフトレジスタクロック
  :rck => PiPiper::Pin.new(:pin => 22, :direction => :out)  # ラッチクロック
}

def shift(key)
  $pins[key.to_sym].on
  $pins[key.to_sym].off
end

def reset
  $pins.values.each{|pin|  pin.off }
end

def send_bits(data)
  # シリアルデータを送信
  0.upto(7) do |byte|
    if ((1 << byte) & data) == 0
      $pins[:ser].off
    else
      $pins[:ser].on
    end
    shift(:sck) # シフトレジスタクロックを送信
  end
  shift(:rck) # ラッチクロックを送信
end

reset

num = 1
0.upto(8) do |byte|
  send_bits(num)
  num = num << 1
  sleep(0.5)
end

send_bits(0)

# close
reset

$pins.values.each do |pin|
  File.write("/sys/class/gpio/unexport", pin.pin)
end
```

こんな感じに光る(地味)

- [シフトレジスタでLEDチカ - YouTube](http://www.youtube.com/watch?v=J7eE38OjeXE)

## バーサライトを作ってみる

LEDの残像で文字とかを表示する装置のこと
実装してみたけど、回路を振り回せないので正しく動作しているかどうかよくわからない

```rb
require 'pi_piper'

$pins = {
  :ser => PiPiper::Pin.new(:pin => 17, :direction => :out), # シリアルデータ
  :sck => PiPiper::Pin.new(:pin => 27, :direction => :out), # シフトレジスタクロック
  :rck => PiPiper::Pin.new(:pin => 22, :direction => :out)  # ラッチクロック
}

def shift(key)
  $pins[key.to_sym].on
  $pins[key.to_sym].off
end

def reset
  $pins.values.each{|pin|  pin.off }
end

def send_bits(data)
  # シリアルデータを送信
  0.upto(7) do |byte|
    if ((1 << byte) & data) == 0
      $pins[:ser].off
    else
      $pins[:ser].on
    end
    shift(:sck) # シフトレジスタクロックを送信
  end
  shift(:rck) # ラッチクロックを送信
end

begin
  reset

  data_str = <<EOS
1111111100011111100011111100011111111000
0001100000011000000011000000000011000000
0001100000011111100011111100000011000000
0001100000011000000000001100000011000000
0001100000011111100011111100000011000000
EOS

  datas = data_str.split("\n").map do |str|
    str.split(//).map(&:to_i)
  end.transpose.map do |data|
    (data.join('')+'000').to_i(2)
  end

  while true do
    datas.each do |num|
      citme = Time.now
      send_bits(num)
      # sleep(0.01)
    end
  end

catch Exception => e
  p e.message
  puts e.join("\n")
ensure
  send_bits(0)
  # close
  reset
  $pins.values.each do |pin|
    File.write("/sys/class/gpio/unexport", pin.pin)
  end
end
```


そんなかんじ

## 参考

- [TC74HC595AP_07 datasheet(1/11 Pages) TOSHIBA | CMOS Digital Integrated Circuit Silicon Monolithic 8-Bit Shift Register/Latch (3-state)](http://html.alldatasheet.com/html-pdf/214419/TOSHIBA/TC74HC595AP_07/301/1/TC74HC595AP_07.html)
- [74595 ‐ 通信用語の基礎知識](http://www.wdic.org/w/SCI/74595)
- [シフトレジスタ(74HC595)の使い方](http://www.chibiegg.net/elec/avr-elec/74hc595_sample.htm)
- [Arduinoでシフトレジスタ（74HC595)を使ってLCDを動かす | サンハヤト電子工作ブログ](http://sunhayato.co.jp/blog/?p=581)
- [武蔵野電波のブレッドボーダーズ](http://pc.watch.impress.co.jp/docs/2008/1226/musashino024.htm)