2019年10月01日 | 公開。 |
4ページではLSBファーストで74HC595にデータを送信する方法を説明し、5ページではMSBファーストで74HC595にデータを送信する方法を説明しました。
この項では、両者のスケッチを統合して、LSBファーストとMSBファーストの両方に対応できるスケッチの作り方を説明します。
3ページでも説明しましたが、図12に示す配線で、Arduinoと74HC595がつながっている前提で、スケッチを作ります。
この回路を使って、LSBファーストで74HC595にデータを送信するには、4ページのリスト10に示すoutputOneByteLsbFirst関数を使いました。
また、MSBファーストで74HC595にデータを送信するには、5ページのリスト13に示すoutputOneByteMsbFirst関数を使いました。
今度は、outputOneByteLsbFirst関数とoutputOneByteMsbFirst関数を統合したoutputOneByte関数を作り、LSBファーストとMSBファーストのどちらでもデータを送信できるようにします。LSBファーストにするかMSBファーストにするかは、引数により指定する事にします。
outputOneByte関数をリスト16に示します。
// 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ファーストで送信されます。
注:LSBFIRSTやMSBFIRSTは、後述するshiftOut関数のためにあらかじめ宣言された定数です。これらの定数は宣言なしで使えます。
outputOneByte関数の中身は単純です。
if文で、もしbitOrderがLSBFIRSTなら、74HC595内部のシフトレジスタにデータを送信するためのforループとして、outputOneByteLsbFirst関数で使った、LSBファースト用のforループを使います。
if文で、もしbitOrderがLSBFIRSTではなければ、74HC595内部のシフトレジスタにデータを送信するためのforループとして、outputOneByteMsbFirst関数で使った、MSBファースト用のforループを使います。
if文の次は、2つのdigitalWrite関数で、RCLK信号に正のクロックパルスを1つ送り、74HC595内部のストレージレジスタにシフトレジスタの出力を転送し、実際に送信したデータを74HC595のQA~QHの端子に出力します。
outputOneByteLsbFirst関数とoutputOneByteMsbFirst関数が統合され、関数名がoutputOneByteになったので、それに伴い、初期化用のinitHc595関数も、一部作り変える必要があります。作り変えたinitHc595関数をリスト17に示します。
// 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ページのリスト12のinitHc595関数と比べると、変わっているのは次の1行だけです。
outputOneByte(0,LSBFIRST);
第2引数にLSBFIRSTを指定している点に注意してください。後にoutputOneByte関数を使う際には、LSBファーストにするのかMSBファーストにするのか分からないのですが、0を送信する場合はLSBファーストであれMSBファーストであれ同じ波形になるので、LSBファーストで送っています。
ここでsetup関数やloop関数や使用するピンを指定する定数の宣言などを追加して、実際に動作するスケッチにしたのがリスト18です。
// 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が一番早く点滅する様子が分かると思います。
次のページでは、shiftOut関数を使って74HC595にデータを送信する方法について説明します。