2015/12/24からのアクセス回数 7188
「8pino」ではじめるミニマム電子工作 (以下ミニマム本と書きます)に触発されて、ブレッドボードで作るATtiny85を使ったワンコインArduinoで 電子工作を楽しんでみました。
例題の多くは、ミニマム本を参考にさせて頂き、これをlbedライブラリを使ってmbed風に書き替えています。
TrinketやGemma使われているブートローダはフリーなのですが、商品やプロジェクトに勝手にAdrafruitのUSB VID/PIDを使ってはいけない との注意書きがあります。趣味で使う分には問題ないと思うのですが、勉強会はプロジェクトかもしれないので、以下の様な対応を取りました。
Arduino IDE 1.6.4以降Gemmaがサポートされたので、そのままブートローダが使えると便利なのですが、 趣味で使う場合に限定したUSB VID/PIDにブートローダを変更したバージョンを用意しました。
USB VID/PIDは、「インターネット・ガジェット設計」の著者が、「ホビーや個人の研究であれば、自由にお使い下さい」 と記述されているご厚意に甘えて使わせて頂きました。
以下のファイルをダウンロードし、展開し、FreeGemma以下のFreeGemmaLoaderとharware2個のフォルダーがあります。 これをユーザのArduinoディレクトリ配下にコピーしてください。
Arduino勉強会/16-ワンコイン・マイコンlbedGemmaで説明した、
mbedはとても使い易いライブラリを提供していますが、mbedが提供されていないボードやArduinoなどで、 mbed風のプログラミングを楽しんでもらうために、lbedライブラリを作成しました。
今回は、ブレッドボードで作るATtiny85を使ったワンコインArduino(lbedGemmaと呼びます) を使ってmbed風のプログラミングを体験してみましょう。
lbedGemmaの作り方は、 Arduino勉強会/16-ワンコイン・マイコンlbedGemma を参照してください。
Arduino IDE 1.6.xを以下のURLからダウンロードし、インストールしてください。
lbedGemmaとTinyWireMは、以下のURLからダウンロードできますが、
以下にTinyWireMとlbedGemmaをまとめましたので、こちらをダウンロードし、 展開したTinyWireM, lbedGemma, lbedGemmaUserをユーザのホームディレクトリ/書類/Arduino/libraries に入れてください。
デジタル入力はスイッチのオン・オフのように0と1だけを入力値とします。 以下の様なスイッチをもちいた回路をlbedGemmaで作ってみましょう。
VCCは、電池のプラスを表しlbedGemmaではUSBからの5Vに相当します。その下にタクトスイッチSWが接続され、 10KΩの抵抗を通り、GND(電池のマイナス)につながっています。途中Switchというピンがタクトスイッチと抵抗の間につながれています。
この抵抗のあることで、スイッチが押されたときに電源のプラスとマイナスが直結し、ショートすることを防いでくれます。 この抵抗はスイッチがオフの時に、Switchピンの電圧をマイナス付近に落としてくれるので、プルダウン抵抗と呼ばれています。
この回路をlbedGemmaのブレッドボードに追加してみます。
「8pinoではじめるミニマム電子工作」のスイッチ・ボタンのスケッチでは、 以下の様に書いています。
int led_pin = 1; // GPIO # LED on board int sw_pin = 2; // GPIO #2 void setup() { pinMode(led_pin, OUTPUT); pinMode(sw_pin, INPUT); } void loop() { if (digitalRead(sw_pin) == HIGH) { digitalWrite(led_pin, HIGH); delay(250); digitalWrite(led_pin, LOW); delay(250); } }
上記のスケッチをlbedを使ったスケッチは以下の様に入力します。 最初の#includeはこれから、TinyWireMとlbedGemmaというライブラリを使うことを 表します。*1
DigitalOutは、デジタル出力のクラス名で、led(1)は1番ピンをデジタル出力するledという変数を宣言しています。 DigitalInは、デジタル入力のクラス名で、sw(2)は2番ピンをデジタル入力するswという変数を宣言しています。
setup関数では特に処理を行いません。
loop関数では、swがHIGHの時にledにHIGHをセットし、250ミリ秒待ち、 ledにLOWをセットし、250ミリ秒待つように処理します。 これで、スイッチが押されている間、LEDが250ミリ秒間隔で点灯と消灯を繰り返します。
mbed風の変数を参照するとピンから値が読まれ、変数に代入するとピンに値が書き込まれる 書き方の方が直感的で分かりやすいと思うのです。
#include "TinyWireM.h" #include "lbedGemma.h" DigitalOut led(1); // GPIO #1 LED on board. DigitalIn sw(2); // GPIO #2 void setup() { } void loop() { if (sw == HIGH) { led = HIGH; wait_ms(250); led = LOW; wait_ms(250); } }
実際にブレッドボードでこのスケッチを動かしてみましょう。
スイッチを押すと電源のプラスとSwitchピン2番が接続され、swの値がHIGHになるので、 if文の中の処理が実行され、LEDが点滅します。
次に、以下の様な抵抗を電池のプラス側につないだスイッチ回路を作ってみましょう。
ブレッドボードでは、マイナスにつながっていた抵抗をプラス(赤い線)につなぎ、 スイッチのプラスにつながっていた線をマイナスにつなぎます。
スケッチは、スイッチが押されたときにGND(電池のマイナス)につながるので、 if文のHIGHからLOWに変更します。 これで、先ほどと同じ動作をします。
#include "TinyWireM.h" #include "lbedGemma.h" DigitalOut led(1); // GPIO #1 LED on board. DigitalIn sw(2); // GPIO #2 void setup() { } void loop() { if (sw == LOW) { led = HIGH; wait_ms(250); led = LOW; wait_ms(250); } }
スイッチを追加するたびに抵抗をつなぐと部品点数が増えるので、 Arduinoなどの最近のマイコンにはデジタル入力端子にプルアップ抵抗を内部で付けてくれる 機能があります。
この機能を使うと回路は以下の様にとても簡単になります。
ブレッドボードも抵抗を外します。
デジタル入力ピンにプルアップ抵抗をセットするには、 setup関数内で、swのmodeをINPUT_PULLUPにセットします。
#include "TinyWireM.h" #include "lbedGemma.h" DigitalOut led(1); // GPIO #1 LED on board. DigitalIn sw(2); // GPIO #2 void setup() { sw.mode(INPUT_PULLUP); } void loop() { if (sw == LOW) { led = HIGH; wait_ms(250); led = LOW; wait_ms(250); } }
実際に動かしてみましょう。
もし、modeでPULL_UPの設定をしなかったらどうなるのでしょう。 setupのmodeの設定部分を//でコメントアウトして動かしてみてください。 スイッチを押さなくても点滅しますね。
これはスイッチ端子の電圧が不定となりスイッチを押していなくてもLOWに近い値になっているからです。
Arduinoでは電圧を変えるアナログ出力機能はありません。その代わりに一定の周期のパルス幅の割合(デューティ比) を変えるパルス幅変調方式を使ってアナログ出力を行っています。
Wikiのデューティ比 からデューティ比の説明図を引用します。
デューティ比が大きいと電圧が掛かっている時間が長く、 デューティ比が小さいと電圧が掛かっている時間が短くなります。 これで、LEDやモータに流れる電流の量を調整することで、明るさや回転の強さをコントロールしています。 また、抵抗とコンデンサーを使った低周波フィルターを通すとデューティ比の変化が波の形で出力します。
ATtiny85でPWMが使えるのは、3番ピンの#4、5番ピンの#0、6番ピンの#1の3つです。
PWMの回路は、以下の様にします。
LED出力には、5番ピンの#0を使用します。抵抗値は470Ωにしました。
lbedのPWMOutクラスを使ったスケッチを以下に示します。
PwmOutはのクラス名で、led(1)で1番ピンにアナログ出力(PWM)するledという変数を宣言しています。 ledへの代入する値は、デューティ比を実数で与えます。とてもすっきりしたスケッチになります。
#include "TinyWireM.h" #include "lbedGemma.h" PwmOut led(0); // PWM LED void setup() { } void loop() { for (led = 0.0; led < 1.0; led = led + 0.02) wait_ms(20); for (led = 1.0; led > 0.0; led = led - 0.02) wait_ms(20); }
電子工作の回路をみるとLEDにつなぐ抵抗の値が330Ωだったり、今回のように470Ωだったりしますが、 この値はどのようにして決めるのでしょうか。
LEDの場合、どの程度の電流を流すかによって抵抗の値が変わります。 LEDに流す電流はデータシート呼ばれる部品の規格を説明した資料で調べます。
秋月のサイトから赤色LED(OSDR3133A)をみると、 「抵抗の計算方法 があります。これに沿って説明します。
赤色LEDの順方向電圧(VF)は、2.0Vであり、LEDに電流が流れたときに電圧が2.0V下がることを意味しています。 順方向電流IF(DC Forward Current)30mAとあります。
通常LEDの電流はIFの半分以下の10mA程度で使うのがよいとされおり、 最近のLEDは輝度も高いので5mA程度でも十分と思われます。
470Ωでは、抵抗による電圧降下はオームの法則から抵抗×電流ですから、 以下の等式から電流は6.3mAと求まります。
$$ 5V = 2.0 + 470 \times 6.3mA $$
スケッチを実際に動かしてみましょう。LEDの明るさが、もわもわっと変わります。
シリアル通信には、UART(調歩同期方式)方式が使われています。 UARTでは、送信(TX or TDX)と受信(RX or RDX)と呼ばれる2本の信号線を使って、 双方向に通信します。
UARTのつなぎ方は特徴的でPC側のTXとArduino側のRX、PC側のRXとArduino側のTX を接続します。
Arduinoとのシリアル通信には、5Vと3.3Vのどちらでも使える https://www.switch-science.com/catalog/1032/ が便利です。 アマゾンで検索すると、同じ機能のモジュールがワンコイン程度であります。 *2
USBシリアル変換モジュールとATtiny85(Gemma)をつないだ回路を作ります。
これをブレッドボードで組み立てると以下の様になります。
ミニマム本に習って、Arduino IDEのシリアルモニターから数値を入力し、その回数分 LEDを点滅させる例題を作ってみましょう。
ATtiny85にはシリアル通式の機能がないので、ArduinoのSoftwareSerialクラスを使って、 ソフトウェアでシリアル通信を処理します。
#include "TinyWireM.h" #include "lbedGemma.h" #include "SoftwareSerial.h" DigitalOut led(1); // Gemmaに付属のLED SoftwareSerial pc(4, 3); // RX=4, TX=3 void setup() { pc.begin(4800); } void loop() { if (pc.available()) { // PCから受信した値 int recv_value = pc.read(); // PCにそのまま送信 pc.write(recv_value); // 数字'0'〜'9'を数値の0〜9に変える int value = recv_value - '0'; if (0 < value && value <= 9) { for (int i = 0; i < value; i++) { led = HIGH; wait_ms(250); led = LOW; wait_ms(250); } } } }
電源は、USBシリアルモジュールから取りますので、スケッチを書き込む時にはUSBシリアルを外しておいて、 書き込みが終わったら、lbedGemmaのUSBケーブルを外し、USBシリアルモジュールに付け直してください。
Arduino IDEのシリアルモニターを起動し、ボーレートを4800baud、改行なしにセットして、 数字を入力して「送信」ボタンをおしてみてください。
数値がシリアルモニターにエコーバックされ、数値の回数だけLEDが点滅します。
ミニマム本では、アナログ入力の例に光センサーCdsセルを使っていますが、 手元にCdsがないので温度センサーLM35を使ってアナログ入力の紹介をします。
LM35は、秋月などで120円程度で買える手軽な温度センサーです。 両端にVCCとGNDをつなぎ、中央の電圧に100倍すると温度になるとてもシンプルなセンサーです。 ピンの配置は平らな部分を上にして、底の左から+Vs, Vout, GNDに割り当てられています。
シリアル通信の回路に温度センサーLM35を追加した回路は、以下の様になります。
この回路をブレッドボードで組み立てると以下の様になります。
AnalogInはのクラス名で、lm35(1)でアナログ1(6番ピン)にアナログ入力するlm35という変数を宣言しています。 lm35からの入力値は、0V〜稼働電圧(5V)を0.0〜1.0の値で返します。
温度は、lm35の値に5V x 100倍で計算されますので、float value = lm35*5.0*100.0; としています。
#include "TinyWireM.h" #include "lbedGemma.h" #include "SoftwareSerial.h" SoftwareSerial pc(4, 3); // RX=4, TX=3 AnalogIn lm35(1); void setup() { pc.begin(4800); } void loop() { float value = lm35*5.0*100.0; pc.print("Temp="); pc.print(value, 1); pc.println(""); wait_ms(1000); }
できたスケッチをブレッドボードに書き込み、USBケーブルをUSBシリアルに付け替えて、 シリアルモニターを開くと、温度が表示されます。
秋月でも400円で購入できる超音波センサーHC-SR04を使って距離を測ってみましょう。 Arduino UNOでは2m程度は測定できましたが、8MHzのATtiny85では測定範囲は1cm~34cm程度でした。
ATtiny85とHC-SR04の結線は、以下の通りです。
Gemma | HC-SR04 |
5V | VCC |
6番ピン #1 | Echo |
5番ピン #0 | Trig |
GND | GND |
このスケッチは、 Arduino and HC-SR04 ultrasonic sensor のスケッチをATtiny85用に修正したものです。
#include "SoftwareSerial.h" #define trigPin 0 #define echoPin 1 SoftwareSerial pc(4, 3); void setup() { pc.begin(4800); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); } void loop() { int duration, distance; digitalWrite(trigPin, HIGH); delayMicroseconds(1000); digitalWrite(trigPin, LOW); duration = pulseIn(echoPin, HIGH); distance = (duration/2) / 29.1; if (distance >= 200 || distance <= 0){ pc.println("Out of range"); } else { pc.print(distance); pc.println(" cm"); } delay(500); }
pulseInはArduinoの提供する関数で、パルスの種類をHIGHに指定すると、 入力がHIGHからLOWになるまでの時間をマイクロ秒で返します。
この関数を使って、超音波を発信してそのエコーを受信するまでの時間を計測して距離を計算します。
例えば、\( \Delta t = 500 \) μ秒だとすると、その半分の 250μ秒が物体まで超音波が届くまでの時間になります。
音の速度cは、以下の式で求まります。 $$ c = 343.5 + 0.6*温度 $$ 気温が20℃だとすると、 c = 331.5 + 0.6 * 20 = 343.5 m/s となります。 単位をcm/μ秒に変換すると、 $$ c = 343.5 * 100/1000000 = 0.0345 cm / \mu s $$ これを使うと\( \Delta t = 500 \)の距離は、D = 250 * 0.03435 = 8.6 cmとなります。
スケッチで使われている29.1という値は、音の伝搬を距離当たりで計算した値(μ秒/cm)です。 $$ 音の伝搬の割合 = 1 / 0.03435 = 29.1 \mu s $$ パルスが戻ってくるまでの時間\(\Delta t \)が変数durationにセットされていますので、距離Dは以下の計算できます。 $$ D = (\Delta t /2 ) / 29.1 $$
測定結果をシリアルモニターで出力している様子です。
皆様のご意見、ご希望をお待ちしております。勉強会で分からなかったこと等、お気軽に問い合わせて下さい。
スパム防止に画像の文字列も入力してください。