Propellerのまわしかた

Propellerで作ったものを公開しています。まだまだ出来がよくなくてもとりあえず動作するモノを公開しています。
日本語のサイトで参考になるのは少ないのですが長嶋先生のページは本当に参考になります。長嶋先生ありがとうございます。
PICやAVRは色々な製作事例がありますがPropellerはちょっと見当たらない。いきなり難しい事はできませんがPropellerを使った簡単な製作を行い徐々にレベルアップをしたいと考えています。

Joystick(2009.9.4)

参考資料 PE Kit Tools: Measure Resistance and Capacitance
使用しているCounterModeについてはPropeller Education Kit LabsのChapter7に詳細があります。

ParallaxのWebPageで2-Axis Joystick(Item code 27800)を見て、どこかで見覚えがある気がしたので部品箱を漁ったら同じような物が出てきました。
そういえば共立電子デジットで面白そうなパーツがあると買ってしまうんですがその中のひとつでした。(そんなパーツがもう山のように・・・)
2-Axis Joystickのpdfを見たら抵抗値も同じで中にスプリングが入っていて常にセンター位置にある構造も同じでした。(後日またデジットに行ったらこのパーツと基本構造は似ているけどJoystickの動きがものすごく滑らかなオムロン製のパーツを見ました。オムロン制は820円、こいつは210円、やっぱり値段の差は歴然)

で、これでStickを動かした時の位置を100パーセント表示に変換するコードを書きました。(参考資料の中のTest Repeated RCTIME.spinを元にして少し書き換えただけですが)

X軸Y軸のMin値及びMax値を記録する際の画面(値は抵抗値ではなくClockTicks)
Stickがセンター位置
Stickを動かした時のXYの値

プログラムをロードしたらParallaxSerialTerminal(PST)にX軸Y軸の値が表示されるのでJogstickを動かして数字が最小になるところでSWを押してMinXとMinYの値を記録します。Stickはすぐ離して値が再表示されるのを待ちます(2秒ほど)。
次はJogstickを動かして数字が最大になるところでSWを押してMaxXとMaxYの値を記録します。
そのあとはJogStickの位置がX軸Y軸ともに+100〜-100の表示となります。(実際は+100以上、-100以下となってしまうこともあります。又Stickがセンターにあってもゼロとならないこともあります)
まだ改良しなければならない箇所が沢山ありますが、一応動作します。Joystick.spinをTop Object Fileにしてロードします。

Joystick1

Joystickの値をLCDに表示(2009.9.9)

上記のJoystickにLCDを付けてみました。
ParallaxのObjectのDisplayからLCD関係ををダウンロードしましたが制御コードが違ってるなど動作しなかったので修正しています。
ParallaxSerialTerminal(PST)に表示されるX軸Y軸の値をLCDにも表示させてるだけです。Joystick_with_LCD.spinをTop Object Fileにしてロードします。
LCDは「SC1602AS*B-SO-GB-G」を使用しています。

Joystick2

シュマートボードでLCDではなくTVモニタに出力してみました。但しEEPROMは外しています。(2009.9.27)

Joystick_with_TV

Propellerチップとシュマートボード購入(2009.9.12)

注文していたPropellerチップとシュマートボードが今朝届きました。
チップは立派な箱に入っていて、シュマートボードはやっぱり小さくて表面実装部品も小さい。
先々月に共立電子主催の表面実装部品のハンダ付け講習会に行ってハンダ付けやってみたけど、シュマートボードは指でパターンをなぞると表面実装部品の端子部分が少し溝になっているから普通のボードよりもさらに簡単みたい。

シュマートボードのハンダ付け(2009.9.25)

シュマートボードのハンダ付けした時、ちょっと?だったけど不安的中でeeprom壊してしまったようです。なので注意点を。
P0〜P27までのポートはLEDチカチカのテストプログラムで動作確認しました。しかしeepromに書き込むと「EEPROM programming error on COM5」のエラーが出て書き込めません、導通テストや電圧チェックなどしましたがどうやらeepromを壊したみたいです。
Propellerチップとeepromチップのハンダ端子の幅は少し違います。eepromチップの方が少し狭いです。だから僕のハンダごてではPropellerチップの端子パターンでは問題なかったんですがeepromチップの方はハンダごての先端がシュマートボードの特徴であるパターンの溝に完全には入ってませんでした。その為ハンダを溶かすのに時間がかかりeepromを熱破壊してしまったようです。(あとからハンダを無理矢理流し込めば良かったなあと思いましたが)
シュマートボードを組み立てる場合ははんだごての先端の大きさに注意した方がいいです。
使用したハンダごての先端チップは結構長いことつかってるので先端が新品に比べれば丸くなってしまっているとは思います。

Parallaxの組み立て説明書の必要ツールのところにBasic soldering iron with 2.4 mm soldering tipてあるけどこれって0.24mmの間違いかな?
個人的な感想としては初めて見た時はシュマートボードっていいなと思いましたが、実際にハンダ付けしてみると?でした。メリットはICがテープで固定しなくても溝に入ってるからずれにくいのでハンダ付けしやすい。でもeepromの様に端子が2方向に出ていてサイズの小さいICはやっぱりテープで固定しないといけない。さらに溝が狭くなるのでハンダごての先端のサイズに注意しないといけない。
メリットがデメリットになってしまっている。(従来の表面実装パターンに慣れている人は流しハンダが使えないからやりにくいんじゃないかな)
シュマートボードでなく従来の表面実装パターンだったら多分熱破壊するほど熱を加えなかったと思います。
まあ、たんに僕が下手だったとも言えるけど。
この基板のメリットはそのサイズにあります。自作ではこんなに小さくできません。(変換基板て結構でかい)小さい基板が必要でなければ完成品で安価なプロトボードを購入した方がいいです。

2009.10.8 今回に限って特別に「マイクロボット教育社」さんからeepromを頂いたので再度ハンダつけをして書き込みの確認をしました。

シュマートボード(抵抗、コンデンサ、LEDはチップ部品使用)
使用したハンダごてと0.4mmの水性ボールペン

LCDにバーライン表示を追加(2009.9.13)

LCDのCG_RAMにキャラクタを書き込んで疑似グラフィック表示できるようにしてStickの位置に応じて縦線が左右(右がマイナス側)に移動するようにしました。
Stick位置のMax/Min設定するときのスイッチを押す度にキャラクタとバー・ライン表示が切り替わります。
X,Yの値が+100以上、-100以下とならないように修正しました。 でも,見た目しょぼいし上側(X)の方が下側(Y)よりちらついてるのはどうしてだろう。一応動作しますがちょっとおかしいのであとで修正します。

Joystick3

LCDコントラスト調整をPropellerのPWMで実行(2009.9.14)

ボリュームを外してPropellerのPWM(1kHz)で調整できるようにしました。スイッチを押すとX/Y指示値(+100〜-100)、バー・ライン表示、コントラスト調整と変わって又、X/Y指示値表示に戻ります。
JoystickのX軸をプラス側に押すと液晶が濃くなってマイナス側だと薄くなります。但しPropellerの出力電圧は3.3Vなので5Vの場合ほど濃くなりません。
バーグラフはコントラストの濃さ(PWMのH期間のパーセント数値)を表していて電圧値ではありません。濃いほど電圧は低くなります。コントラストに5Vを与えるにはトランジスタでレベル変換する必要があります。 バー・ライン表示でちらつかないように修正しましたが、画面のしょぼさは変わりません。

Joystick4

Joystickの位置をLEDマトリクスに表示させる(2009.9.16)

部品箱を漁ってたら8X8のLEDマトリクス(CSM-88261DF 赤&緑)があったのでJoystickの位置をLEDマトリクスに表示させてみました。
(この調子で色々やってたら死蔵部品に日の目を見せてあげられるかも)

Joystick5
DEMO_Matrix
>
左方向がX軸のプラス、上方向がY軸のプラス

LEDをセンサとして使用(2009.9.19)

Parallaxのサイトを見ていたときにLEDをセンサとして使用したプログラムを見付けました。オリジナルの場所はわからなくなりましたがプログラムはInteligent_LED.spinの名前で保存しています。
これはセンサとして使用したLEDの出力をDemo BoardのLED(P16~P23)にVUメータのように表示し、明るい時ほどLEDの点滅が速くなって明るくなります。
ここで面白いコードは最後の outa := (|< >| ratio -1) << 16 です。 >|でratioの最上位のbitナンバーに+1します。次に|<でその数字のbitナンバーのみに1を立てたバイナリを作ります。例えば0000 0080(32bitのビット列)を>|で8を得て|<で0001 0000(32bitのビット列)にして-1で0000 ffffにして16bit左にシフトしてLED表示しています。
これを元にしてLEDに影をつくって光を遮ると点滅するモノに変更しました(Inteligent_LED1.spin)。光センスとLED点灯の繰り返しをもっと工夫すれば明るいと消灯、暗くなると段々と明るくなって点灯していくようにできると思います。
高輝度タイプのLEDを使いましたがLEDによってはPUB LEDの if ticjer0 + 2000 < ticker の2000を調整する必要があります。
コンデンサの値を大きくすると充放電に時間がかかるのであまり大きくできません。又LED自身が容量をもっているのでコンデンサがなくても動作しますが(上記の2000も小さくします)指でLEDをちょっと力を入れて掴むと容量が変化してしまうせいか点滅しなくなります。
Inteligent_LED

2009.10.7
ネットを検索していたらLEDにコンデンサをつけずにやっているのが普通のようなので作りなおしました。
ここを読んでLEDに溜った電荷を放電する時間を測定するDischarge_LED.spinをつくりました。 光がLEDに照射されると光電流が発生することによってLEDの内部容量に充電されていた電荷が放電され、強い光であるほど内部容量の放電が促進される(明るいと放電速度が早く暗いと遅い)ということらしい。
Discharge_LED.spinでLEDに光を当ててる時のクロック数は大体100000〜300000(クロック80MHZなので1.25msec〜3.75msec)、光を遮っている時は1200000(15msec)
LEDに充電されるときの時間を測定したプログラム(Charge_LED.spin)もつくってみました。 Charge_LED.spinでLEDに光を当ててる時のクロック数は大体100000〜900000(クロック80MHZなので1.25msec〜11.25msec)、光を遮っている時は1200000(15msec)
明るい時、Discharge_LED.spinの放電時間もCharge_LED.spinの充電時間も短かったリ長かったりしている(特に充電時間の時の差が大きい)理由がまだよくわからない。

暗い時にLEDの先端を触るだけなら大丈夫だけどLEDの横を指で挟むとやっぱり容量が変わるらしく消灯してしまいます。
LEDの発光面にキチンと光をあてないと光があたっていない状態になってしまうし、又LEDによっては放電(充電)時間は結構かわるようです。
色々なLEDで試してみたら青や緑より赤色LEDが一番よいようでした。ただ古いLEDは全くダメでした、テスターのダイオードレンジでテストしたらあまり明るくなく光にあてて起電力をはかったら100mVもでてませんでした。どうも樹脂が変質していて光を通しにくいのかもしれません。

Intelligent_LED1
Discharge_LED.spin
Charge_LED.spin

ロータリーエンコーダ(2009.9.23)

共立電子デジットでロータリーエンコーダ買ったのでこれのテストプログラムをSPINで書いてみました。ショップで端子配列聞くの忘れたのでたまたまネットで似たようなエンコーダがあったのでその配線を参考にしたんだけど動作がおかしい。CW/CCWどっちに回しても数値が増えてしまう、プログラムではCCWで数値は減るようになってるけど。
どう考えてもわからないのでParallaxからencoderのobject(このquadrature_encoder.spinはアセンブラコードです)探してそれをダウンロードして動作させてみたら(Encoder_with_LCD.spin)ちょっとおかしいけど(1クリックで2カウントしているし、たまにミスカウントする)CW/CCWで数値が増減している。(この時は変な動作はチャタリングのせだろうと思っていた)
Parallaxのサンプルコードでとりあえずは動くのでテストプログラムがおかしいんだろうと考えましたがやっぱりうまくいかない。

かなりはまってしまいましたので念の為、エンコーダの出力をオシロで見たらA相B相のパルスの立ち下がりが同時になってる、どうやらCommonを信号ラインにつないでいたらしい。Common、A,Bを確認して接続しなおしてプログラム(Test_Encoder.spin)を動作させてみたところ、一応動作したけどミスカウントが多い。
Encoder_with_LCD.spinはまともに動作しています。1クリックで4カウント、1回転で96カウント、ちゃんとA相B相のパルスの立ち上がり立ち下がりを検出してカウントしてる。このプログラムのエンコーダ処理部分はアセンブラで書かれています。(でもチャタリングはどうやって回避してるんだろ?ちゃんと読まないと・・)まだ存在しない64bit版Propellerに対応しているし、プログラムコードを実行中に書き換えている部分もあります。RAM上で動作しているPropellerならではです。こういうのはPICやAVRではできません。
まあ、僕にはこれをメリットとして利用出来る程の知識がまだありませんが。

ちょっと煮詰まってるのでエンコーダのテストプログラム(Test_Encoder.spin)はあとで修正します。そのうちに、たぶん。
(このTest_Encoder.spin、間違って削除してしまったらしくどこがおかしかったのか確認できませんでした)
Encoder

2009.10.9
Test_Encoder.spinを作りなおしました。Encoder_SPIN2.spinをobjectで参照しています。Encoder_SPIN2.spinは別のCogでA相とB相の信号の立上り立ち下がりを検出してカウントしていますので1回転96カウントとなります。 Encoder_SPIN2.spinの最後でチャタリング除去用のwaitを入れてました。2msec以上にするとカウント欠損がありました。waitの時間を短くしたらカウントミスで増えるのかと思いましたが全然増えないのでwaitをコメントアウトしましたがカウント値は正常でした。
このロータリエンコーダは擦動式だと思うのでチャタリングがあるはずなんですが手で回してるので発生していないのか?あとでモータで回して確認しないと。
と、思ってたら何度も回してるうちにB相がオープン状態から変化しなくなってしまいました。耐久性はあまりないみたいです。
Encoder1

基板と接続端子は後付け
正しい端子は左からA、Common、B

お台場でガンダム、神戸で鉄人、そして大阪でひよこ?(次は実物大のマクロス・・・は無理か)

SDカードを使う(2009.10.1)

Joystickの位置をTVにX-Yグラフで表示させてX-Yの最小最大の値と5秒間X-Y位置をSDカードに保存するプログラムをParallaxからオブジェクトfsrw-and-friends-1.7をダウンロードして作ってみました。
SDカードコネクタは共立で購入したヒロセのスタンダードタイプのDM1AA-SF-PEJ(250円)。CD,WPも結線していますが今回は使用していません。

ファイルの保存日時はハードコードなので変わりません。(fsrw.spinのpdateで設定しているのでここでRTCなどから得た日時データを反映させるとか・・・ 詳細はfsrw-and-friends-1.7ディレクトリ内のファイル参照)
SDカードのアンマウントはやっていないので途中でカードを抜くとRead/Writeはできません。(アンマウントしていないので電源入れた状態でやらない方がいいと思いますが)エラー処理はエラーナンバー表示のみで何もしていません。
SD_Card_Joystick_with_TVをトップオブジェクトにしてRAMにロードしたらカード内のファイルを表示してからinit_xy.txtがあればX-Yの最小最大値を読み込んでX-Yグラフを表示します。init_xy.txtがなければX-Yの最小値・最大値の設定を行い、その値をinit_xy.txtに書き込みます。Joystickを動かすとグラフ内のドットが動きます。
スイッチを押すと5秒間100msec間隔でX-Yの値をxy_pos.txtファイルに書き込んでから、X-Yグラフの表示モードに戻ります。

SD_Card
エージングも兼ねてシュマートボード使用
X-Y位置表示
X-Y位置記録
SDカード内のファイル
左からX最小、Y最小、X最大、Y最大
X-Yの位置を100msec間隔で記録

phsa~とdira[ポート番号]~との間のクロック数(2009.10.3)

最初にPropeller Education Kit LabsのChapter7を読んだ時からtime:=(phsa-624)#>0の624ってよくわかってなかったんだけどなんとなく「そういうもんなんだ」と納得してました。
でもPE Kit Tools: Measure Resistance and CapacitanceのMeasureTime.spinの中で同じようにCounterModeのPOS detecrorを使用しているけれど(phsa-588)#>0となってる。
これはどういうこと? というわけでちょっと調べてみた。Propeller Education Kit Labsの126ページにあるように0.01uFを100pFに変えてTestRCDecay.spinをロードして実行してみると値がゼロになる直前の値は624でも588でもなかった。
そういえばどこかにポートのスレッショルドレベルはチップによっても違うし同じチップでもポートによって変わると書いてあった。
つまり該当ポートでRC回路のR電圧がVRを回して抵抗値が小さくなっていくとポート電圧がスレッショルドレベルを下回ってしまいL状態の為カウンターがスタートしないので、その直後のカウンターが動作する時の数字がphsa~とdira[ポート番号]~の間で経過するクロック数、つまりスレッショルドレベルが変わると当然このクロック数も変わる。
だから、使用するチップ、ポートごとにこのクロック数を調整してphsaレジスタから減算しなければならない。
ということはJoystickのプログラムのなかにある(phsa-588)#>0の部分も調整する必要があります。

Propellerでモータを駆動(2009.10.22)

ただ単純にモータ駆動してもなーんも面白くないのでLEDを並べてそれをSliderとディスプレーの2つの用途で兼用させてみました。
モータ駆動は専用ICのTA7291Pを使用しました。オブジェクトPWMMotorDriverの引数Frequencyについてですが大きくするとモータが追い付かずパワーがでないし小さすぎるとオフ時間に回転数が落ちて振動するので100Hzぐらいが一番モータ端子電圧が高くなり安定動作するようです。今回はマブチのRE260を使ってますがこれはモータによって変わると思います。TA7219PのVref端子に加えるPWM信号を積分回路で平滑したら引数frequencyは気にしなくていいですがモータが信号の変化に追従できなくなります。
RE260は内部抵抗が1オームぐらいしかないのでモータ電源を単4Ni-MH充電電池4本にしてますがモータに加わる電圧は半分ほどになっています。(TA7291AデータシートのVref-Vout特性参照)
モータ端子電圧が低いのはモータ内部抵抗のせいだけじゃなくてTA7291Pのデータシートをよく読んでいない為使い方が間違っていたせいでした。。ロジック電源電圧はmin4.5V〜20V、モータ印加電圧の方向を決めるVinのH-levelはmin3.5v max5.5Vだったし、モータ印加電圧Vsをモータ制御電圧Vrefの電圧値で制御できる。しかしこの実験回路ではVinのH-levelは3.3V(L-levelは問題ない)だしモータ制御電圧Vrefも0V〜3.3V(PWM)なので100%でもVsの半分ほどしか出ないのは当然。しかしRE260の最大印加電圧は3Vなので不完全な回路ですがこの実験ではこれでも可とします。

LEDにSliderの動作をさせるには常に3つのLEDの明るさをチェックして3つのうち左右どちらかの2つのLEDが影に入っている場合にそちらの方向のLEDを点灯して明るさをチェックする3つのLEDをそっちの方向にずらしていきます。3つのLEDの真ん中にあるLEDの位置を-100(CCW)〜0〜+100(CW)のdutyに変換してモータを駆動します。
最初は指でLEDの上をずらしていこうと考えてましたが、指は丸くて厚みもあり考えていたほど簡単にLEDが変化してくれませんでしたがカッターの刃ならLEDは割と簡単に反応してくれました。
LEDは放電特性の同じようなものを選別し、LED同士の間隔も試行錯誤する必要があります。(光センスなのでライトも重要)さらにソフトで外乱ノイズの影響も除外したらもっと安定動作すると思いますが元々実用性があるものではないし、Propellerならこんなのもspin言語だけで簡単に作れるのを確認するのが目的だったのでこれはここまで。

Motor

LEDセンスはGet_Status.spinでやってますがStack Spaceというのがもうひとつよくわかりません。Propeller Education Kit LabsのChapter5に詳細が書かれていて大きめにとっておいてオブジェクトStackLength.spinで必要な大きさを決めれば良いらしいがStackLengthDemo.spinでチェックしたがうまく動作していない。DemoプログラムのStackSpaceはちゃんと動作したんだけど・・・又後日。

真ん中のLEDは0%を表している(初期値は0%)
現在のDutyは-60%(CCW)

MX2125でモータ制御(2009.11.7)

モータ(ドアミラーのジャンク)の上に2軸AccelerometerのMX2125を固定してPSTから角度を入力し、その角度となるようモータを制御する実験をしてみました。
MEMSICのApplicationNoteを見るとMX2125のX軸Y軸の平面が重力と直角の関係にある場合、X軸Y軸の傾きが+60度〜ー60度の範囲以外は分解能が極端に悪くなるので使用しない方がいいそうなのでここでは使用していません。もっともドアミラーのモータの可動範囲は大変狭いので10度もあれば十分ですが。
MEMSICのApplication Notesの「Inclination Sensing with Thermal Accelerometers」を参照)
PSTから入力した角度になるまでMX2125からの出力値を検出しながらX軸Y軸のモータをPWM駆動(モータ速度が遅いので実際はずーっとDuty100%ですが)してその値(入力角度、MX2125からのHパルスのカウント値、Hパルスの時間[usec]、mG、実測計算角度)をTVモニタに表示(写真参照)しています。
MX2125の処理もメインのCogでやっているので指定した角度になったらそこでモータ制御は終了して又PSTからの角度入力を待ちます。
モータ駆動方法を変えようかと思ったけど、モータ自身かギヤのせいかモータが動かなくなることがあるのでこれでやっても効果がよくわからないのでこれはここまで。 motor_controll.spinの表示角度はいいかげんです。2125.spinではもう少し正確に表示していますが、やっぱり60度〜90度は使えません。

motor_controll
ドアミラーモーター

Propellerのアセンブラ(2010.1.5)

今までアセンブラコードを斜め読みしていたけれどちゃんと理解しないといけないと思い、FullDuplexSerialPlus.spin(ver1.3)をテキストにして読んでみました。
アセンブラ部分を抜き出して備忘録とします。

cognew(@entry, @rx_head)でcogにアセンブラコードのエントリアドレスentryと変数の先頭アドレスrx_headを与えている。
定数,変数の先頭に付いてる#は即値データを表現しており、#transmitはラベルtransmitのアドレスそしてtxcodeは変数に保存されている数値を表現している。
receiveはグローバルアドレス:bitはローカルアドレスを表している。同じ名前のグローバルアドレスはアセンブラコード内で1箇所のみだがローカルアドレスはそのグローバルアドレス範囲内で1箇所となっているので異なるグローバルアドレス範囲では同じ名前のローカルアドレスがある。

アセンブラで参照する定数・変数
CON
	BUFFER_LENGTH = 128
	BUFFER_MASK = BUFFER_LENGTH - 1
VAR
	long	rx_head		rxバッファの先頭ポインタ
	long	rx_tail		rxバッファの最後尾ポインタ
	long	tx_head		txバッファの先頭ポインタ
	long	tx_tail		txバッファの最後尾ポインタ
	long	rx_pin		rxピン番号が保存
	long	tx_pin		txピン番号が保存
	long	rxtx_mode	モード設定が保存
	long	bit_ticks	ボーレートの1ビットのクロック数
	long	buffer_ptr	rx_bufferバッファの先頭ポインタ
	
	byte	rx_buffer[BUFFER_LENGTH]
	byte	tx_buffer[BUFFER_LENGTH]	
初期設定
entry			mov	t1,par			parから変数の先頭アドレスrx_headをt1にコピー
			add	t1,#4 << 2		t1に16(4を2ビット左シフト)を加算
			rdlong	t2,t1			アドレスrx_pinの内容をt2にコピー(long変数)
			mov	rxmask,#1		領域rxmaskに1を代入
			shl	rxmask,t2		rxmaskの内容をt2の数だけ左シフト(rx_pinのビット位置に1を立てる)
			add	t1,#4			t1に4をを加算
			rdlong	t2,t1			アドレスtx_pinの内容をt2にコピー(long変数)
			mov	txmask,#1		領域txmaskに1を代入
			shl	txmask,t2		txmaskの内容をt2の数だけ左シフト(tx_pinのビット位置に1を立てる)
			add	t1,#4			t1に4をを加算
			rdlong	rxtxmode,t1		アドレスrxtx_modeの内容を領域rxtxmodeにコピー(long変数)
			add	t1,#4			t1に4をを加算
			rdlong	bitticks,t1		アドレスbit_ticksの内容を領域bitticksにコピー(long変数)
			add	t1,#4			t1に4をを加算
			rdlong	rxbuff,t1		アドレスbuffer_ptrの内容を領域rxbuffにコピー(long変数)
			mov	txbuff,rxbuff		領域rxbuffの内容を領域txbuffにコピー(long変数)
			add	txbuff,#BUFFER_LENGTH	txbuffに128(BUFFER_LENGTH)を加算
			
			test	rxtxmode,#%100 wz	領域rxtxmodeと%100のAND演算をする。Zフラグのみ変化(Z=1ならtxは出力  Z=0ならtxがopen drain)
			test	rxtxmode,#%010 wc	領域rxtxmodeと%010のAND演算をする。Cフラグのみ変化(C=1ならtxはL-active  C=0ならH-active)
	if_z_ne_c	or 	outa,txmask		Z<>CならレジスタoutaにtxmaskのビットをORする(txラインの無信号状態)
	if_z		or	dira,txmask		Z=1ならレジスタdiraにtxmaskのビットをORする(出力設定)
			mov	txcode,#transmit	領域txcodeにグローバルラベルtransmitのアドレスをコピー

tx,rxなどのデータを各領域にコピーして、モード設定によってtxのピンを設定、bit0が1なら受信データ反転、bit1が1なら送信データ反転、bit2が1ならtxをopen drainにしている

データ受信
receive			jmpret	rxcode,txcode		rxcodeにPC+1のアドレスを保存してtxcodeに保存されてるアドレスへジャンプ
			test	rxtxmode,#%001 wz	rxtxmodeと%001のAND演算をする。Zフラグのみ変化(Z=1ならrxはH-active  Z=0ならL-active)
			test	rxmask,ina wc		レジスタinaの内容とrxmaskのAND演算をする。Cフラグのみ変化(C=1ならrx=1  C=0ならrx=0)
	if_z_eq_c	jmp	#receive		Z=Cならグローバルアドレスreceiveへジャンプ
								start bitを待つ
			mov	rxbits,#9		RXビットカウンタrxbitsに9を代入
			mov	rxcnt,bitticks		rxcntにbitticksをコピー
			shr	rxcnt,#1		rxcntを半分
			add	rxcnt,cnt		rxcntに現在のcntを加算
:bit			add	rxcnt,bitticks		rxcntにbitticksを加算(初回のみ(3/2)ビット待つ あとは1ビット待つ)
:wait			jmpret	rxcode,txcode		rxcodeにPC+1のアドレスを保存してtxcodeに保存されてるアドレスへジャンプ
			mov	t1,rxcnt		t1にrxcntをコピー
			sub	ti,cnt			t1から現在のcntを減算
			cmps	t1,#0 wc		t1と0を比較
	if_nc		jmp	#:wait			t1>0ならローカルアドレスwaitへジャンプ
			test	rxmask,ina		レジスタinaの内容とrxmaskのAND演算をする。Cフラグのみ変化(C=1ならrx=1  C=0ならrx=0)
			rcr	rxdata,#1		受信データrxdataを右回転(Cを含む)
			djnz	rxbits,#:bit		rxbitsを-1 ゼロでなければローカルアドレスbitへジャンプ(ループ終了時8ビットデータ+ストップビット)
			shr	rxdata,#32-9		rxbitsを(32-9)ビット右シフト
			and	rxtxmode,#$FF		rxtxmodeと$FFのAND演算をする。
			test	rxtxmode,#%001,wz	rxtxmodeと%001のAND演算をする。Zフラグのみ変化
	if_nz		xor	rxdata,#$FF		Z=0なら(rxビット反転)なので$FFとxorする
			rdlong	t2,par			parからアドレスrx_headをt2にコピーする
			add	t2,rxbuff		t2にrxbuffを加算
			wrbyte	rxdata,t2		受信データrxdataをt2のアドレスにバイト書き込み
			sub	t2,rxbuff		t2からrxbuffを減算
			add	t2,#1			t2に1を加算
			and	t2,#BUFFER_MASK		t2とBUFFER_MASKのAND演算をする。
			wrlong	t2,par			parにt2を書き込み(次の受信データ保存ポインタ)
			jmp	#receive		グローバルアドレスreceiveへジャンプ

データ送信
transmit		jmpret	txcode,rxcode		txcodeにPC+1のアドレスを保存してrxcodeに保存されてるアドレスへジャンプ
			mov	t1,par			parからアドレスrx_headをt1にコピーする
			add	t1,#2 << 2		t1に8(2を2ビット左シフト)を加算
			rdlong	t2,t1			アドレスtx_headの内容をt2にコピー
			add	t1,#1 << 2		t1に4(1を2ビット左シフト)を加算
			rdlong	t3,t1			アドレスtx_tailの内容をt3にコピー
			cmp	t2,t3 wz		t2とt3を比較
	if_z		jmp	#transmit		Z=1ならグローバルアドレスtransmitへジャンプ
			add	t3,txbuff		t3にtxbuffを加算
			rdbyte	txdata,t3		t3の内容を送信データtxdataにバイト読み出し
			sub	t3,txbuff		t3からtxbuffを減算
			add	t3,#1			t3に1を加算
			and	t3,#BUFFER_MASK		t3とBUFFER_MASKのAND演算をする。
			wrlong	t3,t1			t3にt1を書き込み(次の送信データ保存ポインタ)
			or	txdata,#$100		送信データtxdataに$100をORする(stop bit付加)
			shl	txdata,#2		txdataを2ビット左シフト
			or	txdata,#1		txdataに1をORする(txの無信号状態)
			mov	txbits,#11		txビットカウンタtxbitsに11を代入
			mov	txcnt,cnt		txcntに現在のcntを代入
:bit			test	rxtxmode,#%100 wz	rxtxmodeと%100のAND演算をする。Zフラグのみ変化(Z=1ならtxは出力  Z=0ならtxがopen drain)
			test	rxtxmode,#%010 wc	rxtxmodeと%010のAND演算をする。Cフラグのみ変化(C=1ならtxはL-active  C=0ならH-active)
	if_z_and_c	xor	txdata,#1		Z=C=1ならtxdataと1をXORする(bit0のみ反転)
			shr	txdata,#1 wc		txdataを1ビット右シフト(C=1ならtxはH-active C=0ならL-active)
	if_z		muxc	outa,txmask		Z=1(txは出力)ならtxmaskのtxビットがCの状態(1 or 0)となるようレジスタoutaがセットされる
	if_nz		muxnc	dira,txmask		Z=0(txはopen drain)ならtxmaskのtxビットがCの反転状態(!1 or !0)となるようレジスタdiraがセットされる
			add	txcnt,bitticks		txcntにbitticksを加算
:wait			jmpret	txcode,rxcode		rxcodeにPC+1のアドレスを保存してtxcodeに保存されてるアドレスへジャンプ
			mov	t1,txcnt		t1にtxcntをコピー
			sub	t1,cnt			t1からcntを減算
			cmps	t1,#0 wc		ti>0をチェック		
	if_nc		jmp	#:wait			ti>0ならローカルアドレスwaitへジャンプ
			djnz	txbits,#:bit		txbitsを-1 ゼロでなければローカルアドレスbitへジャンプ
			jmp	#transmit		グローバルアドレスtransmitへジャンプ

受信データ待ち時に送信データチェックを行い、同様に送信データ待ち時に受信データチェックを行うことによって全2重通信を実行している。


Propellerの電波時計(2010.1.31)

ONKYOチューナーT-405FXに付属品の電波時計モジュールをPropellerにつないでLCDに時間を表示しています。 電波時計モジュールの信号ケーブルは8極4芯のモジュラーで信号デコードチップはNPCのSM9501Aでした。電波時計モジュールの電源供給に5Vを入れたら内部で3.3VにしてSM9501Aに供給されます。
又SM9501Aの出力はL-activeですが電波時計モジュール自体の出力はオープンコレクタでモジュールとしてはH-activeとなっています。
切替え信号は0Vで40kHz固定にしています。(3.3V:60kHz)
電波時計モジュールの出力を3.3VでプルアップすればPropellerデモボードのP0に直結できますが付属のコードで接続すると信号の立上りで波形がなまるのでトランジスタを1個追加してL-activeとなっています。

プログラムはCog0〜Cog4の5個使用しています。電波時計モジュールからの信号がなくても時間を表示できるようにCog2がPropClockとして動作しています。

  • Cog0:メインプログラム(信号デコード)ONKYO_Clock.spin
  • Cog1:シリアル通信
  • Cog2:PropClockとLCD表示
  • Cog3:電波時計の信号モニタリング
  • Cog4:電波時計とPropellerClockの偏差測定

Cog0
標準電波の出し方のとおりにP0に入ってくる信号をデコードして、受信に成功するとP18にHighパルスを出力します。
信号パルスがactiveの間P16のLEDが点灯します。
Cog1
PSTにCog0のデータをおくります。
Cog2
Cog0から受信データを受け取ってLCDに表示して時計動作をします。又55秒の時にP20にHighパルスを出力します。
Cog3
電波時計モジュールの信号をモニタしてケーブルが抜けたり全く信号が受信できない時にLCDに"Lost"を表示します。(P0の信号が1秒以上High又はLowの場合)
又信号のパルス幅を測定して有効パルスをカウントして過去60秒間の有効パルスのパーセント表示をします。
Cog4
P20のHighパルスからP18のHighパルスまでのクロック数と5秒間のクロック数を比較してPropClockが電波時計に対して遅れているか(マイナス表示)
進んでいるか(プラス表示)表示します。

電波時計の信号を受信すると大体PropClockが遅れています(-70ms〜-80msほど)、Cog4をアセンブラで書いても同じぐらいなので電波信号のデータを
Cog2:PropClockが受け取ってセットするまでにSPIN言語が必要とする時間ではないかと思われます。
(よく考えたら電波時計とPropClockとの偏差はわかっているのでこのカウント値で時間の補正ができるなあと思います、修正は次回)
電波時計の時刻に同期させてからケーブルを外してPropClockだけで動作させて次にケーブルをつけて(大体12時間)電波時計に同期させると2.2secほど進んでいました。計算するとPropClockの1秒が55usecほど短いのでProp_Drive_Clock.spinでdT:=clkfreq+4488と補正しています。(上記のPropClockの遅れを修正せずに行っているので正確ではありません)
ただ、これはクリスタルの温度特性や周囲環境に左右されるので正確にするにはボード全体を恒温ケースに入れて個別に補正値を加えた方がいいです。

ONKYO_Clock
信号Lost状態
電波時計モジュール(左端子から40kHz/60kHz切替え,OUT,Gnd,+5V)

このプログラム作成中にeepromにロードしてUSBケーブルを外したら動作しませんでした。(FullDuplexSerialPlus.spinがないと問題がでない)PropellerのForumで質問したら以前にも取り上げられていた問題で詳細はこちらを読んでください。
ざっくり簡単に言うとPropellerチップとFT232との相性みたいなもの。ホントはPropellerチップとFT232の間にバッファをいれればよかったんだけど直結してるのでUSBケーブルをつながないと稀に(Forumでも珍しいらしい)すぐリセットされるボードがあるようです。こちらにあるボードは3枚とも相性が悪い。(2枚はPropPlugでつなぐタイプ)
対処はPropellerチップとFT232の間の信号線にプルアップ抵抗をつけるかバッファを入れる、通信コマンドをコメントアウト、PropPlugを使うタイプはPropPlugを外すなどありますがそれができない場合は、常時PCと接続しない用途ではP30/P31はプログラミング用と割り切る。


Stepping Motor(2010.2.19)

日本橋のデジットでバイポーラタイプのステッピングモータTS3166N913(¥250)を購入したので、The Spin ZoneからStepping Out with Spinをダウンロードしてこれを参考にしてステッピングモータのテストプログラムを作りました。

TS3166N913ピン接続

Connection Color
A Sense + Gray
A Sense - Violet
A Power + White
/A Power - Red
B Power + Blue
/B Power - Yellow
B Sense - Orange
B Sense + Black

定格電圧(V) 定格電流(A) コイル抵抗(オーム) センス抵抗(オーム) 基本ステップ角度(°) 使用温度範囲(℃)
DC 12 DC 0.75 4.3 +-10% 0.5〜5.0 0.9 0 - 65

回転角度(度)=ステップ角[°] X パルス数
回転速度[r/min]=(ステップ角[°]/360[°]) X パルス周波数[Hz] X 60[sec]

回転速度RPM[r/min]を入力値とした場合(ステップ角[°]=0.9)
パルス周波数f[Hz]=RPM/0.15
パルス時間 T[sec]=0.15/RPM

A SenseとB Sense出力はモータ電圧12V印加で1000rpmの時に3.45+-0.69Vp-pのACサイン波が出力されます。これをDC変換するかACサイン波のゼロクロスのタイミングが測定できれば回転数も知ることができそうですが、 今回はこれは使わずフォトインタラプタを使用し、又モータ電圧も5Vを使用しています。
参考にしたStepping Out with Spinではモータを回すパルス生成の最小単位を1msecとしていましたがもっと短くしようと思いtest_loop.spinをTopObjectにしてstepper.spinのdt:=clkfreq/1000の1000を大きくしていくと8803でモータが回転しなくなりました。
プログラムが止まったわけではなく、モータを回すパルス生成ループでパルス出力を実行したあとwaitcnt(c+=dt)のところでシステムカウンタがその数値(c+=dt)をオーバしていた為システムカウンタがまた一巡(およそ53秒後)するのをまっているのでプログラムが止まっているようにみえます。
(これはPropeller Official Guide Bookの"Code that Missed the Waitcnt Boat"[page68]で詳細が書かれています)
このループがまわり続けるには113.6usecほど必要としています。(やっぱりspinは遅い)
プログラムの作成上ループ時間を200usecとしました。

最初Full Step Modeで動作させていたのでちょっとおかしなことがありました。
フォトインタラプタ出力のHとLの時間をカウントしていたのですがどういうわけか低速回転時(大体10rpm以下)にカウント値が小さすぎたり、 パルス切替え時間3.6ms(〜277Hz)の時だけCWで回るはずなのにCCWで回ることもある(2歩進んで1歩戻るような・・・)
フォトインタラプタ出力のミスカウントの原因はフォトインタラプタをモータに取り付けているので低速時にその振動を受けて素子自体も一緒に振動していたせいでした。また、特定の回転数でおかしな動作をするのはモータ固有の共振現象が原因だったので、 この両方を解決するにはHalf Step Modeで動作させる必要があります。
Full Step Modeではこの2相ステッピングモータを1ステップ回すのに4回パルスを出力しますがHalf Step Modeは8回パルスを出力します。従ってより滑らかな動作をすることになり振動が減り共振現象も改善できます。

Half Step ModeにするとFull Step Modeと同じ回転数にするにはパルス周波数を2倍にします。
Half Step Modeだと1200Hz、Full Step Modeだと2500Hzぐらいで脱調が起こりました。

stepper_control_with_TV.spinをPropellerにロードしたらロータリーエンコーダを右に回すとモーターが右に回り始め、さらに回すと回転が上がり左に回すと回転が下がりゼロになります。さらに左に回すとモーターは左回りで回転数が増えていきます。
TV画面の左端の数字が1回転の時間(計算値/実測値)です。実測値が計算値と同じにならないのはstepper.spinのループ最小値が200usecに起因します。

StepMotor

モータ電源を12Vに変更して動作させてみてモータB相に直列に2オーム(5W)を入れて電流を測ってみたら1.2Aほどありました。モータの温度が安定したらもっと減るのかもしれないけれどモータ電圧12VではTA7291Pはかなり熱くなるので放熱板が必要かも。又360Hzあたりで共振現象が再発したのでMicro Step Modeを試してみないといけないようです。 脱調の周波数もかなり上がるようですが、Spinだと113usecが上限なのでアセンブラで作る必要がありそうです。これは次回。

JoyStick(2010.2.25)

物置で10年以上前に買ったサイドワインダーとかいう名前のシューティングゲーム用のJoyStick見付けたのでPropellerで使えるように配線変えてみた。
ボタン6個のOn/OffとUP/DOWN,LEFT/RIGHTの可変抵抗器2個のカウント値を表示している。可変抵抗器のカウント値は何も加工していないので下2桁が変動しています。又オブジェクトMeasureTime.spinのlong[resultAddr]:=(phsa-588)#>0を調整していません。実際の使用ではチップ毎/使用ポート毎に調整する必要があります。 The Spin ZoneからLCDs & Thingsのjm_debounce.spinを使わせてもらってます。

Stick_Button_demo

8x8 LED-Matrix(2010.3.1)

Arduinoを扱っているGalileo7さんを見てたらキャラクタをLED-Matrixで横方向に1ドットずつ移動して表示させている動画をみたのでPropellerで真似してみました。PropellerはROMにキャラクタフォントを持っているのでそれを利用しました。
LED-Matrixはデジットで1個100円で買ってきました。
16x32ピクセルのキャラクタを8x8ピクセルに変換しているのでちょっと変な表示もあります。
最初は縦横の両方向に動かそうと思ったけれど面倒なので縦だけにしました。0.1秒で1ドット動かしてるので256キャラクタ全部を表示するのに3分50秒かかってます。
別のCogでLED-Matrixをダイナミックドライブしていますが2つのCogが同じメモリにアクセスしているのでmemory collisionが起こっているはずですがダイナミックドライブが速いので人間の目には見えません。なので対処はしていません。
対処方法はPropeller Official Guide Bookの"Debugging Tools Applied to a Multiprosessing Problem"(page86〜)にlockの使い方など載っています。

8x8_Matrix

波形生成(2010.3.11)

カウンターモードでD/A変換してのこぎり波、矩形波、サイン波を1Hz〜500Hzの範囲で生成しました。PropellerはROMにサインデータ(0度〜90度)を持っているのでそれを利用しています。
一方のエンコーダで波形の種類を選択して別のエンコーダで周波数を可変します。初期値は250Hzです。矩形波、サイン波はP0出力に1kオームと0.1u(103)の積分回路を追加しています。
波形の写真は3種類とも250Hzです。

今回サイン波生成プログラム(sin_wave.spin)のアセンブラのデバッグにPropeller Official Guide Bookに載っているフリーの"DEVELOPMENT WITH PROPELLER ASSEMBLY DEBBUGGER"(page100〜)のデバッガ(PASD)を使ってみました。CogRAM、MainRAMの内容確認や変更もできるしステップ実行、ブレークポイント設定などデバッガとしての必要な機能は揃っています。 PASD (Debugger) ProjektからPASD_05.zip(version0.5)をダウンロードして解凍します。(ドイツのサイトですがマニュアルなどは英語です)
PASD_05.zipを解凍したらPASD05フォルダに以下のファイルが作られます。

asmsource                 PASD_AsmDebugDemoと同じ
PASD                       デバッガ本体
PASD User's Manual     PASDマニュアル
PASD_AsmDebugDemo  デバッグ用サンプルプログラム
PasDebug                  デバッグ用サンプルプログラムが参照するオブジェクト

デバッガの使い方
PASD_AsmDebugDemoをトップオブジェクトにしてPropellerのRAMにロードしてからPASDを起動します。
(PASDはPASD_AsmDebugDemoと同一フォルダにある必要があります)
PASDのCOMメニューから"Com port"でPropellerと通信しているポート番号の設定をします。
Fileメニューから"Get Asm code"を選択したらPASDウインドーにアセンブラリストとアドレスとコードが表示されます。
Debugメニューから"COG RAM Viewer"を選択したらCOG RAMウインドー、"Main RAM Viewer"を選択したらMain RAMウインドーが表示されます。
COG RAMウインドーにはアドレス、値(Hex,Deciaml)、ラベルが表示されているので変更したいRAMのアドレスをクリックしたら下のボックスでクリックして"=$2ff"又は"=345"のように入力したら変更できます。
Debugメニューから"Step"又はF8キーでステップ実行できてCOG RAM、Main RAMの表示が変化していきます。

WAVE

PropellerでBASIC(2010.3.16)

PropBASICの専用ページをつくりました。BASICに興味のある場合はこちら

SpinZone(2010.4.9)

  • SIRCS, Propeller Style!
  • BASIC Propeller Programming
  • Object of the Machine
  • Spin Baby Spin
  • PropellerでForth(2010.8.3)

    PropForthの専用ページをつくりました。Forthに興味のある場合はこちら

    Hydraの本(2010.9.4)

    TVオブジェクトとかで使ってるTILEとか表示プログラムがどうしてもわからないのでHydraの本を買った。読んでみると内容の濃さと分厚さに圧倒された。理解するにはかなり時間がかかりそう。センスのある人なら一度読めば理解できるのだろうけど自分はセンスがないので何度も何度も読んでやっとなあんとなあくうっすらわかるようになるので大変だ。でもPropellerを理解したいなら1冊もっておいて損はない。ただひとつ不満があるのは「装丁が悪すぎる」ことだ。この本ホントに結構重いし紙質もあんまりよくないので雑に扱うとページを糊付けしてる背表紙からページが抜け落ちそうだ(大事に扱ってもいずれそうなる気がする)