Day7. Arduinoで温度センシング!入出力をマスターせよ。
※ひとりでIoTまるっとチュートリアル Advent Calendar 2018 7日目
まだ登録していない方は、ぜひともお願いします!
Day6. では、Arduinoの基本的な使い方について書きました。
しかし、複雑な動作をするものを作れ!と言われても、まだまだ困ると思います。
今回は、値をアナログチックに変えてみたり、センサからの入力を受け取ってみたりといった、数値処理や入出力の仕方について順を追って書いていきます。この辺がわかってくると、入力/出力のつなぎの部分や、ライブラリを見つけたり(あるいは作ったり)することで比較的自由度の高いものが作れるのではないかと思います。
それでは順を追ってやっていきましょう。
目次
・PWMでアナログチックな出力
・センサからデータを入手してみる(I2C編)
・センサデータから、LEDの明るさを変えてみる
PWMでアナログチックな出力
マイコンでアナログチックな出力をするためには、PWM(Pulse Width Modulation)という技術を使います。電圧のONとOFFの時間の比(デューティー比)を変えることで平均電圧を制御し、線形かつ高効率な出力を実現します。
そのPWM制御を出力できるのがあらかじめArduino側で決まっています。ピンアサインによれば3、5、6、9、10、11ピンなので、そのいずれかを使わなければなりません。Arduino上に"~"のマークが付いているやつですね。
今回は9番ピンにつなぎます。前日の13番ピンから9番ピンに変えるだけですね。配線としてはほぼ変わらないので簡単です。
const int LED_PWM = 9; // PWM用ピン
const int interval = 100; // どのくらいの割合で変化させるか
int i = 0;
// 初期起動時処理
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_PWM, OUTPUT);
}
// 起動後処理
void loop() {
//だんだん明るく
for (i=0; i<255; i++){
analogWrite(LED_PWM,i); // PWMによる出力. i は出力の大きさ
delay(interval);
}
//だんだん暗く
for (i=255; i>0; i--){
analogWrite(LED_PWM, i);
delay(interval);
}
}
前回までとの違いは、出力する大きさに数値を入れられるところです。analogWrite関数の第二引数で、大きさを設定できるようになっています。
動画を貼り付けられなさそうなので、静止画で。このように、時間によって明るい⇨暗いを繰り返すようになりました!
センサからデータを入手してみる(I2C編)
さて、デジタル出力もアナログ出力もできるようになったので、次はセンサからの入力を受けてみましょう!
温度センサは、ADT7410というものを使います。I2C通信でデータを受けられ、簡単に温度測定が出来ます。
Day5. の内容では、SCL同士、SDA同士をつなげるんでしたね。センサ、マイコンを電源、GND、SCL、SDAの4本の線でつなぎましょう。
次に、処理を行うコードを実装します。
#include <Wire.h>
// 初期起動時の処理
int adt7410I2CAddress = 0x48;
void setup(void) {
Serial.begin(19200); //コンソール出力のbaudrate
Wire.begin(); //
}
// 起動後の処理
void loop(void) {
uint16_t uiVal; //2バイト(16ビット)の領域
float fVal;
int iVal;
Wire.requestFrom(adt7410I2CAddress, 2); //2バイト要求
uiVal = (uint16_t)Wire.read() << 8; // 1バイト読み出しで上位にシフト
uiVal |= Wire.read(); // 1バイト読み出して下位にセット
uiVal >>= 3; // シフトで13bit化
if(uiVal & 0x1000) { // 13ビットで符号判定
iVal = uiVal - 0x2000; // マイナスの時 (10進数で8192)
}
else{
iVal = uiVal; //プラスの時
}
fVal = (float)iVal / 16.0; // 温度換算(摂氏)
Serial.println(fVal, 4); // シリアル送信
delay(5000); //5秒待つ
}
さっきよりも複雑になってきましたね。と言っても、取ってきたデータを処理しているだけといえばそうなので、やっている事自体はそんなに難しくありません。
ここで
☑ 初回起動時
・温度センサのアドレスを指定する
・値を出力先へのbaudrateを設定
・Wireライブラリ(I2C通信用ライブラリ)の初期化
☑ 起動後
・入力値から温度換算処理を行う
・コンソール画面に値を吐き出す
・5秒待つ
といった内容です。アドレスは、仕様書から読み解きましょう。
なお、センサから取得したデータをみるには、Arduinoのシリアルモニタという機能を使います。このとき、コードで書いているbaudrateと、シリアルモニタのbaudrateを合わせましょう。合わせないと、文字化けして何のことだかわからなくなります。
このように、温度が出力されていたら成功です!
さて、ここで、温度のところでどういう変換を下かについて少し触れてみましょう。下記リンクに、温度センサ"ADT7410"に関する仕様書があります重要なのは、仕様書の中の"換算式"。
これを用いて、0,1のデータをアナログの値に変換していきます。
少し複雑ですが、上のデータを読んで
・ビット列がどうやって格納されているか
・温度の変換式はどんなものか
を抑えることができれば、どんなセンサからの値でもきちんと変換できるようになると思います。今回の温度換算式をどのように変換したかを図示してみます。(少々わかりにくいかもしれませんが、イメージは伝わると嬉しいです)。
個人的には、10進法に直してからの計算のほうが楽で好きです。しかし、2進法の計算も少しは慣れておいてもいいのかなと思います。
センサデータから、LEDの明るさを変えてみる
さて、入出力がともに実装出来たので、最後に、入力の値によって出力を変える回路を実装してみましょう。先程のPWMとセンサ入力を組み合わせます。回路は今までのを組み合わせた感じ。
コードは下記
#include <Wire.h>
int adt7410I2CAddress = 0x48; //温度センサのアドレス
const int LED_PWM = 9; //LED
// 初期化
void setup(void) {
Serial.begin(19200);
Wire.begin();
pinMode(LED_PWM, OUTPUT);
}
void loop(void) {
uint16_t uiVal; //2バイト(16ビット)の領域
float fVal;
int iVal;
Wire.requestFrom(adt7410I2CAddress, 2); //2バイト要求
uiVal = (uint16_t)Wire.read() << 8; // 1バイト読み出しで上位にシフト
uiVal |= Wire.read(); // 1バイト読み出して下位にセット
uiVal >>= 3; // シフトで13bit化
if(uiVal & 0x1000) { // 13ビットで符号判定
iVal = uiVal - 0x2000; // マイナスの時 (10進数で8192)
}
else{
iVal = uiVal; //プラスの時
}
fVal = (float)iVal / 16.0; // 温度換算(摂氏)
Serial.println(fVal, 4); // シリアル送信
analogWrite(LED_PWM,fVal); // LEDの明るさを出力
delay(1000); //1秒待つ
}
センサーをドライヤで当てると、明るさが変わる処理を実装することが出来ました!これで「温度が100℃を超えるとLEDライトを光らせる」なんてことも出来ます!
まとめ
いかがでしたか?今回のお話で、センシングとそのフィードバックを出力として与える事ができるようになりました。
これは、マイコンでいろいろな処理をする際の基本となるものです。是非、一回自分で実装してみてください!
さて、明日はRaspberry Piについて!
Arduinoとの違いや、RaspberryPiだからできることをやってみたいと思います。ではではっ!
前の日 : Day7. ArduinoではじめてのLチカをしよう!
次の日 : Day8. 『Raspberry Pi』セットアップからはじめリアルタイム温度計を作る!
この記事が参加している募集
サポートいただけると励みになります! よろしくおねがいします!!