Arduinoと戯れてみる!

Arduino 入門 番外編 17 【map関数】

arduino-extra-edition-17-00Arduino番外編
スポンサーリンク

Arduino 入門
番外編 17
【map関数 まとめ】

こんにちは管理人のomoroyaです。

arduino 入門 番外編はarduinoの基本的なことを解説している記事です。

 

本記事は、Arduinoで使用するmap関数についてです。

管理人の中では、Arduinoで遊んでいくためには必ず理解しておく関数と考えています。

入門編では、サーボモーターの制御などで使用した関数です。

 

map関数は数値をある範囲から別の範囲に変換する関数です。

Arduinoは10bitのADコンバータ(アナログーデジタル変換)を搭載しています。

これにより、0V~5Vが入力されると0~1023の数値に変換できるようになっています。

その時に使用する関数はanalogRead(pin番号)でしたね。

ちなみに、「10bit = 2^10」で計算できます。

2^10 = 1024種類(0~1023)

 

どういったときに使うのか?

「入力された電圧値をデジタル信号に変換して割付し直す」

といったことに使います。

アナログの電圧値をデジタル値に変えて都合の良いように割付し直すということです。

 

0~1023の数値をそのまま使えるかどうかは受け側の処理で異なります。

受け側が8bitの分解能しかない場合もありますし、任意の値を割り付けたいといったこともあります。

そんなときに便利なのがmap関数です。

入門編では、スケッチに組み込まれてしまっていて本当に変換されてるのかどうか体感できませんよね?

 

そこで、本記事は以下をやってみます。

  1. シリアルモニタに数値を入力。
  2. map関数で変換された数値を表示させる。

といったスケッチを描くことで数値が変換されることを認識します。

 

管理人はプログラマーの専門家というわけではありません。

気が向いたときにテキストを開き、ネットを調べ自己学習。

管理人にとってはブログ記事が自己学習のノートです。

書くことによって頭の中が整理できる。

何よりも、忘れたときに見返せるってのが良い。

 

arduino自身のこと、スケッチ(コード、プログラム)を少しづつ理解して行きましょう。

いやいや、arduinoを早速始めたいんだ!というかたは下記の入門編からお読みください。

 

本Lesson解説で使用しているのはArduino互換品です。

互換品とは言え、Arduinoはオープンソースであり複製して販売するのもライセンス的に問題なし。

そのため互換品の品質も悪くなく、それでいて値段は安いです。

正規品本体の値段程度で豊富な部品が多数ついています。

 

正規品の本体単品がほしい方はこちらとなります。

 

スポンサーリンク

map関数 基本解説

まずは基本的なことを復習。

繰り返しになりますが、「数値をある範囲から別の範囲に変換する」ための関数です。

関数説明
map(value,fromLow,fromHigh
,toLow,toHgih)
value:変換したい変数
fromLow: 現在の範囲の下限
fromHigh:現在の範囲の上限
toLow:変換後の範囲の下限
toHigh:変換後の範囲の上限
例 アナログ入力の0~1023をサーボの0~180に変換。
val = map(val,0,1023,0,180);

 

解説を追記しておきます。

valueがfromLowと同じ値の場合:戻り値はtoLow
valueがfromHighと同じ値の場合:戻り値はtoHigh
valueがfromLowとfromHighの間の値の場合:2つの範囲の大きさの比に基づいて計算

この関数は範囲外の値でも機能します。
範囲に必ず収めたい場合はconstrain関数と併用します。
map関数で使用できるのは整数のみ。
計算結果が少数となる場合は少数部分は切り捨てられます。

 

応用編1:数値の反転に使用することも可能

val = map(x, 1, 100, 100, 1);

とすると「1が100、2が99、・・・100が1」という戻り値になります。

 

応用編2:指定範囲にマイナスを指定することも可能

val = map(x, 1, 100, 50, -50);

とすると「1が50、2が49、・・・100が-50」という戻り値になります。

 

map関数 サンプルスケッチ

シリアルモニタに値を入力、map関数で変換した値をシリアルモニタに出力するスケッチです。

簡単にできるかと思いつつ、実は簡単ではありません・・・。

map関数の処理は簡単です。

しかし、シリアルモニタの処理がとても大変!

 

なぜか?

シリアルモニタでのやり取りは、文字でのやり取りになります。

いわゆるASCIIコードです。

しかもですよ、基本的にキャラクター型の1バイトずつでしかやりとができない。

そう、1文字単位でのやり取りなんです。

例えば、シリアルモニタに123といれても、1と2と3が1文字ずつ送られるってことです。

数桁の数字を送るためにはスケッチに工夫が必要です。

 

大きく処理は2つ。

1.ASCIIコードを数値に変換
ASCIIコードの「0」は10進数で48、16進数で0x0030、char型で’0′
※1文字をシングルクオーテーションで囲うとchar型の表記です。
上記から10進、16進、char型のいずれかで計算してあげます。
10進数で計算する場合は、48を引く。
16進数で計算する場合は、0x0030を引く。
char型として計算する場合は、’0’を引く。
いずれかの計算で「0」になります。
2.桁数を認識させて変換
桁数を認識させるのも手間です。
例えばですが、123と入力してシリアルモニタで送信する。
最初の1は100倍、2は10倍、3はそのままで全ての和を取る。
といった処理が必要になります。

map関数のお勉強が違うお勉強に・・・。

map関数よりASCIIコードの変換の方が大変でした。

 

スケッチに通信用の関数を使いますので念のため説明をのせておきます。

関数説明
Serial.begin(speed)シリアル通信のデータ転送レートをbpsを指定します。
bpsはビット/秒。
speed:転送レート
転送レートは下記が指定可能です。
300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200
戻り値:なし
Serial.available()シリアルポートにデータがあるかどうかの確認をする。
戻り値:シリアルバッファにあるデータのバイト数
Serial.read()受信データの読み込み。
戻り値:
読み込み可能なデータの最初の1バイトを返す。
-1の場合はデータなし。
Serial.print(data,format)ASCIIテキストでシリアルポートにデータを出力する。
data:出力する値
format:基数または有効桁数(BIN,DEC・・・など)
戻り値:送信したバイト数
Serial.println(data,format)データの末尾に改行を入れて送信。
Serial.print()と同じフォーマットが使えます。

 

下記が、map関数をシリアルモニタで確認するためのサンプルスケッチです。

スケッチ内のdelay(100);が肝です。

9600bpsのシリアル通信で64byteぶんのデータを読み込むための時間を計算。

多少マージンを取って100ms待つことでデータを取得完了できると判断。

これによりASCIIコードの複数文字を桁数のある数字として認識させる処理ができています。

//番外編 17 map関数
//map関数の変換を確認するサンプルスケッチ
//https://omoroya.com/

long sum = 0;
long val1=0, val2=0, val3=0;

void setup() {
  Serial.begin(9600); //データ転送レートを指定
}

void loop() {
  
  bailout:

  //受信データがある場合if内を処理
  if (Serial.available() > 0){
    delay(100);                             //64byteぶんのデータを受信できるように100ms待機
    byte data_size = Serial.available();    //受信したデータ数を取得(桁数取得のため)
    byte num[data_size];                    //桁数分の配列を設定
    Serial.print("Number of digits =");
    Serial.println(data_size);              //桁数の表示(動作確認のため)

    //for文内で1文字ずつのASCIIコードを数値に変換
    for (byte i = 0 ; i < data_size ; i++)
    {
      char val = Serial.read();             //受信データの読み込み 1byteぶん

      //char文字valが数字の場合はif文内処理、そうでない場合else内処理
      if (isdigit(val)){
        num[i] = val - '0';                 //ASCII文字を数値に変換
        sum = sum*10 + num[i];              //桁数を考慮して数値に変換
      } else {
        Serial.println("Please enter a number.");
        Serial.println("");
        goto bailout;                       //valが数字でない場合bailoutへ抜ける
      }
      
    }
    
    val1 = map(sum, 0, 1023, 0, 255);    //10bitを8bitに変換
    val2 = map(sum, 0, 1023, 1023, 0);   //反転変換
    val3 = map(sum, 0, 1023, 0,-1023);   //マイナス変換
    
    Serial.print("input value : ");
    Serial.println(sum, DEC);            //入力した値を表示
    Serial.print("10bit->8bit : ");
    Serial.println(val1, DEC);           //10bitを8bitに変換した値を表示
    Serial.print("reverse     : ");
    Serial.println(val2, DEC);           //反転変換した値を表示
    Serial.print("minus       : ");
    Serial.println(val3, DEC);           //マイナス変換した値を表示
    Serial.println("");
    
    sum = 0;                             //数値をリセット
  }
  
}

 

map関数 サンプルスケッチ 実行結果

「ツール」 ⇒ 「シリアルモニタ」 を開きます。

適当な数値を入力してリターンもしくは送信ボタンを押せば結果が表示されます。

数値以外を入力すると「Please enter a number.」と表示されます。

 

下図がシリアルモニタの実行結果。

シリアルモニタは「改行なし」を選択してください。※下図赤枠

改行なしを選択しないと改行も入力値として認識してしまいます。

 

下図は0、1023、1、1022、2、1021を順次入力した結果です。

arduino-extra-edition-17-01

 

map関数が機能しているのがわかりましたでしょうか。

 

まとめ

Arduino 入門 番外編 17 【map関数 まとめ】

いかがだったでしょうか?

 

map関数の学習のつもりがシリアル通信用の関数をお勉強することに・・・。

本記事で記載したASCIIコードを数値に変換、桁数の変換、色々使えそうな気がします。

せっかくですので、数値変換、桁数変換などを関数化していつでも使えるようにしたいと考えます。

 

番外編 18はこちら。

数値変換、関数化しなくても簡単に文字列を数値に変換できる関数がありましたというお話です。

サンプルスケッチも記載しています。

こちらも併せてお読みください。

 

最後に

疑問点、質問などありましたら気軽にコメントください。

この電子部品の解説をしてほしい!などなどなんでもOKです。

リンク切れ、間違いなどあればコメントいただけると助かります。

 

Arduino入門編、番外編、お役立ち情報などなどサイトマップで記事一覧をぜひご確認ください。

 

Arduino入門編で使用しているUNOはAmazonにて購入可能です。

互換品とは言え、Arduinoはオープンソース。

複製して販売するのもライセンス的に問題なし。

 

そのため互換品の品質も悪くなく、それでいて値段は安いです。

正規品本体の値段程度で豊富な部品が多数ついています。

 

学習用、遊び用、お試し用には安価な互換品がおすすめです。

 

 

上記のものでも十分に多数の部品が入っていますが、最初からもっと多数の部品が入っているこちらもお勧めです。

 

Amazonでお得に買う方法

Amazonでお得に購入するなら、Amazonギフト券がおすすめです。

現金でチャージするたびに、チャージ額に応じたポイントが付与されます。

最大2.5%!!!(Amazonプライム会員ならさらにお得)

チャージ額(一回分)一般プライム会員
5,000円~19,999円0.5%1.0%
2,0000円~39,999円1.0%1.5%
40,000円~89,999円1.5%2.0%
90,000円~2.0%2.5%

さらに、初回チャージで1000ポイントもらえるキャンペーンも実施中!

\Amazonギフト券 1000ポイントキャンペーン/
Amazonチャージ 初回購入で1000ポイントキャンペーン

 

補足情報
コンビニ・ATM・ネットバンクが対象
購入は1円単位で可能

コメント

タイトルとURLをコピーしました