見出し画像

KUMIKOMI NO SEKAI ~ #3 Controlling the Speed of the Blink

こんにちは。おっ!全体ビュー数が2000を超えておる。誰かの役立つ情報になっていれば幸いです。さてさて、今回はアナログ信号を取ってみようと思います。前回まではボタンのHigh/Lowを監視して、LEDのHigh/Lowを制御することで、LEDを点けたり消したりしましたね。High/Lowのように1 / 0で表現する信号をデジタル信号と言います。それと比較して、アナログ信号は連続的に変化する信号です。デジタル信号は0か1のどちらかしかありませんが、アナログ信号は中間の値が沢山存在します。アナログ信号の波形は以下のようになります。早速アナログ信号を取ってみましょう。

アナログ波形

関連モジュール

今回関連するモジュール(ハードウェア)はLEDとロータリースイッチになります。

画像2

A/Dコンバーター

今回扱っているボードには、10bitのA/Dコンバーター(アナログ/デジタルコンバーター)が搭載されています。A/Dコンバーターはアナログ値をデジタル値に変換してくれます。このボードは0V~5Vの間の電圧で動作しますが、A/Dコンバーターを通すと0V~5Vの間の電圧を0~1023の整数値に変換した値で取得することができます。0V=0、2.5V=512、5V=1023と言った感じです。何故0~1023の範囲なのかお分かりですか?10bitコンバーターだからですね。10bitで表現でき得る最大値は11 1111 1111 = 0x3FF = 1023だからです。

アナログ信号を読み出すには

本来であればA/Dコンバーターのレジスタがマッピングされているアドレスからデータを読み出す必要があるのですが、そこはArduino先生、やはり関数が用意されています。

analogRead(ピン番号);

これで読み出せてしまいます。ホンマ楽勝ですやん。ピン番号はA0のようです。なので、以下のコードで読めてしまいます。

int rotaryPin = A0;   // ロータリースイッチ用ピン番号
int rotaryValue = 0;  // ロータリースイッチから読み出した値

void setup() {
}

void loop() {
    // ロータリースイッチから値を読み出す
    rotaryValue = analogRead(rotaryPin);
} 

しかし、これではrotaryValueの中身がどんな値なのか分かりません。Visual Studioならウォッチウィンドウで変数の中身丸見えなんですけどね。Arduino IDEはショボいんで見れません。じゃあ、printf関数を使って変数の中身をコンソールに出力するか・・・いや、コンソールが無いんすよ。え?どうすんの?そんな時はシリアル通信です。

シリアル通信とは

シリアル通信とはデータ通信方式の一つで、1本の通信線を使って機器間でデータの送受信を行います。シリアル通信には色々な方式があるのですが、ここで言うシリアル通信はUART(ユーアート)通信のことです。この通信を超簡単に例えると、二人の人が向かい合って握手し、腕を上げると1、腕を下げると0というルールで話をするようなものです。”上げる” ⇒ "下げる" ⇒ "上げる" ⇒ "下げる"と腕を動かした場合、データとして"1" ⇒ "0" ⇒ "1" ⇒ "0"を相手に伝えることができます。UARTでは腕を二本用意し、片方は相手の言うことを聞く用、片方は自分の言いたいことを伝える用として使います。

シリアル通信関数

では、シリアル通信はどうやってするのか?と言う話になりますが、当然自分でプログラムする必要があります。ま、マジかよ・・・。最悪ね、最悪の場合はですよ?じゃ~今回はどうやねん、ありますやん、ちゃんと用意されてますやん。使い方は以下の通りです。

Serial.begin(9600);            // これで初期化(ボーレート9600bps)
Serial.println(rotaryValue);   // これでrotaryValueの中身が送信される

9600と言うのは通信速度の話で、我々は組込み屋さんは”クンロク”と呼びます。先程の例え話で言うと、腕の上げ下げをどんぐらいの速さで行いますか?と言うことです。9600bps(bit per second)の略で、1秒間に9600bitのデータを転送できる速度のことです。腕の上げ下げを1秒間に9600回するわけです。通信の世界では相当ゆっくりですが、腕だったら千切れるな。

Serial.begin/Serial.println

Serial.beginとかSerial.printlnとかなっとるけど、このドットは何?構造体みたいに見えるけど、ドットの後ろは関数なの?これは、初めての記述だと思いますが、この記述はC言語ではなくC++の記述です。クラスと言って構造体とは別のものなのですが、一旦は構造体のメンバーに関数が居ると理解してもらえれば良いです。Serialの中にbeginと言う関数とかprintlnと言う関数が居るんだな。そして、その関数の使い方は構造体のメンバー変数にアクセスするのと同じなんだなと理解して下さい。

シリアル通信してみる

実際にロータリースイッチから取得した値をシリアル出力するコードが以下です。コンパイルできたらボードに書き込んで実行してみましょう。

int rotaryPin = A0;   // ロータリースイッチ用ピン番号
int rotaryValue = 0;  // ロータリースイッチから読み出した値

void setup() {
    Serial.begin(9600);
}

void loop() {
    // ロータリースイッチから値を読み出す
    rotaryValue = analogRead(rotaryPin);
 
    // シリアルへ出力する
    Serial.println(rotaryValue);
}

ボードに書き込めたら、もうプログラムは動いているので、シリアルモニターと繋いでみましょう。Arduino IDEのツール ⇒ シリアルモニタをクリックします。すると以下のような画面が表示されます。これはモニター上にrotaryValueの値が出力されている様子です。ロータリースイッチを時計回りに全開に回すとrotaryValueの値が0になり、反時計回りに全開に回すと値が1023になりました。0~1023の値が取れました。正しく値が取得できていそうです。

シリアルモニター2

何がどうなって、こう見えるのかを簡単な図にしておきます。ボードからrotaryValueの値がUSBケーブルを経由して、シリアル通信でパソコンへ送信され、パソコンは受信した値をシリアルモニターに表示します。

画像4

ロータリースイッチでLEDのチカチカ速度を変える

それでは、ロータリースイッチを使ってLEDの点滅周期を変えてみましょう。ロータリースイッチは右に回すと取得できる値が小さくなり、左に回すと大きくなります。ロータリースイッチから取得した値をdelay関数に渡すと、その時間待ってくれます。最小で0ミリ秒待ち(待ち無し)~1023ミリ秒待ち(約1.023秒待ち)を実現できます。ソースコードは以下の通り。

int rotaryPin = A0;   // ロータリースイッチ用ピン番号
int ledPin = 4;       // LEDピン番号
int rotaryValue = 0;  // ロータリースイッチから読み出した値

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

void loop() {
 rotaryValue = analogRead(rotaryPin);  // ロータリースイッチから値を読み出す

 digitalWrite(ledPin, HIGH);
 delay(rotaryValue);     // ロータリースイッチから読み出した時間分待つ(最大1.023秒)

 digitalWrite(ledPin, LOW);
 delay(rotaryValue);     // ロータリースイッチから読み出した時間分待つ(最大1.023秒)
}

組込み開発におけるデバッグ

プログラムが設計通りに正しく動作するかどうかを確認する作業をデバッグと言います。先程、rotaryValueの中身を確認したのもデバッグ作業の一つです。ArduinoにはSerialクラスが予め用意されているので、それを使えば即シリアルプリントデバッグが可能です。先程も述べましたが、これが無ければシリアル通信用のプログラムを自作する必要があります。私も昔実際の開発で、デバッグをするために先ずシリアル通信プログラムを作った覚えがあります。

しかし、シリアルプリントデバッグも結構厳しいデバッグの方法で、いちいちprint文をソースコード上に書かないといけません。Visual Studioのようにステップ実行や、変数やメモリのウォッチができるのが一番楽です。では、組込み開発ではそれは出来ないのか?と言うと出来ます。ICE(In-Circuit Emulator)通称アイスという機器を使えば、Visual Studioでやれていることと殆ど同じことができます。ちなみに、今私が開発を担当しているプロジェクトはICEがありません。なので、シリアルプリントデバッグをしています。

まとめ

今回はアナログ信号を使ったプログラムを作成しました。それほど難しい話ではなかったと思います。まあ、親切な関数が準備されているので楽勝ですね。今回はむしろシリアル通信の方がレベルの高い話だったかも知れません。興味を持たれた方は、シリアル通信を深堀して頂いても良いかと思います。次回はブザーを使って音を鳴らしてみましょう。それでは、今回はこの辺で。お疲れ様でした。

この記事が気に入ったらサポートをしてみませんか?