ORANGE pico で三原色の図を描く
アドベントカレンダーが始まり、あっという間に日曜日。
今日は……書きたいアレを書くための重めの作業パートをできた!
……が、残りの時間でこれを書こうとするのは間に合わないリスクが高いと判断し、今日も雑プログラムを書いてごまかすことを決定。やっぱり倍速計算機をこっちに書けばよかったかな……?
さて、そうなると次はどの処理系用のプログラムを書くかだ。
なでしこやIchigoJamはアドベントカレンダーで扱っているので、ここでネタを消費するのは癪に障る。
そうなると……アドベントカレンダーで扱っていない ORANGE pico を久しぶりに使ってみるか。
※IchigoJamはjig.jpの登録商標です。
……と思ったが、そういえば先週は事故で週streakを切り、日付が変わってから記事を投稿したんだった。
ということは、新たな記事を日曜日のうちに投稿するのは週streakに貢献せず、もったいない。
もちろん、倍速計算機をこっちに書くのも、Qiita での投稿数への貢献を捨てることになり、もったいない。
このことを1週間経たずに忘れてしまうなんて、やっぱり自分は頭が悪いなあ……
(記事を完成させる前に思い出したので、完成を待たずにサボり散らかし、こうして日付が変わってから投稿することにした)
今回やったこと
ORANGE pico で、丸3個からなるよくありそうな三原色の図をLCDに出力する。
今回は、ORANGE BASIC for PIC32MX Ver 1.06 を用いた。
三原色といっても、三木眞一郎は関係ない。
準備
LCD の接続
まず、ORANGE pico に対応する LCD を接続する。
今回は、リボンケーブルで LCD を接続した後、ORANGE pico と LCD モジュールをマスキングテープで止めた。
この状態で LCD を上にして置くと、しばらくは安定したが、しばらくするとORANGE pico からはがれて倒れてしまった。
シリアル通信モジュールの接続
次に、USB-シリアル変換器を接続する。
接続するピンは公式サイトの「ピン配置」に載っているのに従う。
信号の電圧は 3.3V のものがよいだろう。
通信設定は、115200bps、パリティなし、改行コード CR にする。
送信遅延はなし (0ミリ秒) で支障無くプログラムを流し込めるようだ。
デフォルトでは、UART には起動時のメッセージや print で出力した内容などは出力されないようである。
公式サイトのコマンド一覧の uart コマンドの説明には
モードのbit0(LSB)が1のときはコンソール出力されたものを同時にUARTに送信します。モードのbit1が1のときは、UARTからの入力もキー入力とみなします。モードは起動時に3となっています。
とあり、3 の LSB は 1 なので起動時から UART に送信してくれそうであるが、実際には送信されない。
uart 1, 3, 115200を実行してみると、print で出力した内容などが UART に出力されるようになった。
よって、この起動時のモードは嘘、もしくは別のバージョンについての記述のようである。
LCD を使うモードにする
コマンド
config 2, 1を実行すると、リセットがかかり、LCD に映像を出力するモードになる。
変数の使い方を学ぶ
ORANGE pico では浮動小数点数が使える。
浮動小数点数との計算をすることで整数を浮動小数点数に変換できるが、逆に式中で浮動小数点数から整数に変換する方法は見つけられなかった。
さらに、一部の関数の引数に浮動小数点数を指定すると、Type mismatch というエラーが出ることがある。
浮動小数点数を変数に格納するには、変数名の最後に ! がついた変数を使わなければならないようである。
! がついていない変数に浮動小数点数を格納すると、整数に変換される。
(逆に、この性質を用いれば、浮動小数点数を整数に変換できる)
公式サイトに載っているサンプルから、
dim 変数名(要素数)で配列を確保でき、配列の添字は 0 から始まることが読み取れる。
しかし、この配列の要素は整数であり、浮動小数点数が格納できる配列を作成する方法は見つけられなかった。
プログラム
100 swidth=320:sheight=240
110 cx!=swidth/2.0:cy!=sheight/2.0
120 cr!=40:r!=70:factor!=0.25
130 s3!=sqrt(3)
140 rcx!=cx!:rcy!=cy!-cr!
150 gcx!=cx!-cr!/s3!*2:gcy!=cy!+cr!/s3!
160 bcx!=cx!+cr!/s3!*2:bcy!=cy!+cr!/s3!
170 cls
180 for y=0 to sheight-1
190 for x=0 to swidth-1
200 dr!=sqrt((x-rcx!)*(x-rcx!)+(y-rcy!)*(y-rcy!))
210 if dr!>r! pr=0 else pr=pow((r!-dr!)/r!, factor!)*255
220 dg!=sqrt((x-gcx!)*(x-gcx!)+(y-gcy!)*(y-gcy!))
230 if dg!>r! pg=0 else pg=pow((r!-dg!)/r!, factor!)*255
240 db!=sqrt((x-bcx!)*(x-bcx!)+(y-bcy!)*(y-bcy!))
250 if db!>r! pb=0 else pb=pow((r!-db!)/r!, factor!)*255
260 pset x, y, rgb(pr,pg,pb)
270 next
280 next
290 if inkey()=0 goto 290実行結果
実行すると、約67秒で描画が完了した。
解説
パラメータの設定
100 swidth=320:sheight=240
110 cx!=swidth/2.0:cy!=sheight/2.0
120 cr!=40:r!=70:factor!=0.25以下のパラメータを用意する。
swidth:画面の横幅 [px]
sheight:画面の縦幅 [px]
cx!:円の中心の中心のx座標
cy!:円の中心の中心のy座標
cr!:円の中心の中心から円の中心までの距離 [px]
r!:円の半径 [px]
factor!:明るさの変化の仕方を決める値
factor! は、円の中心を 1、外周を 0 とした値を何乗することでその場所の明るさを決めるかを表す。
小さくするほど、減衰が遅れる (同じ場所ではより明るくなる)。
円の中心座標の計算
130 s3!=sqrt(3)
140 rcx!=cx!:rcy!=cy!-cr!
150 gcx!=cx!-cr!/s3!*2:gcy!=cy!+cr!/s3!
160 bcx!=cx!+cr!/s3!*2:bcy!=cy!+cr!/s3!円の中心の中心の座標と、円の中心の中心から円の中心までの距離から、赤い円 (rcx!, rcy!)、緑の円 (gcx!, gcy!)、青い円 (bcx!, bcy!) それぞれの中心の座標を求める。
描画
170 cls
180 for y=0 to sheight-1
190 for x=0 to swidth-1
200 dr!=sqrt((x-rcx!)*(x-rcx!)+(y-rcy!)*(y-rcy!))
210 if dr!>r! pr=0 else pr=pow((r!-dr!)/r!, factor!)*255
220 dg!=sqrt((x-gcx!)*(x-gcx!)+(y-gcy!)*(y-gcy!))
230 if dg!>r! pg=0 else pg=pow((r!-dg!)/r!, factor!)*255
240 db!=sqrt((x-bcx!)*(x-bcx!)+(y-bcy!)*(y-bcy!))
250 if db!>r! pb=0 else pb=pow((r!-db!)/r!, factor!)*255
260 pset x, y, rgb(pr,pg,pb)
270 next
280 next画面内のそれぞれの点 (x, y) について、それぞれの円の中心までの距離を求め、それに基づいて色の各成分の明るさを決める。
そして、求めた明るさの点を描画する。
描画終了後の待機
290 if inkey()=0 goto 290描画終了時、OK などの余計な表示をされないよう、キーが押されるまで待機する。
おわりに
ORANGE pico でよくありそうな三原色の図を描くことができた。
これだけだとわざわざ pow を使って連続的に明るさを変えた効果がわかりにくい印象があるが、
251 if x>160 && pr>0 pr=255を追加し、半分だけ連続的な変化を無効にして比べてみると、違いがわかる。


コメント