tinyBasicプログラミング ものづくり(Arduino NANO版)

小山智史(koyama88@cameo.plala.or.jp)

コンピュータの仕組み ATtiny2313版 - - - - -
Arduinoでものづくり ATtiny4313版 ATmega328P版 NANO版 - ESP8266版 XIAO版
tinyBasicでものづくり - - NANO版 ProMicro版 ESP8266版 XIAO版
Pythonでものづくり - - - - - XIAO版
Javascriptでものづくり - - - ProMicro版 - XIAO版



0. 準備
1. コマンド操作
2. デジタル出力(1): LEDの点滅
3. デジタル入力: スイッチ操作でLEDのオンオフ
4. アナログ出力: LEDの明るさを変える
5. アナログ入力
6. デジタル出力(2): 数字表示LED
7. デジタル出力(3): 液晶ディスプレイ
8. センサーの利用
9. ブザー音で演奏
10. 合成音声でおしゃべり
11. イルミネーション
12. 赤外線リモコン
13. 動くものを作る
14. 押しボタン信号機
15. シリアル通信教材(光通信)
16. ビデオ表示
(付録1) 入出力モジュール
(付録2) 使用する主な部品
(付録3) 入出力に利用できるピン
(付録4) tinyBasicの書き込み
(付録5) tinyBasic リファレンス
(付録6) 文字と文字コード


 私達の身近にある電子機器の多くにコンピュータが内蔵されており、このようなコンピュータは「マイコン」と呼ばれます。マイクロコンピュータあるいはマイクロコントローラの略です。マイコンにはメーカーが開発したプログラムが書き込まれています。リモコンの中に入っているマイコンには、押したボタンに応じて決まったパターンで赤外線をオンオフするプログラムが書き込まれています。このプログラムはマイコン製造時に書き込まれ、後から書き換えることはできませんが、フラッシュメモリー(電気的に書き換え可能なプログラムメモリー)を搭載したマイコンを使えば、私達もさまざまな機器を作ることができます。実際に、11章ではイルミネーションオブジェ、12章では電池で省電力モードで動作するリモコン、16章ではビデオゲームの製作例をそれぞれ紹介しています。
 マイコンを使った機器を設計・製作するには、電子回路、論理回路、コンピュータの仕組み、プログラミングなど広範囲の知識が要求されます。これは大変なことではありますが、一方ではこれらのことを学ぶ格好の教材であるということを意味しています。
 このテキストでは、Arduino版tinyBasicを使った実習を行いながら、「マイコンを使ったものづくり」について学習します。

☆ 本テキストは実習時に適宜解説や補足を行うことを前提にしています。自学自習には適していないかもしれません。


0. 準備

0.1 ブレッドボードの使い方

 ここでは下図左のブレッドボード(EIC-701)を使います。ボードの内部は下図右のように接続されています。

(外観) (内部の接続)

 ブレッドボードにArduino Nanoを差し込み、GNDと5Vの端子を図のように接続します。USBケーブルをパソコンに接続すると、電源(5V)がパソコンから供給されます。Arduino Nanoに見やすいラベルを貼っておくことをお勧めします

(回路図) (実体配線図)

 初めてブレッドボードを使う場合は、練習としてLEDと抵抗を下図左のように接続して点灯を確認しましょう。電源はパソコンからUSB端子を通じて供給され、電流の流れは下図右のようになります。ブレッドボードの内部の結線も含めて「電流が流れる経路」を意識することが重要です。

(回路図) (実体配線図) (電流の流れ)

0.2 tinyBasicの準備

 付録4を参考に、ArduinoにtinyBasicのプログラム(1)を書き込みます。

 tinyBasicのプログラムはArduinoのマイコンで動作し、パソコンからの指示を受けて、ハードウェアを制御したり、命令の並び(プログラム)としてRAMに一時保存したり、そのプログラムを1行ずつ順に解釈しながら実行(RUN)したりします(下図左)。

 また、RAMのプログラムはマイコン上のEEPROM(不揮発メモリー)に保存(SAVE)することができます。電源を切るとRAM内のプログラムは消えてしまいますが、EEPROMに保存したプログラムをRAMに読み込むことができ(LOAD)、また電源投入時には自動的に読み込まれてプログラムが自動実行されます。

 プログラムが完成したら、電池を直接接続したり、100均などで入手できるUSB電源アダプタを使うとよいでしょう。ただし、電池とUSBを同時に接続しないよう注意してください。

[パソコンと接続してプログラム作成] → 「SAVE」 → [完成後は自立動作]


Arduinoで製作(電源はUSBから供給)


電池で利用

 このテキストはArduino Nanoとブレッドボードを使ったものづくりの練習を中心に扱っています。テレビ画面に表示する応用例は16章に紹介しました。

0.3 通信ソフトTeraTermの準備

 パソコンに通信ソフトTeraTermをインストールします。[設定][シリアルポート]で「ポート」をArduinoを接続して現れるポートにし、「ボー・レート」は「9600」にします。また、[設定][フォント]で「サイズ」を「20」ぐらいにすると見やすいかもしれません。設定が終わったら[設定][保存]で保存します。

 通信ソフトで接続すると「HalfByte...Hitany key!」の表示が現れるので、何かキーを押します。そして、「0.2 ArduinoにtinyBasicを準備」の後初めて使う場合に一度だけ「new」「save」の操作をしてください。

 TeraTermの設定は夢色☆あんどろいどさんが解説してくださっています[4]。


1. tinyBasicのコマンド操作

1.1 コマンドの実行

 パソコンから通信ソフトTeraTermを用いてArduinoに接続すると、下の画面が表示されます。


パソコンの通信ソフト(TeraTerm)の表示画面
 はじめに、コマンドで直接指示を与える方法を試してみましょう。
print 100
これは、「100を表示しなさい」という「命令」を表していて、この1行が「命令文」になっています。「文」といっても、疑問文や感嘆文があるわけではありません。コンピュータ(tinyBasic)に対して指示を与える「命令文」があるだけです。
 では、次のようにするとどうでしょうか。
print 100*200/50+2 print 30000+2000 print 30000+8000
それぞれ計算結果が表示されますが、最後の命令文は計算結果が扱える数「-32767~32767」を越えてしまったため、正しく表示されません。

 文字列を表示することもできます(日本語も表示できます)。また、「,(カンマ)」で区切ると、文字列や数値(計算結果)を続けて表示することができます。

print "ABC" print "弘前大学" print "100+200" print "100+200=",100+200

(練習)大文字と小文字は区別されないので、キー操作は「print」でも「PRINT」でも構いません。また、「print」の代わりに「?」でも構いません。確かめなさい。

1.2 変数

 「変数」は値をしまっておく入れ物です。変数にはA~Zの名前がついていて(変数名)、26個あります。大文字小文字は区別されません。変数には-32767~32767の整数を格納できます。

X=1 Y=2
と操作すると、「X」「Y」という変数(入れ物)にそれぞれ「1」「2」という値が代入されます。XとYに値を入れたので、以下の操作で変数同士の計算結果が表示されます。
print X+Y


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

2.1 LEDを点灯・消灯する

 以下の回路を組み立ててください。


(a) 回路図

(b) 実体配線図

 LEDはD11ピンに接続します。「dWrite」というコマンドでD11ピンに高い電圧を出力したり低い電圧を出力したりすることができます。

dWrite 11, 1 または dWrite 11,HIGH

と操作すると、D11ピンに高い電圧(5V)が出力され、接続したLEDが点灯します。
dWrite 11, 0 または dWrite 11,LOW

と操作すると、D11ピンに低い電圧(0V)が出力され、LEDは消灯します。

上記の「dWrite 11, 1(またはHIGH)」は「D11ピンに1(高い電圧)を出力しなさい」という意味です。

 LEDが点灯する時の電流の流れは下図のようになります。

(練習)「dWrite 11, 1」および「dWrite 11, 0」の時のD11ピンの電圧を、テスターで測りなさい。

(練習)LEDを他のピンにつなぎ替えて、点灯・消灯してみなさい。

2.2 プログラムでLEDを点滅させる

 はじめに、「NEW」の操作でプログラムを消去します。

new

 プログラムのはじめの一歩は「Lチカ」です。以下の「プログラム」を入力してください。プログラムは「命令の並び」で、並びの順に実行されます。各行先頭の10~50は「行番号」で、コンピュータの中では、行番号の小さい行から順に並んでいます。先に大きな行番号の行を入力して後から小さな行番号の行を入力しても結果は同じになります。また、同じ行番号で入力しなおせば、置き換えられます。行番号だけを入力するとその行は削除されます。

10 dWrite 11, 1 20 delay 1000 30 dWrite 11, 0 40 delay 1000 50 goto 10 ピン11に1(HIGH)を出力する 1000ms(1秒)待つ ピン11に0(LOW)を出力する 1000ms(1秒)待つ 行10に行く

 以下、プログラムの内容について簡単に説明します。10~50の各行は「命令文」になっていて、それぞれ次のような意味です。これにより、行10~50が繰り返されます。

 「LIST」と操作すると、入力したプログラムが表示されます。

list

 「RUN」と操作すると、最も小さい行番号から順にプログラムが実行され、LEDが点滅を繰り返します。

run

 プログラムの実行を中断するには「ESCキー」を押します。

 後から途中にプログラムを挿入したくなることもありますから、行番号は10刻みぐらいにしておきます。

 1行に「:」で区切って複数の命令文を書くことができます。以下のプログラムはこの方法で書き直したものです。動作は同じです。

10 dWrite 11, 1: delay 1000 20 dWrite 11, 0: delay 1000 30 goto 10

 このように入力したプログラムは、RAMに一時保存されていて、電源を切ると消えてしまいます。「SAVE」の操作でEEPROM(不揮発メモリー)に保存することができます。

save

 保存したプログラムは、「LOAD」の操作で読み込まれます。

load

 保存できるプログラムはひとつで、名前をつけたりすることはできません。

 保存されたプログラムは、電源投入時に自動的にロードされ、自動実行されます。

(練習) (1)上のプログラムを入力し、LISTで確認後、SAVEで保存しなさい。(2)続いてNEWで消去し、LISTで確認後、LOADして再びLISTで確認しなさい。(3)一旦電源を切断し、その後電源を接続してプログラムが自動実行されることを確認しなさい。可能ならばパソコン以外のUSB電源に接続して動作を確認しなさい。

(練習) LEDを0.5秒点灯、0.5秒消灯を繰り返すようにプログラムを変更しなさい。また、0.2秒点灯、1.8秒消灯を繰り返すように変更しなさい。

2.3 LEDを高速に点滅させる

 LEDの点灯時間と消灯時間を変更してみます。

 「delay 1000」→「delay 100」→「delay 20」→「delay 10」→「delay 1」と変えて、点滅の様子を確認してください。「delay 10」の時は10ms点灯、10ms消灯を繰り返し、50Hzの点滅になります。「delay 20」(25Hz)の時は点滅しているのがわかりますが、「delay 10」(50Hz)では点滅を感じなくなります。人間の目が感じる「点滅のちらつき」はフリッカと呼ばれ、高速の点滅(50~60Hz)ではちらつきを感じなくなります。

 通常の蛍光灯は100Hz(50Hzの2倍)で点滅しますが、蛍光管の状態によっては発光にムラが生じ50Hzで点滅し、その場合はちらつきが気になることがあります。インバーター式の蛍光灯はちらつきを抑えるために超高速(数10kHz)で点滅させています。また、ブラウン管テレビが毎秒30フレーム(実際にはインターレースで60Hzのフリッカ)、映画のフィルムが毎秒24フレーム(実際には同じフレームを2度映すことで48Hzのフリッカ)になっているのは、このような目の特性を考慮してのことです。

(練習) LEDの点滅速度を30Hz, 40Hz, 50Hz, 60Hzと変化させ、ちらつきが感じられるかどうかを、ブレッドボードを静止した場合と、左右に振った場合の両方で調べなさい。

(練習) 緑色LEDと1kΩの抵抗をD12ピンに追加接続し、そのLEDを1秒毎に点滅させなさい。また、赤色LEDと緑色LEDが1秒毎に交互に点灯するようにしなさい。


3. デジタル入力: スイッチ操作でLEDのオンオフ

3.1 スイッチが押されているかどうか調べる

 下図左のようにD7ピンにスイッチを接続すると、D7ピンはスイッチをオンにすると低い電圧(0V)になり、スイッチをオフにすると高い電圧(5V)になります。これは、下図右のようにマイコンの中に抵抗が内蔵されているためです。この抵抗を「プルアップ抵抗」といいます。「高い電圧に引っ張り上げる抵抗」というような意味です。

回路図
スイッチを接続
回路図
プルアップ抵抗
D7ピンが高い電圧(1)か低い電圧(0)かをdRead(7)で読み取り、printで表示することができます。

print dRead(7)
回路図

 以下はスイッチの状態を時々刻々調べて表示するプログラムです。

10 print dRead(7) 20 delay 200 30 goto 10 スイッチ(ピン7)の状態を表示する 200ms待つ 行10に行く
回路図

 以下はこれを「1行プログラム」として書いたものです。プログラムが思ったように動作せずに頭を抱えている時など、このような方法で調べるとすぐに原因がわかることもあります。

10 print dRead(7):delay 200:goto 10
回路図

(練習) スイッチを押した時と放した時のスイッチ両端の電圧を、テスターで測りなさい。

(練習) スイッチを押した場合と放した場合で、「print dRead(7)」が変化することを確かめなさい。

3.2 スイッチ操作でLEDを点灯・消灯する

 以下のプログラムは、行10でスイッチ(ピン7)の状態を読み取って(0または1)変数Aに代入し、行20でこの値をLED(ピン11)に出力し、これを繰り返します。スイッチを押すとAの値は0になりLEDは消灯し、放すとAの値は1になりLEDは点灯します。

10 A=dRead(7) 20 dWrite 11,A 30 goto 10 Aはスイッチ(ピン7)の状態 Aの値をLED(ピン11)に出力 繰り返す
回路図

 「!A」はAが0の時に1、Aが1の時に0となるので、以下のようにするとスイッチを押した時にLEDが点灯します。

10 A=dRead(7) 20 dWrite 11,!A 30 goto 10

3.3 スイッチ操作で交互に点灯・消灯する

 以下のプログラムは、スイッチを押すと交互にLEDが点灯・消灯します。考え方は、「スイッチが押された瞬間に(つまりさっき押されていなくて今押されたら)LED表示を反転する」というものです。変数Lに「LEDの点灯状態(1が点灯、0が消灯)」、変数Aに「さっきのスイッチの状態(0または1)」、変数Bに「現在のスイッチの状態(0または1)」を保存します。

 行30で、現在のスイッチ(ピン7)の状態(1または0)を読み取り、Bに入れます。行40で、スイッチが「さっきまで押されていなくて今押されている」ならLの値を反転(0なら1、1なら0)します。その後、行50で「今のスイッチの状態を記憶」しなおし、行60でLの値をLEDに出力します。行70で、少し待ってから行30に行き、繰り返します。

10 L=0 20 A=1 30 B=dRead(7) 40 if A=1 if B=0 L=!L 50 A=B 60 dWrite 11, L 70 delay 10 80 goto 30 LはLEDの点灯状態 Aはさっきのスイッチの状態 Bは現在のスイッチの状態 さっき押されていなくて今押されたらLを反転 スイッチの状態を覚え直す LをLED出力 少し待って 繰り返す
回路図

 「delay 10」がないと、誤動作することがあります。それは、スイッチを押した時に、ごく短い時間にその接点がオンになったりオフになったりするからです。スイッチを離した時も同様です。スイッチによって異なりますが、10ms程で落ち着きます。この現象は「チャタリング」と呼ばれます。

(練習) 「delay 10」を極端に長くし、例えば待ち時間が2秒になるようにして、どのような動作になるか調べなさい。

(練習) 緑色LEDを増設し、スイッチを押すと赤色LEDと緑色LEDが交互に点灯するようにしなさい。

3.4 スイッチを4回押すと点灯する

 以下のプログラムは、スイッチ操作4回に一度LEDが点灯します。

 上の例ではLEDの表示状態を記憶し、スイッチが押されるとその値を反転させていましたが、ここではCにスイッチが押された回数を記憶します。スイッチがさっきまで押されていなくて今押されているならCの値に1を加えます(行40)。その後、今のスイッチの状態を記憶し(行50)、「C%4=0」つまりCの値を4で割った余りが0であればLEDを点灯し(行60)、そうでなければLEDを消灯します(行70)。最後に、少し待ってから行20に行きます。

10 C=0 20 A=1 30 B=dRead(7) 40 if A=1 if B=0 C=C+1 50 A=B 60 if C%4=0 dWrite 11,1: goto 80 70 dWrite 11,0 80 delay 10 90 goto 30 Cはスイッチが押された回数 Aはさっきのスイッチの状態 Bは現在のスイッチの状態 スイッチが押されたらCに1を加える スイッチの状態を覚え直す Cを4で割った余りが0ならLEDを点灯 LEDを消灯 少し待って 繰り返す
回路図

(練習) 行60の「C%4=0」の箇所を「C%7=0」や「C%4!=0」などに変えて、どのような動作になるか調べなさい。

(練習) 2個の押しボタンスイッチを使い、一方のスイッチを押すとLEDが点灯し、もう一方のスイッチを押すと消灯するようにしなさい。

3.5 スイッチが押されるとLEDを3秒点灯する

 以下のプログラムは、スイッチが押されるとLEDを3秒点灯します。

10 if dRead(7)=0 dWrite 11,1: delay 3000: goto 10 20 dWrite 11,0 30 goto 10
回路図

4. アナログ出力: LEDの明るさを変える

4.1 LEDの明るさを変える

 これまでは、LEDが点灯するか消灯するかでした。しかし、点灯時の明るさを変化させたいこともあります。 aWrite という命令を使い

とすると、指定したピンにアナログ値 0~255 を出力できます。

 LEDの接続はそのままで、以下の操作をしてみましょう。

aWrite 11, 10 aWrite 11, 255
LEDの明るさが変わるのが確認できます。

(練習)LEDの明るさを0~255の範囲で変えてみなさい。また、その時の波形をオシロスコープで観察して記録しなさい。

4.2 プログラムでLEDの明るさを変える

 2.3ではLEDの点灯時間と消灯時間を変えてどのように見えるかを確認しました。ここでは行20と行40を「delay 1」にしてみます(1ms)。

10 dWrite 11,1 20 delay 1 30 dWrite 11,0 40 delay 1 50 goto 10

 既に経験したように、点灯と消灯を高速に切り替えると、私達の目は点滅を認識できなくなります。代わりに、常時点灯している場合よりも少しだけ暗く感じます。「平均的に」半分の明るさになるからです。下図左は、この時のLEDの出力の波形を示したものです。行30の0を1にすれば常時点灯となりますから、LEDの明るさを比較してみてください。私達の目は、明るさが半分になっても、「ちょっと暗くなった」ぐらいにしか感じません。

PWM波形

 次に、行20はそのままにして行40を「delay 9」としてみてください。こうすることにより、1ms点灯、9ms消灯を繰り返すようになり、明るさはより暗く感じられます。この時の波形が上図中央です。

 HIGHとLOWの時間が等しい時「デューティ比50%」、常時HIGHの時「デューティ比100%」、HIGHが1msでLOWが9msなら「デューティ比10%」といいます。この技術は「パルス幅変調(PWM)」と呼ばれ、モータのスピードコントロールや、デジタルオーディオアンプなどに利用されています。

 4.1で使ったaWriteというコマンドを使うと、0/255~255/255のデューティ比で上記のようなPWM信号が出力される仕組みになっています。

(練習) スイッチを押す度に「消灯→暗い→明るい→消灯→...」の動作をするプログラムを作りなさい。

4.3 LEDの明るさを連続的に変える

 デューティ比を連続的に変化させれば、下図のように任意の波形を表すことができます。

PWM波形

 以下は、デューティ比を0%から100%まで少しずつ変化させるプログラムです。暗い状態から次第に明るくなり、その後次第に暗くなり、これを繰り返します。Bが明るさの値、Fが明るさの変化量です。行30でBの値をアナログ出力し、行40でBにFを加えます。

10 B=5 20 F=5 30 aWrite 11, B 40 B=B+F 50 if B=0 F=5 60 if B=255 F=-5 70 delay 30 80 goto 30 Bは明るさ Fは明るさの変化量 LED(ピン11)に明るさ(Bの値)を出力 BにFを加える Bが0ならFを5にする Bが255ならFを-5にする 少し待って 繰り返す

(練習) スイッチを押すとLEDがだんだん明るくなり、スイッチを離すだんだん暗くなるプログラムを作りなさい。


5. アナログ入力

5.1 アナログ値の入力

 以下のようにA0ピンにボリュームを接続し、ボリュームを中ほどの位置にして以下の操作をしてみてください。ボリュームの位置に応じて0~1023の値が表示されます。aReadは指定されたピンのアナログ値(0~1023)を返す「関数」です。aRead(0)は、A0ピンの電圧(0~5V)に応じて0~1023の値が返ってきます。PRINTコマンドを使い、ボリュームの位置を変えて、表示される値を確認してください。また、「1行プログラム」で値を時々刻々表示できます。

print aRead(0)
10 print aRead(0): delay 200: goto 10

(練習) A0の電圧をテスターで測り、ボリュームを回すとどのように変化するか調べなさい(ボリュームの位置が左・中央・右)。また、上記のプログラムを動作させた時に、電圧がいくらの時に表示される値がいくらになるかを調べなさい(ボリュームの位置が左・中央・右)。

5.2 アナログ値に応じてLEDの点灯時間を変える

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

10 dWrite 11,1 20 delay aRead(0) 30 dWrite 11,0 40 delay aRead(0) 50 goto 10
回路図

5.3 アナログ値に応じてLEDを点灯・消灯する

 以下のプログラムは、ボリュームのアナログ値(0~1023)が600未満の時にLEDを点灯します。

10 if aRead(0)<600 dWrite 11,1: goto 10 20 dWrite 11,0 30 goto 10
回路図

5.4 アナログ値に応じて明るさを変える(調光)

 照明の明るさを調整することを「調光」といいます。

 以下のプログラムは、ボリュームのアナログ値(0~1023)に応じてLEDの明るさ(0~255)を連続的に変えます。

10 A=aRead(0)/4 20 aWrite 11, A 30 goto 10 Aは0~255 LED(ピン11)にAの値を出力 繰り返す
以下のように1行プログラムで書くこともできます。
10 aWrite 11,aRead(0)/4: goto 10
回路図

6. デジタル出力(2): 数字表示LED

6.1 数字表示LEDに数字を表示する

 数字表示LED(7セグメントLED C-551SR)に数字を表示してみます。下図の回路を組み立ててください。

 「5」を表示したい場合は a, c, d, f, g を点灯し、b, e を消灯すればいいので、以下のコマンド操作で数字表示LEDに「5」が表示される。

dwrite 2,1 dwrite 3,0 dwrite 4,1 dwrite 5,1 dwrite 6,0 dwrite 7,1 dwrite 8,1
回路図

 これを簡便にするために、7セグメントLEDのa~gをD2~D8に接続した場合は「NUMLED」コマンドで指定した数(0~9)を表示させることができるようになっています。

numled 5
回路図

(練習) 表示する数字を他の数字に変更してみなさい。

6.2 数字表示LEDにカウントアップ表示する

 以下のプログラムは7セグメントLEDに1秒毎に0→9と表示をカウントアップします。

10 for I=0 to 9 20 numled I 30 delay 1000 40 next I 50 goto 10 Iの値を0から9まで繰り返す Iの値を数字表示 1000ms(1秒)待って ここまで繰り返し 同じことを繰り返す
回路図

 以下は、スイッチを押すと数字表示がカウントアップするプログラムです。

10 C=0 20 A=1 30 B=dRead(1) 40 if C<9 if A=1 if B=0 C=C+1 50 numled C 60 delay 10 70 goto 30 Cはカウント値 Aはさっきのスイッチの状態 Bは現在のスイッチの状態 Cの値が9未満でスイッチが押されたらCに1を加える Cの値を数字表示 少し待って 繰り返す
回路図

(練習) 数字表示が9~0にカウントダウンするプログラムを作りなさい。

(練習) 1秒毎ではなく50ms毎に高速でカウントアップするようにしなさい。また、スイッチが押されるとカウントを停止するようにしなさい。

6.3 アナログ値を数字表示LEDに表示する

 以下のプログラムは、ボリュームのアナログ値(0~1023)に応じて、数字表示LEDに0~9を表示させます。

10 A=aRead(0)/103 20 numled A 30 delay 200 40 goto 10 Aは0~9 Aの値を数字表示 少し待って 繰り返す
以下のように1行プログラムで書くこともできます。
10 numled aRead(0)/103: goto 10
回路図

6.4 乱数を数字表示LEDに表示する

 rnd()は乱数を生成する関数で、rnd(10)は0~9の値を返します。以下のプログラムは7セグメントLEDに1秒毎に0~9の数をランダムに表示します。

10 numled rnd(10): delay 1000: goto 10
回路図

(練習) 1秒毎に0~9の数をランダムに表示し、スイッチが押されるとそこで停止するようにしなさい。

6.5 数字の2桁表示

 数字表示LEDに2桁以上の数字を表示するにはどうしたらいいでしょうか。LED毎にa~gをつなげばいいのですが(スタティック点灯)、Arduinoのピンが不足してしまいます。このような場合はダイナミック点灯と呼ばれる方法が用いられます。この方法は、身近にあるさまざまな表示装置に使われています。

 2個の数字表示LEDのa~gに表示したい数字のパターンを出力し、D9ピンを「0(低い電圧)」にすると「10の桁」に、D10ピンを0にすると「1の桁」に表示されます。

 下図の回路を組み立ててください。

 「23」を表示させたい時は以下のようにします。

dWrite 9,1 dWrite 10,1 numled 2 dWrite 9,0 dWrite 9,1 numled 3 dWrite 10,0 dWrite 10,1 (「numled 2」以降を繰り返す)
回路図

 以上のコマンド操作をプログラムで行うと以下のようになります。

10 dWrite 9,1 20 dWrite 10,1 30 numled 2 40 dWrite 9,0 50 delay 1000 60 dWrite 9,1 70 numled 3 80 dWrite 10,0 90 delay 1000 100 dWrite 10,1 110 goto 30 「10の桁」を見せない 「1の桁」を見せない 「2」を数字表示(まだ見えない) 「10の桁」を見せる 1秒待つ(この間「10の桁」が表示される) 「10の桁」を見せない 「3」を数字表示(まだ見えない) 「1の桁」を見せる 1秒待つ(この間「1の桁」が表示される) 「1の桁」を見せない 繰り返す
回路図

 ここで、行50と行90を「delay 1000」→「delay 100」→「delay 20」→「delay 10」と変えてみてください。2.3の時と同様にフリッカが私たちの目にはわからなくなります。

 次に、0~99の数値を表示するにはどうしたらいいでしょうか。今、以下の行25のように変数Tに23という値を入れておきます。行30ではTの10の位の「2」を「T/10」で求め、出力しています。行70ではTの1の位の「3」を「T%10(Tを10で割った余り)」で求め、出力しています。他は前と同じです。行25で0~99の任意の値を指定できます。

10 dWrite 9,1 20 dWrite 10,1 25 T=23 30 numled T/10 40 dWrite 9,0 50 delay 10 60 dWrite 9,1 70 numled T%10 80 dWrite 10,0 90 delay 10 100 dWrite 10,1 110 goto 25 「10の桁」を見せない 「1の桁」を見せない Tは表示したい数 「10の桁」を数字表示(まだ見えない) 「10の桁」を見せる 10ms待つ(この間「10の桁」が表示される) 「10の桁」を見せない 「1の桁」を数字表示(まだ見えない) 「1の桁」を見せる 10ms待つ(この間「1の桁」が表示される) 「1の桁」を見せない 繰り返す
回路図

6.6 アナログ値を数字表示LEDに2桁で表示する

 以下のプログラムは、ボリュームのアナログ値(0~1023)に応じて、数字表示LEDに0~99の2桁で表示させます。行25で「aRead(0)*100/1024」を計算したいのですが、「aRead(0)*100」が数値の範囲 -32767~32767 を越えてしまうので、このようにします。

10 dWrite 9,1 20 dWrite 10,1 25 T=aRead(0)*25/256 30 numled T/10 40 dWrite 9,0 50 delay 10 60 dWrite 9,1 70 numled T%10 80 dWrite 10,0 90 delay 10 100 dWrite 10,1 110 goto 25 「10の桁」を見せない 「1の桁」を見せない Tは0~99 「10の桁」を数字表示(まだ見えない) 「10の桁」を見せる 10ms待つ(この間「10の桁」が表示される) 「10の桁」を見せない 「1の桁」を数字表示(まだ見えない) 「1の桁」を見せる 10ms待つ(この間「1の桁」が表示される) 「1の桁」を見せない 繰り返す
回路図

7. デジタル出力(3): 液晶ディスプレイ

7.1 液晶ディスプレイに文字や数字を表示する

 I2C接続の液晶ディスプレイ(2行16文字)を以下のように接続します。

 CLS(画面クリア)、CURSOR(カーソル位置指定)、PRINT(表示)の3つのコマンドは、通信ソフト(teraTerm等)と液晶の両方の表示に適用されます。ビデオ表示を利用している場合はそちらにも適用されます。

cls print "COUNT: "; print 100

7.2 液晶ディスプレイにカウントアップ表示する

 以下のプログラムは、1秒毎にカウントアップ表示します(通信ソフトの画面にも表示されます)。

10 C=0 20 cls 30 print "COUNT: ",C 40 delay 1000 50 C=C+1 60 goto 20 Cはカウント値 画面クリア Cの値を表示 1秒待つ Cをカウントアップ 繰り返す
回路図

 以下のプログラムは、スイッチを押すとカウントアップするプログラムです(通信ソフトの画面にも表示されます)。

10 C=0 20 A=1 30 cls:print "COUNT: ",C 40 B=dRead(1) 50 if A=1 if B=0 C=C+1:cls:print "COUNT: ",C 60 A=B 70 delay 10 80 goto 40 Cはカウント値 Aはさっきのスイッチの状態 画面クリアしてCの値を表示 Bは現在のスイッチの状態 スイッチが押されたらCに1加えて表示 スイッチの状態を覚え直す 少し待って 繰り返す
回路図

7.3 アナログ値を液晶ディスプレイに表示する

 以下のプログラムは、ボリュームのアナログ値(0~1023)を液晶ディスプレイに表示させます(通信ソフトの画面にも表示されます)。

10 cls 20 print "VAL: ",aRead(0) 30 delay 200 40 goto 10 画面クリア アナログ値を表示 少し待って 繰り返す
回路図

8. センサーの利用

8.1 スイッチをセンサーとして使う

 押しボタンスイッチやスライドスイッチは、操作用のスイッチですが、センサーとしても活躍しています。例えば、CD/DVDデッキやコピー機やプリンタなど動きを伴う機器には、所定の位置に来たがどうかを検知するために、マイクロスイッチが必ずといっていいほど使われています。このような使われ方をするスイッチを「リミットスイッチ」と呼ぶこともあります。

 ふたつの金属片を接触させるだけでスイッチ(センサー)となるので、オリジナルのスイッチを作ることも難しくはありません。所定の水位になったかどうかを検知するピンポン球を使った浮力スイッチ、傾けると金属ボールが移動する傾斜スイッチなど、用途に応じて工夫するのも楽しいでしょう。

 スイッチの値はprintコマンドで表示できます。また、下の1行プログラムでスイッチの様子を時々刻々表示できます。

print dRead(7)
10 print dRead(7): delay 200: goto 10
回路図

8.2 明るさセンサー(CDS): 明るい時にLEDを点灯する

 5.1のボリュームの代わりに明るさセンサー(CDS)をつないでみましょう。CDSは明るくなるほど抵抗値が低くなり、A0ピンの電圧は高くなります。

 printコマンドでA0ピンの値を確認してください。また、下の「1行プログラム」でA0ピンの値を時々刻々表示できます。

print aRead(0)
10 print aRead(0): delay 200: goto 10

 以下のプログラムは一定以下に暗くなるとLEDが点灯します。プログラムは5.3と同様です。ただし、行10の「600」の値は適切な値に変更する必要があります。

10 if aRead(0)<600 dWrite 11,1: goto 10 20 dWrite 11,0 30 goto 10
回路図

 街路灯などでは、境界値付近で点灯したり消灯したり不安定になるのを避けるために、下図のような「ヒステリシス特性」を持たせます。

行20はLEDが消灯(Lが0)している時に600未満の明るさになったらLEDを点灯(Lを1)します。行30はLEDが点灯(Lが1)している時に700以上の明るさになったらLEDを消灯(Lを0)します。実際の点灯消灯は行40で行っています。

10 L=0 20 if L=0 if aRead(0)<600 L=1 30 if L=1 if aRead(0)>=700 L=0 40 dWrite 11,L 50 goto 20 LはLEDの点灯状態 消灯状態で明るさが600未満なら点灯(L=1)にする 点灯状態で明るさが700以上なら消灯(L=0)にする LをLEDに出力 繰り返す
回路図

(練習) 行20の600と行30の700の値を変えて、適切な値をみつけなさい。

8.3 温度センサー(サーミスタ): 温度が高い時にLEDを点灯する

 CDSの代わりに温度センサー(サーミスタ)をつないでみましょう。サーミスタは温度が高くなるほど抵抗値が低くなり、A0ピンの電圧は高くなります。

 printコマンドでA0ピンの値を確認してください。また、下の1行プログラムでA0ピンの値を時々刻々表示できます。

print aRead(0)
10 print aRead(0): delay 200: goto 10

 以下のプログラムは温度がある値以上になるとLEDが点灯します。プログラムは上と同様です。ただし、行10の「25」の値は適切な値に変更する必要があります。

10 if tRead(0)<25 dWrite 11,1: goto 10 20 dWrite 11,0 30 goto 10 温度が25未満ならLEDを点灯し繰り返す LEDを消灯 繰り返す
回路図

(練習) LEDをエアコンに置き換えて考えてみましょう。街路灯の場合と同様、境界値付近で点灯したり消灯したり不安定になるのを避けるために、下図のような「ヒステリシス特性」を持たせます。

ヒステリシス特性を持たせたプログラムでその動作を確かめなさい。

(練習) 温度が高ければ赤、温度が低ければ青のLEDが点灯するようにしてみなさい。

8.4 音量センサー: 音を検知するとLEDを点灯する

 音量センサーは、マイクが検知する音の大きさに応じてA0ピンの電圧は高くなります。

 printコマンドでA0ピンの値を確認してください。また、下の1行プログラムでA0ピンの値を時々刻々表示できます。

print aRead(0)
10 print aRead(0): delay 200: goto 10

 以下のプログラムは、音を検知したら(A0のレベルが300を超えたら)、LEDを3秒点灯します。

10 if aRead(0)>300 dWrite 11,1: delay 3000: goto 10 20 dWrite 11,0 30 goto 10
回路図

(練習) 5.2のスイッチの代わりに音センサを使い、手をたたくとカウントアップするようにしなさい。

8.5 赤外線反射センサー: 何かに接近するとLEDを点灯する

 赤外線反射センサーは、光を反射する物がない時は1000程度の値、数cmのところに光を反射する物がある時は20~30の値を返します。

 printコマンドでA0ピンの値を確認してください。また、下の1行プログラムでA0ピンの値を時々刻々表示できます。

print aRead(0)
10 print aRead(0): delay 200: goto 10

以下のプログラムは、何かに接近したら(A0のレベルが40より小さくなったら)、LEDを点灯します。

10 if aRead(0)>300 dWrite 11,1: delay 3000: goto 10 20 dWrite 11,0: goto 10
回路図

8.6 人感センサー: 人を検知してLEDを点灯する

 以下のプログラムは、人感センサー(焦電センサー)を使って人を検知するとLEDを点灯します。玄関などに使われています。センサーの出力は普段は0(低い電圧)で、人を検知すると一定時間1(高い電圧)になります。センサーについているボリュームで感度や検出後の不感時間を調整できます。

10 dWrite 11,dRead(2) 20 goto 10
回路図

(練習) 人感センサーを2個使い、ある方向で人が通過する時のみLEDが点灯するようにしなさい。

8.7 明るさセンサー(CDS): 明るさを数字表示LEDに表示する

 以下のプログラムは、明るさを数字表示LEDに0~9の数字で表示させます。プログラムは6.5と同様です。

10 A=aRead(0)/103 20 numled A 30 goto 10
回路図

8.8 温度センサー: 温度計を作る

 8.3で使ったサーミスタを使ってもいいのですが、温度計を作ろうとすると「校正」が必要となります。

 ここでは温度センサモジュール(LM61)を使います。temp(0)で、A0ピンに接続した温度センサーから温度直接読み取ることができます。23度であれば、temp(0)は「23」という値を返します。ただし精度はあまり高くはありません。PRINTコマンドで確認してください。また、1行プログラムで温度を時々刻々表示できます。

print temp(0)
10 print temp(0): delay 100: goto 10

 以下は温度を液晶ディスプレイに表示する例です。

10 cls 20 print temp(0),chr(&df),"C" 30 delay 1000 40 goto 10

 プログラムを保存(SAVE)しておくと、パソコンと接続しなくても、電源を入れるとプログラムが起動します。ケースに入れれば温度計の完成です。

 以下は6.6のダイナミック点灯の方法を使ってLEDに2桁表示する例です。

10 dWrite 9,1 20 dWrite 10,1 25 T=temp(0) 30 numled T/10 40 dWrite 9,0 50 delay 10 60 dWrite 9,1 70 numled T%10 80 dWrite 10,0 90 delay 10 100 dWrite 10,1 110 goto 30 「10の桁」を見せない 「1の桁」を見せない Tは温度 「10の桁」を数字表示(まだ見えない) 「10の桁」を見せる 10ms待つ(この間「10の桁」が表示される) 「10の桁」を見せない 「1の桁」を数字表示(まだ見えない) 「1の桁」を見せる 10ms待つ(この間「1の桁」が表示される) 「1の桁」を見せない 繰り返す
回路図

(練習) 上記の「delay 10」の箇所(10ms)を遅くすると(100ms)表示がどうなるか観察しなさい。また、速くすると(1ms)表示がどうなるか観察しなさい。

8.9 温湿度センサー: 温湿度計を作る

 ここでは高精度のデジタル温湿度センサー(SHT31)を使います。tRead()で温湿度を直接読み取ることができます。温度が23度であればtRead()は「23」という値を返し、相対湿度が45%であればhRead()は「45」という値を返します。PRINTコマンドで確認してください。また、1行プログラムで温度を時々刻々表示できます。

print tRead() print hRead()
10 print tRead(): delay 1000: goto 10

 以下のプログラムは、温湿度センサー(SHT31)で測定した温度と湿度を液晶ディスプレイに表示します。なお、パソコンと接続している場合は、通信ソフト(teraTerm等)にも液晶ディスプレイと同じ表示が現れます。

10 cls 20 cursor 0,0 30 print tRead(),chr(&df),"C" 40 cursor 8,0 50 print hRead(),"%RH" 60 delay 1000 70 goto 10

 プログラムを保存(SAVE)しておくと、パソコンと接続しなくても、電源を入れるとプログラムが起動します。ケースに入れれば温湿度計の完成です。


9. ブザー音で演奏

 ここではブザー音で電子オルゴールを作ってみましょう。和音など音にこだわる方は「私だけの電子オルゴール」[8]を参考にしてください。

9.1 ブザー音を作る

 LEDと同じ箇所に圧電ブザー(Bzz)を接続し、「1秒ごとにLEDを点滅させるプログラム」を実行してください。するとブザーからカチカチと音が聞こえます。ここで、点灯時間と消灯時間を以下のように1msにしてみましょう。

10 dWrite 11,1 20 delay 1 30 dWrite 11,0 40 delay 1 50 goto 10

 この時の波形は下図のように500Hzの矩形波となり、聞こえるのは500Hzの音です(といっても倍音成分が含まれていますが)。

トーン波形

(練習) オシロスコープでトーン信号の波形を観察しなさい。また、WaveGeneなどの信号発生ソフトを用い、パソコンで500Hzの矩形波を出し、音を比べてみなさい。

9.2 音程を変える

 指定したピンに、指定した周波数の音を、指定した時間出力する tone という命令を使います。以下は時報の音を出すプログラムです。ソが784Hz、ドが1046Hzです。初めにtoneコマンドで指示した音が出ることを確認し、それからプログラムにします。音の終了を待たずにプログラムは次に進むので、多くの場合は次行にdelayを置きます。

tone 11,784,200 tone 11,784,200 tone 11,784,200 tone 11,1046,3000
10 tone 11,784,200: delay 1000 20 tone 11,784,200: delay 1000 30 tone 11,784,200: delay 1000 40 tone 11,1046,2000

(練習) 440Hzのラの音(A4)に対し1オクターブ高いラ(A5)の音は880Hzで、その間は隣同士(半音)の周波数の比が一定(21/12)となるように音階が作られます。表計算ソフトを用い、A4~A6の各音の周波数を計算しなさい。上のプログラム中の784Hzが「ソ」、1046Hzが「ド」であることが確認できます。

(練習) 上のプログラムを参考に、簡単な曲を演奏させるプログラムを作りなさい。

(練習) 時計のアラーム音、信号機の音、風呂や電気ポットの湯沸かし音など、身近にある電子音を録音し、その音をプログラムで再現しなさい。

9.3 楽譜を演奏する

 以下は、文字列で記述した楽譜データを参照しながら演奏するプログラムです。楽譜データがプログラムと分離されているので、長い曲も表しやすくなっています。プログラム中のFは周波数です。

10 P=top(0):POKE P,"RDDBAGDR RDDBAGER REEcBAFR RdddcABR RDDBAGDR RDDBAGER REEcBAdd ddedcAGR" 20 C=peek(P):P=P+1 30 if C=13 B=0:stop 40 if C=32 goto 20 50 if C=82 F=0 60 if C=67 F=262 70 if C=68 F=294 80 if C=69 F=330 90 if C=70 F=349 100 if C=71 F=392 110 if C=65 F=440 120 if C=66 F=494 130 if C=99 F=523 140 if C=100 F=587 150 if C=101 F=659 160 if C=102 F=698 170 if C=103 F=784 180 tone 11,F,300:delay 300:goto 20 楽譜データ 改行 スペース R(休符) C D E F G A B c d e f g

(練習) 行10の楽譜を変え、必要な場合は行60~170を拡張し、好きな曲の電子オルゴールを作りなさい。

9.4 楽器を作る

 以下のプログラムは、ボタンを押すと、ボリュームで決まる周波数のブザー音がでます。

10 if dRead(7)=1 goto 10 20 A=aRead(0) 30 tone 11,A,200 40 goto 10

 上のプログラムで一応楽器として使えるのですが、ドレミ...の音を丁度よく出すのは難しいと思います。そこで、ドレミ...の音しか出ないようにしたのが次のプログラムです。

10 if dRead(7)=1 goto 10 20 A=aRead(0) 30 if A>784 tone 11,784,200: goto 10 40 if A>698 tone 11,698,200: goto 10 50 if A>659 tone 11,659,200: goto 10 60 if A>587 tone 11,587,200: goto 10 70 if A>523 tone 11,523,200: goto 10 80 if A>494 tone 11,494,200: goto 10 90 if A>440 tone 11,440,200: goto 10 100 if A>392 tone 11,392,200: goto 10 110 if A>349 tone 11,349,200: goto 10 120 if A>330 tone 11,330,200: goto 10 130 if A>294 tone 11,294,200: goto 10 140 tone 11,262,200 150 goto 10

(練習) ボリュームの代わりに明るさセンサで音程が変わるようにしなさい。また、必要ならば音階を拡張しなさい。


10. 合成音声でおしゃべり

10.1 コマンド操作でおしゃべり

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

 まず、コマンド操作で動かしてみてください。

talk "aiueo" talk 123 talk 4,"kakeru",5,"wa",4*5,"desu" talk "ju'nbi/o'-kei"

 日本語音声をしゃべってくれますが、文字列はローマ字で書く必要があります。また、上の最後の操作例のように、アクセントその他さまざまな約束事があります。

10.2 プログラムでおしゃべり

 以下は、「九九」を合成音声で読み上げるものです[音を聞く]。

10 for A=1 TO 9 20 for B=1 TO 9 30 talk A,"kakeru",B,"wa",A*B 40 next B 50 next A

 以下は、外部スイッチが押されると「九九」をランダムに読み上げるプログラムです。

10 A=1 20 B=dRead(7) 30 if A=1 if B=0 gosub 100 40 A=B 50 goto 20 100 X=1+rnd(9): Y=1+rnd(9) 110 talk X,"kakeru",Y,"wa",X*Y 120 return

 利用者に適したスイッチを使い、合成音声の読み上げで支援するさまざまなツール(VOCA)を作ることができます。

(練習) 2個のスイッチを接続し、それぞれ「はい」「いいえ」の合成音声が出るようなVOCAを作りなさい。

10.3 センサーと組み合わせ

 以下は、人感センサーと組み合わせた例です。

10 if dRead(2)=0 delay 50: goto 10 20 talk "maido/ari'gato-gozaimasu" 30 delay 10000: goto 10

 また、以下は、2個の人感センサーを用いた例で、玄関などに置くといいかもしれません。先にセンサーAが反応し(X=1)その後センサーBが反応(Y=0,B=1)すると「行ってらっしゃい」に(行30)、逆に先にセンサーBが反応し(Y=1)その後センサーAが反応(X=0,A=1)すると「お帰りなさい」になります(行40)。この仕組みを念頭に、2つのセンサーの置き方を工夫します。

10 X=A: Y=B: delay 50 20 A=dread(2): B=dread(3) 30 if X=1 if Y=0 if B=1 talk "itterassyai":delay 10000 40 if X=0 if A=1 if Y=1 talk "okaerinasai":delay 10000 50 goto 10

(練習) 人感センサーの反応する時のメッセージを、いくつかの中からランダムに選ばれるようにしてみなさい。


11. イルミネーション

11.1 NeoPixelの利用

 NeoPixelはフルカラーLEDがシリアルに連結されていて(ここでは10連LEDを使用)、1本の信号線で任意のLEDの発光をコントロールできるのが特徴です。tinyBasicでは、ピン17(A3)に接続した最大12連のNeoPixelをpixelコマンドで制御することができます。パラメータで、順にLEDの番号(0~11)、Redの明るさ(0~255)、Greenの明るさ(0~255)、Blueの明るさ(0~255)を指定します。

 LEDの番号(0~11)と色相(0~255)と明るさ(0~255)を指定することもできます。明るさの指定を省略すると255として扱われます。

 RGBの値と色相の関係は下図のようになっています。


HUE04285128170212255
シアンマジェンタ

 まず、コマンド操作で試してみてください。

pixel 0,50,0,0 pixel 1,0,50,0 pixel 2,0,0,50 pixel 0,50,50,0 pixel 1,0,50,50 pixel 2,50,50,50 pixel 0,0,0,0 pixel 1,0,0,0 pixel 2,0,0,0 pixel 0,0 pixel 1,42 pixel 2,85 pixel 0,0,50 pixel 1,42,50 pixel 2,85,50 LED0のRGBを(50,0,0)にする LED1のRGBを(0,50,0)にする LED2のRGBを(0,0,50)にする LED0のRGBを(50,50,0)にする LED1のRGBを(0,50,50)にする LED2のRGBを(50,50,50)にする LED0を消す LED1を消す LED2を消す LED0のHUEを0(赤)にする LED1のHUEを42(黄)にする LED2のHUEを85(緑)にする LED0のHUEを0(赤)明るさ50にする LED1のHUEを42(黄)明るさ50にする LED2のHUEを85(緑)明るさ50にする

11.2 プログラムによる点滅とフラッシュ

 以下のプログラムは、ひとつ目のLEDを赤で点滅させます。1秒点灯・1秒消灯をくりかえします。下図右は点滅の時間的な変化をタイムチャートで示したものです。

10 pixel 0,50,0,0 20 delay 1000 30 pixel 0,0,0,0 40 delay 1000 50 goto 10

10行目を

10 pixel 0,0,50,0 とすると緑で点滅します。

 次のようにすると10個のLEDが点滅します。

10 for i=0 to 9 20 pixel i,0,50,0 30 next i 40 delay 1000 50 for i=0 to 9 60 pixel i,0,0,0 70 next i 80 delay 1000 90 goto 10

20行目を

20 pixel i,0,100,0

40行目を

40 delay 200 とすると明るく短時間点灯する「フラッシュ」になります。

(練習) 10個のLEDが1秒毎に「青→黄→赤」を繰り返すプログラムを作りなさい。

11.3 ワイプ

 以下のプログラムは、10個のLEDを順に点灯させます。このようなイルミネーション効果は「ワイプ」と呼ばれます。

10 for i=0 to 9 20 pixel i,50,0,0 30 delay 100 40 next i

20行目を

20 pixel i,0,0,0 とすると順に消灯します。

(練習) 「赤のワイプ→緑のワイプ→青のワイプ」を繰り返すプログラムを作りなさい。

11.4 スイープ

 以下のプログラムは、10個のLEDを順に点灯・消灯させます。

10 for i=0 to 9 20 pixel i,50,0,0 30 delay 100 40 pixel i,0,0,0 50 next i

(練習) 30行目のdelay を100msにし、また、繰り返しスイープするようにしなさい。

11.5 ウェーブ

 以下のプログラムは、2個おきの点灯パターンがスイープし、波(ウェーブ)のように(あるいは追いかけているように)見えます。100行目はサブルーチンになっていて、与えられた色Hでウェーブ表示します。10行目は赤、20行目は緑、30行目は青のそれぞれウェーブで、これを繰り返します。

10 H=0: gosub 100 20 H=85: gosub 100 30 H=170:gosub 100 40 goto 10 100 for j=20 to 0 step -1 110 for i=0 to 9 120 if (i+j)%3=0 pixel i,H,50:goto 140 130 pixel i,H,0 140 next i 150 delay 80 160 next j 170 return

(練習) 120行目を変更し、「1個おき」「3個おき」のウェーブにしてみなさい。

11.6 フェードイン・フェードアウト

 以下のプログラムは、ひとつ目のLEDをだんだん明るくし(赤を0→50)、だんだん暗くし(赤を50→0)、これを繰り返します。

10 for r=0 to 50 20 pixel 0,r,0,0 30 delay 10 40 next r 50 for r=50 to 0 step -1 60 pixel 0,r,0,0 70 delay 10 80 next r 90 goto 10

(練習) 色を変えてみなさい。また速さを変えてみなさい。

(練習) 10個のLEDを同時にフェードイン・フェードアウトさせなさい。

11.7 クロスフェード

 ひとつ目のLEDをフェードアウトしながら、ふたつ目のLEDをフェードインすると滑らかに変化させることができます。これを「クロスフェード」といいます。

 以下は、クロスフェードをスイープに応用した例で、LEDの点灯位置が滑らかに変化します。

10 for i=0 to 9 20 for r=0 to 50 30 pixel i,50-r,0,0 40 pixel (i+1)%10,r,0,0 50 delay 10 60 next r 70 next i 80 goto 10

11.8 フルカラー表示

 クロスフェードを用いると色を滑らかに変化させることができます。以下のプログラムは、ひとつ目のLEDの色が赤→緑に滑らかに変化します。

10 for r=50 to 0 step -1 20 pixel 0,r,50-r,0 30 delay 10 40 next r

 以下のプログラムは、すべてのLEDの色をフルカラーで連続的に変化させます。

10 for H=0 to 255 20 for i=0 to 9 30 pixel i,H,50 40 next i 50 delay 10 60 next H 70 goto 10

 以下のプログラムは、すべてのLEDの色を場所を変えながらフルカラーで連続的に変化させます。

10 for j=0 to 256 step 8 20 for i=0 to 9 30 pixel i,(i*256/10+j)%256,50 40 next i 50 delay 10 60 next j 70 goto 10

11.9 イルミネーションの例

(1) ドロップ

 以下は、「ドロップ」のイルミネーションの作例です。水滴が滴り落ちるイメージで、最後にキラッと光ります。

10 N=6+rnd(5) 20 for i=0 to N-2 30 u=(i+1)*10 40 for b=0 to u 50 pixel i, u-b,u-b,u-b 60 pixel (i+1)%10,b,b,b 70 delay 3 80 next b 90 delay (10-N)*2 100 next i 110 for b=u to 255 120 pixel N-1,b,b,b 130 delay 3 140 next b 150 for b=255 to 0 step -1 160 pixel N-1,b,b,b 170 delay 3 180 next b 190 delay rnd(2000) 200 goto 10 N:ドロップの長さ(ランダムに6~10) iをNまで繰り返す uは最大の明るさ 明るさbを0~u iのLEDをu-bの明るさで表示(だんだん暗く) i+1のLEDをbの明るさで表示(だんだん明るく) 3ms待つ 速さ調整 明るさbを最大までだんだん明るくする(キラリ) 速さ調整 明るさbを0までだんだん暗くする 速さ調整 次のドロップまで0~2秒待つ

(2) イルミネーションオブジェ

 以下は、NeoPixelリング(12個)を使い、ランダムに点灯させるようにした例です。オブジェの作り方はngo-tecさんのページを参考にしました(カップはダイソーの「ザ・クリアロックカップ」を使用)。点灯位置と点灯色と点灯時間間隔をランダムにし、点灯後はだんだん暗くしています。

10 N=12: T=1 20 for i=0 to N-1 30 @(i)=0: pixel i,0,0,0 40 next i 50 for i=0 to N-1 60 pixel i, @(N+i), @(i) 70 if @(i)>0 @(i)=@(i)*95/100 80 next i 90 delay 50 100 T=T-1 110 if T>0 goto 50 120 p=rnd(N): @(p)=255: @(N+p)=rnd(256) 130 T=1+rnd(20)+rnd(20) 140 goto 50 N:LEDの数, T:50ms単位で次のfire すべて消す(明るさの配列も0に) 明るさを減衰 処理は50ms毎 T*50ms経過したらfire ランダムなLED pの明るさ255, 色はランダム 0~2秒後にfireするようにTをランダムに

(3) イルミネーションオブジェ(オルゴール付き)

 以下は、9.3の電子オルゴールと組み合わせた例で、音楽を演奏しながらイルミネーションが変化します。プログラム中のFは周波数、HはA~Aの1オクターブをHUE 0~255に対応させた値になっています。小型のスピーカ UGSM23Aをブレッドボードに直接付けても、3cmφの圧電サウンダをイルミネーションカップの底に貼り付けてもいいでしょう。

1 P=top(0):POKE P,"DFBaB2FD EgcBagaF FAdcd2AF GBedcBcA dAGAF2R" 10 C=peek(P):P=P+1:L=200 11 if peek(P)=50 L=L*2:P=P+1 12 if C=13 stop 20 if C=32 goto 10 30 B=255 40 if C=82 F=0:B=0 50 if C=68 F=311:H=128 60 if C=69 F=330:H=149 70 if C=70 F=370:H=192 80 if C=71 F=392:H=213 90 if C=103 F=415:H=235 100 if C=65 F=440:H=0 110 if C=97 F=466:H=21 120 if C=66 F=494:H=43 130 if C=99 F=554:H=85 140 if C=100 F=587:H=107 150 if C=101 F=659:H=149 160 gosub 300 170 tone 11,F,L:delay L:goto 10 300 for i=0 to 11 310 pixel i,H,B 320 next i 330 return 楽譜データ 1音データ抽出・200ms 2なら長さ2倍 改行なら終了 スペースなら次へ 明るさ最大 R(休符) D(D#) E F(F#) G g(G#) A a(A#) B c(c#) d e 指定色でLED点灯 周波数F 0.3秒の音  (以下サブルーチン) 12個のLEDを 色H 明るさB で点灯

(4) イルミネーションオブジェ(オルゴール・人感センサ付き)

 以下は、更に人感センサ(焦電センサ)を組み合わせたもので、人を感知するとオルゴールを鳴らしながらイルミネーションが変化します。

1 P=top(0):POKE P,"DFBaB2FD EgcBagaF FAdcd2AF GBedcBcA dAGAF2" 2 if dRead(2)=0 delay50:goto2 10 C=peek(P):P=P+1:L=200 11 if peek(P)=50 L=L*2:P=P+1 12 if C!=13 goto20 13 if B=0 delay10000:goto1 14 B=B*96/100:gosub300 15 delay50:goto13 20 if C=32 goto10 30 B=255 50 if C=68 F=311:H=128 60 if C=69 F=330:H=149 70 if C=70 F=370:H=192 80 if C=71 F=392:H=213 90 if C=103 F=415:H=235 100 if C=65 F=440:H=0 110 if C=97 F=466:H=21 120 if C=66 F=494:H=43 130 if C=99 F=554:H=85 140 if C=100 F=587:H=107 150 if C=101 F=659:H=149 160 gosub300 170 tone11,F,L:delay L:goto10 300 for i=0to11 310 pixel i,H,B 320 next i 330 return 楽譜データ 人を検知するまで待つ 1音データ抽出・200ms 2なら長さ2倍 改行なら 消灯したら10秒後に再開 少し暗くして 50ms待って消灯チェック スペースなら次へ 明るさ最大 D(D#) E F(F#) G g(G#) A a(A#) B c(c#) d e 指定色でLED点灯 周波数F Lmsの音  (以下サブルーチン) 12個のLEDを 色H 明るさB で点灯

 以下は、更に人感センサ(焦電センサ)を2個使い、「おでかけ」と「おかえり」で違うメロディーを鳴らすようにしたものです。玄関などに置くといいかもしれません。

1 U=V: X=Y: V=dread(2): Y=dread(3) 2 if Y=1 if U=0 if V=1 P=top(0):POKE P, "DFBaB2FD EHCBaHaF FAdCd2AF GBedCBCA dAGAF2":goto10 3 if V=1 if X=0 if Y=1 P=top(0):POKE P, "B3AGB c3BAc dcBdgf edcBAG A6 G2RBGd g2":goto10 4 delay 50: goto1 10 C=peek(P):P=P+1:L=240 11 if peek(P)>49 if peek(P)<57 L=L*(peek(P)-48):P=P+1 12 if C!=13 goto17 13 if B=0 goto1 14 B=B*96/100:gosub40 15 delay50:goto13 17 B=255 18 if C=32 goto10 19 if C=82 F=0:B=0 20 if C=68 F=311:H=128 21 if C=69 F=330:H=149 22 if C=70 F=370:H=192 23 if C=71 F=392:H=213 24 if C=72 F=415:H=235 25 if C=65 F=440:H=0 26 if C=97 F=466:H=21 27 if C=66 F=494:H=43 28 if C=99 F=523:H=64 29 if C=67 F=554:H=85 30 if C=100 F=587:H=107 31 if C=101 F=659:H=149 32 if C=102 F=740:H=192 33 if C=103 F=784:H=213 34 gosub40 35 tone 11,F,L:delay L 36 goto10 40 for i=0 to 11 41 pixel i,H,B 42 next i 43 return センサ読取り・記憶 「おでかけ」の時 「おかえり」の時 検知するまで待つ 1音データ抽出 2~8なら長さ 改行なら 消灯したら最初から 少し暗くして 50ms後に消灯チェック 明るさ最大 スペースなら次へ R(休符) D(D#) E F(F#) G H(G#) A a(A#) B c C(c#) d e f(F#) g 指定色でLED点灯 周波数F Lmsの音 次の音へ  (以下サブルーチン) 12個のLEDを 色H 明るさB で点灯

(5) イルミネーションオブジェ(複数台連携動作: グループ学習向け)

 以下は人感センサの代わりに明るさセンサCDSを使い、「隣のLEDが消灯(担当フレーズの演奏終了)したら自分の担当フレーズを演奏(LEDも点灯)する」ようにしたものです。CDSは不要な光が入らないようにヒシチューブで覆っています。グループ学習で利用すると楽しいと思っているのですがいかがでしょうか。

(6) イルミネーションオブジェ + 電子オルゴール(高品質)

 これまでの例は、電子オルゴールはブザー音でしたし、イルミネーションも単調なものでした。以下はより高音質の電子オルゴールと組み合わせて、音量センサで検知した音に応じてイルミネーションが変化するようにしたものです。Arduinoをミニブレッドボードに実装し、電池で動作するようにしました。オルゴールにはDigisparkを使っています。詳しくは「私だけの電子オルゴール」をご覧ください。

(練習) オリジナルのイルミネーションパターンを考え、作ってみなさい。

(練習) 音量センサーを使い、音に反応するイルミネーションを作ってみなさい。


12 赤外線リモコン

12.1 赤外線リモコンを作る

 テレビなどのリモコンは、ボタンを押すと赤外線LEDが「決められたタイミングで点滅」するように作られています。どのように点滅しているかは、リモコン受光器に向けてリモコンのボタンを押し、受光器の信号をオシロスコープで観測するとわかります。

 実際に観測してみると、各社テレビのリモコン信号は以下のようになっています。図の着色した部分が信号が「オン」の箇所で、「オン」とは「赤外線LEDを13μs点灯し、13μs消灯し、これを一定時間繰り返す」ことです。また、「オフ」とは「一定時間消灯する」ことです。これを参考に、赤外線LEDを点滅させるプログラムを作ればよいわけです。

電源 ON/OFF 40 bf 12 ed
チャンネルUP 40 bf 1b e4
チャンネルDOWN 40 bf 1f e0
ボリュームUP 40 bf 1a e5
ボリュームDOWN 40 bf 1e e1
東芝製テレビのリモコン信号
電源 ON/OFF 02 20 80 00 3d bd
チャンネルUP 02 20 80 00 34 b4
チャンネルDOWN 02 20 80 00 35 b5
ボリュームUP 02 20 80 00 20 a0
ボリュームDOWN 02 20 80 00 21 a1
パナソニック製テレビのリモコン信号
電源 ON/OFF 8f 12 16 d1
チャンネルUP 8f 12 11 a1
チャンネルDOWN 8f 12 12 91
ボリュームUP 8f 12 14 f1
ボリュームDOWN 8f 12 15 e1
シャープ製テレビのリモコン信号
電源 ON/OFF 95 0
チャンネルUP 90 0
チャンネルDOWN 91 0
ボリュームUP 92 0
ボリュームDOWN 93 0
SONY製テレビのリモコン信号
OCR-05 ON 78
OFF b4
OCR-05WON 3c
OFF d2
OHM製コンセントリモコンの信号

 以下の回路とプログラムは、CHupボタンを押すと各社リモコンの「チャンネルアップ」信号が次々出力され、CHdnボタンを押すと各社リモコンの「チャンネルダウン」信号が次々出力されます。実際には各社の信号を出す必要はありません。

10 L=13:U=2:D=7 20 if dRead(U)=HIGH goto 90 30 f38k L,9000/26:delayus 4500:rcbyte L,$40,$bf,$1b,$e4:delay 90 50 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$34,$b4:delay 90 60 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$b0,$00,$34,$84:delay 90 70 rcbyte L,$8f,$12,$42,$11,$a1:delay 90 80 scbyte L,$90:delay 90 90 if dRead(D)=HIGH goto 20 100 f38k L,9000/26:delayus 4500:rcbyte L,$40,$bf,$1f,$e0:delay 90 110 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$35,$b5:delay 90 120 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$b0,$00,$35,$85:delay 90 130 rcbyte L,$8f,$12,$42,$12,$91:delay 90 140 scbyte L,$91:delay 90 150 goto 20
回路図

12.2 なんでもリモコン

 以下の回路とプログラムは、1個のスイッチ操作で電源・CHup・CHdnをコントロールできる「なんでもリモコン」のtinyBasic版です(オリジナルはこちら)。ブザー音の「ドに電源」「レにCHup」「ミにCHdn」が割り当ててあります。スイッチを押すと「ドーレーミー」とブザー音が鳴るので、希望の箇所でもう一度スイッチを押します。このプログラムはパナソニックTV用です。他社の場合は、510~530の行を変更します。

10 B=8:L=13:S=2:@(0)=262,294,330,349,392,440,494,523 20 if dRead(S)=HIGH goto 20 30 if dRead(S)=LOW goto 30 40 for i=0 to 2 50 tone B,@(i),1000 60 for j=1 to 100 70 if dRead(S)=LOW gosub 500 80 delay 10 90 next j 100 next i 110 goto 20 500 tone B,1000,100: J=100 510 if i=0 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$3d,$bd 520 if i=1 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$34,$b4 530 if i=2 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$35,$b5 540 i=2:delay 1000:return
回路図

 以下は各社対応のリモコン信号を続けて出すようにしたデモンストレーション用プログラムです。実際には各社の信号を出す必要はありませんので、必要箇所以外はコメントアウトします(511, 521, 531の各行は東芝TV、512, 522, 532の各行はパナソニックTV、513, 523, 533の各行はパナソニックBD、514, 524, 534の各行はシャープTV、515, 525, 535の各行はソニーTV)。

 下の写真は、Arduino ProMini(8MHz)を使い電池で動作させている様子です。

20 sleep
のように省電力モードにすると、待機時の消費電流は250μAでした(sleepを使わない場合は3.5mA)。

10 B=8:L=13:S=2:@(0)=262,294,330 20 if dRead(S)=HIGH goto 20 30 if dRead(S)=LOW goto 30 40 for i=0 to 2 50 tone B,@(i),1000 60 for j=1 to 100 70 if dRead(S)=LOW gosub 500 80 delay 10 90 next j 100 next i 110 goto 20 500 tone B,1000,100: J=100 #POWER 510 if i!=0 goto 520 511 f38k L,9000/26:delayus 4500:rcbyte L,$40,$bf,$12,$ed:delay 90 512 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$3d,$bd:delay 90 513 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$b0,$00,$3d,$8d:delay 90 #514 rcbyte L,$8f,$12,$16,$d1:delay 90 515 scbyte L,$95 #CHup 520 if i!=1 goto 530 521 f38k L,9000/26:delayus 4500:rcbyte L,$40,$bf,$1b,$e4:delay 90 522 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$34,$b4:delay 90 523 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$b0,$00,$34,$84:delay 90 #524 rcbyte L,$8f,$12,$11,$a1:daley 90 525 scbyte L,$90 #CHdn 530 if i!=2 goto 540 531 f38k L,9000/26:delayus 4500:rcbyte L,$40,$bf,$1f,$e0:delay 90 532 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$80,$00,$35,$b5:delay 90 533 f38k L,3600/26:delayus 1600:rcbyte L,$02,$20,$b0,$00,$35,$85:delay 90 #534 rcbyte L,$8f,$12,$12,$91:delay 90 535 scbyte L,$91 540 i=2:delay 1000:return
回路図
回路図

Arduino ProMiniを使い電池で動作

13. 動くものを作る

 これまでの例では、マイコンの出力ピンにLEDや圧電ブザーを接続しました。AVRマイコンは最大20mAの電流を流すことができるので、この範囲であれば直接接続できます。この章では、モータなど大きな電流が流れる素子を駆動する例を紹介します。大きな電流が流れる回路を制御する場合は、「電流が流れる経路」を意識することが回路の誤動作を防ぐことにつながります。

13.1 サーボモーターを動かす

 以下のようにサーボモーターを接続し、コマンド操作で動かしてみてください。なお、モーターの電流変化が大きいことから、図のようにコンデンサを追加してください。

servo 10,0 servo 10,90 servo 10,180

13.2 プログラムでサーボモーターを動かす

 以下の例は、サーボモーターが車のワイパーのように動きます。

10 P=0 20 D=1 30 servo 10,P 40 P=P+D 50 if P=180 D=-1 60 if P=0 D=1 70 delay 20 80 goto 30 Pは角度 Dは角度の変化量 サーボモータの位置をPに Pを更新 Pが180ならDを-1にする Pが0ならDを1にする 少し待って 繰り返す

 以下のように「for文」を使っても結果は同じです。

10 for P=0 to 179 20 servo 10,P 30 delay 20 40 next P 50 for P=180 to 1 step -1 60 servo 10,P 70 delay 20 80 next P 90 goto 10 角度Pを0から179まで サーボモータの位置をPに 少し待って 繰り返す 角度Pを180から1まで サーボモータの位置をPに 少し待って 繰り返す

 以下のプログラムは、ボリュームの値によってサーボモーターの位置(角度)が変わります。

10 servo 10,aRead(0)*9/51 20 delay 50 30 goto 10 サーボモータの位置を0~180に 少し待って 繰り返す

(練習) ボリュームの代わりに明るさセンサを使い、明るさで位置が変わるようにしなさい。

13.3 モーターを動かす

 下図のようにモーターを接続します。まず、「MOTOR」コマンドでモーターを動かしてみてください。左右のモーターの速度は -255~255で指定します。

motor 255,100 motor 100,255 motor 255,255 motor 0,0

13.4 プログラムでモーターを動かす

 以下はボリュームの値によってモーターの回転速度が変わります。

10 A=aRead(0)/4 20 motor A,A 30 delay 100 40 goto 10 Aは0~255 左右のモーターをAの値で回転 少し待って 繰り返す

 以下は音センサモジュールと組み合わせた例で、手を叩く(A0に接続した音センサーが400以上)と1秒間前進します。

10 if aRead(0)<400 goto 10 20 motor 255,255 30 delay 1000 40 motor 0,0 50 goto 10 音が400未満なら待つ 400以上なら左右のモーターを255にし 1秒待つ 左右のモーターを停止 繰り返す

 以下の例は、車の先端がテーブルから落ちそう(A7に接続した赤外線反射センサーが30以上)になると、少し後退し、右回転して、再び前進します。

10 if aRead(0)<30 motor 255,255: delay 100: goto 10 20 motor -200,-200 30 delay 500 40 motor 0,200 50 delay 500 60 goto 10 赤外線反射センサーが30未満なら少しずつ前進 30以上なら一旦後退し 少し待って 左ターンし 少し待って 繰り返す

14. 押しボタン信号機

 押しボタン信号機の制御プログラムです。まず行10で「車用信号を青」、行20で「歩行者用信号を赤」にします。行30と行40で歩行者のボタンが押されるまで待ち、ボタンが押されると、4秒後に行60で「車用信号を黄色」にし、4秒後に行80で「車用信号を赤」、行90で「歩行者用信号を青」にします。その後16秒待ち、行110~160で歩行者用信号を点滅させます。行170で「歩行者用信号を赤」にして4秒後に行190行で「車用信号を青」にして、以上を繰り返します。

10 dWrite 2,0: dWrite 3,0: dWrite 4,1 20 dWrite 12,1: dWrite 11,0 30 B=dRead(7) 40 if B=1 goto 30 50 delay 4000 60 dWrite 2,0:dWrite 3,1:dWrite 4,0 70 delay 4000 80 dWrite 2,1:dWrite 3,0:dWrite 4,0 90 dWrite 12,0: dWrite 11,1 100 delay 16000 110 for I=1 to 8 120 dWrite 12,0:dWrite 11,1 130 delay 500 140 dWrite 12,0:dWrite 11,0 150 delay 500 160 next I 170 dWrite 12,1: dWrite 11,0 180 delay 4000 190 dWrite 2,0: dWrite 3,0: dWrite 4,1 200 A=B 210 goto 30

 以下は歩行者用の「カッコー」の音を付け加えた例です。

10 e=659: c=523 20 dWrite 2,0: dWrite 3,0: dWrite 4,1 30 dWrite 12,1: dWrite 11,0 40 B=dRead(7) 50 if B=1 goto 40 60 delay 4000 70 dWrite 2,0: dWrite 3,1: dWrite 4,0 80 delay 4000 90 dWrite 2,1: dWrite 3,0: dWrite 4,0 100 dWrite 12,0: dWrite 11,1 110 for I=1 to 5 120 tone 10,e,100: delay 400 130 tone 10,c,200: delay 900 140 tone 10,e,100: delay 100 150 tone 10,e,100: delay 100 160 tone 10,c,200: delay 1000 170 next I 180 for I=1 to 8 190 dWrite 12,0:dWrite 11,1: delay 500 200 dWrite 12,0:dWrite 11,0: delay 500 210 next I 220 dWrite 12,1: dWrite 11,0 230 delay 4000 240 dWrite 2,0: dWrite 3,0: dWrite 4,1 250 A=B 260 goto 40

 また、以下はこれを発展させた「交通安全教室用信号機」です。


15. シリアル通信教材(光通信)

 シリアル通信の仕組みを理解するための教材を取り上げます。通信は光の点滅による「光通信」で行います。

15.1 シリアル通信の仕組み

 下図は、送り手が受け手にメッセージとして「G」という文字を送る時の様子を表しています。ここではJISコードを用いることで互いに了解が得られているものとします。「G」の文字コードは(01000111)2と表されます。図(a)はこれをパラレル通信で送る様子を、図(b)はシリアル通信で送る様子を表しています。パラレル通信の場合は8本の信号線が必要ですが、複数ビットのデータを同時に送ることができます。一方、シリアル通信の場合は信号線の数は1本で、データを「時系列信号」として順に送ります。

 ここではシリアル通信のひとつである非同期通信について具体的にみていきましょう。非同期通信は調歩同期とも呼ばれ、パソコンのCOMポート(RS-232C)などで広く用いられています。

 下図は8ビットのデータ(bit0~bit7)を1秒間に1ビットの速さ(1 bps)で送信する時の信号の様子を表したものです。8ビットデータを送るための手順は次のようになります。ビットデータが1の場合はLEDを点灯し、0の場合はLEDを消灯することにより、光通信の信号となります。

 今、送りたい文字が「G」であるとすると、「G」の文字コードは(01000111)2で、これを送信する時の信号は下図のようになります。1文字を表すのに約10秒かかります。

 以下のようにスイッチとLEDを接続すると、スイッチ操作で上記の信号(光信号)を発生させることができます。LEDを明るく点灯するために、抵抗は47Ωにしています。それでは「G」を表す上記の光信号をスイッチ操作で発生させてみましょう。

 今度は2人一組となり、送信者(送り手)と受信者(受け手)を決めます。送信者は上の方法で「G」の文字を送ります。受信者は1秒毎に受信した0または1を「11100...」のように書き取り、8ビット受信したら付録6の文字コード表を見て、「G」を受信したことを確認します。実際にやってみると、送信者が正確なタイミングで信号を変化させる必要があることや、受信者が決まったタイミングでビットを読み取ることが重要であることがわかります。

(練習) 送信者が「A~Z」の何か1文字を送信し、これを受信者が正しく復元できるか試しなさい。

15.2 プログラムによるシリアル信号の送信

 今度は、光信号をスイッチ操作ではなくプログラムで発生させてみます。以下は上と同様に「G」の文字コードの光信号を発生させるプログラムです。

 8ビットデータを下位ビットから順に出力する仕組みは次のとおりです。

10 T=1000 20 C='G' 30 dWrite 11,1: delay T*2 40 dWrite 11,0: delay T 50 for i=0 to 7 60 dWrite 11,C&1: delay T 70 C=C/2 80 next i 90 dWrite 11,1: delay T 1ビット1秒(1000ms) Cは送信文字(G) 通常は点灯状態(1) スタートビット(1秒間0) ビット0~ビット7まで ビット0を1秒間出力 Cを右シフト ストップビット(1秒間1)
回路図

(練習) 上記のプログラムで以下の信号が発生することを確認しなさい。また、行20を変更し、別の文字の信号を発生させ、付録6を参考に正しく信号が作られていることを確認しなさい。

15.3 プログラムによる複数文字の送信

 上のプログラムは「G」を送信するプログラムでしたが、以下は、複数の文字を次々に送信するプログラムです。行20で文字列「Hello」をメモリのフリーエリアにpokeで格納しておき、行30以降でそこからpeekで1文字ずつ取り出して送信します。

10 T=1000 20 P=top(0):poke P,"Hello" 30 dWrite 11,1: delay T*2 40 C=peek(P):P=P+1 50 if C=13 delay T*2: goto 20 60 dWrite 11,0: delay T 70 for i=0 to 7 80 dWrite 11,C&1: delay T 90 C=C/2 100 next i 110 dWrite 11,1: delay T 120 goto 30 1ビット1秒(1000ms) P番地に"Hello"を格納 2秒間点灯(1) Cは送信文字 Cが改行なら終了 スタートビット(1秒間0) ビット0~ビット7まで ビット0を1秒間出力 Cを右シフト ストップビット(1秒間1) 次の文字へ
回路図

15.4 通信ソフトで入力した文字の送信

 以下は、通信ソフトで入力した文字を送信するプログラムです。行20の「in()」は通信ソフトからの文字入力を待ち、文字が入力されるとその文字コードを返します。ESCキーを押されると「-1」が返ってくるので、プログラムを終了します。

10 T=1000 20 C=in(): if(C<0) stop 30 dWrite 11,1: delay T*2 40 dWrite 11,0: delay T 50 for i=0 to 7 60 dWrite 11,C&1: delay T 70 C=C/2 80 next i 90 dWrite 11,1: delay T 100 goto 20 1ビット1秒(1000ms) Cは通信ソフトからの入力文字(ESCで終了) 通常は点灯状態(1) スタートビット(1秒間0) ビット0~ビット7まで ビット0を1秒間出力 Cを右シフト ストップビット(1秒間1)
回路図

15.5 プログラムによるシリアル信号の受信

 今度はシリアル信号を受信するプログラムを作ります。

 はじめに、送信者の光信号が点灯の時と消灯の時に、受信者のアナログ値(0~1023)がどのくらいになるか調べます。

 送信信号はプログラムで発生させても、スイッチ操作のオンオフで行ってもどちらでも構いません。

 受信者は明るさセンサー(CDS)で送信者の光信号を受信します。8.2で行ったように、CDSをつなぎ、1行プログラムでA0ピンの値を時々刻々表示してみると、LEDの点滅に応じて受信信号のアナログ値が変化する様子を確認できます。

10 print aRead(0): delay 200: goto 10

 点灯時と消灯時の受信信号の差が大きいほど安定した通信が可能となります。そのためには、LEDとCDSの向きを合わせる、距離を短くする、外からの光が入りにくくするなどの工夫が有効です。

 点灯時と消灯時の受信信号の値の中間に「境界値」を決め、その境界値よりも大きければ(明るければ)「1」が受信されたとみなし、小さければ(暗ければ)「0」が受信されたとみなします。例えば、点灯時に1000、消灯時に600であれば境界値を800にし、点灯時に200、消灯時に100であれば境界値を150にします。

 受信の仕組みは以下のとおりです。

 以下は明るさの境界値を「800」としたプログラムです。通信ソフト(teraTerm等)に受信文字が表示され、液晶ディスプレイを接続しておけば液晶ディスプレイにも同じく表示されます。

 行100では、それまでのCの値を1ビット右シフトし、ビット7を受信ビットBにします。上記の「G」の光信号を受信した場合、Cの値は「xxxxxxxx」→「1xxxxxxx」→「11xxxxxx」→「111xxxxx」→「0111xxxx」→「00111xxx」→「000111xx」→「1000111x」→「01000111」のように更新されます。

10 T=1000 20 A=800 30 if aRead(0)>=A goto 30 40 delay T/2 50 if aRead(0)>=A print "Error": goto 30 60 C=0: delay T 70 for i=0 to 7 80 B=0:if aRead(0)>=A B=1 90 print B; 100 C=C/2+B*128: delay T 110 next i 120 if aRead(0)<A print " Error": goto 30 130 print ' ',chr(C): goto 30 1ビット1秒(1000ms) 明るさの境界値は800 スタートビットを待つ 500ms待つ スタートビット(0)でなければエラー 受信文字Cを初期化し、1秒待つ ビット0~ビット7まで 明るさに応じてBを0または1 受信ビットBを表示 Cを右にシフトしビット7をBにし 1秒待って次のビットへ ストップビット(1)でなければエラー 受信文字Cを表示し、再び受信待機
回路図

 ディスプレイのブラウザ表示画面で、受信プログラムの動作を確認することができます。受信装置のCDSを下の↓で示された箇所に密着させ、入力欄に「Hello」などの文字を入力し、「送信」ボタンを押すと、その箇所が ■■■□■■□...のように1 bpsの速さで変化し、受信装置がこれを文字として受け取ることができます。ただし、ディスプレイはLEDほど明るくないので、境界値(行20のAの値)は小さくする必要があります(例えば80程度)。

(  ここに受信装置のCDSを当て、入力欄に文字を入力し、送信ボタンを押してください。 )

15.6 シリアル通信システム

 送信装置と受信装置を組み合わせると、通信システムが完成します。送信装置のLEDと受信装置のCDSの距離は数cmの距離であれば確実に動作しますし、部屋を暗くしたり、CDSに不要な光が入らないように覆うなどの工夫をした上で、プログラム中の「境界値」すなわち行20のAの値を小さくすると(例えば300程度)、50cm程度の距離で光通信が可能です。

 本章では 1 bps(1秒間に1ビット)の速さで通信を行ってきましたが、より速い 10 bps(1秒間に10ビット)や 100 bps(1秒間に100ビット)でも通信できます。100 bpsで正しく通信できない時は、Tの値を10±1の範囲で調整するとうまくいく場合があります。

 以下は、100 bpsで通信を行っている様子です。

(練習) 2人一組となり、送信者が15.3のプログラムでデータを送信し、受信者が正しく受信できることを確認しなさい。

(練習) 10 bps(1秒間に10ビット)や100 bps(1秒間に100ビット)でもうまく通信できるかを確かめなさい。


16. ビデオ表示

16.1 テレビに接続してビデオ表示

 下図左のようにテレビと接続します。写真のような先端に抵抗とジャンパピンを付けたケーブルを作っておくと便利です。

 パソコンの通信ソフトで操作している時はテレビにも同じ画面が表示されます。といっても、下の写真のように画面は80×48ドット(480バイトのVRAM)で、4×6ドットの文字フォントです。

 グラフィック表示のコマンドをいくつか試してみましょう。

plot 30,30,1 plot 40,40,1 line 0,0,79,0,1 line 79,0,79,47,1 circle 20,20,8,1 box 40,20,60,30,1

 以下は、正弦波形を描くプログラムです。

10 cls 20 for x=1 to 79 30 plot x,24-sin(x*9)/45,1 40 next x

 以下は、ランダムな場所に四角を表示・消去を繰り返すプログラムです。

10 cls 20 W=80: H=48 30 for i=1 to 10 40 x=rnd(W-5): y=rnd(H-5) 50 box x,y,x+5,y+5,1 60 delay 1000 70 box x,y,x+5,y+5,0 80 next i

 以下は、ボールを動かすプログラムです。

10 cls 20 for x=8 to 72 30 circle x,24,8,11 40 delay 50 50 circle x,24,8,10 60 next x

16.2 ビットマップ画像の表示

 以下は48×32ドットのビットマップ画像を表示するプログラムです。画像を表示し、その後右にスライドします。適当な方法で、画像のピクセルパターンを用意する必要があります。

10 cls 20 bmp 0,0,"fffe00007fff","fff800001fff","fff0000007ff","ffe0000003ff" 30 bmp 0,4,"ffc0000001ff","ff00000001ff","ff40000000ff","ff3c000000ff" 40 bmp 0,8,"ff038000007f","ff00e00000ff","fe003c4000ff","fc0000f7007f" 50 bmp 0,12,"fc100007807f","fc3060027e7f","f878f030007f","f079f070007f" 60 bmp 0,16,"f67ff8f8823f","f27e3ffde27f","f0781fffe63f","ff3fdff3fc1f" 70 bmp 0,20,"ff3fff80fcdf","ff3ff0fcfc9f","ffbff4fff83f","ff9ffffffbff" 80 bmp 0,24,"ffcfc1fff3ff","ffcfc4ffe7ff","ffe7ccffcfff","fff3c5ff9fff" 90 bmp 0,28,"fff9e1ff3fff","ffe077fc7fff","ffc20ff0ffff","ff1e60011fff" 100 for i=1 to 32 110 shift 1,3:delay 100 120 next i

16.3 ビデオゲーム「PONG」

 以下のプログラムはPONGゲームのtinyBasic版です。A0ピンに接続したボリュームでラケットを動かします。このプログラムを入力した時点で残りのメモリー容量はあとわずかしかありませんので、作ることができるプログラムのサイズはこの程度です。

(変数の説明) WとHはそれぞれスクリーンの幅と高さ、AとBはそれぞれプレイヤーとコンピュータのスコア、XとYはボールの座標、DとEはX方向とY方向の移動方向、UとVはラケットの位置、QはBラケットのボール到着予定位置、Cは開始時の1秒カウンタです。

(プログラムの説明) 行120~230がボールの移動。行140~150が得点追加。行160~170がラケットにヒット。行240~280がプレーヤーのラケット移動。行290~370がコンピュータのラケット移動、特に行300~310がコンピュータのラケットが動き始めるまでの遅れを決めている部分で、ここで強弱を調整しています。ラリーが続くと強弱が変化するようにしても面白いでしょう。

 下の写真は、Arduino ProMiniを使い電池で動作させている様子です。ケースに入れれば、立派な(?)「ビデオゲーム機」となります。

10 cls:A=0:B=0:W=48:H=32 20 line 0,0,W-1,0,1:line W-1,0,W-1,H-1,1 30 line W-1,H-1,0,H-1,1:line 0,H-1,0,0,1 40 U=H/2-3:V=U 50 line W-5,U,W-5,U+5,2:line 4,V,4,V+5,2 60 cursor 8,1:print A:if A=9 stop 70 cursor 3,1:print B:if B=9 stop 80 D=1:E=1:if (U+V)&1 E=-1 90 X=5:Y=V+3:plot X,Y,1 100 C=50 110 if C>0 C=C-1: goto 240 120 plot X,Y,2 130 X=X+D 140 if X=0 A=A+1:goto 60 150 if X=W-1 B=B+1:goto 60 160 if X=W-5 if Y>=U if Y<=U+6 D=-D:tone 440,100 170 if X=4 if Y>=V if Y<=V+6 D=-D:tone 440,100 180 Y=Y+E 190 if Y=0 E=-E 200 if Y=H-1 E=-E 210 if X=W-5 if Y=U if E=1 E=-1 220 if X=W-5 if Y=U+5 if E=-1 E=1 230 plot X,Y,2 240 line W-5,U,W-5,U+5,2 250 U=H-1-aRead(0)/16 260 if U<0 U=0 270 if U>H-6 U=H-6 280 line W-5,U,W-5,U+5,2 290 if D=1 goto 400 300 if x>27 goto 400 310 if x=27 if A<=B goto 400 320 line 4,V, 4,V+5,2 330 if E=1 Q=Y+X-4:if Q>=H Q=64-H 340 if E=-1 Q=Y-X+4:if Q<0 Q=-Q 350 if Q<V+3 if V>0 V=V-1 360 if Q>V+3 if V<25 V=V+1 370 line 4,V,4,V+5,2 400 delay 20:goto 110 A:Playerスコア,B:Compuスコア,W:画面幅,H:画面高 枠線描画 枠線描画 U:Aラケット位置(画面右), V:Bラケット位置(画面左) ラケット描画 Aスコア表示(画面右) Bスコア表示(画面左) DはXの増分, EはYの増分 ボール位置(X,Y)にボール描画 サーブまでの待ち時間 サーブまで待つ ボール消去 Xの位置更新 Aが得点 Bが得点 Aラケット(画面右)にヒット Bラケット(画面左)にヒット Yの位置更新 上の壁の跳ね返り 下の壁の跳ね返り Aラケットの上隅で方向変化 Aラケットの下隅で方向変化 ボール表示 Aラケット消去 Aラケット位置はボリューム値 Aラケット位置を範囲内に修正 Aラケット位置を範囲内に修正 Aラケット表示 ボール右移動ならBラケット動かさない ボールが境界位置より遠ければBラケット動かさない ボールが境界位置でB勝っていればBラケット動かさない Bラケット消去 ボール方向が下の時のBラケットボール到着予定位置Q ボール方向が上の時のBラケットボール到着予定位置Q Qに応じてBラケットを上に移動 Qに応じてBラケットを下に移動 Bラケット表示 20ms毎に繰り返す

回路図

PONGの表示画面

Arduino ProMiniを使い
完成後は電池で動作させた例

16.4 ビデオゲーム「シンプルシューター」

シンプルシューター(製作: 山田駿太郎)
 外観は以下の写真のようになっている。また、ディスプレイに表示される画面にはプレイ画面とリザルト画面が あり、それぞれ以下のような画面である。
 プレイ画面の下側に表示された細長いものがプレイヤーの操作する自機である。ボリュームを回すことによって、左右に移動することができる。また、ボタンを押すと自機から真っ直ぐと画面上側に向かって弾が発射される。弾を発射すると、何かにぶつかるまで再び弾を発射することはできない。
 自機のほかに表示されている二つの大きな四角がエネミーである。エネミーは画面上部から出現し、画面下側へ向かってゆっくりと直進する。エネミーに自機の発射した弾が命中すると、そのエネミーは消失し、画面上部から新たなエネミーが出現する。また、エネミーは画面最下部に到着することでも消失し、その場合も新たに画面上部から出現する。この際、右上に表示される3つの小さな四角のうち、1つが消える。これは残りライフであり、すべて無くなるとゲームオーバーとなってリザルト画面に移行する。
 リザルト画面ではGAME OVERの文字とともにスコアが表示される。スコアは倒したエネミーの数×10点で計算される。より高いスコアを目指すことがこのゲームの目的であり、楽しみでもある。
10 cls: clear: w=48: h=48: s=0: i=0: e=0: a=0: n=0: c=0 20 line 0,0,w-1,0,1: line w-1,0,w-1,h,1 30 line w-1,h-1,0,h-1,1: line 0,h-1,0,0,1 40 if n<=2 plot 50,3,2: if n<=1 plot 50,5,2: if n<=0 plot 50,7,2 50 p=aread(0)/22 60 if p<3 p=4 70 if p>w-4 p=w-5 80 if s=1 plot x,y,2 90 box p,w-4,p,w-3,2: plot x,y,1: box r-1,l-1,r+1,l+1,11: box t-1,m-1,t+1,m+1,11: delay 20 100 box p,w-4,p,w-3,2: plot x,y,0: box r-1,l-1,r+1,l+1,10: box t-1,m-1,t+1,m+1,10 110 if a=0 a=1: goto 140 130 if a=1 l=l+1: m=m+1 : a=0 140 if dread(12)=0 i=1: goto 150 150 if dread(12)=1 i=0 160 if s=0 if i=1 x=p: y=h-4 : s=1 170 y=y-1 180 if y=0 s=0 190 if e=1 goto 220 200 r=rnd(40): r=r+4: e=1 210 l=3 220 if r>x-2 if r<x+2 if l>y-2 if l<y+2 e=0: s=0: y=-256: c=c+1 250 if l=48 e=0: n=n+1 260 if f=1 goto 290 270 t = rnd(40): t=t+4 : f=1 280 m=3 290 if t>x-2 if t<x+2 if m>y-2 if m<y+2 f=0: s=0 : y=-256: c=c+1 300 if m=48 f=0: n=n+1 400 if n>=3 goto 420 410 goto 20 420 cls: ? "GAME OVER" 430 ? "SCORE:",c*10
>

外観

プレイ画面

リザルト画面

(参考資料)

[1] George Gray, Half-byte tinyBasic, https://halfbyteblog.wordpress.com/
[2] TinyBasic を動かしてみる, http://ht-deko.com/arduino/tinybasic.html
[3] DSbasic, http://desktopstation.net/wiki/doku.php/dsbasic
[4] Arduinoで超ミニBASICパソコンが作れる!, http://yumeiroandroid.blog.fc2.com/blog-entry-313.html


(付録1) 入出力モジュール

モジュール回路図製作例
可変抵抗モジュール
明るさセンサーモジュール
温度センサーモジュール
赤外線反射モジュール
音量センサーモジュール
10連LEDモジュール
NeoPixel(DinはA3に接続)
モーターモジュール
右モーターはA0とA1をGNDに接続
音声合成モジュール

(付録2) 使用する主な部品

部品表
名称 外観 備考
Arduino Nano 秋月 2780円
(互換品が400円程度で入手できます)
ブレッドボード EIC-701 EIC-701 秋月 250円
ブレッドボード ジャンパーワイヤ 15cm   秋月 10本 300円
ブレッドボード ジャンパーワイヤ EIC-J-S   秋月 250円
LED 秋月 10個 120円
フルカラーシリアルLEDテープ SwitchScience 756円
数字表示LED C-551SR 秋月 40円
圧電スピーカー SPT08 秋月 2個 100円
圧電サウンダ FGT-31T-3.7A1 秋月 70円
スピーカ UGSM23A 秋月 100円
プッシュスイッチ DS-660R-C 千石 84円
抵抗 1/4W 4.7Ω, 100Ω, 220Ω, 470Ω, 1kΩ, 10kΩ 秋月 100本 100円
CDS(光センサ)秋月 30円
温湿度センサ SHT31秋月 950円
温度センサ LM61CIZ秋月 4個 200円
赤外線反射センサ LBR-127HLD   秋月 50円
人感センサ(焦電センサ)
ブレッドボード ジャンパーワイヤ 15cm
  秋月 400円
秋月 10本 220円
サーボモーター SG-90   秋月 400円
リレー SS1A05   秋月 5個 280円
液晶ディスプレイ AQM1602A   秋月 550円
モータードライバ DRV8830   秋月 170円
音声合成LSI ATP3011F4   秋月 850円

(付録3) 入出力に利用できるピン

(1) NANOで使用できるピン

ピン 変数名 備考
デジタル入出力アナログ出力(PWM)アナログ入力
0 D0- -RX
1 D1- -TX
2 D2- -PS/2 Data, SLEEP時はLOWで Wake up
3 D3D3-PS/2 Clock
4 D4- -
5 D5D5-
6 D6D6-
7 D7- -Video out
8 D8- -
9 D9D9-Video sync
10 D10D10-
11 D11D11-Audio out
12 D12- -
13 D13- -
14 D14- A0
15 D15- A1
16 D16- A2
17 -- A3
18 -- A4I2C SDA
19 -- A5I2C SCL
20 -- A6
21 -- A7
22(仮想ピン)--TEMPSHT31/SCD30 温度
23(仮想ピン)--HUMISHT31/SCD30 湿度
24(仮想ピン)--CO2SCD30 CO2濃度
設定値または取得値0 / 10 - 2550 - 1023


(付録4) tinyBasicの書き込み

  1. Arduino 1.8.15をダウンロードし、インストールします。
  2. Arduinoを起動し、[ファイル][環境設定]で、スケッチブックの保存場所を確認し、その下にlibrariesフォルダを作ります。
  3. 液晶モジュールを利用するために、ST7032のライブラリ(ZIPファイル)をダウンロードし、解凍して上記librariesフォルダに置きます。
  4. NeoPixel LEDを利用するために、NeoPixelのライブラリ(ZIPファイル)をダウンロードし、解凍して上記librariesフォルダに置きます。
  5. [ツール][ボード]で「Arduino NANO」を選択し、[ツール][プロセッサ]で「ATmega328」を選択します。また、Arduino NANOを接続し、[ツール][シリアルポート]でポートを選択します。
  6. tinybasic20210909.zipを解凍します。ビデオ機能を利用しない場合はこのままでOKです。ビデオ表示やキーボードを接続する場合は、下表を参考に1行目のTVMODEの定義を1~4に変更します。有効にする機能によって作成できるプログラムのサイズ(概ね文字数)が異なります。16.216.4のように少し大きなプログラムの場合は、TVMODEを3にします。
    TVMODE 0 1 2 3 4
    NeoPixel - - - -
    I2C接続(液晶ディスプレイ,
    モータ, 音声合成, 温湿度センサ)
    - -
    サーボモータ, NeoPixel, 赤外線リモコン - -
    ビデオ表示 -
    キーボード接続 - - -
    最大のプログラムサイズ(バイト)1020698582951835
  7. ビデオ表示を有効にする場合は、ArduinoIDEの「ライブラリを管理」でTVoutライブラリを組み込んでおきます。TVoutフォルダの中にTVoutfontsフォルダがあるので、librariesフォルダの下に移動します。また、video_gen.zipを解凍し、TVoutフォルダの中のvideo_gen.cppを上書きします。今のArduinoのバージョンではasm_macros.hで行っているアセンブラのマクロ定義がうまく展開されずエラーとなるため、マクロ定義を使わないようにしました。
  8. キーボードを接続する場合は、ArduinoIDEの「ライブラリを管理」でPS2Keyboardライブラリを組み込んだ後、日本語キーボードに対応するためにDECOさんの「PS/2キーボードを接続してみる」の下の方にあるps2keyaoard_240_mod.zipを解凍し、2つのファイルを上書きします。
  9. 以上の準備ができたらtinybasic.inoをArduino NANOに書き込みます。

 プログラム(tinybasic.ino)は、「Tyny Basic を動かしてみる[2]」のページの中ほどにある「HalfByteTinyBasic_mod.zip」を拡張したものです。拡張した主な内容は以下のとおりです。

  1. プログラム実行の中断(ブレーク)をESCキーで行うようにしたこと
  2. 入力ミスの修正にBS(BackSpace)キーを使えるようにしたこと
  3. 起動時にEEPROMに保存されているプログラムをLOADし、3秒後に自動実行するようにしたこと(プログラムが完成したらパソコン無しで動作する)
  4. %(剰余) &(and) |(or) !=(<>と同じ)の演算子を使えるようにしたこと
  5. dRead()で内部プルアップ抵抗を有効にしたこと
  6. PRINTコマンドで液晶ディスプレイ(ST7032)にも表示させるようにしたこと
  7. 温度センサ(LM61)用に「TEMP」関数を追加したこと
  8. 温湿度センサ(SHT31)用に「tRead」「hRead」関数を追加したこと
  9. サーボモーター制御用に「SERVO」コマンドを追加したこと
  10. モーター制御用に「MOTOR」コマンドを追加したこと
  11. 「TONE」コマンドを追加したこと
  12. 音声合成用に「TALK」コマンドを追加したこと
  13. NeoPixel LED制御用に「PIXEL」コマンドを追加したこと
  14. 赤外線リモコン信号用に「f38k」「RCBYTE」「SCBYTE」の各コマンドを追加したこと
  15. 電池駆動のための「SLEEP」コマンドを追加したこと
  16. 7セグメントLED表示用の「NUMLED」コマンドを追加したこと
  17. 「PRINT」コマンドでビデオ(有効な場合)と液晶ディスプレイにも表示されるようにしたこと。関連して、「CLS」コマンドや「CURSOR」コマンドもそれらの表示デバイスに適用されるようにしたこと。
  18. ビデオ表示が有効な場合、「SET」「RESET」コマンドの代わりに「PLOT」コマンドを使い、パラメータで色指定するようにしたこと。また、ビットマップパターンをビデオ表示する「BMP」コマンドを追加したこと

 通信ソフトで接続すると「HalfByte...Hitany key!」の表示が現れるので何かキーを押し、初めて使う場合に一度だけ「new」「save」の操作をしてください。

 下図左のようにテレビやキーボードと接続すると、パソコンを使わずにプログラミングができます(このテキストでは扱っていません)。接続したキーボードとパソコンの通信ソフトのどちらからも操作できます。キーボードの接続については、「PS/2キーボードを接続してみる」を参考にしました。


テレビとキーボードの接続

テレビの表示画面

(付録5) tinyBasic リファレンス...グリーンが拡張箇所

□ コマンド

NEW
プログラムを初期化する。変数は「0」に初期化されないので注意。

CLEAR
A~Zのすべての変数の値を0にする。

MEM
メモリーの残量を表示する。

命令文
命令文を入力すると直ちに実行される(行末はEnterキー)。「A=1: B=2: PRINT A+B」のように「:」で区切って1行に複数の文を書いてもよい。

行番号 命令文
行番号をつけて命令文を入力すると、プログラムとして格納される(格納されたプログラムはRUNで実行)。

RUN
格納されたプログラムを先頭の行番号から実行する。

SAVE
EEPROMにプログラムを保存する。最大1000バイトで、プログラムは1つしか保存できない。

LOAD
EEPROMに保存したプログラムをロードする。起動時には自動的にLOADが行われる。

LIST
プログラムすべてを表示する。
LIST 行番号
行番号以降のプログラムを表示する。
LIST 行番号.
行番号のプログラムだけを表示する。

□ 数と変数と演算

-32767~32767の整数。16進表記の場合は、$FF, &FF, #FF のようにする。

定数(組み込み定数)
HIGH(またはHI)は「1」、LOW(またはLO)は「0」と同じ。

文字列
文字列は「"」で囲む。日本語も表示できる。

変数
変数名はA~Zで、大文字小文字は区別されない。変数には-32767~32767の整数を格納できる。
配列
@(0~)で代入・参照する。変数には-32767~32767の整数を格納できる。コマンド操作では利用できない。
演算
+(加算) -(減算) *(乗算) /(除算) %(剰余) &(and) |(or) !(0なら1, 1なら0)
=(等しい) <>(等しくない) !=(等しくない) >(大きい) >=(以上) <(小さい) <=(以下)

□ 命令文

REM または #
以降行末までコメントとなる。メモリーを消費するので注意。

代入
変数に値を代入する。LETは省略してよい。
(例) LET A=100

POKE 番地, 値
指定した番地に値を書き込む。
(例) POKE 1450,64...1450番地の値を64にする
(例) POKE TOP(0),"ABCDE"...メモリーのフリーエリアの先頭に文字列を"ABCDE"を格納する。文字列の末尾には改行コード(13)が付加される。
利用する時はPEEKを使い、何度も使う文字列で利用する。POKEとINKEYを組み合わせると、実行時に入力した文字列をしまっておくことができる。

FOR ループ
以下の例は1~20を表示する。 10 FOR X=1 TO 20 20 PRINT X 30 NEXT X 以下の例は10~100を表示する。 10 FOR X=0 TO 100 STEP 10 20 PRINT X 30 NEXT X ECHO 「FOR」と「NEXT」を同じ行に書くことはできない。

NEXT 変数
対応するFORループを終了する。

IF 式 文
式がtrueなら文を実行する。式に論理演算を使えないが、「IF A=1 IF B=2 PRINT A+B」のような方法で「AND」を表現できる。ELSEはない。

GOTO 行番号
指定した行番号にジャンプする。

GOSUB 行番号
指定した行番号のサブルーチンを呼び出す。サブルーチンは同じ処理を何度も実行する時に使う。

RETURN
サブルーチンを終了し、呼び出されたGOSUBの次の行に戻る。

STOP
プログラムを終了し、編集画面に戻る。

DELAY 時間
時間はms単位で指定する。

CLS
通信ソフトの画面、I2C液晶およびビデオ画面をクリヤーする。

PRINT 変数や文字列
? 変数や文字列
変数や文字列を通信ソフト(teraTerm等)の画面とI2C液晶とビデオ画面に表示する。「,」で区切ると、複数の変数や文字列が連続して表示される。末尾に「;」を置くと改行されない。

INPUT 変数
変数に数値を入力する。 10 X=0 20 PRINT "X? ";: INPUT X 30 PRINT X

CURSOR X, Y
カーソル位置を(X,Y)にする。XとYは4×6ドットの文字単位で位置を指定。その後printで文字を表示する。

AWRITE ピン番号, 値
指定したピン(D3,D5,D6,D9,D10,D11)に値(0~255)を出力する。

DWRITE ピン番号, 値
指定したピン(D2~D13)に値(0または1)を出力する。これを使ってLEDやモーターをオンオフできる。

MOTOR 左速度, 右速度
左速度、右速度はそれぞれ-255~255。0で停止。

SERVO ピン番号, 角度
接続したピン(D2~D13)のサーボモーターを指定した角度(0~180)に動かす。

TONE ピン番号, 周波数, 時間
TONE ピン番号
周波数はHz、時間はmsで指定する。ピン番号のみを指定した場合は音を停止する。ただし、以下に記すTVと接続した場合は、ピン番号は指定しない(D11ピン固定)。

TALK 変数や文字列
数値や文字列を合成音声で読み上げる。「,」で区切ると、複数の変数や文字列を連続して読み上げる。文字列は半角ローマ字を基本とし、「'」アクセント、「/」アクセント区切り、「-」長音、「.」「?」文末ポーズなどで修飾できる。

SLEEP
マイコンをSLEEP(省電力)モードにする。SLEEPモード時、Arduino Mini Pro(8MHz)で約250μA(実測)。D2ピンがPullUp状態となり、スイッチでLOWにするとSLEEPから復帰する。

f38k ピン番号, 繰り返し数
ピンに接続した赤外線LEDを指定回数点灯13μs消灯13μsする。

RCBYTE ピン番号, データ, ...
ピンに接続した赤外線LEDを指定したビットパターンで点滅する。データは複数指定できる。

SCBYTE ピン番号, データ, ...
ピンに接続した赤外線LEDを指定したビットパターンで点滅する(SONY方式)。データは複数指定できる。

NUMLED 数
D2~D8に接続した7セグメント数字表示LEDに「数(0~9)」を表示する。0~9以外の数を指定すると表示が消える。

PIXEL LED番号, R, G, B
PIXEL LED番号, HUE, BRIGHT
PIXEL LED番号, HUE
指定したLED(0~11)に指定した色で点灯する。R(赤),G(緑),B(青)の明るさをそれぞれ0~255、またはHUEとBRIGHTで指定する(BRIGHT省略時は255)。なお、NeoPixelの制御信号(Din)はA3(D17)に接続する。

□ 関数

 括弧内に引数を与えると、値が返される。

ABS, POW, SIN, COS
ABS(絶対値)、POW(べき乗)など、関数として利用する。SIN, COSは「度」で角度を与え、1000倍した値が返される。COS(60)は500となる。

RND(数)
0から指定した数-1までの乱数を返す。RND(5)は0~4のいずれかの整数値を返す。

PEEK(番地)
指定した番地の値を返す。PEEKを使って、ユーザが入力した文字列を調べることができる。

TOP(0)
未使用メモリーの先頭番地を返す。文字列を格納する時に用いる。

CHR(文字コード)
指定した文字コードの文字を返す。「PRINT CHR(65)」で「A」が表示される。

IN
通信ソフトからの文字入力を待って文字コードを返す。ESCキーが押されると-1を返す。

AREAD(ピン番号)
指定したアナログピン(A0~A7)から値を読み取る。0~1023の値が返される。

DREAD(ピン番号)
指定したピン(D2~D13)から値を読み取る。0か1の値が返される。0はLOW、1はHIGHを表す。

TEMP(ピン番号)
指定したアナログピン(A0~A7)に接続した温度センサー(LM61)が計測した温度(℃)が返される。

TREAD()
I2C接続した温湿度センサー(SHT31)が計測した温度(℃)が返される。

HREAD()
I2C接続した温湿度センサー(SHT31)が計測した湿度(%)が返される。

□ 命令文と関数(グラフィック)...TV表示が有効な場合

CURSOR X, Y
カーソル位置を(X,Y)にする。XとYは文字単位で位置を指定。その後printで文字を表示する。

PLOT X座標,Y座標,色
指定した座標(X,Y)にプロットする。色は0(黒), 1(白), 2(反転)で、以下についても同様。

LINE 始点のX座標, 始点のY座標, 終点のX座標, 終点のY座標, 色
画面に線を表示する。

BOX 始点のX座標, 始点のY座標, 終点のX座標, 終点のY座標, 色
画面に四角形を表示する。色は0(黒線), 1(白線), 2(線反転), 10(黒ベタ), 11(白ベタ), 12(反転ベタ), 他(白線黒ベタ)...反転表示に不具合あり!

CIRCLE 中心のX座標, 中心のY座標, 半径, 色
指定した座標に円を描く。色は0(黒線), 1(白線), 2(線反転), 10(黒ベタ), 11(白ベタ), 12(反転ベタ), 他(白線黒ベタ)...反転表示に不具合あり!

GET(X座標, Y座標)
座標(X,Y)の値(0または1)を返す。

SHIFT 移動量, 方向
表示画面を指定方向に指定量シフトする。方向は 0(UP), 1(DOWN), 2(LEFT), 3(RIGHT)。

INVERT
画面を白黒反転する。

BMP X座標, Y座標, 文字列
BMP X座標, Y座標, 文字列, 文字列, ...
座標(X,Y)からX方向に文字列で表したビットパターンを連続表示する。「0」~「F」の文字で4ピクセルの色(0:黒, 1:白)を表す(下表)。文字列を「,」で区切ると次のビットパターンは座標(X,Y+1)から表示される。
文字ピクセルパターン
(0:黒, 1:白)
文字ピクセルパターン
(0:黒, 1:白)
0
1
2
3
4
5
6
7
0000
0001
0010
0011
0100
0101
0110
0111
8
9
A
B
C
D
E
F
1000
1001
1010
1011
1100
1101
1110
1111

(付録6) 文字と文字コード(抜粋)