さくらのジャンク箱ロゴ

Sakura87がほぼ月刊でお届けするPCや電子工作と写真の備忘録てきなブログ @なんと20周年

Raspberry Pi 2 でシフトレジスタを使いIOポートを節約する(74HC595)

この記事は9年ほど前に投稿されました。内容が古くなっている可能性がありますので更新日時にご注意ください。

IMG_4811_20150901

今まで様々なハードウェアをRaspberry Piにて駆動させてきました。
特に液晶関係が多かったと思いますが。今回はちょっと変わったものを制御してみたいと思います。

「変わったもの」と言っても変な機器というわけではなくて。今までは直接光ったり何かを表示したりするものがほとんどでしたが、今回は一風変わって間接的に使用するデバイスを制御してみたいと思います。

というわけで、今回は汎用ロジックIC郡のなかの「8bitシフトレジスタIC」というものを制御してみたいと思います。

汎用ロジックICとは

そもそも汎用ロジックICとはなんぞや?という人もいるかもしれないのでかなり簡単に説明すると。

デジタル回路を作成する上で必要になる簡単な機能を1つのパッケージにしたIC。

みたいなことがWikipediaには書いてあった。例えばNOT回路のみを収録したICやシリアルパラレル変換、ビット演算といった。いまどきそんなのプログラミングでどうにかなるじゃん?という機能を持ったIC。
今時は確かにこれらの機能はコンピュータに組み込まれ。使う必要は殆ど無いだろうが、このIC郡が作られたのは最初期のもので1960年代。もう半世紀も昔の話らしい。東芝が言ってた。

要はCPUやマイコンなんて無いような時代に生まれたICであり。これらを組み合わせて今のマイコンと同等の処理をさせていたらしい。例えばPC-8801とかそのくらいのコンピュータを分解すると74SN…で始まる型番のICがたくさんあったりする。

使いどころ

じゃあそんな古いICを今更何に使うのかというと。例えば入出力ポートが限られたマイコンに、入出力ポートを増やしたり、シリアル通信にしか対応していない機器とパラレルにしか対応していない機器の間の橋渡しに使ったりします。「単機能」だからこそ使い方は色々なのですね。

今回はその数ある汎用ロジックICの中から、8ビットシフトレジスタを使ってみたいと思います。

シフトレジスタとは

そもそもレジスタとはざっくり言うとメモリのことで。この部品は入力した値を記憶しておくための装置で、シフトレジスタとは、その回路内でデータの値を移動することの出来るレジスタのことです。

例えば8bitのシリアル-パラレルのシフトレジスタなら、入力端子にデータを転送後、また次のデータを転送することで最初に転送したデータが2bit目に移動し1bit目に今転送されたデータが保持され、該当するbitのピンから出力されます。この動作を応用すればシリアル→パラレル変換が出来ます。
つまりC言語などのビットシフト演算子(<<+x・>>+x)と同じ動作をするということですね。その値の入力・結果の出力がシリアルもしくはパラレルの違いで

・シリアル入力-パラレル出力
・シリアル出力-パラレル入力
・シリアル入出力
・パラレル入出力

の4種類があり、今回使うのは一番上のシリアル入力-パラレル出力です。見て分かる通り、入力ピンを節約したい場合はシリアル出力-パラレル入力のレジスタを使えばいいということになりますね。

と、かなり偉そうに書いてますが。実は私もよくわかってません。とりあえずこいつを使えばシリアル-パラレル変換が出来ます。ちなみに同じ動作をするICは本品595と164がありますが。164の方はラッチがついていないのでIOポートの増設として使うのであれば595の方が都合がいいと思います。

使い方

このICを使う場合、信号線はシリアル入力・ラッチ信号・シフト信号(シリアルクロック)の3本あれば制御できます。つまり出力ポートを8本→3本となんと5本も節約できます!ただし、クロックやラッチ信号を出力する関係上、実際のIOポートを8本使って出力するより速度は遅いです。パラレル接続のカラー液晶みたいなデータ量の多いデバイスなどでは、その差が大きく変わってきます。

例えば、10万回同じデータを転送したとすると、IOポートを直接8つ変更するのに比べ、3倍近い時間がかかってしまいます。これは単純にクロック信号とCS信号が追加される事によるものです。通常なら1bitに対して1つのIOポートの値を変更すればいいのですが、シフトレジスタを使う場合はデータ転送・クロック立ち上げ・クロックたち下げの計3回IOポートを変更する必要が有るため単純に3倍時間がかかることになります。

よって高速な転送速度が要求される場所には使えませんが、例えばLED表示を行うのをこいつでひとまとめにしたり、複数のキャラクタ液晶やモノクロ液晶を接続したい場合に便利です。

製品としては7セグLEDの制御やドットマトリクスの制御に使われているようです。
(どちらも専用のICがあるのですが。汎用で他のところにも使える分安価に調達出来るからでしょうか?)

回路制作

今回はとりあえず7セグLEDを表示してみたいと思います。

基本的な部品は前回7セグLEDを点灯させたものと同じ。それに今回使用するICが加わった感じです。
74HC595は非常にポピュラーな半導体なので色々なところから出ていますが。今回は東芝製の「TC74HC595AP」を使いました。マルツのオンラインで1つ130円+税ほど。日本企業製以外なら本家Tiのものが秋月なんかで40円程度で買えますね。なんとアマゾンにもあります。 基本的にどのICも同じはずなので好きなものを。特にこだわりがなければTi製の安いものでいいでしょう。

IMG_4819_20150910

めんどく単純な回路なので回路図は省きます。

メーカーから出ている回路図の名称で説明すると。

QA~QH→ 7セグLEDのA~G・DPに繋がる端子
SI→データ入力 GPIOポートに接続 WiringPi番号で12番ポート(物理19番ピン)を使用
RCK→ラッチ信号入力 GPIO(WiringPi 10/物理24)に接続
SCK→クロック信号入力 GPIO(WiringPi 14/物理23 )に接続

 ̄G→ 出力オフ信号 GNDに接続(使用しないので)
 ̄SCLR→リセット信号 3.3Vを供給(使用しないので。してもいいけど。)

という感じで接続します。

これをみると、実際にGPIOポートは3つしか使っていません。

IMG_4823_20150911

(中央の青・黄色・緑が信号線 ツイストしている赤青は電源)

動かしてみる

このICの制御は以下のとおりです。

1.ラッチ信号をL(0)にする
2.データ入力ピンに1bitのデータをセット
3.クロック信号をH(1)にする
4.すぐにクロック信号をLにする
5.1~3を合計8回繰り返す(8bitなら)
6.ラッチ信号をH(1)にする

ちなみにこれ、SPIの制御と同じですね。よってSPIのコマンドでこのICは制御できます。
たとえば、ラズビアンの端末で「echo -ne “\x4F” > /dev/spidev0.0」と入力するとこんな感じになります。

IMG_4819_20150910

 

最後に

以上、簡単ですが使い方を説明しました。
ちなみにこのICはSPIと同じ制御コマンドで制御できますが。ラッチ信号が必要なため、1バイトずつのデータしか転送できません。

参考資料(ここまでにリンクを貼っていないもの)

汎用ロジックICの歴史
シフトレジスタ(74HC595) を使って、複数の LED を制御してみる
Wikipedia 汎用ロジックIC

動作コード

ヘッダはstdioとwiringPiのヘッダだけでOKです。後は使う目的に合わせて追加してください。

#include <stdio.h>
#include <wiringPi.h>

// データ転送用ピンの設定
// 12=MOSI 14=SCLK 10=CE.0 なのでこのピン指定なら
// SPIの命令で制御できる。
#define RegPut 12 // データ転送用ピン
#define RegClk 14 // クロック信号用ピン
#define RegCS  10 // ラッチ信号用ピン

int main(void){
       // メインの処理
}


// データ転送用コマンド 符号なしキャラクタ型を指定する。1バイト。
void DataSend(unsigned char TrData){
	digitalWrite(RegCS,0);
	
		digitalWrite(RegPut,(TrData>>7)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>6)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>5)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>4)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>3)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>2)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>1)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	
		digitalWrite(RegPut,(TrData>>0)&1);
		digitalWrite(RegClk,0);digitalWrite(RegClk,1);
	digitalWrite(RegCS,1);
}

まず最初にラッチをオフにして、データ用ピンに1bit分セット、その後クロックを発生させています。

転送部分ですが、whileやforを使ってループさせたら見栄えもいいですが、単純に7回同じ命令を書いた方が1割程度速かったのでこうしました。
各ビットを抜き出すのは(TrData>>n)&1 (n=7-0)の部分でビットを1ビットシフトし、その値を1でマスクしています。

bitshift

&はAND演算ですが、これは比較対象双方の値が1なら1を返す演算子で、以下のとおりの結果になります。

0 & 0 = 0
0 & 1 = 0
1 & 1 = 1
1 & 0 = 0

これを利用して、シフトした結果に1(2進数 0000 0001)をAND処理することによって1桁目のビットを常に抜き出しています。そしてその結果をGPIOに出力しています。

これをwiringPiのdigitalWriteByteと置き換える事でこのICが使用できます。

単純なICなので、使い方は色々ですね。また、このICは複数のICをつなげて16bit・24bitと拡張できますので、特に7セグLEDやドットマトリクスLEDを複数制御する場合に配線を非常に少なくすることが可能になります。例えばこのICを2つ使うだけで7セグLEDを8つ制御することが出来ます。本来8つの7セグLEDを制御するには合計16本のGPIOが必要となり、GPIOの半分以上を専有してしまいますが。これを使えばうまく制御すれば3本のGPIOを使用するだけで制御出来てしまいます。速度は本体のGPIOで直接制御したほうが圧倒的に速いですが。

そんなわけで。色々と使えそうなICの紹介でした。

総閲覧数:402 PV

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください