どうも部長のKです。
私レスキューロボットのシステム・回路担当しておりますが、今回はkondoのシリアルサーボを使うことになりました。今までRCサーボしか使っていなかったところに初めて導入するのでいろいろと手こずっていました;; # 馬鹿
その都度書けば良かったんですけど、結構更新するのがめんどくさくて(おい
ここに順序を列挙します。
** ちなみにPIC18F23K22使ってます。私のオキニは16F1827なんですけどね! 前の大会の基板に刺しっぱなしなんで仕方なくこれ使ってます。16Fのエンハンスメントと18Fはほとんど変わらないので問題は何も無い……むしろ使いやすくていいんですけどね。尚、18F14K50は糞使いづらい模様……
(1) しりあるさーぼ? 結構PWM出力するのって負担かかるんで、これはありがたい。
だって1500μs基準で10bit精度必要とすると、約1000段階。即ち500-1500-2500として幅2000μsだから1段階で2μsですよ。これは1/2us = 500kHzで動かす必要があると言うことです。
PICで、4MHzで動かしていたとしたら命令は1MHzで、余裕が……2回に1回!!
つまりもっとFoscを高くしないといけないと言うことです。
# PWMを1つのPICで8ポート出力する方法はいろいろありますが、例えばタイマーの値を順次比較して、ON/OFFを切り替えるようなものにすると、その比較の際にかかる時間がタイマーの1カウントあたりの時間より短くないといけないんです。
(2) どうやらkondoサーボはICSという「独自」の通信方式を使っているらしい。まじかよ、シリアル通信ではあるが独自……なんだって3品で送受信しているのか! これは1-wireみたいな通信なのか? ということはソフトウェアで実装しないといけないと言うことか;; 厳しいな。しかも通信速度が最低で100kbps越え!? なかなか厳しい道になるな。
ググってもICSのタイミングチャートが出てこない。仕様書には通信の方式とか、データのレベルとか、そういうことが書いていなくて、コマンドの送りかたしか書いていない!
これで一体どうやって通信しろと言うんでしょう?
(3) いろいろ調べていくうちに、どうやらUARTで送受信すれば言いそうだと分かった。回路図にはTXとRXがつながっていてプルアップされている。うーん、普通のUARTではない……むしろIC2だと踏んでいたが、サンプルソースも何もかもUARTっぽい記述であるのだ。
試しにPICで送信。あれ? 動かない……。どうして? なんで?
(4) 悩んで寝て、悩んで寝て、ある日突然気づくものです。 あ、パリティ忘れてた。
UARTでパリティなんて使ったことがありませんでした。PICではどうやらソフトウェアで計算しなくてはならないみたいで、暫定的に次の計算で導きましたが、もっと効率のいい方法があるはずなので後で変更しておきます。
void sendByte(char data){
char parity = 0, sending_data;
while(!TXIF);
sending_data = data;
parity ^= data & 0x01;
data >>= 1;
parity ^= data & 0x01;
data >>= 1;
parity ^= data & 0x01;
data >>= 1;
parity ^= data & 0x01;
data >>= 1;
parity ^= data & 0x01;
data >>= 1;
parity ^= data & 0x01;
data >>= 1;
parity ^= data & 0x01;
data >>= 1;
parity ^= data;
TXSTA1 &= ~0x01;
TXSTA1 |= parity;
TX1REG = sending_data;
}
[参考] ビットの数を数える : 、
http://marupeke296.com/TIPS_No17_Bit.html
また後で効率のいい方法に変えておきます。
ところでこのコンパイル結果は次のようでした。XC8のlight版です。
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
movf ((c:sendByte@data)),c,w
xorwf ((c:sendByte@parity)),c
bcf (0+(0/8)+(c:4012)),c,(0)&7 ;volatile
movf ((c:sendByte@parity)),c,w
iorwf ((c:4012)),c ;volatile
return
(41命令)
parity ^= data & 0x01;
data >>= 1;
は
movf ((c:sendByte@data)),c,w
andlw low(01h)
xorwf ((c:sendByte@parity)),c
bcf status,0
rrcf ((c:sendByte@data)),c
となっていることが分かりますね。
movfでdataをWレジスタに入れて、andlwで&0x01してxorwfでparityと排他的論理和して、bcfでstatusの0bit目をクリアして、rrcfでローテ!
RRCFでローテ!!
なんでや! これキャリー付きの右へのローテーション.つまり、直前の
bcf status,0
が意味するところは、このローテーションだとキャリーとして1bit目が8bit目に写されてしまうことを嫌ってのキャリーフラグクリア!
18F23K20にはRRNCFという命令があって、キャリーフラグ無視したローテーと、即ちシフト演算が出来るんです。 # というか一般的なCPUではローテーとよりもシフト演算の方が一般的だと思うんですけど……
それをわざわざ2命令で実現するなんてなんていう無駄!
ところで4時間くらい格闘していたのは TXSTA1 &= ~0x01;を忘れていたからです。TX9Dは勝手にクリアされるわけではありませんでした;;
つまり、今まで動かなかった原因は私のPIC理解不足によるものでした;;勉強します!
** 今後の展望 **
・受信はまだできていないのでそれを実装
・TPIPからデータを受信して、IC2で各基板に伝達
・そこからPWM/シリアルデータを出力
これらの基板を作る。
他の皆さんは……勉強に追われていました! あとがれき除去機の配線部分をばらしたりしてました。後で設定のし直しが必要ですね; 電源基板の作り直しも必要ですね。今回の機体には7.2Vと11Vが混合しますがスイッチをどうしようか迷います。スイッチに電流を直接流し込むのが簡単でいいんですけど、どうなんでしょう?
電源の制御は必要な感じがしてきているので(だって今あるNi-MHばってりーは容量少ないからこれを効率よく割り振らないといけないんですよねー)、結構大変ですね。