マイコンとのRS232C通信
方法は元の16軸多軸ラジコンサーボのソフトに パソコンからパルス長に関わる数値を送ってやるだけという案外簡単なものです。肝は送受信方法だけでしょう。
それもハイパーターミナルなら以前やったように簡単にやりとりはできます。
受け取ったパルス長数値を配列に入れてやるだけ、という簡単なものです。
一度に1軸だけ動かせる程度のものをつくってみました。でも、続けて入力すると全部の軸を動かせます。実用というよりも確認用に作ってみるといった感じです。
実用にするにはやはりPC側でちゃんとソフトを作ることになるでしょう。(もし動かす基本がわからない人がいれば、この簡易的なプログラムを足がかりに)
単なるテスト用ということで、ここでは一度に1軸だけ動かす数値をハイパーターミナルから送ることにします。
送信は簡易的にハイパーターミナルから 文字列として送信
- ラジコンサーボの配列番号 0~15
- パルス長 25未満
を送り
H8-3664F で文字列受信関数で受け、加工して放り込むだけというものです。
このプログラムは 上記HPのSISOさんが作成されたもので、同様のことを手がけているときに偶然出会い、SISOさんの厚意により当HPで公開許可いただけたものです。
内容はよくわからないが実用に改良したい等、一番問い合わせが多いのがここの多軸RCサーボ制御のところですが、これは多軸RCサーボ制御方法の1つとして加えました。sisoさんのソースもきれいに簡潔に書かれていて、下に説明も加えましたので処理内容を理解し発展させる種として活用してください。
回路図
SISOさん作成のものと同様、以下各ポートにパルスが出力されます。
awServoPos[0] P14 | awServoPos[1] P15 | awServoPos[2] P16 | awServoPos[3] P17 |
awServoPos[4] P50 | awServoPos[5] P51 | awServoPos[6] P52 | awServoPos[7] P53 |
awServoPos[8] P80 | awServoPos[9] P81 | awServoPos[10] P82 | awServoPos[11] P83 |
awServoPos[12]P84 | awServoPos[13]P85 | awServoPos[14] P86 | awServoPos[15] P87 |
プログラム
SISO_sarvos10ms_PC
#include <3664.h>
#define TIMERW_10MSEC 45535 // 10msec待つためのタイマW初期値
#define TIMERW_2M5SEC 60535 // 2.5msec待つためのタイマW初期値
_BYTE bStep; // サーボ制御ステップ
_WORD awServoPos[16]; // サーボ制御位置
unsigned char txb[10], rxb[10] ;
char b[20]; //通信用
//
// タイマW割り込みルーチン
//
void int_timerw( void )
{
_BYTE bSrvA, bSrvB, bSrvC, bSrvD; // サーボ制御信号ON作業用
if( TW.TSRW.BIT.OVF == 1 ){ // オーバーフロー発生
// オーバーフロー発生時の処理
TW.TSRW.BIT.OVF = 0; // オーバーフローフラグクリア
TW.TMRW.BIT.CTS = 0; // タイマストップ(他のビットはデフォルト)
TW.TCNT = TIMERW_2M5SEC; // 2.5msec後にOVFする値設定
// GRレジスタへの制御信号OFF時間の設定
TW.GRA = TIMERW_2M5SEC + awServoPos[(bStep-1)+0];
TW.GRB = TIMERW_2M5SEC + awServoPos[(bStep-1)+4];
TW.GRC = TIMERW_2M5SEC + awServoPos[(bStep-1)+8];
TW.GRD = TIMERW_2M5SEC + awServoPos[(bStep-1)+12];
bSrvA = 1 << (( bStep-1 )+4 ); // 元ネタの計算
bSrvB = 1 << (( bStep-1 )); // 元ネタの計算
bSrvC = 1 << (( bStep-1 )); // 元ネタの計算
bSrvD = 1 << (( bStep-1 )+4 ); // 元ネタの計算
IO.PDR1.BYTE |= bSrvA; // 信号ON!!
IO.PDR5.BYTE |= bSrvB; // 信号ON!!
IO.PDR8.BYTE |= bSrvC; // 信号ON!!
IO.PDR8.BYTE |= bSrvD; // 信号ON!!
// ステップ情報の操作
// 1~4:サーボ制御信号出力なので、5になっていたら
// 数値を0に戻す。
bStep++;
if( bStep == 5 ){
bStep = 1;
}
TW.TMRW.BIT.CTS = 1; // タイマスタート
}
if(TW.TSRW.BIT.IMFA == 1){ // GRA コンペアマッチ
// GRAコンペアマッチ発生時の処理
IO.PDR1.BYTE &= 0x0F;
TW.TSRW.BIT.IMFA = 0; // 割り込みフラグクリア
}
if(TW.TSRW.BIT.IMFB == 1){ // GRB コンペアマッチ
// GRBコンペアマッチ発生時の処理
IO.PDR5.BYTE &= 0xF0;
TW.TSRW.BIT.IMFB = 0; // 割り込みフラグクリア
}
if(TW.TSRW.BIT.IMFC == 1){ // GRC コンペアマッチ
// GRCコンペアマッチ発生時の処理
IO.PDR8.BYTE &= 0xF0;
TW.TSRW.BIT.IMFC = 0; // 割り込みフラグクリア
}
if(TW.TSRW.BIT.IMFD == 1){ // GRD コンペアマッチ
// GRDコンペアマッチ発生時の処理
IO.PDR8.BYTE &= 0x0F;
TW.TSRW.BIT.IMFD = 0; // 割り込みフラグクリア
}
}
int main()
{
unsigned char SavNo ,Pls_w;
//
// 初期化
//
//通信用初期化
SCI3_INIT(br38400, txb, sizeof(txb), rxb, sizeof(rxb));
// タイマモードレジスタ
TW.TMRW.BIT.CTS = 0; // タイマストップ(他のビットはデフォルト)
// タイマコントロールレジスタ
TW.TCRW.BIT.CKS = 3; // クロックセレクト
// 内部クロックをΦ8でカウントアップ
// タイマインタラプトイネーブルレジスタ
TW.TIERW.BIT.OVIE = 1; // オーバーフロー割り込み有効
TW.TIERW.BIT.IMIEA = 1; // GRA割り込み有効
TW.TIERW.BIT.IMIEB = 1; // GRB割り込み有効
TW.TIERW.BIT.IMIEC = 1; // GRC割り込み有効
TW.TIERW.BIT.IMIED = 1; // GRD割り込み有効
IO.PCR1 = 0xF0; // ポート1のP14-17を出力設定
IO.PCR5 = 0x0F; // ポート5のP50-53を出力設定
IO.PCR8 = 0xFF; // ポート8は全部出力設定
bStep = 1; // ステップを0に初期化
// データの初期化
awServoPos[0] = 3000; // 1.5msec P14
awServoPos[1] = 3200; // 1.6msec P15
awServoPos[2] = 3400; // 1.7msec P16
awServoPos[3] = 3600; // 1.8msec P17
awServoPos[4] = 3800; // 1.9msec P50
awServoPos[5] = 4000; // 2.0msec P51
awServoPos[6] = 3000; // 1.5msec P52
awServoPos[7] = 3200; // 1.6msec P53
awServoPos[8] = 3400; // 1.7msec P80
awServoPos[9] = 3600; // 1.8msec P81
awServoPos[10] = 3800; // 1.9msec P82
awServoPos[11] = 4000; // 2.0msec P83
awServoPos[12] = 3000; // 1.5msec P84
awServoPos[13] = 3200; // 1.6msec P85
awServoPos[14] = 3400; // 1.7msec P86
awServoPos[15] = 3600; // 1.8msec P87
EI; // 割り込み許可
TW.TCNT = TIMERW_2M5SEC;// タイマカウンタに2.5msec後にOVFする値設定
TW.TMRW.BIT.CTS = 1; // タイマスタート
//文字列送信→PC
//送信文字は 2桁_2桁
SCI3_OUT_STRING ("\nサーボNo(2桁) スペース パルス長(2桁)入力\n");//文字列送信関数
while( 1 ){
// せっかくなのでパソコンからキーボード入力でサーボを
// 動かすプログラムを書いてみましょ。
SCI3_IN_STRING (b, sizeof(b) - 1); //文字列受信関数
SCI3_PRINTF("[%s]\n",b); //オウム返し表示
//受信文字 10進数へ変換
//サーボ配列No
SavNo = ( b[0]-'0')*10;
SavNo += ( b[1]-'0');
//パルス長
Pls_w = ( b[3]-'0')*10;
Pls_w += ( b[4]-'0');
if(SavNo<16 && Pls_w<25){ //範囲処理
awServoPos[SavNo] = Pls_w*200;
}
}
}
PCとの通信
通信設定などに関しては
パソコンと通信してみる を参考にしてください。
通信速度は main()最初の初期化で
SCI3_INIT(br38400, txb, sizeof(txb), rxb, sizeof(rxb));
ボーレート38400に設定してあります。
ハイパーターミナル側も初期設定時には、この部分の数値に合わせてください。
パルス長を変えるには
このプログラムではラジコンサーボ用のパルス出力は
配列 awServoPos[ 0~15 ] = パルス長×2000
の数値をパルス長時間としてタイマW時間にして、割り込みで毎回読み込んでいます。
ここの配列の数値を変更すると、対応する各ポートからパルスが数値に応じて出力されます。
配列に入れる数値は ここの設定ではパルス長の2000倍です。
ハイパーターミナルでの入力
簡単にするためにパソコンからハイパーターミナルでの数値の入力のカタチは
2桁 | 1桁 | 2桁 |
ラジコンサーボの配列番号(0~15) | スペース | パルス長(25未満) |
としてあります。
- ラジコンサーボの配列番号2桁 0~15
- パルス長は 実際の10倍 2桁 0~24
をスペースで区切り、入力して送ることに。
これを守って
ラジコンサーボの配列番号2桁 に続いて
スペース1つ 続いてパルス長(25未満)2桁
をハイパーターミナルに入力
例)ポート80 のパルスを2.0ms にするなら
awServoPos[8] = 4000; // P80
とすべきなので
08_20 (_はスペースのコト)
のように ハイパーターミナルに入力して送ります。
8のように 1桁でも 08と必ず2桁にします。
3664Fでの受信と加工
文字列として配列b[] に受け取り、そのデータを数値にします。
ハイバーターミナルでの入力のカタチを決めてあるので、データは必ず5桁になるように来ます。(こうすることで受信と加工が簡単になります)
- 最初の2桁の数値が b[0],b[1]に
- ・b[3]にはスペース
- b[4],b[5]にはパルス長の10倍に入力された数値
が1桁(0~9)ずつに分解されて文字列で配列b[]に受け取れます。
その文字列を10進数値に変換 変数SavNo 、Pls_w に入れています。
文字列→10進数値の変換処理もべた書きでやってます。
//受信文字 10進数へ変換
//サーボ配列No
SavNo = ( b[0]-'0')*10;
SavNo += ( b[1]-'0');
//パルス長
Pls_w = ( b[3]-'0')*10;
Pls_w += ( b[4]-'0');
if(SavNo<16 && Pls_w<25){ //範囲処理
awServoPos[SavNo] = Pls_w*200; //ここで受取り加工した数値を配列に入力!
}
これを 配列 awServoPos[] に放り込んでるだけです。。
awServoPos[SavNo] = Pls_w*200;
こんな方法で簡易的にできることになります
その代わり送信側での入力のカタチを守らなければ、入力でチェックは範囲以外なにもしません。
(文字列でなく、数値を直接送ればいいのでは、とも思いますが数値そのものは簡単に送れないので)
実行
ハイパーターミナル
まずはハイパーターミナルを起動します。
そのへんは
パソコンとシリアル通信する を見てください。本元のTekuRobo工作室の説明もみれば、通信の種類など基本的な説明が全部あるのでよくわかると思います。
このプログラムではボーレート38400に設定してあります。
ハイパーターミナル側も初期設定時には、この部分の数値に合わせてください。
3664F
続いて 3664Fを起動させると
このようにでれば正しく接続されています。
ハイパーターミナルに入力
ここで
- ラジコンサーボの配列番号2桁 0~15
- パルス長は msの10倍 2桁 0~24
をスペースで区切り、入力
* 配列番号がどのポートなのかは、上の 回路図のところの表を参照
入 力
ポートP80 のパルス長を 1.2msにしてみます。
ポートP80 は 配列番号8です。
上図の行ように、まず
8 12 と入力しました。
[8 12] と入力がH8から返され表示されます
ポートP80パルス長を測定すると
初期設定のまま 1.7ms
で変化はありません。
8 12の
最初の8がいけないのです。(入力のカタチを守りましょう, 自分でも忘れてました)
目標通り
1.2msの
パルス長になっています。
上図の三番目
11 15 は
ポートP83 を1.5msにする入力です。
* 配列番号がどのポートなのかは、上の 回路図のところの表を参照
確認できるポートは測定してみましたが、正しく変更されました。
- twtter
- google+
- hatena