74HC595を使ってArduinoの出力ピンを拡張する方法(6)

このページをスマートフォンなどでご覧になる場合は、画面を横長にする方が読みやすくなる事があります。
目次へ  前のページへ (1) (2) (3) (4) (5) (6) (7) (8) 次のページへ
2019年10月01日 公開。

4-1-5.digitalWrite関数を使って1つの74HC595を制御するスケッチを作る方法(LSBファースト・MSBファースト両対応)

4ページではLSBファーストで74HC595にデータを送信する方法を説明し、5ページではMSBファーストで74HC595にデータを送信する方法を説明しました。

この項では、両者のスケッチを統合して、LSBファーストとMSBファーストの両方に対応できるスケッチの作り方を説明します。

広告

3ページでも説明しましたが、図12に示す配線で、Arduinoと74HC595がつながっている前提で、スケッチを作ります。

図12(再掲)、Arduinoに1つの74HC595を接続する場合の配線図
↑ 画像をクリックすると拡大
図12(再掲)、Arduinoに1つの74HC595を接続する場合の配線図

この回路を使って、LSBファーストで74HC595にデータを送信するには、4ページリスト10に示すoutputOneByteLsbFirst関数を使いました。

また、MSBファーストで74HC595にデータを送信するには、5ページリスト13に示すoutputOneByteMsbFirst関数を使いました。

今度は、outputOneByteLsbFirst関数とoutputOneByteMsbFirst関数を統合したoutputOneByte関数を作り、LSBファーストとMSBファーストのどちらでもデータを送信できるようにします。LSBファーストにするかMSBファーストにするかは、引数により指定する事にします。

outputOneByte関数をリスト16に示します。

リスト16outputOneByte関数(digitalWrite関数使用版)COPY
// 74HC595に1バイトを送信する。valは送信するデータ。
// bitOrderにLSBFIRSTを指定するとLSBファーストで送信。bitOrderにMSBFIRSTを指定するとMSBファーストで送信。
void outputOneByte(uint8_t val,uint8_t bitOrder)
{
  const int DATA_BITS=8; // 送信するデータのビット数

  if(bitOrder==LSBFIRST) {
    // シフトレジスタにデータを送信(LSBファースト)
    for(int i=0; i<DATA_BITS; i++) {
      digitalWrite(SER,(val&1) ? HIGH : LOW); // SERにvalの最下位ビットを出力
      digitalWrite(SRCLK,HIGH); // SRCLKを立ち上げる(この時74HC595がシフト動作)
      digitalWrite(SRCLK,LOW ); // SRCLKを立ち下げる(次にSRCLKを立ち上げるため)
      val>>=1; // valを1ビットだけ右シフト
    } // for i
  } else {
    // シフトレジスタにデータを送信(MSBファースト)
    for(int i=0; i<DATA_BITS; i++) {
      digitalWrite(SER,(val & 0x80) ? HIGH : LOW); // SERにvalの最上位ビットを出力
      digitalWrite(SRCLK,HIGH); // SRCLKを立ち上げる(この時74HC595がシフト動作)
      digitalWrite(SRCLK,LOW ); // SRCLKを立ち下げる(次にSRCLKを立ち上げるため)
      val<<=1; // valを1ビットだけ左シフト
    } // for i
  } // if

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

outputOneByteLsbFirst関数やoutputOneByteMsbFirst関数では、引数は、送りたいデータを渡すvalだけでしたが、outputOneByte関数は、第2引数として、LSBファーストにするかMSBファーストにするかを決める、bitOrderというuint8_t型(8ビット符号なし整数)の引数を取ります。

第2引数bitOrderに定数LSBFIRSTを渡すと、データはLSBファーストで送信されます。また定数MSBFIRSTを渡すと、データはMSBファーストで送信されます。

注:LSBFIRSTMSBFIRSTは、後述するshiftOut関数のためにあらかじめ宣言された定数です。これらの定数は宣言なしで使えます。

outputOneByte関数の中身は単純です。

if文で、もしbitOrderLSBFIRSTなら、74HC595内部のシフトレジスタにデータを送信するためのforループとして、outputOneByteLsbFirst関数で使った、LSBファースト用のforループを使います。

if文で、もしbitOrderLSBFIRSTではなければ、74HC595内部のシフトレジスタにデータを送信するためのforループとして、outputOneByteMsbFirst関数で使った、MSBファースト用のforループを使います。

if文の次は、2つのdigitalWrite関数で、RCLK信号に正のクロックパルスを1つ送り、74HC595内部のストレージレジスタにシフトレジスタの出力を転送し、実際に送信したデータを74HC595のQA~QHの端子に出力します。

outputOneByteLsbFirst関数とoutputOneByteMsbFirst関数が統合され、関数名がoutputOneByteになったので、それに伴い、初期化用のinitHc595関数も、一部作り変える必要があります。作り変えたinitHc595関数をリスト17に示します。

リスト17initHc595関数(LSBファースト・MSBファースト両対応)COPY
// 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

このinitHc595関数を、5ページリスト12initHc595関数と比べると、変わっているのは次の1行だけです。

outputOneByte(0,LSBFIRST);

第2引数にLSBFIRSTを指定している点に注意してください。後にoutputOneByte関数を使う際には、LSBファーストにするのかMSBファーストにするのか分からないのですが、0を送信する場合はLSBファーストであれMSBファーストであれ同じ波形になるので、LSBファーストで送っています。

ここでsetup関数loop関数や使用するピンを指定する定数の宣言などを追加して、実際に動作するスケッチにしたのがリスト18です。

リスト18、1つの74HC595を制御するテストスケッチ(LSBファースト・MSBファースト両対応)COPY
// oneByte.ino

const int SER  =2; // SER制御用にするピンの番号を宣言
const int SRCLK=3; // SRCLK制御用にするピンの番号を宣言
const int RCLK =4; // RCLK制御用にするピンの番号を宣言

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

void loop() {
  for(int i=0; i<256; i++) { // iを0から255までカウントアップ
    outputOneByte(i,LSBFIRST); // iをLSBファーストで74HC595に送信
    delay(100); // 0.1秒待つ
  } // for i

  delay(1000); // 1秒待つ

  for(int i=0; i<256; i++) { // iを0から255までカウントアップ
    outputOneByte(i,MSBFIRST); // iをMSBファーストで74HC595に送信
    delay(100); // 0.1秒待つ
  } // for i

  delay(1000); // 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)
{
  const int DATA_BITS=8; // 送信するデータのビット数

  if(bitOrder==LSBFIRST) {
    // シフトレジスタにデータを送信(LSBファースト)
    for(int i=0; i<DATA_BITS; i++) {
      digitalWrite(SER,(val&1) ? HIGH : LOW); // SERにvalの最下位ビットを出力
      digitalWrite(SRCLK,HIGH); // SRCLKを立ち上げる(この時74HC595がシフト動作)
      digitalWrite(SRCLK,LOW ); // SRCLKを立ち下げる(次にSRCLKを立ち上げるため)
      val>>=1; // valを1ビットだけ右シフト
    } // for i
  } else {
    // シフトレジスタにデータを送信(MSBファースト)
    for(int i=0; i<DATA_BITS; i++) {
      digitalWrite(SER,(val & 0x80) ? HIGH : LOW); // SERにvalの最上位ビットを出力
      digitalWrite(SRCLK,HIGH); // SRCLKを立ち上げる(この時74HC595がシフト動作)
      digitalWrite(SRCLK,LOW ); // SRCLKを立ち下げる(次にSRCLKを立ち上げるため)
      val<<=1; // valを1ビットだけ左シフト
    } // for i
  } // if

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

loop関数を工夫して、LSBファーストとLSBファーストの違いを、分かる様にしてあります。まずLSBファーストで0から255まで出力データをカウントアップして、1秒休んでから、次にMSBファーストで0から255まで出力データをカウントアップし、1秒休む動作を繰り返す様にしてあります。

写真9の回路(回路図は3ページ図15)の様に、LEDをQA~QHの各端子に接続した基板で、でリスト18のスケッチを動作させると、LSBファーストで送信している時は、LED8が一番速く点滅し、MSBファーストで送信している時は、LED1が一番早く点滅する様子が分かると思います。

写真9(再掲)、74HC595の動作確認用の基板のおおまかな部品配置
↑ 画像をクリックすると拡大
写真9(再掲)、74HC595の動作確認用の基板のおおまかな部品配置

次のページでは、shiftOut関数を使って74HC595にデータを送信する方法について説明します。

目次へ  前のページへ (1) (2) (3) (4) (5) (6) (7) (8) 次のページへ

このページで使われている用語の解説

関連ページ

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