(農業)情報工学・課題 (2020/12/17))

 Simlation入門(2)

前回、TinkerCadのセットアップを行ったが、今回の講義では更に回路を作成して、その使い方を体験する。今回もシミュレーション環境はtinkercadである。
2-1.光センサの読み取り
ここでは、光センサ(CdSセル)を利用したLEDの点灯制御を行う。CdSセルは照度が低いと抵抗値が大きくなり、高いと抵抗値が小さくなる。その抵抗値の違いを利用して、LEDの点灯制御を行ってみる。
最初は、まず、CdSの数値の読み取りに挑戦してみる。アナログポートとシリアルモニタ機能を利用する。また、スケッチ(プログラム)は、テキストモードで記入することとする。(ブロックモードでも記述できるが、授業ではテキストモードとする)

<部品>
CdS(フォトセル):g19-g20
2.20KΩ抵抗:f20-f24
<配線>
黒:GND(-) j8, j19
赤:5V(+) j24
白:Analog(A0) - j20
CdS(硫化カドミウム)は、光が当たると抵抗値が変化する性質がある。つまり、光センサーとして利用する事が出来る。
この回路では、CdSと直列に抵抗(2.2Kオーム)を配置して5Vを印可し、CdSの電圧をアナログ入力ポート(A0)で計測する事によって、明るさを計測している。
スケッチは次の様になる。

        // CdSセンサの計測
          int val=0; //入力される値を格納する為の変数(0 - 1023)
          void setup() {
              Serial.begin(9600); //モニターに出力するための設定
          }
                  
          void loop() {
              val=analogRead(0);//ANALOG INの0番ピンからデータを受け付ける
              Serial.println(val); //入力された値をモニターに出力
              delay(500); // 回路の安定化
          }
      

2-2.光センサでLEDの制御
これで、CdSセンサーの変化が確認できた。次に、この数値を使ってLEDの点灯制御を行う。
今度は、LEDに印可する電圧に変化をつけて、LEDの明るさを変化させる事を試みる。そのために、LEDに出力するポートとしては、アナログ電圧として3番ポートを用いて、出力している。
(注):実はこの説明は正確では無い、3番ポートへの出力はPWM制御で行っている。詳しくは、この資料の「参考」部分に記述した。

<部品>
1KΩ抵抗:f8-f12
LED:g12-g13
CdS(フォトセル):g19-g20
2.20KΩ抵抗:f20-f24
<配線>
黒:GND(-) j8, j19
赤:5V(+) j24
黄:OutPut(D3) - j13
白:Analog(A0) - j20
LEDに対しては、PWM出力ポート(3)を利用して、計測した明るさ(というか暗さ)に対応した数値を出力して、「暗いときにLEDが明るく点灯する」という機能を持たせている。
スケッチは次の様になる。

        // CdSセンサでLEDの制御(明るさを4段階で制御)
        int val=0; //入力される値を格納する為の変数(0 - 1023)
        int ledVal = 0; //LEDに出力する値の変数 (0 - 255)
        int Level1 = 50;  //周囲の明るさレベル1
        int Level2 = 100;  //周囲の明るさレベル2
        int Level3 = 150;  //周囲の明るさレベル3
        int Level4 = 200;  //周囲の明るさレベル4
        void setup() {
        Serial.begin(9600); //モニターに出力するための設定
        }
        
        void loop() {
        val=analogRead(0);//ANALOG INの0番ピンからデータを受け付ける
        ledVal = val/4; //LED出力用の値を変数に格納
        Serial.println(ledVal); //入力された値をモニターに出力
        //明るさを4段階に設定する
          if(ledVal < Level1){ // 入力値がLevel1以下
            analogWrite(3,0); //出力は0
          }
          else if(ledVal < Level2){ // Level1 - Level2
            analogWrite(3,100); //出力は100
          }
          else if(ledVal < Level3){  // Level2 - Level3
            analogWrite(3,150); //出力は150
          }
          else if(ledVal < Level4){ // Level3 - Level4
            analogWrite(3,200); //出力は200
          }
          else{ // > Level4
            analogWrite(3,255); //出力は255 
          }
          delay(100); // 回路の安定化
        }
      
このスケッチを実行する際に、「コード」から「シリアルモニタ」を確認すると、CdSの測定値を見ることが出来る。アナログ出力は(0-1023)の10ビットであるが、ここでは4で割った(0-255)の8ビットにしている。
シミュレーション開始後、フォトセルをクリックして、明るさを変化させて、数値の変化を見ると、理解が出来ると思う。明るさの対応を見るために、スケッチ内の数値を変化させてLEDのレベルがどのように変わるかを試して見ると良い。(コンピュータ上なので、あまり再現性が高くない可能性がある。)
2-3.音の出力
Arduinoからの音の出力も可能である。音は圧電素子(スピーカー)を決まった周期で発振させる事によって出力できる。
Arduinoには音の関数があるので、それを利用すると簡単にビープ音を出すことができる。なおこの機能で出力される波形は矩形波なので音質はあまり良くない(耳障り)なので、実施する際には気を付けること。
接続は、圧電素子の一方にGNDを、一方にデジタルポートを接続するのみである。なお、tone関数の実行中は、PWMの3番ポートと11番ポートは利用できない。また音の停止は、noTone(ポート番号); である。

<接続ポート>
圧電素子の陽極(+)を、12番出力
陰極(-)を、GND

    // https://novicengineering.com/ を参照した。
    // ドレミを順番に出力するスケッチ。
    // 音を出さなくするには、noTone(PIN); 

    #define BEATTIME 300  // 音の持続時間を300msにしている。
    #define PIN 12 // 12番ピンに出力。
    
    #define DO 262  // ドの周波数は262Hz
    #define RE 294
    #define MI 330
    #define FA 349
    #define SO 392
    #define RA 440
    #define SI 494
    #define HDO 523
    
    void setup() {
    }
    
    void loop() {
      tone(PIN,DO,BEATTIME) ; // ド
      delay(BEATTIME) ;
      tone(PIN,RE,BEATTIME) ; // レ
      delay(BEATTIME) ;
      tone(PIN,MI,BEATTIME) ; // ミ
      delay(BEATTIME) ;
      tone(PIN,FA,BEATTIME) ; // ファ
      delay(BEATTIME) ;
      tone(PIN,SO,BEATTIME) ; // ソ
      delay(BEATTIME) ;
      tone(PIN,RA,BEATTIME) ; // ラ
      delay(BEATTIME) ;
      tone(PIN,SI,BEATTIME) ; // シ
      delay(BEATTIME) ;
      tone(PIN,HDO,BEATTIME) ; // ド
      delay(BEATTIME) ;
    }
  

2-4.温度センサ
今度は、温度センサを接続して、その数値を読み取ってみる。今回接続するセンサはTMP36である。 以上の事から、0℃の時の出力電圧Voutは、0.5Vとなり、温度Tは、100xVout−50で計算できる。
なお、Analogポートで読み取る電圧Voutは、0-5Vが、0-1023の10ビット値として読み取られる事に留意する必要がある。
また、TMP36のような電子部品を利用するときは、電圧変動やノイズ混入を防ぐために、「パスコン」(バイパスコンデンサー)を部品と並列に設置する。今回は、0.1μFのパスコンを挿入している。

<部品>
TMP36:g17,18,19
コンデンサ:c17,c18
<配線>
黒:GND:(-),i19,f19-e19
赤:5V:(+),i17,f17,e17
黄色:A1,j18
接続方法とスケッチ例:
今回のTMP36センサは、電源線(GNDと5Vの2本)と信号線(1本のみ)の合計3本をArduinoUNOに接続する。電源線はArduinoUNOのGNDと5V、信号線は、今回、1番ポートを利用する。

      const int PIN_TMP36 = 1; // TMP36の入力ポートをA1とする。
    void setup()
    {
      Serial.begin(9600);	//シリアルモニタの設定
    }

    void loop()
    {
      float a = (float) analogRead( PIN_TMP36 );	//アナログ入力
      float v = a * 5.0 / 1023.0;	//電圧値に変換
      float t = v * 100.0 - 50.0;	//温度値に変換
      Serial.println( t );	//シリアルモニタへ書き出し
      delay(1000);	// 回路の安定化
    }
このスケッチを転送して、「ツール」から「シリアルモニタ」を開くと、気温が読み取れる。
さらに、回路上のTMP36をクリックして、温度を変化させると、数値も変化する。
27.12
27.12
27.12
-20.12
-20.12
.....

2-5.LCDの接続
次に、LCDに文字を表示する課題に取り組む。
今回利用するLCDの1602Aは、tinkercadの基本コンポーネントには入っていないので、画面右側で、コンポーネント「すべて」を指定して選択する。この1602Aは、基本的な英文字と数字を、16文字x2行表示できる。Arduinoから文字列を送って、表示させることができる。まず全体を、左図のように配置する。

詳細な配線は、次の通りである。


<接続ポート>
ArduinoLCD1602A
GND(黒)GND,V0,RW,LED(右端)
5V(赤)VCC
10(橙)DB4
11(橙)DB5
12(橙)DB6
13(橙)DB7
6(緑)E
4(黄)RS
なお、LCD1602AのLED+側(バックライト用)は、1KΩの抵抗で電流を下げて、接続している。
スケッチ例:

  #include <LiquidCrystal.h>	//LCD制御のライブラリをインクルード
    LiquidCrystal lcd( 4, 6, 10, 11, 12, 13 );	//LCDの設定
    
    void setup() {
      lcd.begin( 16, 2 );	//LCDの初期化
      lcd.clear();			//表示のクリア
      lcd.setCursor(0, 0);	//表示位置
      lcd.print("Hello, world!");	//LCDに文字列の表示!
    }
    
    void loop() {
    }
このスケッチで、シミュレーションの実行を行うとLCDに表示される。
今回の課題:提出は不要

今回はArduinoのシミュレーションで、いろいろな回路を作ってみた。上手くいかない場合には、少しずつ修正して自分で体験して欲しい。
なお、余裕があれば、温度の読み取り値をLCDに表示させる事に挑戦してみよう。2-4と2−5を組み合わせれば、表示できる筈である。

リンク集


以下は参考(2019年の例など)

PWMの説明と
Lチカのバリエーション

Lチカでは、点滅の周期を変更させることができた。この点滅の周期を工夫すると、人間の目には明るさが変化したように見える制御も可能である。点灯時間を5ms、消灯時間を15msにすると、約半分の明るさに見える筈である。また、点灯時間を1ms、消灯時間を19msにすると更に暗くなる筈である。→時間のある人は、やってみよう
Arduinoでは、この方式をマイコン上でパルス制御として組み込んである。それがPWM(Pulse Width Modulation)機能である。ただ、このPWM機能を用いる事の出来る出力ピンは、3,5,6,9,10,11である。(ピン番号の横に~(チルダ)が表示されている。プログラム的には次の様になる。(この例では、11番ピンでLED出力をしている。)

const int LED_PIN=11; // No 11 を出力ピン
const int DUTY = 250; // Duty は、出力強度(0−255) 

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  analogWrite(LED_PIN, DUTY);
}
このPWMを応用すると、例えば次の様に、徐々にLEDを明るくするといった点灯も可能になる。
  
const int LED_PIN = 11;
const int WAITTIME = 100; // 徐々に明るくなる制御の待ち時間を100msに
const int STEP = 5; // 明るくなるタイミングを5ステップずつ増やす。

void setup(){
    pinMode( LED_PIN, OUTPUT ); // 11番ピンを出力に指定
}

void loop(){
    int i;
    i = 0;
    while ( i <= 255 ){
        analogWrite( LED_PIN, i );
        delay( WAITTIME );
        i = i + STEP;
    }
    delay(1000); // 1秒間そのままで
}

スイッチを使う
電子回路でよく利用されるスイッチに「タクトスイッチ」がある。これはスイッチのボタンを押している時に回路がつながり、離すと切れるスイッチである。
電子回路においては基本的に端子の電圧はH(High)またはL(LOW)の状態が期待されている。スイッチの取り扱いでも、そのどちらかの状態を保つことが期待されるため、スイッチが切れた状態でも、電圧が不安定にならないようにスイッチの片側には電圧を保障するための「プルアップ抵抗」(または「プルダウン抵抗」)を置くことが基本である。
Arduinoに置いては、そのプルアップ抵抗が回路に内蔵されているので、その回路を用いてスイッチの制御を行う事とする。実際のスケッチは次の様になる。
スイッチの接続としては、タクトスイッチの左側にArduinoUNOのGND信号線を、右側に7番ピンの信号線を接続する。

    const int DIN_PIN = 7; // スイッチの接続ピン
    const int LED_PIN = 12; // LEDの接続ポート
    
    void setup(){
        pinMode( DIN_PIN, INPUT_PULLUP );  // スイッチにプルアップ設定
        pinMode( LED_PIN, OUTPUT );
    }
    
    void loop(){
        int value;  // スイッチの状態
        
        value = digitalRead( DIN_PIN ); // スイッチ状態の確認
    
        if ( value == HIGH ){     // 押されていれば、HIGH
            digitalWrite( LED_PIN, LOW ); // LEDはLOWで点灯
        }
        else{
            digitalWrite( LED_PIN, HIGH );
        }
    
        delay( 100 ); // スイッチのチャタリング防止
    }
  

温湿度モジュールDHT11の利用
このセンサを利用するには、ライブラリの利用が簡単である。以下の手順でArduinoIDEにライブラリをインストールする。
「ツール」⇒「ライブラリを管理…」からインストールする。※下記2つともインストールが必要である。
1.タイプで「推奨」を選択、「DHT sensor library」でフィルタリング
2.タイプで「推奨」を選択「Adafruit Unified Sensor」でフィルタリング
接続方法とスケッチ例:
今回のDHT11モジュールは、既にプルアップ抵抗が組み込まれている。そのため電源線(GNDと5Vの2本)と信号線(1本のみ)の合計3本をArduinoUNOに接続する。電源線はArduinoUNOのGNDと5V、信号線は、今回、8番ポートを利用する。

  //温湿度センサモジュールを使って温度、湿度を測定するスケッチ
  //(https://omoroya.com/arduino-lesson11/ から引用)
  //
  #include "DHT.h" //ライブラリインクルード
  
  #define DHT_Pin 8 //DHT11のDATAピンを定義
  #define DHT_Type DHT11 //センサの型番定義 DHT11,DHT22など
  
  DHT dht(DHT_Pin, DHT_Type); //センサ初期化
  
  /* 計測値設定 */
  float humidity = 0.0f; //湿度(実数値)
  float tempC = 0.0f; //摂氏温度(実数値)
  
  void setup() {
  Serial.begin(9600); //シリアル通信のデータ転送レートを9600bpsで指定。bpsはビット/秒。
  Serial.println("DHT11 読み取り結果"); //画面に表示
  dht.begin(); //温湿度センサー開始
  }
  
  void loop() {
  delay(2000); //2秒待つ データの読み出し周期1秒以上必要。
  
  humidity = dht.readHumidity(); //湿度の読み出し
  tempC = dht.readTemperature(); //温度の読み出し 摂氏
  
  /* 読み取れたかどうかのチェック */
  if (isnan(humidity) || isnan(tempC)) {
  Serial.println("読み取り失敗!");
  return;
  }
  
  /* 以下読み取り値の表示 */
  Serial.print("湿度: ");
  Serial.print(humidity);
  Serial.println("[%]");
  Serial.print("温度: "); 
  Serial.print(tempC);
  Serial.println("[℃]");
  }
このスケッチを転送して、ArduinoIDEの「ツール」から「シリアルモニタ」を開くと、現在の気温と湿度が読み取れる。
DHT11 読み取り結果
湿度: 47.00[%]
温度: 19.50[℃]
湿度: 47.00[%]
温度: 19.40[℃]
湿度: 47.00[%]
温度: 19.40[℃]
.....