Arduinoを使ってよう

小学校でもプログラミングの授業がはじまりました。プログラミングを勉強すると、考え方や物事の進め方を学ぶことができるそうです。

でも、ただ勉強するだけでは面白くないよね。そう、高専では目的を持ってプログラムを学びます。今日は熱中症対策組込システムを作製するぞ!

0.準備

袋の中身を確認しましょう。ちゃんと入っていますか?

入っているもの一覧

回路 が含まれている画像

自動的に生成された説明@マイコンボード

AUSB通信ケーブル

B温湿度センサー

CフルカラーLED

Dジャンパー線 メス−オス 7

E袋

 

 

 

 

1.使うマイコンボードはこれだ!

電子機器の部品

中程度の精度で自動的に生成された説明使うボードはこれだ! マイコンボードと呼ばれています。

真ん中にあって黒い四角いところから銀色の足が4方向に出ていて、合計で32本の銀色の端子があります。

これがマイコンボードの本体で、中にはコンピュータの計算を司るCPUCentral Processing Unitと呼ばれるコア部分があります。

その他LEDを点けたりスイッチの入力を読み取ったりある程度の情報を覚えることができるメモリが詰め込まれているぞ!


 

2.パソコンとマイコンボードを接続してみよう!

パソコンのUSBポートとマイコンボードをUSB通信ケーブルで接続します。

 

接続すると、マイコンボード上の電源ランプが青色に点灯します。

電源ランプが点灯していない人はスタッフに声をかけてください。ケーブルの接続不良か、あるいはマイコンボードが壊れているかもしれません。

電子機器の部品

中程度の精度で自動的に生成された説明

3.開発環境を動かしてプログラミングしてみよう!

プログラミングにはArduinoIDEという開発環境を使います。

緑色の顔のようなアイコンをダブルクリックします。

                     ※デスクトップにアイコンが無い場合は、スタートArduinoの順にクリックしてください。

* 家のコンピュータでやってみたい人は、「ArduinoIDE インストール」と検索して、家のパソコンにインストールしてみてね。10分もあればできるよ!

起動するとこんな感じ(下図)です。

グラフィカル ユーザー インターフェイス, アプリケーション, PowerPoint

自動的に生成された説明

ウィンドウの上にファイル名が示され、メニューバーと呼ばれる場所には「ファイル」「編集」「スケッチ」「ツール」「ヘルプ」などのメニューコマンドがあります。

 

プログラムを書いたら「ファイル」メニューから「保存」か「名前を付けて保存」をすることで、プログラムを保存することができます。なお、Arduinoではプログラムのことをスケッチといいます。

よく使うのは「」マークのボタンで示された、プログラムの検証です。これは自分で書いたプログラムがちゃんとマイコン上で動くかを検証するためのボタンです。

次によく使うのは「⇒」マークで示された、プログラムをマイコンに転送するボタンです。マイコンにプログラムを転送するとマイコンが自動的に動き始めます。

マイコンが動き始めてからよく使うのが、「虫眼鏡」のマークで示された、シリアルモニタを起動するボタンです。これを使うと、マイコンからのメッセージを表示するなど、マイコンと通信することができます。

プログラミングの準備

プログラミングに入る前に、開発環境の準備を行います。

メニューバーの「ツール」から「ボード」という場所が「Aruduino Uno」となっていることを確認してみてください。

もしなっていなかった場合は「ボード」から「Arduino AVR Boards」、表示される一覧から「Aruduino Uno」を選択してみてください。

グラフィカル ユーザー インターフェイス

低い精度で自動的に生成された説明

4.はじめてのプログラム開発 「Hello World!

最初は、マイコンに「 Hello!! 」と言わせるプログラムを作成してみましょう。

といっても、今回のマイコンには音を出すスピーカなどはついていません。ですので、マイコンに「 Hello!! 」という文字を出力させます。

ここで、文字を出力?と言われておかしいなと思った人もいるでしょう。そうです、マイコンにはディスプレイなど文字を表示する装置が付いていません。

そこでマイコンで出力した文字を、通信ケーブルを使ってパソコンのディスプレイに出力します。それを実現するのがシリアルモニタです。

シリアルモニタとは、マイコンとパソコンとを繋いでいる通信ケーブルでやり取りされている内容を表示してくれる便利なモニターなのです。

シリアルポートを設定

メニューバーの「ツール」から「シリアルポート」を選び、マイコンがUSBケーブルで接続されているシリアルポートを選びます。

下の図ではCOM3というのシリアルポートが表示されていますが、これはパソコンによって変わります。

もし、他のシリアルポートも表示されていて、次に行うシリアルポートの確認で失敗するようであれば、他のシリアルポートを選択してみてください。

グラフィカル ユーザー インターフェイス, アプリケーション

自動的に生成された説明

シリアルポートの確認

 

 

メニューバーの「ツール」から「ボード情報を取得」をクリックします。

 

ウィンドウが現れ「ボード情報」が表示されれば、シリアルポートが正しく設定されています。

 

 

 

 

 

うまく設定できていないと、ボード情報ウィンドウは現れず、コンソールにエラーメッセージが表示されます。

その場合には、シリアルポートの番号を変更するか、USBケーブルを抜き差ししてマイコンとパソコンがしっかりと接続されているかを確認しましょう。

グラフィカル ユーザー インターフェイス, テキスト, アプリケーション

自動的に生成された説明

 

プログラムを作ってみましょう

それでは下記のプログラムを打ってみましょう。マウスで枠内の文字を選択してコピー&ペーストすると楽です。

void setup() {
    // シリアル通信速度の設定
    Serial.begin(9600);
}

void loop() {
    // シリアルモニタにテキストを表示する
    Serial.println("  Hello!!  ");

    // 1秒間待機
    delay(1000);
}

プログラムを打ち終わったら「Ctrl」+「t」を同時に押してください。見やすいように自動的に整形してくれます。

動作の説明

まず、void setup()と呼ばれる関数のなかで、マイコンに必要な設定を行います。

具体的にはパソコンとマイコンの通信設定を行います。通信速度を9600bpsに設定します。

次に,void loop()と呼ばれる関数の中で、パソコンのシリアルモニタに「 Hello!! 」と表示します。

次に、1000ミリ秒、つまり1秒間停止します。

マイコンはvoid loop()という関数を繰り返し実行し続けるようにできているので、シリアルモニタには1秒おきに「 Hello!! 」という文字が表示されることになります。

 

 

 

 

*関数ってなに? 

プログラム言語では処理の固まりに名前を付けますが、それを関数といいます。

上のプログラムでは、void setup () void loop()という2つの関数があり、各々setuploopという関数名が付いています。

関数名の後の中カッコ始まり「{ 」から中カッコ終わり「 }」までの間に、マイコンに行わせたい処理を書きます。

プログラムの検証

 

検証が終わると、コンソールに「コンパイルが完了しました。」と表示されます。

プログラムに間違いがあると、コンソールにエラーの内容が表示されます。

下記の例は、文字の打ち間違いと、日本語をプログラム中に入れてしまった場合の例です。

 


プログラムをマイコンに転送(書き込み)

「ボードへの書き込みが完了しました」と出たら成功です。すでにマイコンは皆さんが書いたプログラムの内容を実行し始めています。次にマイコンの動作を確認してみましょう。


 

シリアルモニタを開く & 動作確認

シリアルモニタが現れます。

8行目の「 Hello!! 」を他の文字に変えたり、9行目のdelayの値を変更したりして再度マイコンボードに転送すると、表示やタイミングの変更ができます。

5.プログラム開発その1 「フルカラーLED

3色の色を表示できるLEDをマイコンに接続していろいろな色を表示させてみましょう。LEDには銀色に伸びる端子が4本ついています。

短い端子はアノードと呼ばれる端子でここに電圧を加えます。いちばん長いのがカソードと呼ばれます。

各色のアノードとカソードとをそれぞれプラスとマイナスにつなぐと赤、緑、青色に点灯します。

LEDとマイコンを配線 & プログラミング

電子機器, 回路, テーブル が含まれている画像

自動的に生成された説明

#define RLED 2
#define GLED 3
#define BLED 4

void setup() {
    // シリアル通信速度の設定
    Serial.begin(9600);

    // フルカラーLEDの設定
    pinMode(RLED, OUTPUT);
    pinMode(GLED, OUTPUT);
    pinMode(BLED, OUTPUT);
}

void loop() {
    // フルカラーLEDを赤色に点灯させる
    Serial.println("赤 RED");
    digitalWrite(RLED, HIGH);
    delay(1000);
    digitalWrite(RLED, LOW);

    // フルカラーLEDを緑色に点灯させる
    Serial.println("緑 GREEN");
    digitalWrite(GLED, HIGH);
    delay(1000);
    digitalWrite(GLED, LOW);

    // フルカラーLEDを青色に点灯させる
    Serial.println("青 BLUE");
    digitalWrite(BLED, HIGH);
    delay(1000);
    digitalWrite(BLED, LOW);
}

 

setup関数内のpinModeという命令OUTPUTを用いることで、2番ピンを赤色の出力モード、3番ピンを緑色の出力モード、4番ピンを青色の出力モードとします。

INPUTと打つと入力モードとなり、スイッチを接続した場合に使います。

loop関数内ではdigitalWriteという命令で、光らせたい色の番号のピン(赤色は2番、緑色は3番、青色は4番)の電圧を+5Vとします。指定した番号のピンに関連する色にLEDが点灯します。

次にdelay命令で1秒間待った後、再度digitalWrite命令を使い、光らせた色の番号のピンの電圧を0Vとします。そうするとLEDが消灯します。

これを赤緑青の順番に行い、loop関数の最初に戻る、という動作を繰り返します。

 

なお、「//」で始まる行はコメント行と言ってプログラムを説明するためのもので、マイコンの動作には関係しません。

一般的にはここは英語で書いてあります。今回は分かりやすいようにあえて日本語で書いています。

グラフィカル ユーザー インターフェイス, テキスト, アプリケーション, メール

自動的に生成された説明

 

6.プログラム開発その2 「温度と湿度の表示」

温度と湿度を測ることができるセンサー(DHT11)をマイコンに接続し、温度と湿度を読み取りシリアルモニタを使って表示します。

コンピューターの回路

中程度の精度で自動的に生成された説明

 

上の図のように配線します。

赤色の電源ラインに5Vを差しセンサーに電源を供給します。

黄色は温度や湿度などの信号を送信するラインで、マイコンの12番ピンに接続します。プログラム中の「#define DHTPIN  12」が12番ピンに信号線が接続されていることを意味しています。

黒色のラインはGNDラインです。マイコンのGNDと書かれたところに接続します。

 

新規ファイルを作成し下記コードをコピー&ペーストしてマイコンボードに書き込みましょう。温度と湿度がシリアルモニタに表示されます。

#include "Adafruit_Sensor.h"
#include "DHT.h"
#define DHTPIN 12
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

void setup() {
    // シリアル通信速度の設定
    Serial.begin(9600);

    // 温湿度センサーのセットアップ
    dht.begin();
}

void loop() {
    delay(2000);
    
    // データの取得
    float temperature = dht.readTemperature();
    float humidity = dht.readHumidity();
    
    // データの表示
    Serial.println("------------------------------");
    Serial.println("温度" + (String)temperature + "℃");
    Serial.println("湿度" + (String)humidity + "%");
}

 

7.プログラム開発その3 「熱中症予防マシン」

「フルカラーLED」と「温度と湿度を表示」を組み合わせて熱中症予防マシンを作成しましょう。

熱中症危険度指数 WBGT

WBGT値とは温度と湿度から算出される熱中症予防指針です。

下表で熱中症への警戒レベルがわかります。同じ温度でも湿度が高い場合は熱中症の危険度が上がります。

薄ピンク

注意

黄色

警戒

ピンク

厳重警戒

危険

 

LEDで熱中症を警告します。

WBGT値をLEDで下記の4パターンで表示し、警告を行うプログラムをマイコンに書き込みます。

注意

緑の点灯

警戒

黄色の点滅

 

 

 

 

 

 

厳重警戒

赤の点滅

 

 

 

 

 

 

危険

赤と黄色

早い点滅

 

 

 

 

 

 

 

電子機器, 回路 が含まれている画像

自動的に生成された説明

 

#include "Adafruit_Sensor.h"
#include "DHT.h"

#define DHTPIN 12
#define DHTTYPE DHT22
#define RLED 2
#define GLED 3
#define BLED 4

DHT dht(DHTPIN, DHTTYPE);

// 熱中症警報用マトリクス
// 0:注意、1:警戒、2:厳重警戒、3:危険
int wbgt[20][17] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2},
    {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2},
    {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3},
    {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3},
    {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3},
    {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3},
    {0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3},
    {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3},
    {1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
    {2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
};

void setup() {
    // シリアル通信速度の設定
    Serial.begin(9600);

    // 温湿度センサーのセットアップ
    dht.begin();

    // フルカラーLEDの設定
    pinMode(RLED, OUTPUT);
    pinMode(GLED, OUTPUT);
    pinMode(BLED, OUTPUT);

    //フルカラーLEDの点灯確認
    LED_Initial(10);
    Serial.println("熱中症警告システム DHT22");
}

void loop() {

    // データの取得
    float tempareture = dht.readTemperature();
    float humidity = dht.readHumidity();

    // データの表示
    Serial.println("--------------------------------");
    Serial.println("温度" + (String)tempareture + "℃");
    Serial.println("湿度" + (String)humidity + "%");

    // 警報レベルの判定
    int necchu;
    if ((tempareture < 21) || (humidity < 20)) {
        necchu = 0;
        if (tempareture < 0)
            necchu = 4;
    } else {
        necchu =  wbgt[int (tempareture - 21)][int ((humidity / 5) - 4)];
    }



    // 警報レベルの表示
    String mess[5];
    mess[0] = "注意";
    mess[1] = "警戒";
    mess[2] = "厳重警戒";
    mess[3] = "危険";
    mess[4] = "零下警報";
    Serial.println("WBGT値 " + mess[necchu]);

    // LEDの点灯制御
    int delay_time = 2000;
    WARNNING(necchu, delay_time);
}

/****************************************************
  警報レベルによってLEDの色と点灯パターンを変化させる。
  0:注意       緑、点灯
  1:警戒      黄色、ゆっくり点滅
  2:厳重警戒   赤、はやめに点滅
  3:危険    赤と黄色が交互に素早く点滅
  4:零下警報  青、点灯
 ****************************************************/
int flag = 1;
void WARNNING(int necchu, int delay_time)
{
    // 0:注意、1:警戒、2:厳重警戒、3:危険 4:零下警報
    digitalWrite(RLED, LOW);
    digitalWrite(GLED, LOW);
    digitalWrite(BLED, LOW);

    // 警報レベルによるLEDの点灯制御
    switch (necchu) {
        case 0: //0:注意 緑
            digitalWrite(GLED, HIGH);
            for (int n = 0; n < (int)(delay_time/100); n++) {
                delay(100);
            }
            break;
        case 1: //1:警戒 黄色
            digitalWrite(RLED, flag);
            digitalWrite(GLED, flag);
            for (int n = 0; n < (int)(delay_time/400); n++) {
                flag = 1 - flag;
                digitalWrite(RLED, flag);
                digitalWrite(GLED, flag);
                delay(400);
            }
            break;
        case 2: //2:厳重警戒 赤
            digitalWrite(RLED, flag);
            for (int n = 0; n < (int)(delay_time/250); n++) {
                flag = 1 - flag;
                digitalWrite(RLED, flag);
                delay(250);
            }
            break;
        case 3: //3:危険 赤黄色の点滅
            digitalWrite(RLED, HIGH);
            for (int n = 0; n < (int)(delay_time/100); n++) {
                flag = 1 - flag;
                digitalWrite(GLED, flag);
                delay(100);
            }
            break;
        case 4: //4:寒すぎる 青点灯
            digitalWrite(BLED, HIGH);
            for (int n = 0; n < (int)(delay_time/100); n++) {
                delay(100);
            }
            break;
        default:
            digitalWrite(RLED, flag);
            digitalWrite(GLED, flag);
            digitalWrite(BLED, flag);
    }
}

/* LED を赤、青、緑、で点灯させる 初回動作 */
void LED_Initial(int num)
{
    int n;

    for (n = 0; n < num; n++) {
        Serial.println(" R");
        digitalWrite(RLED, HIGH);
        delay(100);
        digitalWrite(RLED, LOW);

        Serial.println(" B");
        digitalWrite(BLED, HIGH);
        delay(100);
        digitalWrite(BLED, LOW);

        Serial.println(" G");
        digitalWrite(GLED, HIGH);
        delay(100);
        digitalWrite(GLED, LOW);
    }
}

 

おまけ LEDHSV色空間を表現してみよう!

今回使ったLEDは赤(R)、緑(G)、青(B)3色に光らせることができるものですが、HSV色空間を使うことで赤緑青以外の3色も表現することができます。以下のプログラムを実行すると、最初にLEDを光らせた時と色がどのように変わるのか見てみよう!

#define RLED 2
#define GLED 3
#define BLED 4

// Buling speed. You may change this value.
#define PWM_Factor 30 

int j, k;
float s = 1.0, v = 1.0, f;
long h;
int i, vi;
int p1, p2, p3;
int r, g, b;

void setup() {
  h = 0;
  pinMode(RLED, OUTPUT);
  pinMode(GLED, OUTPUT);
  pinMode(BLED, OUTPUT);
}

void loop() {

  //chage to HSV color model
  i = (int)(h / 60.0);
  f = h / 60.0f - i;
  p1 = (int)(v * (1 - s) * 255.0);
  p2 = (int)(v * (1 - s * f) * 255.0);
  p3 = (int)(v * (1 - s * (1 - f)) * 255.0);
  vi = (int)(v * 255);
  //Red -> Yellow
  if (i == 0) {
    r = vi ;
    g = p3 ;
    b = p1;
  }
  //Yellow -> Green
  if (i == 1) {
    r = p2 ;
    g = vi ;
    b = p1;
  }
  //Green -> Light blue
  if (i == 2) {
    r = p1 ;
    g = vi;
    b = p3;
  }
  //Light blue -> Blue
  if (i == 3) {
    r = p1 ;
    g = p2 ;
    b = vi;
  }
  //Blue -> Pink
  if (i == 4) {
    r = p3 ;
    g = p1 ;
    b = vi;
  }
  //Pink -> Red
  if (i == 5) {
    r = vi ;
    g = p1 ;
    b = p2;
  }

  //PWM loop
  for (j = 0; j < PWM_Factor ; j++) {
    digitalWrite(RLED, LOW);
    digitalWrite(GLED, LOW);
    digitalWrite(BLED, LOW);

    for (k = 255; k > 0; k--) {
      if (k == r)
        digitalWrite(RLED, HIGH);
      if (k == g)
        digitalWrite(GLED, HIGH);
      if (k == b)
        digitalWrite(BLED, HIGH);
    }
  }
  h = h + 1;
  if (h >= 360) h = 0;
}