こんにちは。NABEです。
前回はサンプルプログラムのSTEP2を使ってブザーを制御しました。
今回はSTEP3でスイッチを扱います。
スイッチを使う
トレーニングトレーサーには2つのスイッチがあります。
タクタイルスイッチ(タクトスイッチ)という、押している間は通電できるように設計されているスイッチです。
タクタイルスイッチは「感触のあるスイッチ」を意味しています。
STEP3ではこのスイッチを使って制御します。
STEP3
ファイルを開いてプログラムを書き込んでみると…
今まではLED点灯やブザー鳴動がすぐ始まりましたが、今回は何も起きません。
ここでSW1、SW2を押してみると…
SW1を押しているときはLEDが点灯、押していないときはLEDが消灯します。
SW2を押しているときはブザーが鳴り、押していないときはブザーが消音します。
つまり、LEDやブザーの動きがスイッチによって制御されていると分かります。
プログラムを見ていきましょう。
12 int LED_Pin = D13; 13 int BUZZER_Pin = D2; 14 int SW1_Pin = D7; 15 int SW2_Pin = D8; 16 17 void setup() { 18 // put your setup code here, to run once: 19 pinMode(LED_Pin,OUTPUT); 20 pinMode(BUZZER_Pin,OUTPUT); 21 pinMode(SW1_Pin,INPUT_PULLUP); 22 pinMode(SW2_Pin,INPUT_PULLUP); 23 24 } 25 26 void loop() { 27 // put your main code here, to run repeatedly: 28 if(digitalRead(SW1_Pin)==LOW){ 29 digitalWrite(LED_Pin,HIGH); 30 }else{ 31 digitalWrite(LED_Pin,LOW); 32 } 33 if(digitalRead(SW2_Pin)==LOW){ 34 digitalWrite(BUZZER_Pin,HIGH); 35 }else{ 36 digitalWrite(BUZZER_Pin,LOW); 37 } 38 }
見慣れない関数などが増えていますね。
上から順番に見ていきます。
12 int LED_Pin = D13; 13 int BUZZER_Pin = D2; 14 int SW1_Pin = D7; 15 int SW2_Pin = D8;
14、15行目で新しくスイッチのピン設定が追加されました。
17 void setup() { 18 // put your setup code here, to run once: 19 pinMode(LED_Pin,OUTPUT); 20 pinMode(BUZZER_Pin,OUTPUT); 21 pinMode(SW1_Pin,INPUT_PULLUP); 22 pinMode(SW2_Pin,INPUT_PULLUP);
setup()ではLED、ブザーの設定に加えて、SW1とSW2をINPUT_PULLUPに設定しています。
LEDやブザーとは違う、INPUTとPULLUPという言葉がでてきました。
INPUTは入力モードのことで、ピンに流れる電圧を読み取るモードにするということです。
INPUT_PULLUPは入力モード(内部プルアップ)という意味で、マイコン内部にあるプルアップ抵抗を使った入力モードに設定することを示しています。
プルアップ抵抗、内部プルアップについては説明すると長くなるので後半で解説します。
SW1とSW2がINPUT_PULLUP設定になることで、スイッチの動作が以下のように入力されます。
スイッチを押しているとき→LOW
スイッチを押していないとき→HIGH
LEDやブザーと比べて、HIGHとLOWの感覚が逆になるので注意しましょう。
メインの関数を見ていきます。
26 void loop() { 27 // put your main code here, to run repeatedly: 28 if(digitalRead(SW1_Pin)==LOW){ 29 digitalWrite(LED_Pin,HIGH); 30 }else{ 31 digitalWrite(LED_Pin,LOW); 32 } 33 if(digitalRead(SW2_Pin)==LOW){ 34 digitalWrite(BUZZER_Pin,HIGH); 35 }else{ 36 digitalWrite(BUZZER_Pin,LOW); 37 } 38 }
ここで、if文が登場します。
とある条件の真偽によって命令が変わるという仕組みになっています。
書き方はこのようになります。
if(条件式){真の場合の命令}else{偽の場合の命令}
今回は2つのif文が使われています。
28 if(digitalRead(SW1_Pin)==LOW){ 29 digitalWrite(LED_Pin,HIGH); 30 }else{ 31 digitalWrite(LED_Pin,LOW); 32 }
1つ目(28~32行目)では
if(digitalRead(SW1_Pin)==LOW)が条件式になります。
digitalRead()はピンに流れる電圧を読み取り、結果がHIGHかLOWとなります。
==は等しいことを表します。私たちが日ごろ使っている=(イコール)の意味と同じです。
条件を文章で言うと
「もしSW1ピンの電圧を読み取った結果がLOWであるとき」となり
スイッチ1がLOW、つまり押されているときを真としています。
条件が真のときはLEDをHIGH(点灯)
偽のときはLEDをLOW(消灯)
と命令しています。
33 if(digitalRead(SW2_Pin)==LOW){ 34 digitalWrite(BUZZER_Pin,HIGH); 35 }else{ 36 digitalWrite(BUZZER_Pin,LOW); 37 }
2つ目のif文では、if(digitalRead(SW2_Pin)==LOW)
つまり、スイッチ2が押されているときを真としています。
条件が真のときはブザーをHIGH(鳴動)
偽のときはブザーをLOW(消音)
と命令しています。
このように、スイッチごとにif文を使ってLEDの点灯やブザーの鳴動を命令していました。
スイッチとHIGH、LOW
先ほども書きましたが、スイッチのピン設定がINPUT_PULLUPの場合は
スイッチを押しているとき→LOW
スイッチを押していないとき→HIGH
となります。
今までLEDやブザーの制御をやってきた後だと
ON=HIGH OFF=LOW
のイメージがついてしまっているので
その逆であることに慣れるまで少し大変そうです。
PULLUPとは何か、どうしてINPUT_PULLUPだと逆になるのか調べてみました。
INPUT_PULLUP
INPUT_PULLUPはArduino IDE 1.0.1から使えるようになったモードです。
マイコン内部で電源に接続されている抵抗(プルアップ抵抗)を持っている場合、その抵抗を有効にできます。
マイコン外部にプルアップ抵抗を設置せずに済むので、回路がシンプルになります。
NUCLEO-F303K8にも内部プルアップ抵抗があるので、INPUT_PULLUPを使うことが出来ます。
プルアップ抵抗とプルダウン抵抗
いきなり出てきた「プルアップ抵抗」とは一体何なのか?
プルアップ抵抗とは、スイッチの入力を安定な状態に保つための抵抗です。
同じ用途でプルダウン抵抗というものもあります。
まず、スイッチの配線で例えば下の図のような回路を作るとします。
(5V流れればHIGH、0V流れればLOWと入力される場合)
スイッチを押したときに電流が流れてHIGH、押していないときには電流が流れずLOWとなりますが、スイッチを押していないとき、回路は電源にもGNDにも接続されていない「オープン」状態になります。
「浮いている」状態とも言われます。
この状態だと、電磁誘導や静電気の影響で微量の電流が流れてしまう可能性などがあり、値の信頼性が低下します。
このような状態になることを防ぎ、HIGHかLOWかを安定して入力するために使うのがプルアップ抵抗、プルダウン抵抗です。
下の図のような配線になります。
抵抗を使う理由は、GNDに電流が流れる際に、スイッチに過度な電流が流れてショートするのを防ぐためです。
この図を見ると分かるように、プルアップ抵抗を使うときはスイッチを押したときがLOW、押していないときがHIGHになります。
ちなみに、この場合をアクティブ・ロー(負論理)と言います。
逆に、プルダウン抵抗を使ったときのように、スイッチを押したときがHIGH、押していないときがLOWとなる場合をアクティブ・ハイ(正論理)と言います。
正論理の方が日常的な感覚に近いので理解しやすいのですが、慣例的にプルアップ抵抗の方が多用されるようです。
なぜなのか、教えて詳しい人……
※こちらの説明では、HIGH、LOWの感覚を勉強するために初心者が調べて書いたものなので、かなりざっくりとした説明になっています。
詳しくは「プルアップ抵抗 プルダウン抵抗」などで検索してみてください。
【後日追記】
詳しい人(社内のエンジニアさん)が教えてくれました!!!!
「プルアップが多いのは、安全だからです。GND-0.6Vを下回る電圧をportに入れるとマイコンが壊れます。電源の3.3+0.6Vを超えても壊れます。STM32F303の場合は±
5mAを超えた電流を流すとportが壊れます。基準電圧はGNDなので大きな差があっては回路全体がおかしくなります。マイコンの電源が3.0Vでswitchが3.6vのように差があるときにあ〜となります。プルアップであれば抵抗でIR Dropが起きるのと電流が小さくなるので安全になります。
ただ、STM32のポートの多くは5Vトレラントなので、先ほど挙げたような電位差によるマイコンの破壊が起きないのでどっちでもよいというのが正解になります。」
まとめ
スイッチを使うときは、HIGH、LOWの入力を安定させるためにプルアップ抵抗がよく使われます。
外部にプルアップ抵抗を設置しても良いですが、マイコンによっては内部にプルアップ抵抗があり、内部プルアップの設定をすることで利用できます。
トレーニングトレーサーのマイコンボードNUCLEO-F303K8には内部プルアップ抵抗があり、ArduinoIDEのスケッチではpinMode()でINPUT_PULLUPと設定すればそれを有効にできます。
お知らせ
さて、サンプルプログラムのSTEP3まで実習することができました。
ここからはより細かい条件でLED、ブザーを制御したり、センサを使った値の読み取り方やモータ制御が待っています。
が、諸事情により、ここで一度研修をお休みします。
まだまだ在宅勤務も続いているため、大会ルールで作られたコースで走るところをお見せできるのももう少し先になりそうです。
サンプルプログラムと解説について
Arduino IDEでのサンプルプログラムは2020年9月現在STEP9まで公開されています。
STEP8まで学べば、ライントレースロボットとしての一通りの制御が身に付きます。
STEP9からは、「公益財団法人ニューテクノロジー振興財団( New Technology Foundation:以下NTFと略)が主催するロボトレース競技で完走できるプログラムに仕上げること」を要求仕様として、要求を解決するためにどのような考えを持ち、出した答えについて判断すればいいかのアドバイスが細かく書かれています。
ここからは自分で考え、悩むことが多くなるはずです。
STEP8まで進んだ方はぜひ、思う存分試行錯誤をしてみてください。
アールティでは初心者向けの基礎部分の解説や上級者向けのアドバイスまで、お客様に応じてカスタマイズできる研修やセミナーも承っております。(主に企業向け)
詳しくはアールティのHPをご覧ください。
ここまでNABEのロボトレース研修をお読みいただきありがとうございました!
ほかのキット製作研修などもぜひご覧ください!