「shiftOut関数」の解説

このページをスマホなどでご覧になる場合は、画面を横長にする方が読みやすくなります。
2019年10月03日 更新。
用語:shiftOut関数
用語の読み方:シフトアウトかんすう
このページで解説している他の用語:LSBFIRST定数LSBFIRSTMSBFIRST定数MSBFIRST

shiftOut関数は、Arduinoで使える標準関数のひとつで、8ビットの符号なし整数の引数を、クロック同期方式のシリアルバスに出力する働きをします。

データ出力に使うピンとクロック出力に使うピンを指定すると、クロック出力ピンから8クロックが出力され、そのクロックに同期して、8ビットのデータがシリアル方式で出力されます。

データは、MSBファースト(MSBから順にLSBまで出力する方式)でもLSBファースト(LSBから順にMSBまで出力する方式)でも出力できます。

shiftOut関数は、モード0あるいはモード1で動作する、SPI接続のスレーブ機器に対し、ソフトウェアSPI方式によりデータを送信する用途に使えます。

またshiftOut関数は、74HC59574HC164等のシリアル-パラレル変換シフトレジスタにデータをする用途にも使えます。

なお、Arduinoは、SPIライブラリにより、ハードウェアSPI方式にも対応しています。ハードウェアSPI方式の場合は、使える信号ピンが決まっているという欠点はあるものの、shiftOut関数と同様の動作をより高速に行える利点があります。SPIライブラリに関しては、この用語集のSPIの項目をご覧ください。

目次

1. shiftOut関数の書式 … 1ページ
2. 出力波形 … 1ページ
2-1. LSBファーストの場合の出力波形 … 1ページ
2-2. MSBファーストの場合の出力波形 … 1ページ
3. shiftOut関数を使う前に必要な初期化 … 1ページ
4. Arduinoに74HC595を接続して出力ピンを拡張する場合にshiftOut関数を使う例 … 1ページ
広告

1.shiftOut関数の書式

shifitOut関数は、次の書式を取ります。

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)

第1引数dataPinは、uint8_t型(符号なし8ビット整数)で、データを出力するピンの番号を指定します。

第2引数clockPinは、uint8_t型で、クロックを出力するピンの番号を指定します。

第3引数bitOrderは、uint8_t型で、データをMSBファーストで送信するか、LSBファーストで送信するかの指定に使います。MSBファーストで送信する場合は、第3引数に定数MSBFIRSTを指定します。LSBファーストで送信する場合は、第3引数に定数LSBFIRSTを指定します。

第4引数valは、uint8_t型で、送信したい8ビットのデータを指定します。

なお、shiftOut関数には返り値はありません。

2.出力波形

shiftOut関数を呼び出した時の出力波形を、LSBファーストの場合(第3引数にLSBFIRSTを指定した場合)と、MSBファーストの場合(第3引数にMSBFIRSTを指定した場合)に分けて、図説します。

2-1.LSBファーストの場合の出力波形

LSBファーストの場合のタイミングチャートを図1に示します。

図1、LSBファーストの場合のタイミングチャート(CLOCK信号の初期化なし)
↑ 画像をクリックすると拡大
図1、LSBファーストの場合のタイミングチャート(CLOCK信号の初期化なし)

CLOCK信号は、shiftOut関数の第2引数で指定されたピンから出力される信号を表しています。

CLOCK信号の最初の部分(左端の部分)にUと書いてある部分がありますが、これは不定(LHか分からない事)を表しています。この部分がLになるかHになるかは、shiftOut関数が呼び出される直前に、digitalWrite関数の呼び出しなどにより、CLOCK信号にLHの内、どちらの電圧が出力されたかにより決まります。

なお、shiftOut関数は、必ずCLOCK信号がLになった状態で帰ってきますから、同じI/Oピンに対してshiftOut関数を連続で複数回呼び出す場合は、2回目以降の呼び出しでは、CLOCK信号の最初の部分は不定ではなく、電圧がLに確定しています。

DATA信号は、shiftOut関数の第1引数で指定されたピンから出力される信号を表しています。

DATA信号の最初の部分も不定です。この部分がLになるかHになるかは、shiftOut関数が呼び出される直前に、別のshiftOut関数の呼び出しや、digitalWrite関数の呼び出しなどにより、DATA信号にLHの内、どちらの電圧が出力されたかにより決まります。

shiftOut関数が呼び出されると、DATA信号にまず第4引数(val)のビット0(LSB)が出力されます。

DATA信号にvalのビット0が出力されている間に、CLOCK信号が一度Hになって、直後にLに戻ります。

その次にDATA信号にvalのビット1が出力され、その出力中にCLOCK信号が一度Hになって、直後にLに戻ります。

同様の事が合計8回繰り返され、最後の繰り返しの時は、DATA信号にvalのビット7(MSB)が出力され、その出力中にCLOCK信号が一度Hになって、直後にLに戻ります。

最後の繰り返しの時に、CLOCK信号がLに戻ったら、DATA信号にはvalのビット7を出力したままで、shiftOut関数から帰ってきます。

1つのビットをDATA信号に出力し続けている間に、CLOCK信号が1度立ち上がって1度立ち下がるため、Dフリップフロップや、あるいはDフリップフロップをカスケード接続したシフトレジスタでデータを受け取る場合、ポジティブエッジトリガでもネガティブエッジトリガでもデータを取得できます。

 また、CLOCK信号がHの状態でshiftOut関数が呼び出されると、DATA信号にビット0を出力している間にCLOCK信号は立ち上がりませんから、データを受信する機器がCLOCK信号の立ち上がりでデータを取り込む場合は、データを1ビット取りこぼしてしまいます。

この取りこぼしを防ぐためには、あらかじめ一度CLOCK信号をLに初期化しておき、shiftOut関数を呼び出す前にCLOCK信号の電圧をLに確定しておく必要があります。初期化を行った場合のshiftOut関数のタイミングチャートを図2に示します。

注:データをCLOCK信号の立ち下がりで取り込む場合(SPI通信ならモード1の場合)は、CLOCK信号を初期化しておく必要はありません。

図2、LSBファーストの場合のタイミングチャート(CLOCK信号をLに初期化)
↑ 画像をクリックすると拡大
図2、LSBファーストの場合のタイミングチャート(CLOCK信号をLに初期化)

2-2.MSBファーストの場合の出力波形

MSBファーストの場合のタイミングチャートを図3に示します。

図3、MSBファーストの場合のタイミングチャート(CLOCK信号の初期化なし)
↑ 画像をクリックすると拡大
図3、MSBファーストの場合のタイミングチャート(CLOCK信号の初期化なし)

MSBファーストの場合のタイミングチャートは、LSBファーストの場合のタイミングチャート(図1)と比較すると、DATA信号に出てくるval(第4引数)の内容のビット順だけが異なります。LSBファースト(図1)の場合はLSBが最初に出力され、最後にMSBが出力されましたが、MSBファースト(図2)の場合はMSBが最初に出力され、最後にLSBが出力されます。

MSBファーストの場合も、データを受信する機器が、CLOCK信号の立ち上がりでデータを取り込むなら、最初に一度、CLOCK信号をLに初期化してからshiftOut関数を呼ばないと、最初のビットを取りこぼします。CLOCK信号を初期化した時のshiftOut関数のタイミングチャートを図4に示します。

図4、MSBファーストの場合のタイミングチャート(CLOCK信号をLに初期化)
↑ 画像をクリックすると拡大
図4、MSBファーストの場合のタイミングチャート(CLOCK信号をLに初期化)

SPI通信ではMSBファーストでデータを送る事になっているので、SPI機器ににデータを送る目的でshiftOut関数を使用する場合は、第3引数にMSBFIRSTを渡します。

shiftOut関数では、1ビットの情報をDATA信号に出力している間に、CLOCK信号が一度立ち上がって再び立ち下がるため、クロックの立ち上がりでデータを取得するモード0の機器にでも、クロックの立下りでデータを取得するモード1の機器にでも、データを送信できます。(図5参照)

ただし、shiftOut関数は、必ず正極性のクロックパルスを発生するため、負極性のクロックパルスを要求するモード2やモード3の機器へのデータの送信には使えません。

参考:SPI通信をする場合は、CLOCK信号をSCLK信号と読み替えてください。またDATA信号は、MOSI信号と読み替えてください。SS信号については、shiftOut関数で生成する事はできませんので、別途digitalWrite関数で生成する必要があります。

図5、(参考)SPI通信における4つのモード
↑ 画像をクリックすると拡大
図5、(参考)SPI通信における4つのモード

これら4つのモードの内、shiftOut関数を使って実現できるのは、クロックパルスが正極性の(クロックが出ていない時にSCLK信号がLになる)モード0とモード1です。クロックパルスが負極性の(クロックが出ていない時にSCLK信号がHになる)モード2とモード3は、shiftOut関数では実現できません。

3.shiftOut関数を使う前に必要な初期化

shiftOut関数はピンの入出力モードを変えませんので、CLOCK信号に使うピンとDATA信号に使うピンとを、あらかじめpinMode関数により出力モード(OUTPUT)に設定しておく必要があります。

また、データを受信する機器がCLOCK信号の立ち上がりでDATA信号を読み込む場合は、CLOCK信号はLに初期化されていなければなりませんので、digitalWrite関数によりL(LOW)に初期化しておかなければなりません。

これらの初期化は、スケッチの実行の最初に1度だけ行えばいいので、通常はsetup関数内に記述します。

4.Arduinoに74HC595を接続して出力ピンを拡張する場合にshiftOut関数を使う例

shiftOut関数を使うスケッチの例として、Arduinoに74HC595を接続して出力ピンを拡張する回路(図6)の制御を、shiftOut関数を用いて行うスケッチを紹介します。

図6、Arduinoに74HC595を接続して出力ピンを拡張する回路
↑ 画像をクリックすると拡大
図6、Arduinoに74HC595を接続して出力ピンを拡張する回路

この回路では、ArduinoのデジタルI/Oピンを3個消費して、74HC595上に8個の出力ピンを拡張しますので、差し引き5個の出力ピンが増える事になります。

74HC595にLSBファーストでデータを送信する場合のタイミングチャートを図7に示します。

図7、LSBファーストでデータを74HC595に送信する場合のタイミングチャート
↑ 画像をクリックすると拡大
図7、LSBファーストでデータを74HC595に送信する場合のタイミングチャート

この図でXと書いてある部分(背景が水色の部分)は、Don't care(LでもHでも構わない)を表しています。また、Uと書いてある部分(背景がオレンジ色の部分)は、不定(LHか分からない)を表しています。

このタイミングチャートにおいて、Arduinoから74HC595に送信する制御信号はSRCLK、RCLK、SERの3本です。これらの内、SRCLKとSERの2本については、shiftOut関数で生成できます。RCLK信号はshiftOut関数では生成できませんので、別途digitalWrite関数で生成する必要があります。

図7のタイミングチャートを踏まえて、作成したスケッチを、リスト1に示します。

リスト1、74HC595上の出力ピンに信号を出力するテストスケッチCOPY
const int SER  =2; // SER制御用にするピンの番号を宣言
const int SRCLK=3; // SRCLK制御用にするピンの番号を宣言
const int RCLK =4; // RCLK制御用にするピンの番号を宣言

void setup()
{
  initHc595();
} // setup

void loop() {
  static uint8_t cnt=0; // 74HC595へ出力する値を格納するカウンタ変数。uint8_tは8ビット符号なし整数。staticを付けるとloop関数を抜けても値を保持し続ける
  outputOneByte(cnt++,LSBFIRST); // iをLSBファーストで74HC595に送信
  delay(100); // 0.1秒待つ
} // loop

// 74HC595の制御用ピンおよび74HC595を初期化する
void initHc595()
{
  // 74HC595制御用ピンを出力モードにする
  pinMode(SER,OUTPUT);
  pinMode(SRCLK,OUTPUT);
  pinMode(RCLK,OUTPUT);

  // SRCLKとRCLKをLOWにする(これらのピンはデータを送信していない時はLOWであるべき)
  digitalWrite(SRCLK,LOW);
  digitalWrite(RCLK,LOW);

  // 0を送信して74HC595のパラレル出力ピンを全て0にする(74HC595の初期状態を気にしない場合は省略可能)
  outputOneByte(0,LSBFIRST);
} // initHc595

// 74HC595に1バイトを送信する。valは送信するデータ。
// bitOrderにLSBFIRSTを指定するとLSBファーストで送信。bitOrderにMSBFIRSTを指定するとMSBファーストで送信。
void outputOneByte(uint8_t val,uint8_t bitOrder)
{
  // シフトレジスタにデータを送信
  shiftOut(SER,SRCLK,bitOrder,val);

  // ストレージレジスタにデータを転送
  digitalWrite(RCLK,HIGH); // RCLKを立ち上げる(この時に74HC595のシフトレジスタのパラレル出力がストレージレジスタに転送され、74HC595のしパラレル出力端子にデータが出力される)
  digitalWrite(RCLK,LOW ); // RCLKを立ち下げる(次にRCLKを立ち上げるため)
} // outputOnebyte

このスケッチは、0~255のデータを74HC595のQA(MSB)~QH(LSB)の端子に出力し、255まで出力したら、次に0に戻るという動作を繰り返します。

スケッチの最初でSER、SRCLK、およびRCLKの3つの定数が宣言されていますが、それぞれSER信号用のピンの番号、SRCLK信号用のピンの番号、およびRCLK信号用のピンの番号を表しています。これらの定数の値を変える事により、自由にArduinoのピン配置を変えられます。

このスケッチでは、initHc595関数とoutputOneByte関数の2つの関数を定義しています。

initHc595関数は、制御ピンをpinMode関数で出力ピンに設定し、またSRCLK信号とRCLK信号の初期値をLに設定しています。

outputOneByte関数が、データを74HC595に送信する関数です。この関数の中で、shiftOut関数を呼び出しています。

shiftOut関数を使って74HC595を制御する方法については、74HC595を使ってArduinoの出力ピンを拡張する方法(7)という記事で詳しく説明していますので、詳細な情報についてはそちらをご覧ください。

関連用語

関連ページ

Arduino 電子工作
このサイトの記事が本になりました。
書名:Arduino 電子工作
ISBN:978-4-7775-1941-5
工学社の書籍の内容の紹介ページ
本のカバーの写真か書名をクリックすると、Amazonの書籍購入ページに移動します。