ArduinoでNOT・AND・OR回路を再現する

プログラムと電気回路の勉強を兼ねて、論理回路をArduinoマイコンを使って再現してみようと思います。まずは基本の論理回路であるNOT・AND・ORからやってみます。

基本的な考え方として、

考え方
  1. 論理入力は、タクトスイッチのON-OFFをdigitalReadする。
  2. 論理出力は、LEDの点灯・消灯で表す。
  3. 各基本回路は関数として作成し、loop関数内から呼び出す形で実行する。

という前提で行きます。そんなことをして何の意味があるのか?という素直な疑問が湧きますが、気にしないことにします。

NOT回路

結果1 とりあえず動くプログラム

#define s1 7
#define LED 13

void setup() {
  pinMode(s1, INPUT_PULLUP);        //スイッチは内部プルアップを利用して接続
  pinMode(LED, OUTPUT);
}

void loop(){
  NOT(s1,LED);
}

//NOT回路の関数
//引数として入出力ピン番号を指定できるようにした
void NOT(int inpin, int outpin) {
  int a;
  a = digitalRead(inpin);
  digitalWrite(outpin, a);
}

上記プログラムで、NOT動作するプログラムになりました。しかしこれだと拡張性がないので、

もう少し拡張性をもたせる
  1. スイッチからの入力だけでなく、他の論理回路の出力値を受け取って入力とする場合にも対応する(変数で動作モードを設定すれば対応できそう)
  2. ということは、この関数の出力も値として取得したいので、戻り値として返すようにする

以上の観点で改良してみました。

結果2 拡張したNOT回路

#define s1 7
#define LED 13
#define L1 12

void setup() {
  pinMode(s1, INPUT_PULLUP);        //スイッチは内部プルアップを利用して接続
  pinMode(LED, OUTPUT);
  pinMode(L1,OUTPUT);
}

void loop(){
  NOT(1,s1,LED);
  NOT(2,NOT(1,s1,L1),LED);         //このように入れ子で実行できる
                                   //この場合NOTのNOTなので入力=出力になる
}

//mode=1で通常動作 mode=2の場合は値を渡してそれをNOTする動作
//出力はint型で返すようにする
int NOT(int mode, int inp, int outpin) {
  int a;
  switch (mode) {
    case 1:
      a = digitalRead(inp);
      digitalWrite(LED, a);
      break;
    case 2:
      a = inp;
      a = !a;
      digitalWrite(outpin, a);
      break;
  }
  return a;
}

このようにして、引数としてモードを設定する値を指定してやります。モード1ならスイッチからの入力、モード2なら値として入力値を渡します。

AND回路

結果

//setup及びloop関数は省略

int AND(int mode, int inp1, int inp2, int outpin) {
  int a;
  switch (mode) {
    case 1:
      if (digitalRead(inp1) == 0 && digitalRead(inp2) == 0) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
      break;
    case 2:
      if (inp1 == 1 && inp2 == 1) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
  }
  return a;
}

関数の部分のみを記載しています。NOT回路と共通の考え方で、mode=1のときはスイッチの状態を入力とし、mode=2のときは値として入力値を渡して結果を返します。

OR回路

結果

setup,loop関数は省略

int OR(int mode, int inp1, int inp2, int outpin) {
  int a;
  switch (mode) {
    case 1:
      if (digitalRead(inp1) == 0 || digitalRead(inp2) == 0) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
      break;
    case 2:
      if (inp1 == 1 || inp2 == 1) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
  }
  return a;
}

こちらも考え方は同じ。これで基本の3回路が揃いました。

組み合わせ回路を再現する

上記の3つの基本回路を利用して、NAND回路3つの組み合わせ回路を再現してみます。

回路図

この回路を再現します。

上記回路は一見複雑ですが、実はOR回路です。NAND回路を3つ組み合わせるとOR回路に変換できます、的なアレです。

プログラム

#define s1 3
#define s2 4
#define LED 13
#define L1 12
#define L2 11
#define L3 10
#define L4 9
#define L5 8

void setup() {
  pinMode(s1, INPUT_PULLUP);
  pinMode(s2, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  pinMode(L1,OUTPUT);
  pinMode(L2,OUTPUT);
  pinMode(L3,OUTPUT);
  pinMode(L4,OUTPUT);
  pinMode(L5,OUTPUT);
}

void loop() {
 //回路一つずつ実行して変数に代入していく方法
  /*int a = AND(1, s2, s2, l2);  
  int b = AND(1, s2, s2, l3);
  int a1 = NOT(2, a, l4);
  int b1 = NOT(2, b, l5);
  int c = AND(2, a1, b1, l6);
  NOT(2, c, LED);*/

  //一行で一気に書くとこうなる
  NOT(2,AND(2,NOT(2,AND(1,s1,s1,l2),l4),NOT(2,AND(1,s2,s2,l3),l5),l6),LED);
  
}

int NOT(int mode, int inp, int outpin) {
  int a;
  switch (mode) {
    case 1:
      a = digitalRead(inp);
      digitalWrite(LED, a);
      break;
    case 2:
      a = inp;
      a = !a;
      digitalWrite(outpin, a);
      break;
  }
  return a;
}

int AND(int mode, int inp1, int inp2, int outpin) {
  int a;
  switch (mode) {
    case 1:
      if (digitalRead(inp1) == 0 && digitalRead(inp2) == 0) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
      break;
    case 2:
      if (inp1 == 1 && inp2 == 1) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
  }
  return a;
}

int OR(int mode, int inp1, int inp2, int outpin) {
  int a;
  switch (mode) {
    case 1:
      if (digitalRead(inp1) == 0 || digitalRead(inp2) == 0) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
      break;
    case 2:
      if (inp1 == 1 || inp2 == 1) {
        a = 1;
        digitalWrite(outpin, a);
      }
      else {
        a = 0;
        digitalWrite(outpin, a);
      }
  }
  return a;
}

int NAND(int mode, int inp1, int inp2, int outpin) {
  int a;
  switch (mode) {
    case 1:
      if (digitalRead(inp1) == digitalRead(inp2)) {
        a = 0;
        digitalWrite(outpin, a);
      }
      else {
        a = 1;
        digitalWrite(outpin, a);
      }
      break;
    case 2:
      if (inp1 == inp2) {
        a = 0;
        digitalWrite(outpin, a);
      }
      else {
        a = 1;
        digitalWrite(outpin, a);
      }
  }
  return a;
}

えらく長いですが、こんな感じになりました。回路一つ一つを順に実行して行き、結果を変数に格納しながら順次進めていく方法と、関数同士を入れ子にして一気に実行する方法と、どちらでも動かすことができました。

Tips!

各基本回路の出力ピンを別々に設定しているので、それぞれにLEDを接続しておけば、出力の途中経過を目で確認出来るようになります。

現状だと出力のフィードバックに関数レベルで対応できてない気がするので、もう少し改良の余地がありそうです。引き続き勉強してみることにします。

コメントを残す

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