2010.4.30 -

Arduino風 パソコン制御とマイコン制御[ATtiny4313版テキスト][ATtiny2313版テキスト][ATmega328版テキスト]

小山智史(弘前大学)
 ここに記載した内容は、千秋さんirukaさんkumanさんと共同で取り組んでいるnutshellプロジェクトにより実現したものです。また、多くの無償のツールと、たくさんの先人の努力の積み重ねにより実現したものです。心より感謝申し上げます。

 ここで、「パソコン制御」は、スイッチやセンサやLEDなどの入出力素子をパソコンにUSB接続し、パソコン側のプログラムで制御する方法です。また、「マイコン制御」は、パソコンと切り離して、マイコン単独で入出力素子を制御する方法です。

マイコン制御

 ArduinoIDEでプログラムを作り、書き込みます。

  1. マイコンは電池(3V)で動作します。
  2. HIDaspxライタ[4]でHEXプログラムを書き込みます。書き込みが終了すると、直ちにプログラムを実行します。

(参考サイト)
[1] V-USB, http://www.obdev.at/products/vusb/
[2] hidmon-2010-0214, http://hp.vector.co.jp/authors/VA000177/html/A3C4A3EFA3F7A3EEA3CCA3EFA3E1A3E4.html
[3] WinAVR, http://sourceforge.net/projects/winavr/
[4] hidspx-2012-0326, http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDaspx_news02
[5] SFCmini, http://kandk.cafe.coocan.jp/sfcmini/[1.0.5β]
[6] Arduino, http://www.switch-science.com/trac/wiki/Arduino-ja-jp
[7] dude-wrap, http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDaspx_news02
[8] USB直結Arduino互換ボード, http://www.geocities.jp/arduino_diecimila/make/usbasp/
[9] シンプルなA-Dコンパータ, http://elm-chan.org/docs/avr/avradc_j.html

(技術情報)
* main2313.batはATtiny2313(12MHz Xtal)のhexファイル作成用のバッチファイルです。
** hidmon.dllは予めパスを設定したフォルダ(例えばC:\bin)に入れておきます。
*** (10)(11)のAD変換は[9]を参考にしました。D9ピンにコンデンサを接続する必要があります。また、コンデンサの値はパソコン制御では0.1μF、マイコン制御では0.01μFと異なりますので注意してください。パソコン制御では値が多少不安定ですので目安程度に留まります。また、パソコン制御ではTimer1を使用しているため、PWMを使用するanalogWrite()と同時に利用することはできません。


(0a) 部品の準備

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
使用する部品の例(作る物に応じて部品を選択します)
部品名・型番備考
ヒダピオ学習回路 6530-7001TopMan @1785
ピンヘッダ(オスL型) 1×40(40P)1秋月 @50
ブレッドボード EIC-3011秋月 @150
ジャンパワイヤ EIC-J-L1秋月 @300
ジャンパワイヤ 15cm(白)1秋月 @300
押しボタンスイッチ DS-660R1共立 @84
LED 5mmφ 赤2@10
LED 5mmφ 緑2@10
LED 5mmφ 黄1@10
数字表示LED C551SR1秋月 @100
圧電スピーカ PKM22EPPH20011秋月 @50
カーボン抵抗 220Ω(赤赤茶)1秋月
カーボン抵抗 1kΩ(茶黒赤)2秋月
カーボン抵抗 10kΩ(茶黒橙)1秋月
ボリューム 10kΩB1秋月 @50
ボリューム用ツマミ ABS-281秋月 @20
CDSセル 5mmφ1秋月 @40
サーボモータ GWS PICO/STD/F1秋月 @800
音声合成LSI ATP3011F41秋月 @850
液晶モジュール1ストロベリーリナックス @1260
温度センサ STTS7511秋月 @100
使用する部品の例(作る物に応じて部品を選択します)
部品名・型番備考
ヒダピオ学習回路 6530-7001TopMan @1785
ブレッドボード EIC-3011秋月 @150
ジャンパワイヤ EIC-J-L1秋月 @300
ジャンパワイヤ 15cm(白)1秋月 @300
電池ボックス(単3×2) BH-321-AS1秋月 @60
電池(単3)2ダイソー @10
AVRマイコン ATtiny2313V/ATtiny4313/ATmega328P1秋月 / DigiKey
押しボタンスイッチ DS-660R1共立 @84
LED 5mmφ 赤2@10
LED 5mmφ 緑2@10
LED 5mmφ 黄1@10
数字表示LED C551SR1秋月 @100
圧電スピーカ PKM22EPPH20011秋月 @50
カーボン抵抗 220Ω(赤赤茶)1秋月
カーボン抵抗 1kΩ(茶黒赤)2秋月
カーボン抵抗 10kΩ(茶黒橙)1秋月
ボリューム 10kΩB1秋月 @50
ボリューム用ツマミ ABS-281秋月 @20
CDSセル 5mmφ1秋月 @40
サーボモータ GWS PICO/STD/F1秋月 @800
音声合成LSI ATP3011F41秋月 @850
液晶モジュール1ストロベリーリナックス @1260
温度センサ STTS7511秋月 @100
GPSモジュール GT-723F1秋月 @2800

(0b) マイコンの準備

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
ヒダピオボードの準備
  1. ヒダピオボード上の8個のLEDにテープを貼り、見えないようにします。これは無用な混乱を避けるために行うものです。
  2. コネクタにピン配置が分かるようにシールを貼ります。(テプラ用ファイル)。
  3. ピンヘッダ(オスL型)をコネクタに差し込みます。
  4. スライドスイッチを「IO」側にします。
AVRマイコンATtiny2313/4313の準備

ATtiny2313/4313に、Arduino風にするためのシールを貼ります(テプラ用ファイル)。

AVRマイコンATmega328Pの準備

ATmega328Pに、Arduino風にするためのシールを貼ります(テプラ用ファイル)。

(0c) ブレッドボードの準備

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
  1. ヒダピオボードをピンヘッダを介してブレッドボードに差し込みます。
  2. コネクタの「Gnd」をブレッドボードのGNDラインに接続します。




(0d) ライタの準備

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
必要ありません。 □ 専用ライタ
 HIDaspxライタを準備します。写真のライタは、配線を簡略化するためにICクリップを使っています。

□ ヒダピオライタ
 ヒダピオボードをライタとして利用する場合は、以下のように接続します。

(1) ジャンパワイヤで接続(最安)
(2) ICクリップ(サンハヤト STC-20A)で接続(オススメ)
(3) 20P ゼロプレッシャーICソケット(サトー電気)で接続(たくさんのAVRマイコンに書き込む場合にオススメ)
※ ライタソフトについては、下記の[パソコンの準備]参照
□ 専用ライタ
 HIDaspxライタを準備します。写真のライタは、配線を簡略化するためにICクリップを使っています。

□ ヒダピオライタ
 ヒダピオボードをライタとして利用する場合は、以下のように接続します。

(1) ジャンパワイヤで接続(最安)
(2) ICクリップ(3M)で接続(オススメ)
(3) 28P ゼロプレッシャーICソケットで接続(たくさんのAVRマイコンに書き込む場合にオススメ)
※ ライタソフトについては、下記の[パソコンの準備]参照

(0e) パソコンの準備

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
  1. hidmon.dll**をパスの設定したフォルダ(例えばC:\bin)に入れておきます。
  2. SFCmini[5]を解凍し、例えばC:\libに置き、パソコンのCPUに応じてinstall-INTELまたはinstall-AMDでインストールします。
  3. hidmon.jsを、作成するHTAプログラムと同じ場所に置きます。
これで、JavascriptのプログラムからATtiny2313のIOレジスタを読み書きすることができるようになります。ここでは、HTAプログラムを作成し、実行します。hidmon.jsで定義した定数と関数は以下のとおりです。
定数
定数の名称内容
DDRB, PINB, PORTB,
DDRD, PIND, PORTD
外部入出力ポート
TCNT1H, TCNT1L,
TCCR1A, TCCR1B, TCCR1C,
OCR1AH, OCR1AL,
OCR1BH, OCR1BL,
ICR1H, ICR1L, TIMSK
タイマー関連レジスタ
UDR,
UCSRA, UCSRB,
UBRRH,UBRRL
シリアル通信関連レジスタ
HIGH, LOW, INPUT, INPUT_PULLUP, OUTPUTピン入出力設定値
PB0-7, PD0-6Arduinoのpin番号
関数
関数の名称内容
poke(a,d)アドレスaにデータdをセット
peek(a)アドレスaの読み取り
pinMode(pin, mode)pin(8-16)をmode(INPUT/OUTPUT)に
digitalWrite(pin,val)pin(8-16)をval(HIGH/LOW)に
digitalRead(pin)pin(8-16)の値(HIGH/LOW)を読み取り
analogWrite(pin,val)pin(12,13)をval(0〜255)に
pin(8-11,14-16)はvalが0〜127でLOW、128〜でHIGH
analogRead(pin)pin(10)の値(0〜1023)を読み取り
serialBegin(baud)シリアル送信の速度をbaudに
serialWrite(val)valをシリアル送信(ピンはD1(PD1))
servoAttach(pin)pin(12,13)をサーボモータに接続
servoWrite(deg)サーボモータの位置をdeg(0〜179)に
tone(pin, freq, t)pin(12,13)に周波数freq(Hz), 長さt(ms)の矩形波出力
beep(freq, t)パソコンの内蔵ブザーに周波数freq(Hz), 長さt(ms)の矩形波出力
(ブザーが内蔵されていないノートPCなどで音が出ない)
delay(t)t(ms)スリープ
map(x, in_min, in_max, out_min, out_max) in_min〜in_max間の値xをout_min〜out_maxの間にマッピング
$(id)HTAオブジェクトのID参照(getElementByIdの短縮形)
  1. Arduino-1.0.5[6]をインストールします。
  2. hardware.zipを解凍し、Arduino-1.0.5/hardwareに上書きします。これにより以下のことが行われます。
    • Arduino-1.0.5/hardware/arduinoフォルダにboards.txtを上書きコピー。
    • Arduino-1.0.5/hardware/tools/avr/binフォルダのavrdude.exeをavrdude_orig.exeに名前を変え、dude-wrap-2010-0517[7]のavrdude.exeをコピー。
    • hidspx-2012-0326[4]のhidspx.exeとhidspx.iniをarduino-1.0.5/hardware/tools/avr/binフォルダにコピー。
    • hardware/arduino/variantsフォルダにatmega328rcとattiny2313rcを追加。
    • hardware/arduino/cores/arduinoフォルダのHardwareSerial.cppの130行目の「PE」を「UPE」に修正。
    • 同フォルダにtone.cppを上書きコピー。
    • ***同フォルダにwiring_analog.cを上書きコピー(analogRead()とanalogWrite()に対応)。
    • ***同フォルダにservo.hを上書きコピー。
  3. ArduinoIDEを利用する場合は、Arduinoを起動し、[ツール][マイコンボード]で「ATTINY2313(8MHz RC)」または「HIDapio - ATTINY2313(8MHz/RC)」(ヒダピオボードをライタとして使う場合)を選択します。これでArduinoIDEの操作でプログラムの書き込みを行うことができます。
  4. ArduinoIDEを利用しない場合は、a2313.bat, a328.bat, arduino.batを、Arduino-1.0.5/hardware/tools/avr/binフォルダまたはパスの設定したフォルダ(例えばC:\bin)に入れ、a2313.batのショートカットを作り、名前を「Arduino」としてデスクトップなどに置いておきます。メモ帳でinoファイルを作成し、そのファイルアイコンを作成したショートカット「Arduino」にドラッグ&ドロップ操作すると、プログラムが書き込まれます。なお、inoファイルは例えば「c:\home\Arduino」など日本語やスペースを含まないフォルダに入れてください。

(1) LEDの点滅(デジタル出力)

 LEDを点滅させます。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[Blink.hta]
<html><head><title>LEDの点滅</title> <script src=hidmon.js></script> <script> var ledPin=13; function setup(){ window.resizeTo(240, 200); pinMode(ledPin, OUTPUT); } function loop(){ digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); delay(1000); } </script> </head><body> <h2 align=center>LEDの点滅</h2> </body></html>

参考: [BlinkDX.hta]は、LEDの点滅と連動してパソコン画面の●も点滅する拡張版です。

ArduinoIDE [スケッチの例][01.Basics][Blink] (ledPin 13→11に変更)

 正味のプログラムは下記のとおりです。

[Blink.ino]
int ledPin=11; void setup(){ pinMode(ledPin, OUTPUT); } void loop(){ digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); delay(1000); }

■ ArduinoIDEを利用する場合は、Arduinoを起動し、blink.inoを作成し、書き込み操作を行います。

■ ArduinoIDEを利用しない場合は、メモ帳でblink.inoを作成し、そのファイルアイコンを「Arduino」にドラッグ&ドロップします。



ArduinoIDE [スケッチの例][01.Basics][BlinkWithoutDelay] (ledPin 13→11に変更)

 このプログラムには点滅時間を正確にする工夫が盛り込まれていますが、内蔵クロックで動作させているため、正確さは期待できません。

 正味のプログラムは下記のとおりです。

[BlinkWithoutDelay.ino]
int ledPin=11; int ledState=LOW; long previousMillis=0, interval=1000; void setup(){ pinMode(ledPin, OUTPUT); } void loop(){ unsigned long currentMillis = millis(); if(currentMillis - previousMillis > interval) { previousMillis = currentMillis; if(ledState == LOW) ledState = HIGH; else ledState = LOW; digitalWrite(ledPin, ledState); } }

(2) LEDの明滅(アナログ出力)

 LEDをだんだん明るくし、だんだん暗くし、これを繰り返します。アナログ出力はパルス幅変調(PWM)で行われています。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)

 アナログ出力に利用できるピンは、12, 13です。


 アナログ出力に利用できるピンは、7, 11, 12, 13です。


 アナログ出力に利用できるピンは、3, 5, 6, 9, 10, 11です。


[Fade.hta]
<html><head><title>LEDの明滅</title> <script src=hidmon.js></script> <script> var ledPin=13; var brightness=5, fadeAmount=5; function setup(){ window.resizeTo(240, 200); pinMode(ledPin, OUTPUT); } function loop(){ analogWrite(ledPin, brightness); brightness = brightness + fadeAmount; if(brightness==0 || brightness==255) fadeAmount = -fadeAmount; } </script> </head><body> <h3 align=center>LEDの明滅</h3> </body></html>

[Fading.hta]
<html><head><title>LEDの明滅</title> <script src=hidmon.js></script> <script> var ledPin=13; function setup(){ window.resizeTo(240, 200); pinMode(ledPin, OUTPUT); } function loop(){ for(var fadeValue=0; fadeValue<=255; fadeValue+=5){ analogWrite(ledPin, fadeValue); delay(30); } for(var fadeValue=255; fadeValue>=0; fadeValue-=5){ analogWrite(ledPin, fadeValue); delay(30); } } </script> </head><body> <h3 align=center>LEDの明滅</h3> </body></html>

参考: [FadeDX.hta]は、LEDの明滅と連動してパソコン画面のバー表示も変化する拡張版です。

ArduinoIDE [スケッチの例][01.Basics][Fade] (ledPin 9→11に変更)

 正味のプログラムは下記のとおりです。

[Fade.ino]
int ledPin=11; int brightness=5, fadeAmount=5; void setup(){ pinMode(ledPin, OUTPUT); } void loop(){ analogWrite(ledPin, brightness); brightness = brightness + fadeAmount; if(brightness==0 || brightness==255) fadeAmount = -fadeAmount; delay(30); }

ArduinoIDE [スケッチの例][03.Analog][Fading] (ledPin 9→11に変更)

 正味のプログラムは下記のとおりです。

[Fading.ino]
int ledPin=11; void setup(){} void loop(){ for(int fadeValue=0; fadeValue<=255; fadeValue+=5){ analogWrite(ledPin, fadeValue); delay(30); } for(int fadeValue=255; fadeValue>=0; fadeValue-=5){ analogWrite(ledPin, fadeValue); delay(30); } }

(3) ボタンでオンオフ制御(デジタル入力)

 ボタンを押すと、LEDを点灯させます。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[Button.hta]
<html><head><title>スイッチ</title> <script src=hidmon.js></script> <script> var ledPin=13, buttonPin=8; var buttonState=0; function setup(){ window.resizeTo(240,200); pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT); } function loop(){ buttonState = digitalRead(buttonPin); if(buttonState==HIGH) digitalWrite(ledPin, HIGH); else digitalWrite(ledPin, LOW); } </script> </head><body> <h3 align=center>スイッチ</h3> </body></html>

[Debounce.hta]
<html><head><title>オルタネート</title> <script src=hidmon.js></script> <script> var ledPin=13, buttonPin=8; var ledState=HIGH, buttonState, lastButtonState=LOW; var lastDebounceTime=0, debounceDelay=50; function setup(){ window.resizeTo(240,200); pinMode(ledPin,OUTPUT); pinMode(buttonPin, INPUT); digitalWrite(ledPin, ledState); } function loop(){ var reading = digitalRead(buttonPin); if(reading != lastButtonState) lastDebounceTime=millis(); if((millis()-lastDebounceTime) > debounceDelay){ if(reading != buttonState){ buttonState = reading; if(buttonState == HIGH) ledState = !ledState; } } digitalWrite(ledPin, ledState); lastButtonState = reading; } </script> </head><body> <h3 align=center>オルタネート</h3> </body></html>

[StateChangeDetection.hta]
<html><head><title>スイッチの状態変化検出</title> <script src=hidmon.js></script> <script> var ledPin=13, buttonPin=8; var buttonPushCounter=0, buttonState=0, lastButtonState=0; function setup(){ window.resizeTo(240,200); pinMode(ledPin,OUTPUT); pinMode(buttonPin, INPUT); } function loop(){ buttonState=digitalRead(buttonPin); if(buttonState!=lastButtonState && buttonState==HIGH) buttonPushCounter++; lastButtonState = buttonState; if(buttonPushCounter%4 == 0) digitalWrite(ledPin, HIGH); else digitalWrite(ledPin, LOW); delay(10); } </script> </head><body> <h3 align=center>スイッチの状態変化検出</h3> </body></html>

参考: [ButtonDX.hta]は、ボタンスイッチの操作またはマウスのボタン操作でLEDと同時にパソコン画面の●も点灯する拡張版です。

ArduinoIDE [スケッチの例][02.Digital][Button] (ledPin 13→11に変更)

 このプログラムは、ボタンを押している間LEDが点灯します。

 正味のプログラムは下記のとおりです。

[Button.ino]
int ledPin=11, buttonPin=2; int buttonState=0; void setup(){ pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT); } void loop(){ buttonState = digitalRead(buttonPin); if(buttonState==HIGH) digitalWrite(ledPin, HIGH); else digitalWrite(ledPin, LOW); }

ArduinoIDE [スケッチの例][02.Digital][Debounce] (ledPin 13→11に変更)

 このプログラムは、ボタンを押すと交互にLEDが点灯したり消灯したりします。

 正味のプログラムは下記のとおりです。

[Debounce.ino]
int ledPin=11, buttonPin=2; int ledState=HIGH, buttonState, lastButtonState=LOW; long lastDebounceTime=0, debounceDelay=50; void setup(){ pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); digitalWrite(ledPin, ledState); } void loop(){ int reading = digitalRead(buttonPin); if(reading!=lastButtonState) lastDebounceTime = millis(); if((millis() - lastDebounceTime) > debounceDelay){ if(reading!=buttonState){ buttonState = reading; if(buttonState==HIGH) ledState = !ledState; } } digitalWrite(ledPin, ledState); lastButtonState = reading; }

ArduinoIDE [スケッチの例][02.Digital][StateChangeDetection] (シリアル通信に関係する行を除き、loop() の最後にチャタリング防止のために「delay(10)」を挿入)

 このプログラムは、ボタン操作4回に1度LEDが点灯します。

 正味のプログラムは下記のとおりです。

[StateChangeDetection.ino]
int ledPin=11, buttonPin=2; int buttonPushCounter=0, buttonState=0, lastButtonState=0; void setup(){ pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); } void loop(){ buttonState = digitalRead(buttonPin); if(buttonState!=lastButtonState && buttonState==HIGH) buttonPushCounter++; lastButtonState = buttonState; if(buttonPushCounter%4==0) digitalWrite(ledPin, HIGH); else digitalWrite(ledPin, LOW); delay(10); }

(4) 内蔵プルアップ抵抗を利用したスイッチ入力

 下図(1)は前出の入力回路を示したものです。マイコンの入力信号はスイッチがONの時にHIGH、OFFの時にLOWとなります。(2)はスイッチと抵抗を入れ替えた回路で、マイコンの入力信号はスイッチがONの時にLOW、OFFの時にHIGHとなります。この場合の抵抗は「プルアップ抵抗」と呼ばれます。マイコンのプルアップ抵抗を利用すると、(3)のように抵抗を用意しなくてもよくなります。

 回路が簡単になる反面、プログラムでは「スイッチを押した時にLOW(0)、押さない時にHIGH(1)が入力」されるので、慣れないうちは混乱するかもしれません。


(1)前出の入力回路

(2)スイッチと抵抗を逆に接続

(3)マイコン内蔵の抵抗を利用
パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[DigitalInputPullup.hta]
<html><head><title>プルアップ</title> <script src=hidmon.js></script> <script> var ledPin=13, buttonPin=8; function setup(){ window.resizeTo(240, 200); pinMode(ledPin, OUTPUT); pinMode(buttonPin, INPUT_PULLUP); } function loop(){ var sensorVal = digitalRead(buttonPin); if(sensorVal==HIGH) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); } </script> </head><body> <h3 align=center>プルアップ</h3> </body></html>
ArduinoIDE [スケッチの例][02.Digital][DigitalInputPullup] (ledPin 13→11に変更)

 正味のプログラムは下記のとおりです。

[DigitalInputPullup.ino]
int ledPin=11, buttonPin=2; void setup(){ pinMode(buttonPin, INPUT_PULLUP); pinMode(ledPin, OUTPUT); } void loop(){ int sensorVal = digitalRead(buttonPin); if(sensorVal==HIGH) digitalWrite(ledPin, LOW); else digitalWrite(ledPin, HIGH); }

(5) アナログ入力

 ボリュームのアナログ値(0〜1023)に応じて、LEDの点滅時間を制御します。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[AnalogInput.hta]
<html><head><title>アナログ入力</title> <script src=hidmon.js></script> <script> var sensorPin=A0, ledPin=13; var sensorValue=0; function setup(){ window.resizeTo(310,200); pinMode(ledPin, OUTPUT); } function loop(){ sensorValue = analogRead(sensorPin); digitalWrite(ledPin, HIGH); delay(sensorValue); digitalWrite(ledPin, LOW); delay(sensorValue); } </script> </head><body> <h1 align=center>アナログ入力</h1> </body></html>

参考: [AnalogInputDX.hta]は、ボリュームのアナログ値に応じて、LEDとパソコン画面の●の点滅時間が変化する拡張版です。

ArduinoIDE [スケッチの例][03.Analog][AnalogInput] (ledPin 13→11に変更)

 このプログラムは、ボリュームのアナログ値(0〜1023)に応じて、LEDの点滅時間が変化します。

 正味のプログラムは下記のとおりです。

[AnalogInput.ino]
int sensorPin=A0, ledPin=11; int sensorValue=0; void setup(){ pinMode(ledPin, OUTPUT); } void loop(){ sensorValue = analogRead(sensorPin); digitalWrite(ledPin, HIGH); delay(sensorValue); digitalWrite(ledPin, LOW); delay(sensorValue); }

ArduinoIDE [スケッチの例][03.Analog][AnalogInOutSerial] (ledPin 9→11に変更)

 ボリュームのアナログ値(0〜1023)に応じて、LEDの明るさを制御します。

 正味のプログラムは下記のとおりです。

[AnalogInOut.ino]
int analogInPin=A0, analogOutPin=11; int sensorValue=0, outputValue=0; void setup(){} void loop(){ sensorValue = analogRead(analogInPin); outputValue = map(sensorValue, 0, 1023, 0, 255); analogWrite(analogOutPin, outputValue); delay(2); }

(6) 楽譜の演奏 1

 楽譜データを参照しながら演奏させます。パソコン制御で使用しているbeep関数はPC内蔵ブザーから指定した音を出しますが、ブザーを内蔵していないノートPCでは音が出ません。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)

プログラムサイズの関係でATtiny4313を使います。



[toneMelody.hta]
<html><head><title>楽譜の演奏</title> <script src=hidmon.js></script> <script> var bzzPin=13; var melodyStr= "C4,G3,G3,A3,G3, 0,B3,C4"; var DurationStr=" 4, 8, 8, 4, 4, 4, 4, 4"; function setup(){ window.resizeTo(240, 180); pinMode(bzzPin, OUTPUT); var melody=melodyStr.replace(/ /,"").split(","); var noteDurations=DurationStr.replace(/ /,"").split(","); for(var thisNote=0; thisNote<melody.length; thisNote++){ var Duration=1000/noteDurations[thisNote]; tone(bzzPin, NOTE[melody[thisNote]], Duration); var pauseBetweenNotes=Duration*1.30; delay(pauseBetweenNotes); noTone(bzzPin); } } function loop(){} </script> </head><body> <h2 align=center>楽譜の演奏</h2> </body></html>

[PlayNote.hta]
<html><head><title>楽譜の演奏</title> <script src=hidmon.js></script> <script> var Tempo=300; // テンポ(ms) var bzzPin=13, n=0, note; var Freq={ C4:262, C#4:277, D4:294, D#4:311, E4:330, F4:349, F#4:370, G4:392, G#4:415, A4:440, A#4:466, B4:494, C5:523, C#5:554, D5:587, D#5:622, E5:659, F5:698, F#5:740, G5:784, G#5:831}; // 楽譜...C〜BはC4〜B4, c〜gはC5〜g5 var notes="RDDBAGDR RDDBAGER REEcBAFR RdddcABR RDDBAGDR RDDBAGER REEcBAdd ddedcAGR dR BBBR BBBR BdGABRRR cccccBBB BAABAR dR BBBR BBBR BdGABRRR cccccBBB ddcAGR gR"; function setup(){ window.resizeTo(240, 180); pinMode(bzzPin, OUTPUT); } function loop(){ if(n<notes.length){ note=notes.charAt(n++); if(note=="R") delay(Tempo); else if(note!=" "){ if(note==note.toUpperCase()) note+="4"; // C〜BはC4〜B4 else note=note.toUpperCase()+"5"; // c〜gはc5〜g5 tone(bzzPin, Freq[note], Tempo); // 接続したブザー使用 } } } </script> </head><body> <h2 align=center>楽譜の演奏</h2> </body></html>

参考: [PlayNoteDX.hta]は、画面に鍵盤が表示され、演奏中の鍵の色が変わる拡張版です。

ArduinoIDE [スケッチの例][02.Digital][toneMelody] (bzzPin 8→11に変更)

 正味のプログラムは下記のとおりです。

[toneMelody.ino]
#include "pitches.h" int bzzPin=11; int melody[]={ NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4}; int noteDurations[]={ 4, 8, 8, 4,4,4,4,4 }; void setup(){ for(int thisNote=0; thisNote<8; thisNote++){ int noteDuration = 1000/noteDurations[thisNote]; tone(bzzPin, melody[thisNote],noteDuration); int pauseBetweenNotes = noteDuration*1.30; delay(pauseBetweenNotes); noTone(bzzPin); } } void loop(){}

 正味のプログラムは下記のとおりです。

[PlayNote.ino]
#include <avr/pgmspace.h> PROGMEM prog_int16_t notes[]={ #define C 262 #define D 294 #define E 330 #define F 349 #define G 392 #define A 440 #define B 494 #define c 523 #define d 587 #define e 659 #define f 698 #define g 784 #define R 1 // Rest R,D,D,B,A,G,D,R, R,D,D,B,A,G,E,R, R,E,E,c,B,A,F,R, R,d,d,d,c,A,B,R, R,D,D,B,A,G,D,R, R,D,D,B,A,G,E,R, R,E,E,c,B,A,d,d, d,d,e,d,c,A,G,R, d,R, B,B,B,R, B,B,B,R, B,d,G,A,B,R,R,R, c,c,c,c,c,B,B,B, B,A,A,B,A,R, d,R, B,B,B,R, B,B,B,R, B,d,G,A,B,R,R,R, c,c,c,c,c,B,B,B, d,d,c,A,G,R, g,R,0 }; #define Tempo 300 int bzzPin=11, i, note; void setup(){ pinMode(bzzPin,OUTPUT); } void loop(){ for(i=0;;i++){ note=pgm_read_word(&notes[i]); if(note==0) break; else if(note!=R) tone(bzzPin, note, Tempo); delay(Tempo*1.1); } delay(Tempo*8); }

ArduinoIDE [スケッチの例][02.Digital][toneMultiple]

 正味のプログラムは下記のとおりです。

[toneMultiple.ino]
void setup(){} void loop(){ tone(6, 440, 200); delay(200); noTone(6); tone(7, 494, 500); delay(500); noTone(7); tone(11,523, 300); delay(300); noTone(11); }

(7) カウントアップ

 LEDの数字表示をカウントアップさせます。パソコン制御では、パソコン画面にも数字を表示させます。LEDの数字表示プログラムはPORTBを直接操作するようになっていて、Arduino風ではありません。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[Countup.hta]
<html><head><title>カウントアップ</title> <script src=hidmon.js></script> <script> var count=0; // 0 1 2 3 4 5 6 7 8 9 var LED=[0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67]; function setup(){ window.resizeTo(240, 200); poke(DDRB, 0xff); } function loop(){ poke(PORTB,LED[count]); delay(1000); if(++count==10) count=0; } </script> </head><body> <h2 align=center>カウントアップ</h2> </body></html>

参考: [CountupDX.hta]はLEDのカウントアップと連動してパソコン画面のカウントアップ値とバー表示が変化する拡張版です。

 正味のプログラムは下記のとおりです。

[Countup.ino]
char LED[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67}; void setup(){ DDRD=0xff; PORTD=0x00; for(int i=0;i<10;i++){ PORTD=LED[i]; delay(1000); } } void loop(){}

(8) ボタン操作でカウントアップ

 ボタン操作でLEDの数字表示をカウントアップさせます。パソコン制御では、マウスのクリック操作でもカウントアップし、パソコン画面にも数字を表示させます。LEDの数字表示プログラムはPORTBを直接操作するようになっていて、Arduino風ではありません。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[ButtonCountup.hta]
<html><head><title>カウントアップ</title> <script src=hidmon.js></script> <script> var buttonPin=0; var count=0, buttonMemo; // 0 1 2 3 4 5 6 7 8 9 var LED=[0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67]; function setup(){ window.resizeTo(240, 200); pinMode(buttonPin, INPUT); poke(DDRB,0xff); poke(PORTB,LED[0]); buttonMemo=digitalRead(buttonPin); } function loop(){ var button=digitalRead(buttonPin); if(button!=buttonMemo && button==LOW){ count++; poke(PORTB,LED[count]); } buttonMemo=button; } </script> </head><body> <h3 align=center>カウントアップ</h3> </body></html>

参考: [ButtonCountupDX.hta]は、マウスボタンを押してもカウントアップし、またLEDのカウントアップと連動してパソコン画面のカウント値とバー表示が変化する拡張版です。

 正味のプログラムは下記のとおりです。

[ButtonCountup.ino]
char LED[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67}; int buttonPin=2; // ATmega328の場合は buttonPin=19 int buttonMemo, num=0; void setup(){ DDRD=0xff; PORTD=LED[0]; buttonMemo=digitalRead(buttonPin); } void loop(){ int button=digitalRead(buttonPin); if(button!=buttonMemo && button==LOW){ num++; PORTD=LED[num]; } buttonMemo=button; }

(9) アナログデジタル変換

 ボリュームのアナログ値(0〜1023)に応じて、LEDに0〜9の数字を表示させます。パソコン制御では、パソコン画面にも数字を表示させます。LEDの数字表示プログラムはPORTBを直接操作するようになっていて、Arduino風ではありません。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[adc.hta]
<html><head><title>アナログデジタル変換</title> <script src=hidmon.js></script> <script> var analogPin=A0; // 0 1 2 3 4 5 6 7 8 9 var LED=[0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67]; function setup(){ window.resizeTo(240, 200); poke(DDRB,0xfc); poke(PORTB,LED[0]<<2); poke(DDRD,0x40); poke(PORTD,LED[0]); } function loop(){ var val=analogRead(analogPin); val=Math.floor(val/103); poke(PORTB,LED[val]<<2); poke(PORTD,LED[val]); } </script> </head><body> <h2 align=center>アナログデジタル変換</h1> </body></html>

参考: [adcDX.hta]は、LED表示と連動してパソコン画面の数字表示とバー表示が変化する拡張版です。

 変換値は多少不安定で、目安程度にとどまります。

[adc.ino]
char LED[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67}; int analogPin=A0; void setup(){ DDRD=0xff; PORTD=0x00; } void loop(){ int val=analogRead(analogPin)/103; PORTD=LED[val]; }

(10) アナログデジタル変換(明るさセンサCDS)

 (9)のボリュームを明るさセンサCDSに置き換えたもので、明るさを0〜9の数字で表示させます。プログラムは(9)と同じです。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[adc.hta]
<html><head><title>アナログデジタル変換</title> <script src=hidmon.js></script> <script> var analogPin=A0; // 0 1 2 3 4 5 6 7 8 9 var LED=[0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67]; function setup(){ window.resizeTo(240, 200); poke(DDRB,0xfc); poke(PORTB,LED[0]<<2); poke(DDRD,0x40); poke(PORTD,LED[0]); } function loop(){ var val=analogRead(analogPin); val=Math.floor(val/103); poke(PORTB,LED[val]<<2); poke(PORTD,LED[val]); } </script> </head><body> <h2 align=center>アナログデジタル変換</h2> </body></html>

参考: [adcDX.hta]は、LED表示と連動してパソコン画面の数字表示とバー表示が変化する拡張版です。

 変換値は多少不安定で、目安程度にとどまります。

[adc.ino]
char LED[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x67}; int analogPin=A0; void setup(){ DDRD=0xff; PORTD=0x00; } void loop(){ int val=analogRead(analogPin)/103; PORTD=LED[val]; }

(11) 楽器

 スイッチを押すと音が出ます。ボリュームを回して音階を調整します。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[instrument.hta]
<html><head><title>楽器</title> <script src=hidmon.js></script> <script> var bzzPin=13, buttonPin=8, analogPin=A0; function setup(){ window.resizeTo(310,200); pinMode(bzzPin, OUTPUT); } function loop(){ var val=analogRead(analogPin); if(digitalRead(buttonPin)==HIGH) tone(bzzPin, val, 300); else noTone(bzzPin); } </script> </head><body> <h1 align=center>楽器</h1> </body></html>
[inst2313.ino]
int bzzPin=11, buttonPin=2, analogPin=A0; void setup(){ pinMode(bzzPin,OUTPUT); } void loop(){ int note=analogRead(analogPin); if(digitalRead(buttonPin)==HIGH) tone(bzzPin, note, 100); else noTone(bzzPin); delay(100); }

(12) サーボモータの制御

 サーボモータの位置を連続的に制御します。パソコン制御では、パソコン画面のバー表示も変化します。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)


[Sweep.hta]
<html><head><title>サーボモータ</title> <script src=hidmon.js></script> <script> var pos=0, d=1; function setup(pos){ window.resizeTo(240, 200); servoAttach(12); } function loop(){ servoWrite(pos); pos+=d; if(pos==179) d=-1; else if(pos==0) d=1; delay(15); } </script> </head><body> <h2 align=center>サーボモータ</h2> </body></html>

参考: [SweepDX.hta]は、サーボモータの動きと連動してパソコン画面のバー表示が変化する拡張版です。

[Sweep.ino]
#include <Servo.h> int pos=0, d=1; void setup(){ servoAttach(13); } void loop(){ servoWrite(pos); pos+=d; if(pos==179) d=-1; else if(pos==0) d=1; delay(15); }

(13) 押しボタン信号機

 押しボタン信号機の制御をします。これを発展させた本格的な信号機(交通安全教室用)もあります。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[Signal.hta]
<html><head><title>信号機</title> <script src=hidmon.js></script> <script> var buttonPin=8, RPin=16, YPin=15, GPin=14, RRPin=10, GGPin=9, buttonMemo; function carsig(r,y,g){ digitalWrite(RPin,r); digitalWrite(YPin,y); digitalWrite(GPin,g); } function mansig(r,g){ digitalWrite(RRPin,r); digitalWrite(GGPin,g);} function setup(){ window.resizeTo(310,200); pinMode(RPin, OUTPUT);pinMode(YPin, OUTPUT);pinMode(GPin, OUTPUT); pinMode(RRPin,OUTPUT);pinMode(GGPin,OUTPUT); pinMode(buttonPin,INPUT_PULLUP); carsig(LOW,LOW,HIGH); mansig(HIGH,LOW); // 車青 歩赤 } function loop(){ var button=digitalRead(buttonPin); if(button!=buttonMemo && button==HIGH){ delay(4000); carsig(LOW,HIGH,LOW); delay(4000); // 車黄4秒 carsig(HIGH,LOW,LOW); mansig(LOW,HIGH); // 車赤 歩青16秒 delay(16000); for(var i=0;i<8;i++){ // 歩青点滅8秒 mansig(LOW,HIGH); delay(500); mansig(LOW,LOW); delay(500); } mansig(HIGH,LOW); delay(4000); // 歩赤4秒 carsig(LOW,LOW,HIGH); // 車青 } buttonMemo=button; } </script> </head><body> <h3 align=center>信号機</h3> </body></html>
[Signal.ino]
int buttonPin=2; int RPin=16, YPin=15, GPin=14, RRPin=10, GGPin=9, buttonMemo; void carsig(int r, int y, int g){ digitalWrite(RPin,r); digitalWrite(YPin,y); digitalWrite(GPin,g); } void mansig(int r,int g){digitalWrite(RRPin,r); digitalWrite(GGPin,g);} void setup(){ pinMode(RPin, OUTPUT); pinMode(YPin, OUTPUT); pinMode(GPin, OUTPUT); pinMode(RRPin,OUTPUT); pinMode(GGPin,OUTPUT); pinMode(buttonPin,INPUT_PULLUP); carsig(LOW,LOW,HIGH); mansig(HIGH,LOW); // 車青・歩赤 } void loop(){ int button=digitalRead(buttonPin); if(button!=buttonMemo && button==LOW){ delay(4000); carsig(LOW,HIGH,LOW); delay(4000); // 車黄4秒 carsig(HIGH,LOW,LOW); mansig(LOW,HIGH); // 車赤・歩青16秒 delay(16000); for(int i=0;i<8;i++){ // 歩青点滅8秒 mansig(LOW,HIGH); delay(500); mansig(LOW,LOW); delay(500); } mansig(HIGH,LOW); delay(4000); // 歩赤4秒 carsig(LOW,LOW,HIGH); // 車青 } buttonMemo=button; }

(14) 押しボタン信号機(カッコー音付き)

 押しボタン信号機の制御をします。パソコン制御では、パソコン画面の信号機表示が変化し、歩行者信号が青の時にパソコンから「カッコー」の音が出ます。マイコン制御では、歩行者信号が青の時に「カッコー」のブザー音が鳴ります。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[SignalKakko.hta]
<html><head><title>信号機</title> <script src=hidmon.js></script> <script> var buttonPin=8, RPin=16, YPin=15, GPin=14, RRPin=10, GGPin=9, buttonMemo, t=0; function sndPlay(sndfile){ $("BGSND").src=sndfile;} function carsig(r, y, g){ digitalWrite(RPin,r); digitalWrite(YPin,y); digitalWrite(GPin,g); $("R").style.color=(r==HIGH?"red":"darkred"); $("Y").style.color=(y==HIGH?"yellow":"#a0a000"); $("G").style.color=(g==HIGH?"lightgreen":"#003200"); } function mansig(r, g){ digitalWrite(RRPin,r); digitalWrite(GGPin,g); $("RR").style.color=(r==HIGH?"red":"darkred"); $("GG").style.color=(g==HIGH?"lightgreen":"#003200"); } function setup(){ window.resizeTo(310,200); pinMode(RPin, OUTPUT); pinMode(YPin, OUTPUT); pinMode(GPin, OUTPUT); pinMode(RRPin,OUTPUT); pinMode(GGPin,OUTPUT); pinMode(buttonPin,INPUT_PULLUP); carsig(LOW,LOW,HIGH); mansig(HIGH,LOW); //車青 歩赤 } function loop(){ // 10ms毎に呼び出される var button=digitalRead(buttonPin); if(t==0 && button!=buttonMemo && button==HIGH) t++; else if(t>0){ t++; if(t==400) carsig(LOW,HIGH,LOW); //車黄 else if(t==800){carsig(HIGH,LOW,LOW); mansig(LOW,HIGH);} //車赤 歩青 else if(t==801||t==1000||t==1200||t==1400||t==1600) sndPlay("kakko1.wav"); else if(t==1800||t==1900||t==2000||t==2100||t==2200) mansig(LOW,HIGH); else if(t==1850||t==1950||t==2050||t==2150||t==2250) mansig(LOW,LOW); else if(t==2300) mansig(HIGH,LOW); //歩赤 else if(t==2700){ carsig(LOW,LOW,HIGH); t=0;} //車青 } buttonMemo=button; } </script> </head><body> <center> <table cellpadding=4><tr><td valign=top> <table border=1 cellspacing=0 cellpadding=1> <tr><td bgcolor=grey><big><big> <span id=RR>■</span><br><span id=GG>■</span> </big></big></td></tr></table> </td><td valign=top colspan=2> <table border=1 cellspacing=0 cellpadding=6> <tr><td bgcolor=grey><big><big><big> <span id=R>●</span><br> <span id=Y>●</span><br> <span id=G>●</span> </big></big></big></td></tr></table> </td></tr></table> </center> <bgsound id=BGSND loop=1 src='about:blank'> </body></html>
[SignalKakko.ino]
int bzz=11; // 変数bzzに11を代入する int button=2; // 変数buttonに2を代入する int RPin=16; // 変数RPinに16を代入する int YPin=15; // 変数YPinに15を代入する int GPin=14; // 変数GPinに14を代入する int RRPin=10; // 変数RRPinに10を代入する int GGPin=9; // 変数GGPinに9を代入する int lastState=0; // 直前のbuttonの状態 void carsig(int r, int y, int g){ // 関数定義 digitalWrite(RPin, r); // RPinピンにrを出力する digitalWrite(YPin, y); // YPinピンにyを出力する digitalWrite(GPin, g); // GPinピンにgを出力する } void mansig(int r, int g){ // 関数定義 digitalWrite(RRPin, r); // RRPinピンにrを出力する digitalWrite(GGPin, g); // GGPinピンにgを出力する } void setup(){ pinMode(bzz, OUTPUT); pinMode(RPin, OUTPUT); pinMode(YPin, OUTPUT); pinMode(GPin, OUTPUT); pinMode(RRPin,OUTPUT); pinMode(GGPin,OUTPUT); pinMode(button,INPUT_PULLUP); carsig(LOW, LOW, HIGH); mansig(HIGH,LOW); // 車青・歩赤 } void loop(){ int i, Tempo=200, button=digitalRead(buttonPin), e=659, c=523; if(button!=buttonMemo && button==LOW){ delay(4000); carsig(LOW,HIGH,LOW); delay(4000); // 車黄4秒 carsig(HIGH,LOW,LOW); mansig(LOW,HIGH); // 車赤・歩青 for(i=0;i<5;i++){ // カッコー16秒 tone(bzzPin, e, Tempo/2); delay(Tempo*2.5); tone(bzzPin, c, Tempo); delay(Tempo*5.5); tone(bzzPin, e, Tempo/2); delay(Tempo); tone(bzzPin, e, Tempo/2); delay(Tempo); tone(bzzPin, c, Tempo); delay(Tempo*6); } for(i=0;i<8;i++){ // 歩青点滅8秒 mansig(LOW,HIGH); delay(500); mansig(LOW,LOW); delay(500); } mansig(HIGH,LOW); delay(4000); // 歩赤4秒 carsig(LOW,LOW,HIGH); // 車青 } buttonMemo=button; }

(15) 楽譜の演奏 2 (Midi楽器の制御)

 Midi楽器を制御します。マイコン制御の内容は「ジングルベル」のページと同じです(鈴付き!!)。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)


[Midi.hta]
<html><head><title>Midi制御</title> <script src=hidmon.js></script> <script> var VOICE=["Vibraphone","Marimba","Xylophone","Tubular Bells","Dulcimer","Drawbar Organ"]; var freqNote="CDEFGABcdefgZzR"; var freq=[60,62,64,66,67,69,71,72,74,76,78,79,125,126,127], Freq=[]; var notes="RDDBAGDR RDDBAGER REEcBAFR RdddcABR RDDBAGDR RDDBAGER REEcBAdd ddedcAGR dR BBBR BBBR BdGABRRR cccccBBB BAABAR dR BBBR BBBR BdGABRRR cccccBBB ddcAGR gR"; var Tempo=300, voice=11, n=0; function noteOn(data1, data2){ serialWrite(0x90); serialWrite(Freq[data1]); serialWrite(data2); } function setup(){ window.resizeTo(310,200); serialBegin(31250); for(var i=0;i<freq.length;i++) Freq[freqNote.charAt(i)]=freq[i]; $("VOICE").innerText=VOICE[voice-11]; serialWrite(0xc0); serialWrite(voice); } function loop(){ var note=notes.charAt(n); if(note in Freq){ if(note!="R"){ noteOn(note,0x70); delay(Tempo); noteOn(note,0x00); }else delay(Tempo); } if(++n==notes.length){ n=0; if(++voice>16) voice=11; $("VOICE").innerText=VOICE[voice-11]; serialWrite(0xc0); serialWrite(voice); delay(Tempo*8); } } </script> </head><body> <h1 align=center id=VOICE></h1> <div></div> </body></html>
[Midi.ino]
#include <avr/pgmspace.h> #define C 262 #define D 294 #define E 330 #define F 349 #define G 392 #define A 440 #define B 494 #define c 523 #define d 587 #define e 659 #define f 698 #define g 784 #define R 1 // Rest PROGMEM prog_int16_t notes[] ={ R,D,D,B,A,G,D,R, R,D,D,B,A,G,E,R, R,E,E,c,B,A,F,R, R,d,d,d,c,A,B,R, R,D,D,B,A,G,D,R, R,D,D,B,A,G,E,R, R,E,E,c,B,A,d,d, d,d,e,d,c,A,G,R, d,R, B,B,B,R, B,B,B,R, B,d,G,A,B,R,R,R, c,c,c,c,c,B,B,B, B,A,A,B,A,R, d,R, B,B,B,R, B,B,B,R, B,d,G,A,B,R,R,R, c,c,c,c,c,B,B,B, d,d,c,A,G,R, g,R,0 }; #define Tempo 300 int bellPin=9, i, note; void setup(){ pinMode(bellPin,OUTPUT); } void loop(){ for(i=0;;i++){ note=pgm_read_word(&notes[i]); if(note==0) break; else if(note!=R) tone(bellPin, note, Tempo); delay(Tempo*1.1); } delay(Tempo*8); }

(16) 楽譜の演奏 3 (ドラム)

 (4)にドラムを追加してみました。現在、マイコン制御のみです。構想は野尻抱介氏のリズムボット(Make, vol.06, p37)を参考にしました。レパートリーは「大きなたいこ」「ジングルベル」「大きな古時計」「ハッピーバースデー」「クリスタルチルドレン」「附属特別支援学校校歌」...。詳しくはミニドラム・ミニ鉄琴のページを参照してください。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
 

 
[Drum.ino]
#include "drum1.h" PROGMEM prog_int16_t notes[] ={ Z+Lc,Z+Ri, Z,D,D+R,B,A+L,G,D+L2+R,Z+L,D+R,D+R,B,A+L,G,E+L2+R, Z+L,E+R,E+R,c,B+L,A,F+L2+R, Z+L, d+R,d+R,d,c+L,A,B+L2+R, Z+L,D+R,D+R,B,A+L,G,D+L2+R, Z+L,D+R,D+R,B,A+L,G,E+L2+R, Z+L,E+R,E+R,c,B+L,A,d+R,d, d+L, d+R,e+R,d,c+L,A+R,G+R, Z+Li, d+Rc,Z, B+R,B+R,B+L2+R, B+R,B+R,B+L2+R, B+R,d,G+R,A+L, B+L3+R,Z+L, c+R,c+R,c+R,c, c+R,B+R,B+R,B, B+R,A+L,A+R,B+L, A+R,Z+L, d+R,Z, B+R,B+R,B+L2+R, B+R,B+R,B+L2+R, B+R,d,G+R,A+L, B+L3+R,Z+L, c+R,c+R,c+R,c, c+R,B+R,B+R,B, d+R,d+L,c+R,A+L, G+R,Z, g+LR,Z+Lc,0 }; #include "drum2.h"

(17) 楽譜の演奏 4 (鉄琴)

 おもちゃの鉄琴を演奏させてみました。現在、マイコン制御のみです。レパートリーは「ハッピーバースデー」...。詳しくはミニドラム・ミニ鉄琴のページを参照してください。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
 

 
[Tekkin.ino]
#define RIN 1000 // 右サーボの基準位置 #define RCENTER 1300 // 右サーボの中位置: 1000〜2000 #define ROUT 1800 // 右サーボの外位置: RCENTER〜2000 #define LIN 2000 // 左サーボの基準位置 #define LCENTER 1400 // 左サーボの中位置: 2000〜1000 #define LOUT 1000 // 左サーボの外位置: LCENTER〜1000 #define Tempo 360 // 音符の基本長 300ms #define Td 60 // ドラムを打つ時間 60ms...バチによって調整 #define bellPin 0 #define LdrumPin 6 #define RdrumPin 10 #define LservoPin 12 #define RservoPin 13 // xxxx00xx xxxxxxxx 長さ1 #define L2 0x0400 // xxxx01xx xxxxxxxx 長さ2 #define L3 0x0800 // xxxx10xx xxxxxxxx 長さ3 #define L4 0x0c00 // xxxx11xx xxxxxxxx 長さ4 #define R 0x4000 // 0100xxxx xxxxxxxx Rを叩く #define Ri 0x5000 // 0101xxxx xxxxxxxx Rをinへ #define Rc 0x6000 // 0110xxxx xxxxxxxx Rをcenterへ #define Ro 0x7000 // 0111xxxx xxxxxxxx Rをoutへ #define L 0x8000 // 1000xxxx xxxxxxxx Lを叩く #define Li 0x9000 // 1001xxxx xxxxxxxx Lをinへ #define Lc 0xa000 // 1010xxxx xxxxxxxx Lをcenterへ #define Lo 0xb000 // 1011xxxx xxxxxxxx Lをoutへ #define LR 0xc000 // 1100xxxx xxxxxxxx LとRを同時に叩く #define AA 220 // A3 #define AA_ 233 // A3♯ #define _BB 233 // B3♭ #define BB 247 // B3 #define C 262 // C4 #define C_ 277 // C4♯ #define _D 277 // D4♭ #define D 294 // D4 #define D_ 311 // D4♯ #define _E 311 // E4♭ #define E 330 // E4 #define F 349 // F4 #define F_ 370 // F4♯ #define _G 370 // G4♭ #define G 392 // G4 #define G_ 415 // G4♯ #define _A 415 // A4♭ #define A 440 // A4 #define A_ 466 // A4♯ #define _B 466 // B4♭ #define B 494 // B4 #define c 523 // C5 #define c_ 554 // C5♯ #define _d 554 // D5♭ #define d 587 // D5 #define d_ 622 // D5♯ #define _e 622 // E5♭ #define e 659 // E5 #define f 698 // F5 #define f_ 740 // F5♯ #define _g 740 // G5♭ #define g 784 // G5 #define g_ 831 // G5♯ #define _a 831 // A5♭ #define a 880 // A5 #define a_ 932 // A5♯ #define _b 932 // B5♭ #define b 988 // B5 #define Z 1 // Rest #include <avr/pgmspace.h> int tempo; PROGMEM prog_int16_t notes[] ={ Z+L4+Li,Z+Ri, C+L,C+R,D+L2+L,C+L2+R, F+L2+L,E+L2+R,Z+L2+Rc, C+L,C+L,D+L2+L,C+L2+R, G+L2+L,F+L2+L,Z+R,Z+Lc, C+L,C+L,c+L2+L,A+L2+R, F+L2+L,E+L2+L,D+L4+R,Z+Li,Z+Ri, _B+L,_B+R,A+L2+L,F+L2+R,G+L2+L,F+L4+R,0 }; void drumServo(uint8_t pin,int u){ int t; for(t=0;t<tempo;t+=20){ digitalWrite(pin,HIGH); delayMicroseconds(u); digitalWrite(pin,LOW); delayMicroseconds(20000-u); if(t>Td){ digitalWrite(LdrumPin,LOW); digitalWrite(RdrumPin,LOW);} } } void setup(){ pinMode(LdrumPin,OUTPUT); pinMode(RdrumPin,OUTPUT); pinMode(RservoPin,OUTPUT); pinMode(bellPin,OUTPUT); } void loop(){ int note; uint8_t i, drum, len; for(i=0;;i++){ note=pgm_read_word(&notes[i]); drum=(note>>8)&0xf0; // ドラムコード 0x0x-0xfx len=((note>>10)&0x03)+1; // 音符の長さ 2-4 tempo=Tempo*len; // 音符の長さ(ms) note&=0x03ff; // 音階(周波数 Hz) if(note==0) break; // 終了 else if(note!=Z) tone(bellPin, note, tempo-50); if(drum==L/256||drum==LR/256) digitalWrite(LdrumPin,HIGH); // Lを叩く if(drum==R/256||drum==LR/256) digitalWrite(RdrumPin,HIGH); // Rを叩く if(drum==Ri/256) drumServo(RservoPin,RIN); // Rをinへ else if(drum==Rc/256) drumServo(RservoPin,RCENTER); // Rをcenterへ else if(drum==Ro/256) drumServo(RservoPin,ROUT); // Rをoutへ else if(drum==Li/256) drumServo(LservoPin,LIN); // Lをinへ else if(drum==Lc/256) drumServo(LservoPin,LCENTER); // Lをcenterへ else if(drum==Lo/256) drumServo(LservoPin,LOUT); // Lをoutへ else{ delay(Td); digitalWrite(LdrumPin,LOW); digitalWrite(RdrumPin,LOW); // 叩き終える delay(tempo-Td); } } delay(Tempo*8); }

(18) モーターカーの制御

 モーターを2個使ったモーターカーを制御します。パソコン制御では、パソコン画面の自動車が連動して動きます。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)


[Motorcar.hta]
<html><head><title>モータの制御</title> <script src=hidmon.js></script> <script> function setup(){ window.resizeTo(240,200); poke(DDRB,0xff); delay(1000); } function stop(){ poke(PORTB,0x00);delay(1000);} function fwd(){stop(); poke(PORTB,0xa0);} function bwd(){stop(); poke(PORTB,0x50);} function right(){ // 1秒間停止し、1秒間右回転し、1秒間停止 stop(); poke(PORTB,0x90); delay(1000); stop(); } function left(){ // 1秒間停止し、1秒間左回転し、1秒間停止 stop(); poke(PORTB,0x60); delay(1000); stop(); } function loop(){ fwd(); // 前進 while(digitalRead(8)==LOW && !ENDFLAG) delay(10); // 衝突スイッチがオン(HIGH)まで待つ bwd(); delay(1000); right(); // 1秒後退して右回転 } </script> </head><body><h3 align=center>モーターの制御</h3></body></html>

参考: [MotorcarDX.hta]は、画面に自動車が表示され、制御と連動して画面上を動く拡張版です。

[Motorcar.ino]
void setup(){ DDRB=0xff; delay(1000);} void stop(){ PORTB=0x00; delay(1000);} void fwd(){ stop(); PORTB=0xa0;} void bwd(){ stop(); PORTB=0x50;} void right(){ stop(); PORTB=0x90; delay(200); stop();} void left(){ stop(); PORTB=0x60; delay(200); stop();} void loop(){ fwd(); while(digitalRead(8)==LOW); bwd(); delay(300); right(); }

(19) 音声合成

 音声合成LSI(ATP3011F4)を使ってスピーカから合成音声を出します。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)



[Talk.hta]
<html><head> <title>音声合成</title> <script src=hidmon.js></script> <script> var si=0; function setup(){ window.resizeTo(320, 200); serialBegin(9600); serialWrite(0x3f); // '?'を送信 delay(1000); talk(); } function loop(){} function talk(){ serialPrintln($("TEXT").value); while(1){ delay(100); if(serialAvailable()&&serialRead()==0x3e) break; // '>'を待つ } } </script> </head><body> <h2 align=center>音声合成</h2> <input size=38 id=TEXT value="ju'nbi/o'-kei"> <button id=TALK onclick=talk()>TALK !</button> </body></html>

参考: [TalkDX.hta]は、17種の音声がランダムに再生される拡張版です。

[Talk.ino]
void setup(){ Serial.begin(9600); while(1){ Serial.write('?'); delay(300); if(Serial.available()>0 && Serial.read()=='>') break; } } void loop(){ Serial.println("ju'nbi/o'-kei"); delay(1000); }

(20) 音声合成(I2C版)

 I2C版で音声合成LSIを使ってスピーカから合成音声を出します。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
 

 
[i2cTalk.ino]
#include "i2c2313.h" int AquesTalk=0x2e; void setup(){ delay(300); I2cInit(); } void loop(){ I2cPrintln(AquesTalk,"ju'nbi/o'-kei"); while(I2cReadByte(AquesTalk)!='>') delay(10); delay(2000); }

(21) 温度計(I2C版)

 I2C接続の温度センサ(STTS751)を使った温度計です。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
 

 
[i2cThermo.ino]
#include "i2c2313.h" #define CONTRAST 60 // 0-63 #define THERMO 0x39 void setup(){ LcdBegin(CONTRAST); I2cWriteByte(THERMO,0x03,0x0c);} void loop(){ uint8_t t1=I2cReadByte(THERMO,0x00); // 整数部(符号ビット付) uint8_t t2=I2cReadByte(THERMO,0x02); // 小数部 t2>>=4; t2+=(t2>>2)+1; t2>>=1; // 小数以下1桁 LcdSetCursor(0,0); if(t1&0x80){LcdPut('-'); t1&=0x7f; } // 負なら「-」表示 else LcdPut(' '); LcdPut(t1/10+0x30); // 10の位 LcdPut(t1%10+0x30); // 1の位 LcdPut('.'); LcdPut(t2+0x30); // 0.1の位 LcdPut(0xf2); LcdPut('C'); // ℃ delay(1000); // 1秒毎に繰り返す }

 なお、同じフォルダにi2c2313.hを置いておきます。


(22) GPS時計

 GPSモジュール(GT-723F)を使った時計です。ただし、3Vでの使用は定格外です。まだ、プログラムサイズが少し大きいのでATtiny4313を使っています。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
 

 
[GPSClock.ino]
#include "i2c2313.h" void GPSread(char *s){ uint8_t i; while(1){ if(Serial.available() && Serial.read()=='$') break; } for(i=0;i<10;i++){ while(!Serial.available()); s[i]=Serial.read(); } } void setup(){ Serial.begin(9600); LcdBegin(44); } void loop(){ char str[10]; GPSread(str); if(strncmp(str,"GPGGA,",6)==0){ if(str[6]=='2'){ str[6]='0'; str[7]+=5;} else if(str[6]=='1' && str[7]>='5'){ str[6]='0'; str[7]-=5;} else if(str[7]=='0') str[7]+=9; else{ str[6]++; str[7]--;} if(str[6]=='0') str[6]=' '; LcdSetCursor(0,0); LcdPut(str[6]); LcdPut(str[7]); LcdPut(':'); // hh LcdPut(str[8]); LcdPut(str[9]); // mm } }

 なお、同じフォルダにi2c2313.hを置いておきます。


(23) ワイヤレストランシーバ

 ボタンを押すと相手側のLEDが点灯します。

パソコン制御(ATtiny2313 ヒダピオ)マイコン制御(ATtiny2313/4313)マイコン制御(ATmega328)
   
(1台は破線を接続)
 
[rf24.ino]
#include <SPI.h> #include "nRF24L01.h" #include "RF24.h" #define Role() (digitalRead(rolePin)==LOW) #define buttonOn() (digitalRead(buttonPin)==LOW) RF24 radio(8,10); uint8_t count=0; const int rolePin=3, buttonPin=2, ledPin=7; const uint64_t pipes[2]={ 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; void setup(void){ pinMode(rolePin, INPUT_PULLUP); pinMode(buttonPin, INPUT_PULLUP); pinMode(ledPin, OUTPUT); delay(20); radio.begin(); radio.setRetries(15,15); radio.setPayloadSize(1); if(Role()){ radio.openWritingPipe(pipes[0]); radio.openReadingPipe(1,pipes[1]); }else{ radio.openWritingPipe(pipes[1]); radio.openReadingPipe(1,pipes[0]); } radio.startListening(); } void loop(void){ if(buttonOn()){ radio.stopListening(); uint8_t c=20; radio.write(&c, 1); radio.startListening(); delay(20); } if(radio.available()) for(bool done=false; !done; ){ done=radio.read(&count, 1); delay(20); } if(count>0) count--; digitalWrite(ledPin, (count>0?HIGH:LOW)); delay(20); }

(付録) 私が理解したArduino

 Arduino(やそれに近いもの)を大学や高校や中学校の実習用教材に利用したいと思っています。Arduinoおよびそれに近いものが、それぞれどのような関係にあるのか自分なりに整理してみました。(1)〜(5)のようにマイコン制御(ボード単独)で動作させるか、(1)(2)(6)(7)のようにパソコン制御とするかは、やりたいこと(やらせたいこと)によって変わってくるところです。

(1) 標準的Arduino(マイコン制御またはパソコン制御)

 ボードは標準のArduinoボードを用い、開発はArduino IDEで行います。ボード単独で動作しますが、プログラム(Processing)と連携させることもできます。

(参考URL)
http://www.arduino.cc/
http://www.musashinodenpa.com/arduino/ref/

(2) Arduino GUI を使わない方法(マイコン制御またはパソコン制御)

 ボードは標準のArduinoボードを用い、開発は標準のArduino GUIを使わずに、エディタでスケッチ(pdeファイル)を作り、ドラッグ&ドロップまたはコマンドライン操作でアップロード(コンパイルと書き込み)します。ボード単独で動作しますが、プログラム(Processing)と連携させることもできます。

Arduinoにはコマンドライン操作のためのMakefileが用意されていますが、Arduino ATmega328用のa328.batを作ってみました。パスの通ったフォルダ(例えばc:\bin)に入れ、コマンドプロンプトで のように使います。ドラッグ&ドロップで利用する場合はa328.batのショートカットを作っておき、ここにpdeファイル(スケッチ)をドラッグ&ドロップします。

参考: a328.bat, arduino.bat(a328.batから呼び出されます)...a328.batはパソコンに合わせてAVRDUDE_PORTの値(comポートの番号)を変更する必要があります。

(参考URL)
http://cpansearch.perl.org/src/MONTUORI/Device-Arduino-LCD-1.02/arduino/Makefile
http://mjo.tc/atelier/2009/02/arduino-cli.html
http://www.arduino.cc/en/Hacking/CommandLine

(3) Metaboard(簡略化したArduinoボード)(マイコン制御)

 Arduinoボードの代わりに部品を最小限に抑えたMetaboardを使う方法です。開発はArduino IDEを用い、標準的なArduino GUIで(または(2)のような方法で)行います。ボード単独で動作します。

(参考URL)
http://metalab.at/wiki/Metaboard

(4) Arduino IDEを用いてプログラム開発(マイコン制御)

 Arduinoボードを使わずに、任意のAVR搭載ボードのプログラム開発環境としてArduino IDEを用いる方法です。Arduino GUIで(または(2)のような操作で)、Arduinoのライブラリを活用したアプリケーション開発を行えます。ボード単独で動作します。

Arduino ATtiny2313用のa2313.batを作ってみました。パスの通ったフォルダ(例えばc:\bin)に入れ、コマンドプロンプトで のように使います。ドラッグ&ドロップで利用する場合は、a2313.batのショートカットを作っておき、ここにpdeファイル(スケッチ)をドラッグ&ドロップします。

 この方法でATtiny2313を使ったmidiコントローラATtiny2313を使ったミニドラム・ミニ鉄琴を作ってみました。どちらも2048バイトの範囲に収まっています。

参考: a2313.bat, arduino.bat(a2313.batから呼び出されます)

(参考URL)
http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2Fnews46
http://hci.rwth-aachen.de/luminet

(5) WinAVR(gcc)を用いた一般的なプログラム開発(マイコン制御)

 Arduinoを用いずに、WinAVR(gcc)を用いてプログラムを開発する一般的な方法です。

(参考URL)
http://winavr.sourceforge.net/
http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDaspx

(6) HIDmon / ヒダピオ(パソコン制御)

 パソコン側のプログラム(Visual BasicやExcel VBAやHTA)で外部入出力を制御する方法です。

ヒダピオは、HIDmonを中学校技術科教育の制御教材として利用できるように工夫されています。私もHIDmonをHTAで利用する方法を模索しています。

概観 画面
(参考URL)
http://hp.vector.co.jp/authors/VA000177/html/AVR_Monit.html
http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDmon00
http://www.ne.jp/asahi/ja/asd/gijutu/HIDapio/

(7) Gainer/Pepper(パソコン制御)

 パソコン側のプログラム(ProcessingやFlash)で外部入出力を制御する方法です。

(参考URL)
http://gainer.cc/
http://web.mac.com/kuwatay/morecat_lab./Pepper.html

ふたつのシナリオ

(シナリオ1)

コンピュータの仕組み
HIDaspx(tiny2313)
アセンブラ
マイコン制御(上の(4))
HIDaspx(tiny2313)
Arduino(スケッチ)/WinAVR(C)

 シナリオ1は、従来の「AVRマイコン入門」のトレーニングボードをブレッドボードに変更し、まずはアセンブラと機械語でコンピュータの仕組みを理解し、その後、Arduino(スケッチ)でさまざまなプログラムを開発するというものです。tiny2313はアナログ入力が無いのが残念なところです。また、Arduinoで作成できるプログラムサイズは限られてしまいますが、tiny4313が利用できるようになるとこの点は改善されます。tiny2313にこだわるのは、

というふたつの理由です。また、なぜこのようなことを重視するかというと、対象として想定している中学校の技術科教員(あるいはその卵)がこの分野の学習に充てることができる時間は少なく、核心となる事柄に集中して取り組んでもらいたいからです。

(シナリオ2)

HP作成
プログラミング入門
(Javascript)
パソコン制御
HIDmon&bootloadHID(mega328P)
Arduino風HTA(Javascript)

 シナリオ2は、HTMLタグによるHP作成、Javascriptプログラミングの延長線上でパソコン制御を扱おうというものですが、...実際にはちょっと難しいかもしれません。


(参考)
方法ボードアナログ入力パソコン制御マイコン制御
ArduinoGUI非ArduinoGUIその他
標準的Arduino(mega168/328)専用ボード○(Processing/Flash) 
Gainer(PSoC)
Pepper(tiny85)
専用ボード○(Processing/Flash) × 
Metaboard(mega168/328)ブレッドボード ×  
ヒダピオ(tiny2313)専用ボード+ブレッドボード×○(専用ソフト/Arduino風HTA) ×バスコンピ
HIDmon(tiny2313)ブレッドボード×○(Arduino風HTA)× 
HIDaspx(tiny2313)ブレッドボード×× 
HIDmon&bootloadHID
(mega328)
ブレッドボード○(Arduino風HTA)  

koyama@cc.hirosaki-u.ac.jp