Propeller Basic プログラミング 状態:この文書の翻訳作業は完了しています 原文:nvp5.pdf 翻訳者:caskaz 対象読者:PropBASICの初歩知識(この文書は初期[2010年 3月]のPropBASICを対象にしているので現在のバージョンとは違う記述があります) ParallaxとBASICはそれ自体素晴らしいけどそれがマカロニとチーズみたいに一緒になった。これを使うとまるで魔法使いみたいな気分になれるよ。 PropellerではBASICを使えないので失望している人が少なからずいた。 さて、よいおしらせだ。”Bean”の名で知られるTerry Hittが率いたSX/B開発チームがPropeller専用のBASICコンパイラ(PropBASIC)を作った。 PropBASICとはなにか †はっきりしている事はPropBASICはアセンブラコードに変換する1パスコンパイラなのでBASICよりも速いということだ。 そのコードは一つ以上のSPINファイルだ。Version1でメインプログラムコードはひとつのCogに限定されているがこれで困ることはない。 SX/Bを使ったことのある人にとってはPropBASICはとてもよくわかり、少しの変更で今あるプロジェクトを移植することができるし、もしBASIC Stampを使ったことがあればPBASICに似ている印象を持つと思うよ。 こんにちはPropBASIC †どの学習書でも必ず”Hello World”で始まるのがお決まりになってるけど、大きなプログラミングと格闘する前に基礎を覚えるのは大事だ。 ちらかって汚いプログラムリストは大嫌いだ。最後まできちんとしたプログラムをかく簡単な方法はテンプレートを使うことだ。沢山のプロジェクトを始めるのに使ったtemplate.pbasをダウンロードできる。 デバイス設定 †DEVICE P8X32A, XTAL1, PLL16X XIN 5_000_000 上記はPropBASICでは定番だ。 もちろん定番以外もある。時間にシビアでない用途ならRCモードを選べる.こいつは低パワーというおまけもついてる。 DEVICE P8X32A RCFASTの設定の場合はなにも指定しないけれどRCSLOWの場合はRCSLOWを指定しなければならない。 10msecのパルスを出力するプログラムを作って(speed_test.pbas)オシロでパルスを計ってみた。−やってみるとパルス巾は9.06msecだった。 Scale = 10.0/measured 私の場合、scale factorは1.1038だった。クロック周波数20kHzのRCSLOWを選択しているのでプログラムの先頭に下記の調整値を付け加える DEVICE P8X32A, RCSLOW FREQ 22_075 FREQ設定でコンパイルすることにより、PAUSEやSEROUTでも正しい時間管理がされる。 定数” †テンプレートの次の項目は定数定義だ。数字とキャラクタ文字は同じように扱える。 OnTime CON 250 OffTime CON 750 IsOn CON 1 IsOff CON 0 Asterisk CON “*” プログラムでSERIN,SEROUTを使う場合はボーモード定数の設定もここで扱う。 Baud CON “T9600” 上記ではSERIN,SEROUTをTrueモードで使う場合の定義を示している。 I/Oピン †LED PIN 16 LOW PropBASICではI/O ピンの宣言はPBASIC2.5やリセット後にピン状態を定義しておくSX/Bとよく似ている。ピンのオプションはINPUT(default),OUTPUT,LOW,Highなどである。 RX PIN 31 INPUT TX PIN 30 HIGH HIGHオプションの使用に注意:シリアル通信のTXピンをアイドル状態(output,high)にしておくようにスタートアップコードにおいている。 PropBASICはI/Oピンのグループを定義することもできる。例えばPropellerDemoBoard?のLEDはP16からP23に接続されている。これらのLEDをグループとして定義している。 LEDs PIN 23..16 LOW ピングループ定義で最初の数字がグループの最上位ピン(MSB)、2番目の数字がグループの最下位ピン(LSB)となっている。数字の順番は重要でグループが入力としてセットされている場合は読み出し、出力でセットされている場合は書き込みのビットが影響をうける。 PropBASIC1.0では出力ピングループにバイナリを割り当てることもできる。 LEDs = %100000 上記はOK、しかし LEDs = 1 << position はNG。これは将来実装されるかもしれない。現在のところは下記のようにする。 __temp = 1 << position LEDs = __temp 変数の共有 †PropBASICでは変数及び配列をHubに保存しており、それらはどのCogからもアクセスできる。 rxHead HUB Byte = 0 rxTail HUB Byte = 0 rxBuffer HUB Byte(64) = 0 PropBASICではHub変数の初期値を設定できるが、初期値設定されない場合はゼロにセットされる。(配列の場合は全部の要素) データの共有 †変数と同じようにHubにあるデータも共有できる、そして32KバイトのRAMには大きなテーブルデータも作れてどのCogからもアクセスできる。 Zip4 DATA %0001 DATA %0010 DATA %0100 DATA %1000 Hub変数のようにRDxxxx/WRxxxxを使ってHubのデータにアクセスする。 SFX1 FILE “BABY.WAV” DATA 0 タスク定義 †PropBASICで2個以上のCogを使用して「裏プロセス」の処理を実行するにはTASK定義が必要です。BASIC Stampを使った経験があったらシリアルデータの入力データのwait処理で悩んだことがあると思う。SX/Bではシリアル入力データ処理の為に割り込みを使っていました。しかし、もう気にすることはない。 PropellerではHub変数を使ってシリアル入力処理を別のプロセッサに行わせます。TASK定義は単純だがタスクが起動する前に設定する必要がある。 SERIAL_RX TASK ローカル(Cog)変数 †プログラムやタスクで使う変数はCogにとってローカルでLongとしてのみ定義できます。 Idx VAR Long PropBASICはコンパイラによって生成されるアセンブラコードで使用されるいくつかのローカル変数(サブルーチンや関数内部で使うパラメータのような)を生成する。 サブルーチンと関数の宣言 †始めに述べたようにPropBASICは1パスコンパイラでアセンブラコードを最適化しません。 mov __temp1, cnt adds __temp1, _1msec mov __temp2, #100 __L001 waitcnt __temp1, _1msec djnz __temp2, #__L001 オーケー、もしPAUSEが出現する度にアセンブラコードを生成したら酷いコードになるだろう。これはサブルーチンにPAUSEをカプセル化したら解決できる。 DELAY_MS SUB 1 DELAY_MSは1個の引数が必要だ。Propeller変数は32bitなのでそれはとても長い遅延時間でもOKだ。 SIRCS_RX FUNC 0 メインプログラム †LED blinkerプログラム本体は大体下記のようになる PROGRAM Start Start: FOR idx = 1 TO 3 LED = IsOn DELAY_MS OnTime LED = IsOff DELAY_MS OffTime NEXT DELAY_MS 1_000 GOTO Start PROGRAMディレクティブはユーザが作ったプログラムの始点と、さらに時度生成start-upコードの位置も示している。 見てのとうり、コードはまったくのBASICだ。PBASICやSX/B、他の言語を扱った人達にとっても簡単だろうと思う。 サブルーチンと関数の中身を作る †サブルーチンと関数のコードはリストの最後に書くことになっているのでDELAY_MSという名前のサブルーチンをリストの前部で定義してコードを書いてみた。 SUB DELAY_MS PAUSE __param1 ENDSUB 他の言語同様にサブルーチンは別のサブルーチンをcallすることもできる。ターミナルへのデータ送信のプログラムで2つのサブルーチンを書いた。 SUB TX_STR strAddr VAR __param2 strChar VAR __param3 strAddr = __param1 DO RDBYTE strAddr, strChar IF strChar = 0 THEN EXIT TX_BYTE strChar INC strAddr LOOP ENDSUB SUB TX_BYTE SEROUT TX, Baud, __param1 ENDSUB 2番目のサブルーチンはSEROUTのシェルで、最初のサブルーチンはシリアルポートに文字を送信するのに使う。 Banner DATA “PropBASIC”, 0 関数のコードはサブルーチンコードと比較するとFUNC..ENDFUNCブロックと関数の呼出し側に1つ以上の戻り値(ENDFUNCの直前にRETURNをおく)があることを除けばよく似ている。下記はPropBASICで書いたSIRCS受信関数だ FUNC GET_SIRCS irCode VAR __param1 irBits VAR __param2 COUNTERA NEG_DETECT, IR, 0, 1 COUNTERB FREE_RUN, 0, 0, 1 Wait_Start: WAITPEQ IR, IR PHSA = 0 WAITPNE IR, IR PHSB = 0 WAITPEQ IR, IR IF PHSA < BIT_S THEN Wait_Start irCode = 0 irBits = 0 Check_Frame IF PHSB > MS_044 THEN IR_Done Wait_Bit: IF IR = 1 THEN Check_Frame PHSA = 0 WAITPEQ IR, IR irCode = irCode >> 1 Measure_Bit: IF PHSA > BIT_1 THEN irCode = irCode | $8000_0000 ENDIF INC irBits IF irBits = 20 THEN IR_Done GOTO Check_Frame IR_Done __temp1 = 32 – irBits irCode = irCode >> __temp1 RETURN irCode, irBits ENDFUNC まったくそのまんまのコードだと思う。これはアセンブリコードに変換されるので大変速い。だからRC-5のような別のIRプロトコルで実験したい場合はhigh-level-code(sircs_rx.pbas参照)を使った方がいいよ。 PropBASICはSIRCSの例のようにPASMにあるWAITPEQ、WAITPNEなどのSpinやPASMのキーワードもいくつか持っていることを指摘しておくよ。 タスクの中身を作る †タスクは別のCogで動いてるのでその構成はサブルーチンや関数よりも少し込み入ってる。 TASK SERIAL_RX rxb VAR __param1 hPntr VAR __param2 DO SERIN RX, Baud, rxb RDBYTE rxHead, hPntr WRBYTE rxBuffer(hPntr), rxb INC hPntr hPntr = hPntr & $3F WRBYTE rxHead, hPntr LOOP ENDTASK そのとうり、これが全部だ。タスクはCON,PIN,HUB宣言もできるしこれら全部の要素を含んでいる。 タスクをスタートするには2種類あるがたいていCOGSTARTを使う。 COGSTART SERIAL_RX 別のCogが立ち上がり準備が整うまで十分な時間は必要なので、タスクで供給したデータにアクセスしようとする前に数ミリ秒待たせたいこともあるかもしれない。 PropBASICコンパイラはタスクの名前でSpinファイルも作れるので、同一フォルダにあるかもしれないSpinプログラムを上書きしないようにタスクの名前に注意する必要がある。 FUNC RX_BYTE rxh VAR __param1 rxt VAR __param2 rxchar VAR __param3 DO RDBYTE rxHead, rxh RDBYTE rxTail, rxt LOOP UNTIL rxh <> rxt RDBYTE rxBuffer(rxt), rxchar INC rxt rxt = rxt & $3F WRBYTE rxTail, rxt RETURN rxchar ENDFUNC 最初のループでヘッドとテイルポインタの値を比較してデータを得ている。 別のCogがシリアルバッファにデータを保存するやっかい事をやってくれているのでバッファが空でもメインプログラムの邪魔をする事はない。 FUNC RX_CHECK head VAR __param1 tail VAR __param2 bufcnt VAR __param3 RDBYTE rxHead, head RDBYTE rxTail, tail IF head >= tail THEN bufcnt = head – tail ELSE bufcnt = tail – head ENDIF RETURN bufcnt ENDFUNC これはバッファの先頭と最後尾間の差をリターンする。バッファはリング形式でtailはheadに追随し、headポインタがtailポインタより小さくなって負数にならないようにIF..THENを使っている。 誰でもアセンブラ? †難解なアセンブラ言語から解放してくれて速いプログラムをコーディングできるので沢山の人がこのコンパイラを楽しむと思う。 まとめよう †ここだけで多様な機能をもつPropBASICを述べる事はできない。でもPropBASICとは何かとか始め方はわかってもらえたと思う。SX/B同様、条件付きコンパイルディレクティブもあるしPropBASICファイルに外部のアセンブラコードを読み込ませることもできる。 PropBASICの将来 †一言でいえばワクワクしているんだ。 |