ホーム

電子工作

腕ロボット

二足歩行ロボット

無線コントローラ

工作機械

電子工作動画

自作ソフト(C言語)

Webページ作成

Javascriptゲーム

FLASHとは!

自学自習のテキスト

その他

 
二足歩行ロボットの電子工作(2010年12月〜)
PWM波形の考え直し(フリーランニングタイマー)2010年12月
 フリーランニング動作でタイマーを使った方がPWM波形を生成しやすいことが分かりました。
 H8の3052のハードウエアマニュアルを読むと自由に読み込み・書き込みが出来る16ビットのタイマーカウンタTCNTがあることがわかりました。
 そのハードウエアマニュアルを読むとタイマーカウンタを0から動作させて好きな時にその値を調べられるフリーランニング動作というものがあることがわかりました。
 それを読んでやってみるとうまくフリーランニング動作を使ったPWM波形を生成することが出来ました。
 まずカウンタのクロックを選びます。このカウンタクロックはシステムクロックφを分周したクロック(φ/2、φ/4、φ/8)から選択できます。

 H8の3052の場合、システムクロックは25MHzなのでカウンタクロックはφ/8を選ぶとΦ/8=25MHz/8=3.125MHz。 1周期は1/3.125MHz。1カウンタごとに1/3.125M秒だけ時間が刻まれることになります。ちょうど3125だけカウンタが過ぎると1Msの時間が 過ぎることになります。

 ハードウエアマニュアルにはこう書いてあります。
 ITU チャネル0〜4 のカウンタ(TCNT)はリセット直後は、すべてフリーランニングカウンタの設定となっており、 TSTR の対応するビットを1 にセットするとフリーランニングカウンタとしてアップカウント動作を開始します。 TCNT がオーバフロー(H'FFFF→H'0000)するとTSR のOVF フラグが1 にセットされます。 このとき、対応するTIER のOVIE ビットが1 ならば、CPU に割込みを要求します。 TCNT はオーバフロー後、H'0000 から再びアップカウント動作を継続します。
 このポート1のビット0からPWM波形を出力するためのフローチャートをこのようなもので、これに従ったソースコードは下のようになります。
インクルードファイル<3048f.h>で定義されているのですがITU0のタイマーカウンタのレジスタは ITU0.TCNT と記述されています。
1行目に #include <3048f.h> と書いておけばこのレジスタをITU0.TCNTで表すことができます。
先ほど書きましたようにこのレジスタは書換・読込が自由にできるレジスタです。

#include <3048f.h>
/* フリーランニングモードでITU0初期化 *********************/
/* 3125:1ms、4687.5:1.5ms、6250:2ms、62500:20ms***/
void timer0FreeInit(void){
	ITU0.TCR.BYTE = 0x03;	/* TCNTクリア禁止 clock 1/8 */
	ITU.TSTR.BIT.STR0 = 0;	/* カウント停止状態 */
}
/*プログラムの始まり*/
main()
{
	timer0FreeInit();/*ITU0初期化*/		
	P1.DDR = 0xff;	/*PORT1を出力に設定*/ 
	ITU.TSTR.BIT.STR0 = 1;	/* ITU0 TCNTカウント開始 */
	/*無限ループ開始*/
	while(1){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		/*P1のBit0(CN3のピンNo.15)を1にする*/
		P1.DR.BIT.B0 = 1;
		while(ITU0.TCNT<6250) ;/*指定時間だけ待つ*/
		P1.DR.BIT.B0 = 0;/*P1のBit0を0にする*/
		while(ITU0.TCNT < 62500);/*20ms経過するまで待つ*/
	}
}
このソースコードにより生成されたPWM波形はこれです。
3125の待ち時間は1msに当たります。
5V出力し続けている時間を6250にしています。そのあと62500まで待ち時間が0Vです。
すると理論上は2msだけ5Vを出力し、20ms経過するまで0Vが続く ことになります。
確かにその通りの波形が生成されていることがわかります。
回路図の作成(2011年1月)


 サーボが全部で12個あります。これ以外にジャイロセンサ・距離センサ・加速度センサを搭載します。

顔の目・口を光らすためにLEDを3個つけます。

これがそのための回路図です。

回路図にはアース・VCCの線を省いていますので中途半端な感じになっています。

ピッチ軸:前後回転
ロール軸:左右回転
ヨー軸:地面と平行に回転
電子回路組込み(2011年2月)
胸のH8(3052)のCPUと脚・腕等のサーボモータとの中継のためのコネクタを並べた基盤を作り、腰ボックスに入れます。

これがその画像です。

この単3電池4個はサーボモータを駆動させるためのものです。 右の画像はこの基板の裏です。この配線にはすごく苦労しました。





左の図が胸ボックスと腰ボックスを後ろから見たものです。

上の胸ボックスにはH8(3052)を載せた基盤とCPUを駆動させるための9V電池、 下の腰ボックスには中継コネクタの基盤とサーボ駆動電池があります。

顔に小さい基盤をつけ6ピンコネクタで中継して胸のCPUと顔のLED・距離センサとを結んでいます。

胸の基盤から出ているケーブルはサーボモータ・ジャイロセンサ・加速度センサ、顔のLED・距離センサの ためのものです。

サーボモータ・ジャイロセンサ・加速度センサのためのケーブルは腰の基盤の8ピンコネクタにつながり、 さらにそれぞれの3ピンコネクタを中継してつながります。

加速度センサのためのケーブルは腰の基盤の3ピンコネクタを中継してつなげています。
腰の基盤上の小さい基盤が加速度センサです。
この加速度センサの端子(X,Y,Z軸に対応)3つをH8(3052)のAD変換端子につなぎます。 このためのコネクタがその上のX,Y,Zと書いてある3ピンコネクタです。
電子回路組込み完了(2011年2月)
下の画像は配線が完了したものです。
自宅の前で撮影したものです。
右も同じロボットですが、背景の奥行きを見せるために後ろの方まで表示させましたのでロボットのみかけの大きさが小さくなっています。
まだプログラムを入れていませんので動きません。
これから12個のモータをどのように動かせばいいのかを考えてプログラムを組みます。
実際に動き出せば嬉しいです。
PCとマイコンとの通信(2011年3月)
「二足歩行ロボット入門」に書かれているように、PCのVisual Basicでアプリを作って PCからデータをロボットに流してロボットのサーボ位置をきちんとしようとしました。
 本の通りにやったのにPCとロボットとの通信が出来ませんでした。
 本を再度読み返すと229ページのC言語のロボットプログラムの初期化関数の説明中に
「本来ならここにシリアル・コミュニケーション ・インタフェース機能の初期化もあるべきなのですがモニタデバッガが初期化を済ませてありその通信条件を そのまま使うので省略しました。将来プログラムをモニタから起動するのではなくH8内蔵ROMから独自に 起動する形に書き換えるときは忘れずに追加してください。」
とありました。
 本の説明でのWindowsのOSはwindowsXPで僕の使っているPCのOSはwindows7です。本の方では PCのターミナルソフトとしてHtermを使っていますが、windows7ではHtermが省かれていて ありません。
 それで僕の方では、ターミナルソフトでのシリアルインタフェースの初期化が出来ていないと気がつきました。
 そこで前に書いたRikiyaさんのWEBサイト(http://homepage1.nifty.com/rikiya/index.htm) に書いてあるシリアルインターフェースについての記事を勉強して、初期化の部分をそのまま利用した ところ(通信速度に関するデータはH8のpdfを参照)見事に動きました。

 これに力を得て手元にあったマイコンボードを利用して、PC側にVisual Basicで簡単なアプリを作り、 このアプリ上のボタンをクリックすると、マイコンボード上の赤と黄色のLEDを「両方光る、
黄色だけ光る、赤だけ光る、両方消える」という仕組みを作ってみました。
左がVBで作ったアプリ、右がPCにつながっているマイコンボードです。
マイコンボード上の左上にこのアプリで光らそうとしている二つのLEDです。
ふたつのLEDはポート3の0ビット目と2ビット目につなげています。
画像では「両方光る」のボタンをクリックすることによって赤黄の両方とも光った状態です。
右上のコネクタがシリアル(RS232C)のコネクタでここにケーブルを介してPCのUSBに つながっています。
このケーブルはUSBとシリアルを結ぶケーブルで秋月電子で購入したものです。windows7でもきちんと 動作しています。

 下はマイコン(H8の3052)を動かすためのC言語プログラムです。
ITUの初期化はITU0を初期化するだけでいいのですが、ITU1を削除するのも面倒なので残しています。
シリアル通信初期化の部分はRikiyaさんの方とほぼ同じなのですが、通信速度を19200bpsに設定する、 の行と1ms待つ、の行を少し変えています。

 シリアルコミュニケーションの初期化は、譲歩同期式、データ長8ビット、パリティなし、STOPビット1、 通信速度19200bpsでしています。
 この設定値はPC側の設定と合わせておく必要がありますが、VBでは通信速度を同じ19200bpsにしただけで 通信できました。通信速度以外の設定値はこの値がPC側のVBの既定値と思います。
 VBではこれ以外に、PortNameとReadTimeOutを設定する必要があります。USBにつないでいるのでその都度 PortNameは変化します。僕の場合はCOM3かCOM4でした。 ReadTimeOut(受信時に応答がなければエラーとするまでの時間)は3000(ms)にしました。
 通信速度についてH8の電子マニュアルを調べますと、25MHZのH8(3052)の場合、 「シリアルのBRRレジスタの値を9600bps=80,19200bps=40,38400bps=19に設定しなさい」 とありました。
 そこで19200bpsに設定したいのでBRRレジスタの値を40にしました。

 下から4行目は、信号を受信したら受信確認のために「k」の文字をシリアルに送るための行です。
VBの方では、それを受けて送信を確認しています。
 下から3行目は20msの待ち時間です。 つまり20msごとにシリアルインタフェースにVBからの新たな信号が来ていないかを見に行っている わけです。
信号の値(signal)は最初に0にしています。つまり最初はLEDがふたつとも消えた状態になります。
#include "3048f.h"
/* 待ち時間発生 引数に、必要なミリ秒を指定する***********/
void init_io(void)
{
	/*ポート3を出力に設定*/
	P3.DDR = 0xff;
	/*ITU0、1のクロックを8分週 3125:1ms、4687.5:1.5ms、6250:2ms、62500:20ms*/
	ITU0.TCR.BYTE = 0x03;	/* ITU0、TCNTクリア禁止 clock 1/8 */
	ITU1.TCR.BYTE = 0x03;	/* ITU1、TCNTクリア禁止 clock 1/8 */
	ITU.TSTR.BIT.STR0 = 1;	/* ITU0 TCNTカウント開始 */
	ITU.TSTR.BIT.STR1 = 1;	/* ITU1 TCNTカウント開始 */
/* シリアル通信初期化*******************************/
	SCI1.SCR.BYTE = 0x00;	/* SCI1設定 stop,内部クロック */
	SCI1.SMR.BYTE = 0x00;	/* data8.stop1,pari non */
	SCI1.BRR = 40;		/* 19200bps */
	ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
	while(ITU0.TCNT <= 3125);/*1ms待つ*/
	SCI1.SCR.BYTE = 0x30;	/* Tx,Rx有効 ,割込み無効 */
	SCI1.SSR.BYTE &= 0x80;	/* エラーフラグのクリア */
	return;
}
/* SCI1から1文字受信する****************************/
char sci1_rx(void){
char data;
	while((SCI1.SSR.BYTE & 0x78)==0); /* 受信とエラーのフラグが立つまで待つ*/
	if(SCI1.SSR.BIT.RDRF == 1){      /* データ受信が正常 */
		data = SCI1.RDR;	/* データを受け取りdataに保存 */
		SCI1.SSR.BIT.RDRF = 0;	/* 受信フラグのクリア*/
		return(data);
	}
	else{                           /* データ受信にエラー発生 */
		SCI1.SSR.BYTE &= 0xc7;	/* エラーフラグをクリア */
		return(0xff);           /* エラー時はFFを返す */
	}
}
/* SCI1に1文字送信する */
void sci1_tx(char data){
	while(SCI1.SSR.BIT.TDRE == 0);	/*未送信データが送られるまで待つ*/
	SCI1.TDR = data;		/*送信データのセット*/
	SCI1.SSR.BIT.TDRE = 0;		/*送信フラグのクリア*/
	return;
}
/*プログラムの始まり*/
main()
{
char signal;
int	i, j,k;
	/*H8ハードの初期化を行う*/
	init_io();
	/*制御信号出力スイッチを0で初期化*/
	signal = '0';
	/*無限ループ開始*/
	while(1){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		/*コマンドが受信されているか確認する*/
		signal = sci1_rx();
		if( signal =='A' || signal=='B'|| signal=='C' || signal=='D')
			sci1_tx(signal);
		else continue;		
		/*制御信号出力スイッチの振り分け*/
		if(signal == 'A')/*両方とも点灯*/
		{
			P3.DR.BIT.B0 = 1;
			P3.DR.BIT.B2  = 1;
		}
		else if(signal=='B')/*0のみ点灯*/
		{
			P3.DR.BIT.B0 =1;
			P3.DR.BIT.B2 = 0; 
		}
		else if(signal=='C')/*2のみ点灯*/
		{
			P3.DR.BIT.B0 = 0;
			P3.DR.BIT.B2  = 1;
		}
		else if(signal=='D')/*両方消灯*/
		{
			P3.DR.BIT.B0 = 0;
			P3.DR.BIT.B2  = 0;
		}
		while(ITU0.TCNT<62500) ;
	};
}
失敗1(〜2011年6月)  
 失敗です。
電源、スイッチをONにして、いろいろな数値をサーボに与えてモータの動作確認をしようとしました。
最初の5分くらいはそれらしき動作をするのですが、その後は異常な動きをします。
そこで、サーボに与えている電圧の値を調べました。
サーボに与えるべき電圧は定格で5Vです。
乾電池4個の電圧6Vをサーボに与えています。
「スイッチをONした直後は5V以上をキープしているのですが5分ぐらい経つと3V未満に電圧が下がる」ということがわかりました。
「電池からの電源を切り、再度電池の電源をONにすると、5V以上の電圧を5分ぐらいキープしてそのあと急速に3V未満に 電圧が下がる」ということもわかりました。
 ネットに何か情報がないか、いろいろ調べました。
すると「普通の乾電池ではサーボの電源には不向きである。充電池でないとサーボには耐えられない。」ということがわかりました。
そこで、6Vの充電池を購入して再度挑戦です。
 しかし結果は前と同じです。
それで「あのロボットの吉野さん」にメールを送り、ご意見を伺いました。
すると「使っているモータ(秋月電子で購入したGWSMICRO/2BBMG/J]が電圧を食いすぎる」というお返事をいただきました。このモータは 小型の割にトルクが強い(5.4kg)ので買ったものです。
また吉野さんのWEBサイトを訪問して、このサイトに書いてあるSRM102というモータを購入しました。
ところがこのモータは前のモータとはサイズが全然違い、かなり大きいのです。
作っているロボットの体の部品はモータに合わせて寸法をとっていますので、出来上がったロボットのサーボをそっくり入れ替える ことはできません。部品はすべて作り直しです。
二足歩行2号の組立まで(2011年7月〜9月)
1号と作り方はほぼ同じですが異なるところもありますので、異なるところを中心に新たに作成した ロボット(2号)の制作を紹介いたします。








 頭につけている目玉みたいなもの、距離センサーなのですが、これをつけるのにすごく苦労しました。
 1号では、顔の幅が広かったので、距離センサーを顔にねじで直接くっつけました。
 この2号では、顔をスマートにしようとして顔の幅を狭くしました。このことが仇になりました。
 このセンサの両側にねじをつける穴があります。顔の幅が狭いためにねじ1本で直接顔につける ことが出来ません。
 そこで細長い板を作ってまず距離センサをねじでこの板に取り付けます。
この板を顔に取り付けるために、細長い板の中心部に二つ穴をあけてこの穴にねじを 逆向きに固定します。
 普通にねじをつけるだけではねじの頭・ナットが細長い板の表面から出っ張ります。
だから細長い板にあけた穴の両側に面取りをしてねじの頭とナットが板に埋め込まれるようにしました。
 板の両端の穴もねじの頭が埋め込まれるように面取りをしています。
 真ん中の写真が細長い板にセンサを取り付けた状態、右の写真が細長い板の4つの穴に面取りを した状態です。

















 左の写真が胸と腰を後ろから見たものです。
 真中が胸、右が腰のボックスです。
 胸のボックスにはサーボを動かす信号を発生するためのマイコンが載った基盤があります。
 1号では胸のボックスにマイコンを駆動させる電池を置きました。
 右の写真を見てもらえばわかりますように、2号ではこれを腰のボックスの後ろ外側に取り付けています。 その分、胸のボックスはすっきりしています。

 
 腰のボックスの左側には、サーボへのケーブル、胸の基盤からのケーブル、スイッチ等が載った基盤を配置しています。

 腰のボックスの右側は、内部にサーボを駆動する充電池(6V)、外側に胸のマイコンを 駆動する電池を配置しています。






ロボットを道路に置いてみました。

歩かすにはマイコンにそのためのプログラムを転送する必要があります。


歩行プログラムを転送していませんのでまだ動きません。

二足歩行2号の歩行プログラムの方針(2011年10月)
 1.歩行するときの左右の足の軌跡の数値データを実際のmm単位で取る。
 2.1のデータをサーボの信号データに変換する。
 3.2のデータをサーボに送る。
 この手順ですが、具体的には次のようになります。
 足の軌跡の数値データ(mm単位)をいかにしてサーボの信号データに変換するか! になりますが・・
 足を前に何mm、上に何mm移動させるには膝の2つのそれぞれサーボが何度回転すればいいかを求めます。
このサーボの回転数をサーボに与えるパルス幅に対応した数値に直します。
こうやって求めたパルス幅に対応した数値データ列をサーボに送ればよいことになります。
 文章で書くのはこんなものですが、これがなかなか難しいです。

二足歩行2号の配線の考え直し(2013年2月〜)
 この1年以上ものあいだ、2011年10月に立てた方針に従ってやってきました。
 プログラムをいろんな風に試しました。
それらしい動きはするのですが思い通りに動いてくれません。
 またやけにモータを動かす電池の減りが早い気がします。
そこで再度、吉野氏の著書「二足歩行ロボットの自作入門」を読み返してみました。
この書物では「モータの3芯コネクタを切断して『信号、電源、アース』の3線に分離して、 信号線は信号線だけの基盤に、電源線、アース線もそれぞれだけが集めた基盤に直結して います。さらに電源線をつなぐ基盤としてを使っています。」
 これだけでかなりの電気抵抗を減らせるのでは、と思いました。
3芯コネクタはそのままで、『全面が銅箔の基盤』を使ってやってみようと思います。

サーボモータの検証機器の制作(2013年3月〜10月)



















『全面が銅箔の基盤』を使って配線やり直しがほぼ出来た頃、2、3個のサーボモータが 『あれ!』と思うような動きをしました。
 そこで、使っていない『H8 3052マイコン』を利用して『サーボ検証器』を作りました。

 さらに8極のディップスイッチを取り付けました。下の方の横に長い青いやつです。

 デモンストレーションのために手持ちのサーボを右上に取り付けています。別のサーボをテストするときは このサーボのコネクタを外してテストしたいサーボのコネクタを取り付けることになります。

 二つの部分に分かれています。左側がマイコン部分、右側がサーボを接続する部分とLED部です。

 マイコン部の左上に2極ディップスイッチ(青いやつ)を新たに取り付けました。 このままで通常動作、両方スイッチをON(下に押し下げ)にするとマイコンへの書き込み可となります。 これによってプログラム書き込みが格段と楽になりました。これまでは2本のジャンパピンを挿す ことによりMD2をグラウンドに、FWEを5Vにショートさせてブートモードにしてプログラムを 書き込み、2本のジャンパピンを外して書き込んだプログラムを動作させていました。

ディップスイッチは8個のスイッチを使うことができますので、P2ポートの第0ビットから第7ビット の計8個のピンを使っています。

 ディップスイッチの接続は図のようにします。

 VCCの5Vを抵抗を介して、例えばP2ポートの第0ビットのピンに つなぎます。このピンとディップスイッチの1番をつなぎ、ディップスイッチの1番の片方をグラウンド につなぎます。
 これにより、ディップスイッチスイッチONのときはP2の第0ビットの電位が0、 ディップスイッチOFFのときはP2の第0ビットの電位がほぼVCCの電位となります。
 つまり、ディップスイッチのON・OFFでP2の第0ビットの電位がLOW・HIGHに 変化します。
 この変化をプログラムで利用します。
 このようなVCCに介する抵抗をプルアップ抵抗といいます。
 ところが、今使っているマイコンのP2,P4,P5はプルアップ抵抗を内蔵していて、 プログラム上でこのプルアップ機能をON・OFF出来ます。

 プルアップ抵抗とは、このようなVCC電圧が付属していることがわからなくて、実際の抵抗を つけて試したりして、何日間かを無駄にしました。
 ネットで調べてやっとわかりました。

 サーボモータの取り付け部の下の黒い所には単4電池4個が入っていますので、サーボの 駆動力は6Vということになります。
 マイコンからのPWM波形はP6ポートの第5ピンによって生成して、ケーブルを経由して サーボ取り付け部に送られます。

 8極のディップスイッチなので8つの最大8つの機能を持たすことができます。次のような 8つの機能をもたせました。
ディップスイッチの1のON:『基準位置と+90度回転を繰り返し』、
ディップスイッチの2のON:『基準位置と−90度回転を繰り返し』
ディップスイッチの3のON:『+90度と−90度回転を繰り返し』

 ディップスイッチの4のON:PCとこの機器をシリアルケーブルで接続して PCで設定した数値だけの回転をします。
 左がその設定画面で、PC側でVisualBasicで作ったものです。  上下二つの部分からなっています。
常時LED部の左端の上から3ツ目が点灯します。これはPC側からの命令を常時モニタリング しているということです。
上部に4つのボタンがあります。それぞれをクリックするたびにそこに表示されている数値に 相当する回転をサーボに与えます。
同時に常時点灯の右の2つのLEDが表示通りに点灯(消灯)します。
下部の上下矢印のボタンをクリックするたびにテキストボックスの 数値が50または200上下します。
 好みの数値に設定した後に送信ボタンをクリックすると その数値に対応した角度までサーボモータの羽が回転します。
 サーボモータの回転角度の基準位置に対応した数値は「4678(H8 3052 ではそうなります)」、この数値を与えるとPWMのパルス幅が1.5msになります ので理論的にはサーボモータの回転角度が基準位置です。

ディップスイッチの5のON:5×5個のLEDを順番に点灯表示
ディップスイッチの6のON:5×5個のLEDで文字列「CNON」を順次表示
ディップスイッチの7のON:5×5個のLEDで文字列「FOREVER」を順次表示
ディップスイッチの8のON:5×5個のLEDで文字列「LEVEYOU」を順次表示

 実はこの『サーボ検証器』を作っているとき、拡張性を考えて8極のディップスイッチをつけ ました。サーボ用に4個の機能を与えて、あと4個の機能を拡張できる可能性が残りました。

 そんなとき妻から「LEDは光らへんのん?」と言われました。

 そこでポート2つ分の4×4個のLEDをつけて「ランダム点灯」とか試していました。
 そんなときまた妻から「アルファベットは?」と言われました。
 しかし、4×4個のLEDでは限られたアルファベットしか表示させることはできません。ただ、 5×5個のLEDならかろうじてあらゆるアルファベットを表示させることができる、と思い、 右と下にもう一段LEDを増やすことにしました。
 しかし、この「もう一段」が難物でした。合計25個分のLEDの配線、これにはLED1個 について1個の抵抗が必要なのですごい数の、煩雑な配線となります。

 そんなわけで挫折しかかった頃、秋月のサイトを何気なく見ていると、抵抗内蔵のLEDが あるではありませんか? 
 これで狭い場所に抵抗を省くことができ、なんとか25個のLEDを付けることができました。
いろいろ調べてみると、この抵抗内蔵のLEDは秋月でしか売っていませんでした。

 なんやかんやで出来上がりと思った頃、マイコンが変な動作をします。今まで正常に動作していた ピンが動作しなかったり、そのうち新規に書き込みができなくなりました。
 結局、書き込みが許されていた回数を超過したようでした。
 2年ぐらい使い、何回も書き込みをするとこのようになるのですね・・・・。
 秋月から「H8 3052」のボードのみを新たに買い、交換してやっとできあがりました。

P6ポートの第5bitを使ってサーボを動かすためのPWM波形を出します。
 PWMを生成するための待ち時間を2124、7250にすることにより、−90度 と+90度を実現しています。
 つまりパルス幅が0.68msでサーボが−90度回り、2.32msでサーボが+90度回転するということになります。
 PWM波形の間隔は20msが基本ですが、13msにしても動作しました。

 LEDで文字を表示するための文字のコード化ですが、下のようにLEDに番号をつけた結果、文字をコードで 表せるようにしました。
 C言語プログラムのmain関数の最初の配列がそれです。
 @ABC25
 GFED24
 HIJK23
 ONML22
 PQRS21
 この下にこのためのC言語プログラムとVisualBasicのプログラムを載せます。
 C言語プログラムのシリアル関係部はrikiyaさんのサイトからほぼ丸写しです。
 VisualBasicの部分は吉野さんのサイトのプログラムをこれ用に直しました。
/*ディップスイッチにより8つの機能を持つ*/
/*ディップスイッチ1:サーボを7250(左)から4687(基準位置)*/
/*ディップスイッチ2:サーボを4687(基準位置)から2124(右)*/
/*ディップスイッチ3:サーボを7250(左)から2124(右)*/
/*ディップスイッチ4:PCとRS232Cで接続しPCでの指定値だけサーボを回転*/
/*ディップスイッチ5:5×5個のLEDすべてを順次点灯*/
/*ディップスイッチ6:5×5個のLEDによりCNONの文字列を順次表示*/
/*ディップスイッチ7:5×5個のLEDによりFOREVERの文字列を順次表示*/
/*ディップスイッチ8:5×5個のLEDによりLOVEYOUの文字列を順次表示*/
/*2BBMG 0.34ms/60度 SRM102 0.2ms/60度*/
#include <3048f.h>
void init_io(void)
{
/* フリーランニングモードでITU0初期化 ***************************/
/* 3125:1ms、4687.5:1.5ms、6250:2ms、62500:20ms***/
	ITU0.TCR.BYTE = 0x03;	/* TCNTクリア禁止 clock 1/8 */
	ITU.TSTR.BIT.STR0 = 1;	/* カウント開始 */
/* シリアル通信初期化*******************************/
	SCI1.SCR.BYTE = 0x00;	/* SCI1設定 stop,内部クロック */
	SCI1.SMR.BYTE = 0x00;	/* data8.stop1,pari non */
	SCI1.BRR = 40;		/* 19200bps */
	ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
	while(ITU0.TCNT <= 3125);/*1ms待つ*/
	SCI1.SCR.BYTE = 0x30;	/* Tx,Rx有効 ,割込み無効 */
	SCI1.SSR.BYTE &= 0x80;	/* エラーフラグのクリア */
	return;
}
unsigned char sci_read_char_wait(void)
{
unsigned char	data;

	/*受信レジスタにデータがあるかチェックする。来るまで待つ*/
	while((SCI1.SSR.BYTE & 0x40) == 0);
	/*受信レジスタのデータを取り出す*/
	data = SCI1.RDR;
	SCI1.SSR.BYTE = SCI1.SSR.BYTE & 0xbf;
	return(data);
}
/*unsigned int型変数(2バイト)をシリアルポートから入力する*/
/*備考:データが来るまで待つ  */
unsigned int sci_read_uintA(void)
{
unsigned int	data;
unsigned char	data_L, data_H;	
	/*unsigned charのデータ2個を受け取る*/
	data_H = sci_read_char_wait();
	data_L = sci_read_char_wait();
	/*unsigned intのデータに変換する*/
	data = (unsigned int)data_H * 256 + (unsigned int)data_L;
	return(data);
}
/* SCI1から1文字受信する****************************/
char sci1_rx(void){
char data;
	if((SCI1.SSR.BYTE & 0x78)==0)  return 0; /* 受信とエラー以外は0を返す*/
	if(SCI1.SSR.BIT.RDRF == 1){      /* データ受信が正常 */
		data = SCI1.RDR;	/* データを受け取りdataに保存 */
		SCI1.SSR.BIT.RDRF = 0;	/* 受信フラグのクリア*/
		return(data);
	}
	else{                           /* データ受信にエラー発生 */
		SCI1.SSR.BYTE &= 0xc7;	/* エラーフラグをクリア */
		return(0xff);           /* エラー時はFFを返す */
	}
}
/* SCI1に1文字送信する */
void sci1_tx(char data){
	while(SCI1.SSR.BIT.TDRE == 0);	/*未送信データが送られるまで待つ*/
	SCI1.TDR = data;		/*送信データのセット*/
	SCI1.SSR.BIT.TDRE = 0;		/*送信フラグのクリア*/
	return;
}
/* SCI1に文字列を送信する 文字列は'\0'で締めくくっておく**************/
void sci1_strtx(char *str){
	while(*str != '\0'){	/* 文字が\0になるまで繰り返す */
		sci1_tx(*str);	/* 1文字送信*/
		str++;		/* 次の文字に移る*/
	}
	return;
}
/*20msの整数倍の時間待ち*/
void wait(int many20){
	int i;
	for(i=1;i<=many20;i++){
	   ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
	   while(ITU0.TCNT < 62500);/*20ms経過するまで待つ*/
	}
}
void light( int x ) /*LED変化*/
{
	P1.DR.BIT.B0 = x;
	P1.DR.BIT.B1 = x;
	P1.DR.BIT.B2 = x;
	P1.DR.BIT.B3 = x;
	P1.DR.BIT.B4 = x;
	P1.DR.BIT.B5 = x;
	P1.DR.BIT.B6 = x;
	P1.DR.BIT.B7 = x;
	P3.DR.BIT.B0 = x;
	P3.DR.BIT.B1 = x;
	P3.DR.BIT.B2 = x;
	P3.DR.BIT.B3 = x;
	P3.DR.BIT.B4 = x;
	P3.DR.BIT.B5 = x;
	P3.DR.BIT.B6 = x;
	P3.DR.BIT.B7 = x;
 	P5.DR.BIT.B0 = x;
	P5.DR.BIT.B1 = x;
	P5.DR.BIT.B2 = x;
	P5.DR.BIT.B3 = x;
	P6.DR.BIT.B0 = x;
	P6.DR.BIT.B1 = x;
	P6.DR.BIT.B2 = x;
	P6.DR.BIT.B3 = x;
	P6.DR.BIT.B4 = x;
}
void dip1(void){
	int i;		
	for(i=1;i<=30;i++){	
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
		while(ITU0.TCNT<7250) ;/*2124でほぼー90度(左) 7250で+90度(右)*/
		P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
		while(ITU0.TCNT < 40000);/*13ms経過するまで待つ*/
	    }
	    for(i=1;i<=20;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		while(ITU0.TCNT<62500) ;/*20msだけ待つ*/	
	    }
	    for(i=1;i<=30;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
		while(ITU0.TCNT<4687) ;/*指定時間だけ待つ*/
		P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
		while(ITU0.TCNT < 40000);/*13ms経過するまで待つ*/
	    }
	 for(i=1;i<=20;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		while(ITU0.TCNT<62500) ;/*20msだけ待つ*/	
       	  }
}
void dip2(void){
	int i;
	for(i=1;i<=30;i++){	
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
		while(ITU0.TCNT<2124) ;/*2000でほぼー90度 7400で+90度*/
		P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
		while(ITU0.TCNT < 40000);/*13ms経過するまで待つ*/
	    }
        for(i=1;i<=20;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		while(ITU0.TCNT<62500) ;/*20msだけ待つ*/	
	    }
	for(i=1;i<=30;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
		while(ITU0.TCNT<4687) ;/*指定時間だけ待つ*/
		P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
		while(ITU0.TCNT < 40000);/*13ms経過するまで待つ*/
	    }
	for(i=1;i<=20;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		while(ITU0.TCNT<62500) ;/*20msだけ待つ*/	
	   }
}
void dip3(void){
	int i;
	for(i=1;i<=30;i++){	
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
		while(ITU0.TCNT<2124) ;/*2200でほぼー90度 7400で+90度*/
		P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
		while(ITU0.TCNT < 40000);/*13ms経過するまで待つ*/
	    }
        for(i=1;i<=20;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		while(ITU0.TCNT<62500) ;/*20msだけ待つ*/	
	    }
	for(i=1;i<=30;i++){	
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
		while(ITU0.TCNT<7250) ;/*2000でほぼー90度 7400で+90度*/
		P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
		while(ITU0.TCNT < 40000);/*13ms経過するまで待つ*/
	    }
        for(i=1;i<=20;i++){
		ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
		while(ITU0.TCNT<62500) ;/*20msだけ待つ*/	
	    }
}
int dip4(int pWidth){
	int signal;
	/*コマンドが受信されているか確認する*/
	signal = sci1_rx();
	if( signal =='A' || signal=='B'|| signal=='C' || signal=='D' || signal=='E')	sci1_tx(signal);
	/*制御信号出力スイッチの振り分け*/
	if(signal == 'A')/*両方とも点灯*/
	{
		P3.DR.BIT.B0 = 0;
		P3.DR.BIT.B1 = 1;
		P3.DR.BIT.B2  = 1;
		P3.DR.BIT.B3 = 0;
		pWidth = 2000;	/*パルス幅に相当する数*/	
		}
	else if(signal=='B')/*0のみ点灯*/
	{
		P3.DR.BIT.B0 = 0;
		P3.DR.BIT.B1 =1;
		P3.DR.BIT.B2 = 0; 
		P3.DR.BIT.B3 = 0;
		pWidth = 3700;	/*パルス幅に相当する数*/	
			}
	else if(signal=='C')/*2のみ点灯*/
	{
		P3.DR.BIT.B0 = 0;
		P3.DR.BIT.B1 = 0;
		P3.DR.BIT.B2  = 1;
		P3.DR.BIT.B3 = 0;
		pWidth = 5400;	/*パルス幅に相当する数*/	
	}
	else if(signal=='D')/*両方消灯*/
	{
		P3.DR.BIT.B0 = 0;
		P3.DR.BIT.B1 = 0;
		P3.DR.BIT.B2  = 0;
		P3.DR.BIT.B3 = 0;
		pWidth = 7200;	/*パルス幅に相当する数*/	
	}
	else if(signal=='E')/*指定数値でサーボ回転*/
	{
		P3.DR.BIT.B0 = 0;
		P3.DR.BIT.B1 = 0;
		P3.DR.BIT.B2  = 0;
		P3.DR.BIT.B3 = 0;
		P3.DR.BIT.B4 = 0;P3.DR.BIT.B5 = 0;
		P3.DR.BIT.B6 = 0;P3.DR.BIT.B7 = 0;
		pWidth = sci_read_uintA();	/*パルス幅に相当する数*/
		if(pWidth <3200)	P3.DR.BIT.B7 = 1;
		else if(pWidth>=3200 && pWidth<4400) P3.DR.BIT.B6 = 1;
		else if(pWidth>=4400 && pWidth<5600) P3.DR.BIT.B5 = 1;
		else 	P3.DR.BIT.B4 = 1;	
	}
	else if( signal == 0)	{	
		P3.DR.BIT.B0 = 1;
	}
	else if( signal == 0xff )	{
		P3.DR.BIT.B0 = 0;
		P3.DR.BIT.B1 = 0;
		P3.DR.BIT.B2 = 0;
		P3.DR.BIT.B3 = 1;
	}
	ITU0.TCNT = 0;	/* ITU0 TCNTカウントを0にクリア */
	P6.DR.BIT.B5 = 1;/*P6のBit5(CN2のピンNo.8)を1にする*/
	while(ITU0.TCNT< pWidth) ;/* 設定値のパルス幅*/
	P6.DR.BIT.B5 = 0;/*P6のBit5を0にする*/
	while(ITU0.TCNT < 62500);/*20ms経過するまで待つ*/
	return pWidth;
}
int dip5678(int y){
	int i,x,z,k;
	int putC[25]= {25,4,3,2,1,8,9,16,17,18,19,20,21,25,4,3,2,1,8,9,17,18,19,20,21};
	int putO[25]= {4,3,2,8,9,16,18,19,20,22,23,24,4,3,2,8,9,16,18,19,20,22,23,24,4};
	int putN[25]= {17,16,9,8,1,7, 11,13,21,22,23,24,25,17,16,9,8,1,7, 11,13,21,22,23,24};
	int putF[25]= {1,2,3,4,25,8,9,16,17,10,11,12,23,1,2,3,4,25,8,9,16,17,10,11,12};
	int putR[25]= {1,8,9,16,17, 2,3,4,25,24,23,12,11,10,14,20,21,1,8,9,16,17, 2,3,4};
	int putE[25]= {1,2,3,4,25,8, 9,16,17,9,10,11,12,23,17,18,19,20,21,1,2,3,4,25,9};
	int putV[25]= {1,8,10,15,19,13,12,24,25,1,8,10,15,19,13,12,24,25,1,8,10,15,19,13,12};
	int putL[25]= {1,8,9,16,17,18, 19,20,21,1,8,9,16,17,18, 19,20,21,1,8,9,16,17,18, 19};
	int putY[25]= {1,7,25,5,11, 14,19,1,7,25,5,11, 14,19,1,7,25,5,11, 14,19,1,7,25,5};
	int putU[25]= {1,8,9,16,18, 19,20,22,23,24,25,1,8,9,16,18, 19,20,22,23,24,25,1,8,9};
	x = 1;
	if ( P2.DR.BIT.B5 == 0 )  z = 4;
	if (P2.DR.BIT.B6 == 0 || P2.DR.BIT.B7 == 0)		z = 7;		
	y =  y  % z + 1; 
	for(i=1;i<=25;i++){
		if( P2.DR.BIT.B4 == 0 ) k = i;	/*順番*/
		else if( P2.DR.BIT.B5 == 0 )	{		/*CNON*/
			if( y == 1 )	k = putC[i-1];
			else if ( y == 3 ) k = putO[i-1];
			else k = putN[i-1];
			 }
		else if( P2.DR.BIT.B6 == 0 )	{		/*FOREVER*/
			if( y == 1 )	k = putF[i-1];
			else if ( y == 2 ) k = putO[i-1];
			else if ( y == 3 || y == 7) k = putR[i-1];
			else if ( y == 4 || y == 6) k = putE[i-1];
			else if ( y == 5 ) k = putV[i-1];
		 }
		else {		/*LOVEYOU*/
			if( y== 1 )	k = putL[i-1];
			else if ( y == 2 || y == 6) k = putO[i-1];
			else if ( y == 3 ) k = putV[i-1];
			else if ( y == 4 ) k = putE[i-1];
			else if ( y == 5 ) k = putY[i-1];
			else if ( y == 7 ) k = putU[i-1];
			}
		if( P2.DR.BIT.B4 == 0 )	light(0);
		wait(1);
       		switch(k){
			case 1:	P1.DR.BIT.B0 = x;break;
			case 2:	P1.DR.BIT.B1 = x;break;
			case 3:	P1.DR.BIT.B2 = x;break;
			case 4:	P1.DR.BIT.B3 = x;break;
			case 5:	P1.DR.BIT.B4 = x;break;
			case 6:	P1.DR.BIT.B5 = x;break;
			case 7:	P1.DR.BIT.B6 = x;break;
			case 8: P1.DR.BIT.B7 = x;break;
			case 9:	P3.DR.BIT.B0 = x;break;
			case 10:P3.DR.BIT.B1 = x;break;
			case 11:P3.DR.BIT.B2 = x;break;
			case 12:P3.DR.BIT.B3 = x;break;
			case 13:P3.DR.BIT.B4 = x;break;
			case 14:P3.DR.BIT.B5 = x;break;
			case 15:P3.DR.BIT.B6 = x;break;
			case 16:P3.DR.BIT.B7 = x;break;
  			case 17:P5.DR.BIT.B0 = x;break;
			case 18:P5.DR.BIT.B1 = x;break;
			case 19:P5.DR.BIT.B2 = x;break;
			case 20:P5.DR.BIT.B3 = x;break;
			case 21:P6.DR.BIT.B0 = x;break;
			case 22:P6.DR.BIT.B1= x;break;
			case 23:P6.DR.BIT.B2 = x;break;
			case 24:P6.DR.BIT.B3 = x;break;
			case 25:P6.DR.BIT.B4 = x;break;
  		  }
		wait(1);
	}/*FOR 25 END*/
	if( P2.DR.BIT.B4 != 0 ) { 
		if ( y == z ) wait(20);/*文字列の最後で1秒待つ*/
		else	wait(10);
		light(0);
	  }	
	return y;  
}
/*プログラムの始まり*/
main()
{
	int y = 0;
	int pWidth = 5000;
	P2.DDR = 0x00;          /*port2入力に設定 ディップスイッチ用*/
	P2.PCR.BYTE = 0xff;      /*port2プルアップon */
	P5.DDR = 0xff;           /*port5出力に設定 */
	P5.PCR.BYTE = 0x00;      /*port5プルアップOFF */
	init_io();/*H8ハードの初期化(タイマー初期化、SCII初期化*/
	P1.DDR = 0xff;	/*PORT3を出力に設定*/ 
	P3.DDR = 0xff;	/*PORT3を出力に設定*/ 
	P6.DDR = 0xff;	/*PORT6を出力に設定*/ 
	ITU.TSTR.BIT.STR0 = 1;	/* ITU0 TCNTカウント開始 */	
	while(1){
		if (P2.DR.BIT.B0 == 0)	dip1();      /*ディップスイッチ1 */
      		else if (P2.DR.BIT.B1 == 0)	dip2(); /*ディップスイッチ2*/
		else if (P2.DR.BIT.B2 == 0)	dip3(); /*ディップスイッチ3*/
      		else if (P2.DR.BIT.B3 == 0)	pWidth = dip4(pWidth); /*ディップスイッチ4*/
     		else if (P2.DR.BIT.B4 == 0 || P2.DR.BIT.B5 == 0 || P2.DR.BIT.B6 == 0 || P2.DR.BIT.B7 == 0 ) 
 			y = dip5678(y);   				
	}
}

	
次のものはVisualBasicの側のプログラムです。
Public Class Form1
    'マイコン側はken1
    Dim servoMax, servoMin As Integer
    Dim text1 As TextBox

    Private Sub targetGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles targetGo.Click
        write_sio_command("E")
        write_sio_int(target.Text)
    End Sub
    Private Sub UpBig_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpBig.Click
        target.Text += 200
    End Sub

    Private Sub DownBig_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownBig.Click
        target.Text -= 200
    End Sub

    Private Sub UpSmall_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpSmall.Click
        target.Text += 50
    End Sub

    Private Sub DownSmall_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DownSmall.Click
        target.Text -= 50
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim response As MsgBoxResult
        Try
            SerialPort1.Open()
        Catch ex As IO.IOException
            response = MsgBox("エラー!シリアルポートオープンに失敗。このまま起動?", MsgBoxStyle.YesNo, "起動の確認")
        End Try
        If response = MsgBoxResult.No Then End
    End Sub
    'ロボット制御コマンドキャラクター送信********************
    Private Sub write_sio_command(ByVal command As Char)
        '変数定義
        Dim command_char(64), buff(64) As Byte
        'マイコンにコマンドを送信
        command_char(0) = Asc(command)
        SerialPort1.Write(command_char, 0, 1)
        '受信確認待ちとエラー処理
        Try
            SerialPort1.Read(buff, 0, 1)
        Catch ex As TimeoutException
            MsgBox("通信エラーです。規定時間以内に応答しません")
            Exit Sub
        End Try
        If command_char(0) <> buff(0) Then
            MsgBox("通信エラーです。コマンドに正しく応答しません")
            Exit Sub
        End If
    End Sub
    "2バイトの整数をシリアルポートから出力する(引数は文字列)********************
    Private Sub write_sio_int(ByVal input_str As String)
        '変数定義,
        Dim buff(64) As Byte
        Dim output_val As Integer
        'テキストボックスの文字列を整数に変換
        output_val = Val(input_str)
        '変換した整数の出力値を上位バイトと下位バイトに分割してバッファにセット
        buff(0) = Int(output_val / 256)
        buff(1) = output_val - Int(output_val / 256) * 256
        'シリアルポートから出力
        SerialPort1.Write(buff, 0, 2)
    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        write_sio_command("A")
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        write_sio_command("B")
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        write_sio_command("C")

    End Sub
    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        write_sio_command("D")
    End Sub
  

    Private Sub owari_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles owari.Click
        Try
            'シリアルポートをクローズする
            SerialPort1.Close()
        Catch ex As IO.IOException
            MsgBox("エラー!シリアルポートのクローズに失敗しました")
        End Try
        'プログラム終了
        End
    End Sub
End Class