109.パソコンとシリアル通信する


2001/05/25 【ソフトウエア編TOPに戻る】

ここでは、パソコンの通信ソフト「ハイパーターミナル」とシリアル通信を行なう方法についてご紹介します。長いページになってしまったので、以下の目次を参考にして下さい。

109−1.シリアル通信とは

109−2.ソフトウエアのご紹介

109−3.ソフトウエアsertest1.cの説明

■109−3−1.シリアル通信初期化関数 sci_init( );

■109−3−2.sci1からの1文字受信関数 sci1_rx( );

■109−3−3.sci1への1文字送信関数 sci1_tx( data );

■109−3−4.sci1への文字列送信関数 sci1_strtx( *str )

■109−3−5.メイン関数の説明

109−4.ソフトsertest1の動作説明


AKI-H8/3048Fボードとパソコンとの間のシリアル通信は、ソフトウエア書き込みの際に既に行なっていることですね。ただしそれは、F-ZTATという書き込み用アプリケーションソフトと、書き込みモード時のAKI-H8が勝手にやってくれていることで、私たちが好きなように通信を制御している訳ではありません。

パソコンとAKI-H8が自由にデータ通信を行なえるようになると、色々と便利です。例えば、パソコンを使ってロボットの遠隔操作をしたり、ロボットの動作パターンをパソコンから設定してあげたり、またロボットの状態をパソコン側でモニタリングしたりといったことが出来るようになります。

ロボットの動作パターンは、例えばプログラムの中に記述してしまい、AKI-H8に初めっから書き込んでしまうのが簡単ですが、ちょっとした動作の修正を行なったり、色々なパターンを試したりしたいような場合に、いちいちコンパイルして書き込み直すのは面倒です。また、AKI-H8のフラッシュROMには書き込み回数に寿命があることを考えると、やはり通信でデータを与えてあげるのがスマートです。

AKI-H8/3048Fには、シリアルポートが2ポートあり、このうちポート1のチャンネルが通常プログラム書き込みの際に接続しているポートです。今回は、この開発環境をそのまんま利用して、パソコンとAKI-H8の間でデータ通信を行なう方法をご紹介します。

ハードウエアについては、電子回路編3.AKI-H8開発キットの回路[6]RS232Cポートコネクタの項目を参照して下さい。

【先頭に戻る】


109−1.シリアル通信とは

通信にはパラレル(並列)通信というのもあります。パソコンのプリンタポートなどがその例になります。機器間でデータのやりとりを行う場合、通常1バイト単位以上で行ないます。この場合、8bit分全部を一度にやり取りするのがパラレル(並列)通信です。パラレル通信は8bitものデータを一度にやり取りするため通信速度が速いのですが、沢山の芯数のケーブルが必要になるため、ガサバる方式です。

今回はシリアル(直列)通信を行ないます。パソコンのシリアルポートとの通信なので、RS-232Cという信号規格に基づくことになります。シリアル通信では、1本の信号線で1bitずつ順番にデータを送り出します。受ける側も1bitずつ受け取り、8bit分が揃ったところで1バイトのデータとして取り扱います。

これはAKI-H8開発ボード側の接続図です。CN5がパソコンのシリアルポートに繋がり、CN4がAKI-H8に繋がります。シリアル通信では、通常受け用の回線RxDと、送り用の回線TxDの2本で通信を行ないます。この他に、パソコン側から見てRTSは「データを送りたいんだけど、そっちの準備はいい?」と相手に対してこちらからの送信を要求する信号で、CTSに信号が入力されると「データを送ってもいいよ!」という相手からの合図になります。で、ここで初めてデータ送信動作に入ります。こういったデータ通信に絡んで準備の確認をしあうことをハンドシェイクと言います。

AKI-H8開発ボードとパソコンとの通信では、ハンドシェイクは行なっていません。CN5の接続を見てもらうと分かりますが、RTSがCTSに直接繋がっています。これは、自分が出した送信許可の要求を、そのまんま相手からの送信許可として受け取ることになります。なので、お互いにデータ送受信の準備が間違いなくちゃんと出来ていることが、通信を行なう上での条件となります。(ソフトウエア上のやり取りでの対応もできます。)

ちなみにハンドシェイク線には、この他にDTR,DSRといった信号も良く使われますが、AKI-H8開発ボードでは使用していません。RS-232Cシリアル通信については、本屋さんで沢山文献があるので、そちらを参照してみて下さい。

【先頭に戻る】


109−2.ソフトウエアのご紹介

このプログラムは、シリアル通信初期化関数、1文字受信関数、1文字送信関数、そして文字列送信関数からなります。あと、タイマーによる時間稼ぎ関数や液晶表示関数も使用していますが、103.タイマーで正確な時間稼ぎをする、と108.開発キットの液晶表示器を使うの説明を参照して下さい。

このプログラムでは、パソコンのハイパーターミナルから16文字以下の半角文字を打ち込むと、その文字が1文字ずつAKI-H8開発キットの液晶表示器の1行目に表示されて行きます。そして、最後にパソコンでリターンを押すと、入力された文字列が液晶画面の2行目に一気に表示されます。同時にパソコンにも文字列を送信して、ハイパーターミナルの画面に表示させます。

実は基本の関数類は、またまた仙台電波高専電子制御工学科 熊谷研究室ホームページを参考にしながら作りました。というより、ほとんどそのまんまという方が正しいかもしれません。ただ、力弥が理解し易いような文法に書き直しているだけ、という感じです...。(熊谷先生すみませんm(_ _)m ) 

ソースプログラムは、ここをクリックするとダウンロードできます。(sertest1.c) 以下に掲載しているプログラムでは、時間稼ぎ関数類と液晶表示関数類を省いていますが、ダウンロードできるソースプログラムにはちゃんと載ってるので、確実に動作します。

なお、スタートアップオブジェクトは、今回割込みを利用していないので、startup.marで結構です。(ちなみに割込み対応のstartup2.marでも問題なく動作します)

/**************************************************/
/* シリアル通信テスト           RIKIYA 2000/05/19 */
/*                                     sertest1.c */
/*                                      H8-3048/F */
/* パソコンのハイパーターミナルでシリアル通信を   */
/* 行なう。AKI-H8側はSCIチャンネル1を使い、開発時 */
/* と同じ環境で通信する。                         */
/* 通信条件は以下の通り                           */
/*    ボーレート 9600bps                          */
/*    データ長 8bit                              */
/*    ストップビット 1                            */
/*    パリティ 無し                              */
/*    フロー制御 無し                            */
/*************************************************/

#include <3048f.h>

/*メイン関数 ***************************************/
void main(void){

     int i;
     char rx_data;
     char tx_data[16];

     timer_init();                          /* タイマー初期化           */
     lcd_init();                            /* LCD初期化                */
     sci1_init();                           /* sci1初期化               */

     sci1_strtx("ARE YOU READY?");          /* パソコンにメッセージ送信 */
     lcd_locate(0,1);
     lcd_print("OK! READY GO!");            /* 液晶にメッセージ表示     */


     while(1){
          for(i=0;i<16;i++){                /* tx_data[]の初期化        */
               tx_data[i] = '\0';
          }
          i = 0;                            /* 変数iで文字数を数える    */
          lcd_locate(0,0);                  /* 液晶表示位置指定         */
          sci1_tx('\r');                    /* パソコンカーソル先頭     */
          sci1_tx('\n');                    /* パソコン改行             */

          /* リターンが入力されるまでの処理 */
          do{
               rx_data = sci1_rx();         /* 1文字受信                */
               if(rx_data != '\r'){
                    sci1_tx(rx_data);       /* 1文字送信                */
                    lcd_write4(rx_data,1);  /* 1文字液晶表示            */
                    tx_data[i] = rx_data;   /* 1文字を文字列に格納      */
                    i++;                    /* iをプラス1する           */
               }
          }while(rx_data != '\r');          /* リターン入力を検出       */

          /* 入力された文字列を送信し、液晶表示する */
          sci1_tx('\r');                    /* パソコンカーソル先頭     */
          sci1_tx('\n');                    /* パソコン改行             */
          sci1_strtx(tx_data);              /* 文字列を送信する         */
          lcd_write4(0x01,0);               /* 画面クリア               */
          lcd_locate(0,1);                  /* 液晶表示位置指定2行目    */
          lcd_print(tx_data);               /* 液晶に文字列を表示       */
     }
}

/* シリアル通信初期化*******************************/
sci1_init(void){
     SCI1.SCR.BYTE = 0x00;                  /* SCI1設定 stop,内部クロック */
     SCI1.SMR.BYTE = 0x00;                  /* data8.stop1,pari non       */
     SCI1.BRR = 51;                         /* 9600bps                    */
     wait(1);
     SCI1.SCR.BYTE = 0x30;                  /* Tx,Rx有効 ,割込み無効      */
     SCI1.SSR.BYTE &= 0x80;                 /* エラーフラグのクリア       */
     return;
}

/* SCI1から1文字受信する****************************/
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文字送信する ******************************/
sci1_tx(char data){
     while(SCI1.SSR.BIT.TDRE == 0);         /*未送信データが送られるまで待つ */
     SCI1.TDR = data;                       /*送信データのセット          */
     SCI1.SSR.BIT.TDRE = 0;                 /*送信フラグのクリア          */
     return;
}

/* SCI1に文字列を送信する 文字列は'\0'で締めくくっておく*******/
sci1_strtx(char *str){
     while(*str != '\0'){                   /* 文字が\0になるまで繰り返す */
          sci1_tx(*str);                    /* 1文字送信                  */
          str++;                            /* 次の文字に移る             */
     }
     return;
}

【先頭に戻る】


109−3.ソフトウエアsertest1.cの説明

今回のソフトは、メイン関数がちょっとだけややこしいので、先にシリアル通信の各関数から動作をご紹介し、最後にメイン関数で全体の動作についてご紹介します。

 

■109−3−1.シリアル通信初期化関数 sci_init( );

sci1_init(void){
     SCI1.SCR.BYTE = 0x00;           /* SCI1設定 stop,内部クロック */
     SCI1.SMR.BYTE = 0x00;           /* data8.stop1,pari non       */
     SCI1.BRR = 51;                  /* 9600bps                    */
     wait(1);
     SCI1.SCR.BYTE = 0x30;           /* Tx,Rx有効 ,割込み無効      */
     SCI1.SSR.BYTE &= 0x80;          /* エラーフラグのクリア       */
     return;
}

ここでは、シリアル通信ポートの初期化を行なっています。初期化を行なう各レジスタについて以下にご説明します。

 

     SCI1.SCR.BYTE = 0x00;       /* SCI1設定 stop,内部クロック */

SCR(シリアルコントロールレジスタ)では、送受信動作とクロックの選択について設定します。各BITには以下の意味があります。

7 6 5 4 3 2 1 0
TIE RIE TE RE MPIE TEIE CKE1 CKE0

TIEは、送信データをセットするレジスタが空になった時に発生する割込みを許可(1)/禁止(0)します。

RIEは、データの受信時と受信エラー時に発生する割込みを許可(1)/禁止(0)します。

TEは、送信動作の許可(1)/禁止(0)を設定します。

REは、受信動作の許可(1)/禁止(0)を設定します。

MPIEは、マルチプロセッサ割込みを許可(1)/禁止(0)します。

TEIEは、送信終了時に送信データをセットするレジスタが空だった時に発生する割り込みを許可(1)/禁止(0)します。

CKE1、CKE0は、通信に使用するクロックの選択と、クロックの入出力動作を選択します。今回使用する調歩同期式モードでは、以下のような動作モードがあります。

CKE1 CKE0 説 明
0 0 内部クロック、SCK端子は入出力
0 1 内部クロック、SCK端子は出力
1 0 外部クロック、SCK端子は入力
1 1 外部クロック、SCK端子は入力

初期化の最初で、次のSMRの設定のために、全ての送受信動作と割込み動作を禁止しておきます。なので、SCRの設定は以下のようになります。

7 6 5 4 3 2 1 0
TIE RIE TE RE MPIE TEIE CKE1 CKE0
0 0 0 0 0 0 0 0

従って、 SCI1.SCR.BYTE = 0x00; です。 

 

     SCI1.SMR.BYTE = 0x00;       /* data8.stop1,pari non */

SMR(シリアルモードレジスタ)では、通信フォーマットと通信速度を決定するボーレートジェネレータのクロック選択を行ないます。各BITには以下の意味があります。

7 6 5 4 3 2 1 0
C/A CHR PE O/E STOP MP CKS1 CKS0

C/Aは、調歩同期式(0)/クロック同期式(1)の選択を行ないます。パソコンとの通信には調歩同期式を利用します。

CHRは、データビット長を選択します。8BIT(0)/7BIT(1)です。

PEは、パリティビットの付加とチェックを禁止(0)/許可(1)します。パリティビットとは、通信途中でビットが化けた場合に、誤りを検出するためのビットのことです。

O/Eは、パリティモードを偶数パリティ(0)/奇数パリティ(1)から選択します。これらは、それぞれパリティビットとデータビットの中の1の数が、合わせて偶数か奇数であることをチェックするものです。今回はパリティ自体を使用しないので、取りあえず関係ありません。

STOPは、STOPビットを1ビット(0)/2ビット(1)から選択します。

MPは、マルチプロセッサ通信機能を禁止(0)/許可(1)します。マルチプロセッサ機能については使用しないので、説明は省きます。

CKS1,CKS0は、内部ボーレートジェネレータに使用するクロックソースを選択します。

CKS1 CKS0 説 明
0 0 φクロック
0 1 φ/4クロック
1 0 φ/16クロック
1 1 φ/64クロック

今回の設定は、一般的によく使われる設定で、以下の通りとします。

7 6 5 4 3 2 1 0
C/A CHR PE O/E STOP MP CKS1 CKS0
0 0 0 0 0 0 0 0

調歩同期式、データ長8BIT、パリティなし、STOPビット1、そして、この後出てきますが、ボーレート9600bps。この設定は良く使われる設定で、またパソコン側もこの設定に合わせることになるので、良く憶えておいて下さい。

従って、SCI1.SMR.BYTE = 0x00;になります。

 

     SCI1.BRR = 51;             /* 9600bps */

BRR(ビットレートレジスタ)では、内部クロックφ(標準AKI-H8なら16MHz)と、SMRのCKS1,0で選択したクロックソースを元に、実際に必要なボーレートを得るための設定を行ないます。H8-3048Fの取り扱い説明書には一覧表が用意されていて、必要なボーレートに設定するためのパラメータが載っています。本当はここにも載せたかったのですが、沢山あるので今回はパスします。

一覧表によれば、φ16MHzで、SMRのCKS1,0をφクロックに設定すると、BRRに51という数字を書き込めば9600bpsになります。

従って、SCI1.BRR = 51; です。

 

     wait(1);
     SCI1.SCR.BYTE = 0x30;         /* Tx,Rx有効 ,割込み無効 */

BBRを設定してから、1ビット期間待機する。とマニュアルに記載がありますので、大分多いのですが、wait(1);で1ms待ってからSCRの再設定に入ります。ここでは送信Txと受信Rxを有効にしています。ただし、割込み処理は無効のままです。SCRの各ビットは以下の通りになります。

7 6 5 4 3 2 1 0
TIE RIE TE RE MPIE TEIE CKE1 CKE0
0 0 1 1 0 0 0 0

なので、SCI1.SCR.BYTE = 0x30;となります。

 

     SCI1.SSR.BYTE &= 0x80;         /* エラーフラグのクリア */

SSR(シリアルステータスレジスタ)は、主にシリアルポートの状態を示しています。レジスタの各ビットは以下の意味です。

7 6 5 4 3 2 1 0
TDRE RDRF ORER FER PER TEND MPB MPBT
1 0 0 0 0 0 0 0

TDREは、送信データをセットするレジスタに、データ書き込みが可能である時に1になります。

RDRFは、受信が完了して、データ読み出しが可能な状態である時に1になります。

ORERは、受信時にオーバーランエラーが発生すると1になります。

FERは、受信時にフレーミングエラーが発生すると1になります。

PERは、パリティエラーが発生すると1になります。

TENDは、送信が終了すると1になります。

MPB、MPBTはマルチプロセッサ動作の時に使用します。今回は使用しません。

これらのビットは、上記の表の状態(TDREだけが1)が初期値です。もしエラービットのどれかが1になっていた場合は0(ゼロ)に戻し、また現在までのTDREの状態を保持させるための処理として、 SCI1.SSR.BYTE &= 0x80; を行なっています。

【先頭に戻る】


■109−3−2.sci1からの1文字受信関数 sci1_rx( );

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文字単位(アスキーコード)で行ないます。

 

     while((SCI1.SSR.BYTE & 0x78)==0); /* 受信とエラーのフラグが立つまで待つ*/

SSR(シリアルステータレジスタ)の各ビットには以下の意味がありました。

7 6 5 4 3 2 1 0
TDRE RDRF ORER FER PER TEND MPB MPBT
0 1 1 1 1 0 0 0

で、0x78 は上の表のようなビットの対応となります。つまり、SCI1.SSR.BYTE & 0x78とは、RDRFの受信フラグも、ORER,FER,PERの各エラービットも0(ゼロ)の場合だけ、答えが0(ゼロ)となります。なので、while((SCI1.SSR.BYTE & 0x78)==0); とは、「データを受信するか、受信エラーが発生するまで、時間を潰していなさい」という命令になります。

 

データを受信するか受信エラーが発生すると、次の命令文に進みますが、まだ正常な受信なのか、エラーなのかが分からないため、以下のif文に進みます。

     if(SCI1.SSR.BIT.RDRF == 1){          /* データ受信が正常           */
          data = SCI1.RDR;                /* データを受け取りdataに保存 */
          SCI1.SSR.BIT.RDRF = 0;          /* 受信フラグのクリア         */
          return(data);
     }

ここでは、RDRFフラグを見て、1なら正常なデータ受信であると判断しています。そして、if文の中で、RDR(レシーブデータレジスタ)に格納されているデータを、変数dataに入力します。データ読み込み後は、受信フラグを0(ゼロ)に戻して次の受信に備えます。最後にreturn(data);文で、この関数の戻り値として、変数dataの中身つまり受信したデータを戻してあげます。

 

一方、先ほどのif文で、RDRFフラグが1じゃなかった場合は、エラーが発生していたことになります。今回のプログラムでは、エラーが発生していたとしても特別な処理はしないで、ただエラーフラグをクリアして、戻り値としてFFを戻してあげるだけにしておきます。

     else{ /* データ受信にエラー発生 */
          SCI1.SSR.BYTE &= 0xc7;          /* エラーフラグをクリア */
          return(0xff);                   /* エラー時はFFを返す   */
     }

SSR
(シリアルステータレジスタ)の各ビットには以下の意味がありました。

7 6 5 4 3 2 1 0
TDRE RDRF ORER FER PER TEND MPB MPBT
1 1 0 0 0 1 1 1

つまり、SCI1.SSR.BYTE & = 0xc7; とすると、エラービット以外は状態が保持されて、ORER,FER,PERの各エラービットだけが強制的に0(ゼロ)になります。ちなみに、A &= B という書き方は、A = A & B を省略した書き方です。

【先頭に戻る】

 

■109−3−3.sci1への1文字送信関数 sci1_tx( data );

sci1_tx(char data){
     while(SCI1.SSR.BIT.TDRE == 0);     /*未送信データが送られるまで待つ*/
     SCI1.TDR = data;                   /*送信データのセット */
     SCI1.SSR.BIT.TDRE = 0;             /*送信フラグのクリア */
     return;
}

ここでは、引数で受け取るdataというデータを、アスキーコード1文字分としてsci1から送信します。

     while(SCI1.SSR.BIT.TDRE == 0);     /*未送信データが送られるまで待つ*/
SSR
(シリアルステータレジスタ)のTDREビットは、送信データをセットするレジスタが空である時に1になるのでした。なので、 while(SCI1.SSR.BIT.TDRE == 0);は、「送信データをセットするレジスタが空になるまで時間を潰していろ」という命令文になります。TDREビットが1になると、次の命令文に進むことができます。

 

     SCI1.TDR = data;                   /*送信データのセット*/
TDR
(トランスミットデータレジスタ)は、送信データをセットするレジスタです。ここではTDRに、送信したいデータdataをセットします。このタイミングでは、まだ送信動作に入りません。

 

     SCI1.SSR.BIT.TDRE = 0;             /*送信フラグのクリア*/
次にTDREを0(ゼロ)にセットします。このタイミングでTDRにセットしたデータが、実際に送信動作を行なうTSR(トランスミットシフトレジスタ)に転送されます。TSRへの転送が終了するとTDREが1にセットされ、次の送信データのセットが可能になります。

【先頭に戻る】

 

 

■109−3−4.sci1への文字列送信関数 sci1_strtx( *str )

sci1_strtx(char *str){
     while(*str != '\0'){               /* 文字が\0になるまで繰り返す */
          sci1_tx(*str);                /* 1文字送信                  */
          str++;                        /* 次の文字に移る             */
     }
     return;
}

ここでは、引数で受け取った文字列 *str(実際はポインタ変数)の、1文字目から連続して送信して行き、最後のNULL(ヌル)文字で動作を終了させます。ヌル文字とは「何もないよ」という意味の文字(?)で、記号'\0'で表します。C言語で文字列を設定すると、最後の文字の後ろに自動的に付加されます。(と思った...) なので、文字列の終了を検出するために使用します。

そして先ほどの 1文字送信関数 sci1_tx( );  を使って、*strという1文字を送信しています。*strstrとは、*strという文字データが格納されているメモリ上のアドレスを示しているので、str++とやると、次のアドレスに移動(次の文字へ移動)ということになります。ちなみに、str++ は、str = str + 1 という意味です。これをヌル文字になるまで繰り返すと、文字列の送信が終了します。

【先頭に戻る】

 

■109−3−5.メイン関数の説明

お疲れ様です。シリアル通信のための関数の説明が終わりましたので、ようやくメイン関数のご紹介に移りましょう。だらだらと説明が長くてすみませんでした...。

     int i;
     char rx_data;
     char tx_data[16];

先ず始めに、関数内で使用する変数の宣言を行ないます。i は数を数えるための汎用変数。rx_dataは受信した文字を格納する変数。tx_data[16]は、tx_data[0]から[15]まで最大16文字分の文字列が格納できる配列変数です。

 

     timer_init();       /* タイマー初期化 */
     lcd_init();         /* LCD初期化      */
     sci1_init();        /* sci1初期化     */

次に、タイマー、液晶表示器、シリアルポートの各初期化を行ないます。

 

     sci1_strtx("ARE YOU READY?");    /* パソコンにメッセージ送信 */
     lcd_locate(0,1);
     lcd_print("OK! READY GO!");      /* 液晶にメッセージ表示     */

ここから実際の動作に入ります。まず、プログラムがしっかり動き、シリアル通信もちゃんと出来ていることを確認するため、パソコン(ハイパーターミナル)には「ARE YOU READY?」というメッセージを表示させ、液晶表示器には「OK! READY GO!」などと表示させてみます。AKI-H8の電源を入れてもこれらの表示がされない場合は、何か問題があるということです。

 

     while(1){

ここからは、while(1){  }の中の処理を繰り返します。

 

          for(i=0;i<16;i++){         /* tx_data[]の初期化     */
               tx_data[i] = '\0';
          }

          i = 0;                     /* 変数iで文字数を数える */

始めに、変数の初期化をします。文字列変数16文字分の中身を全てヌル文字に初期化し、汎用の変数 i も0(ゼロ)としておきます。


          lcd_locate(0,0);           /* 液晶表示位置指定      */
          sci1_tx('\r');             /* パソコンカーソル先頭  */
          sci1_tx('\n');             /* パソコン改行          */

次に、液晶表示器の文字表示位置を、左端の1行目にセットします。また、パソコンに対してリターン\rと改行\nの制御コードを送信します。これで、ハイパーターミナルのカーソル位置は、1行改行された左端にセットされます。


          /* リターンが入力されるまでの処理 */
          do{
               rx_data = sci1_rx();          /* 1文字受信           */
               if(rx_data != '\r'){
                    sci1_tx(rx_data);        /* 1文字送信           */
                    lcd_write4(rx_data,1);   /* 1文字液晶表示       */
                    tx_data[i] = rx_data;    /* 1文字を文字列に格納 */
                    i++;                     /* iをプラス1する      */
               }
          }while(rx_data != '\r');           /* リターン入力を検出  */

次に、パソコンからの文字を受信します。rx_data = sci1_rx(); で1文字受信したら、sci1_tx(rx_data);で、すぐにパソコンに受信した文字を投げ返します。そして、lcd_write4(rx_data,1);で液晶表示器にも同じ文字を表示させて、 tx_data[i] = rx_data; で、今受信した文字を文字列変数に保存していきます。do{  }while(rx_data != '\r'); は、これを\r(リターン)が送られてくるまで繰り返すという意味です。

なお、 if(rx_data != '\r'){  } は、リターンが送られてきた時に、文字の返信や表示、および文字列への格納をしないための判断文です。rx_dataがリターンじゃなければ{  }の中身を実行するという意味です。

 

          /* 入力された文字列を送信し、液晶表示する */
          sci1_tx('\r');                     /* パソコンカーソル先頭 */
          sci1_tx('\n');                     /* パソコン改行         */
          sci1_strtx(tx_data);               /* 文字列を送信する     */
          lcd_write4(0x01,0);                /* 画面クリア           */
          lcd_locate(0,1);                   /* 液晶表示位置指定2行目*/
          lcd_print(tx_data);                /* 液晶に文字列を表示   */

リターンが押されたら、パソコンからの文字列入力が終了したと判断し、今度は入力された文字列を一気にパソコンに送信し、同時に液晶表示器の2行目にも文字列を表示させます。

これで一連の動作が終了し、再びパソコンから文字列が入力されるのを待つ状態になります。

【先頭に戻る】


109−4.ソフトsertest1の動作説明

さて、このソフトの動作をご紹介しましょう。ここでは、パソコンの通信ソフト「ハイパーターミナル」の設定からお話しますが、TekuRobo工作室での開発環境であるWindows2000での例ということになります。Windows98やNTなどでは、もしかしたら違うかも知れないので、個別にハイパーターミナルのヘルプなどを参照して下さい。

新しい接続 1.ハイパーターミナルを立ち上げる

スタート→プログラム→アクセサリ→通信→ハイパーターミナルとたどってハイパーターミナルを立ち上げると、左図の画面が現れます。この画面で新しい接続の設定、つまりAKI-H8との通信設定を行なっていきます。

取りあえず、接続の名前に「AKI-H8」と入力してOKを押します。

ポートの選択 2.パソコンの通信ポートを設定する

AKI-H8と接続しているパソコンのシリアルポートを設定します。ここでは「接続方法」欄にCOM1を選択しました。ポート番号は、皆さんの環境に合わせて選んでください。

設定したらOKを押します。

通信の設定 3.通信の設定をする

それぞれの設定を以下のようにします。

ビット/秒 9600

データビット 8

パリティ なし

ストップビット 1

フロー制御 なし

これらの設定って、どこかで見たことありませんか?そう、シリアル通信初期化の関数 sci1_init( );で行なった設定と一緒なんです。つまり、パソコンとAKI-H8の通信条件をここで合わせるのです。この設定を間違えると、プログラムが動きません。

設定したらOKを押します。

 

ハイパーターミナル準備OK 4.ハイパーターミナル準備完了

これでハイパーターミナルの準備が完了しました。次の立ち上げからは、スタートからたどって、「AKI-H8」という接続名のハイパーターミナルを選べばOKです。

では、AKI-H8との接続を確認したら、AKI-H8の電源を入れてみましょう。もちろん、AKI-H8には、先ほどのsertest1.motがインストールされていなければいけませんよ。

ARE YOU READY? 5.AKI-H8の電源を入れる

AKI-H8の電源を入れると、左図のようにメッセージが表示されます。このとき、液晶表示器には以下のようなメッセージが表示されます。

OK READY GO

 

文字入力 6.キーボードから文字を入力する

ここでは一気に「TEKUROBO」と入力しました。まだリターンは押していません。ハイパーターミナルに表示されている「TEKUROBO」は、AKI-H8から送り返した文字です。パソコン側で勝手に表示させている訳ではありませんよ。このとき、液晶表示器は以下のように表示されます。

液晶へ文字表示

リターンを押した動作 7.リターンを押して文字列を確定してみる

さて、文字列を入力したらリターンキーを押してみましょう。今度は1文字ずつではなく、文字列が一気にパソコン上に表示されます。

このとき、液晶表示器は以下のように表示されます。

文字列確定の液晶表示

再び文字列入力 8.再び同じ動作を繰り返す

以上の動作を延々と繰り返します。今度は続けて「KOUSAKU」と入力して見ました。あとは気が済むまで楽しんでください。(すぐに飽きる...)

このとき、液晶表示器は以下のように表示されます。

再び文字入力の液晶表示

【先頭に戻る】


非常にダラダラと長いページになってしまいました。ごめんなさい。m(_ _)m

長くなりすぎて要点がはっきりしなくなってしまった感じもありますが、要はシリアル通信とは基本的には1文字分のデータずつしかやり取りできないということです。連続した文字列を送信したり受信したりする場合には、ソフトウエア的に工夫してあげなければいけません。

取りあえずは、ここでご紹介した関数を使えば、簡単なデータのやり取りがすぐにできるでしょう?でも、ここでご紹介した関数には、ある弱点があります。それは1文字受信関数ですが、相手からデータが送られてくるまで、ひたすら待ち続けるということです。つまり、相手から声を掛けられるまで他の仕事が手につかず、ただボーっと待っているのです。これだけでは効率の良いソフトは作れませんね。

そこで登場するのが割込み処理です。つまり、普段は他の仕事をしていて、相手から声を掛けられたら受信の動作に入るようにするのです。これが出来れば結構自由度の高いソフトが作れると思いませんか? それは次回にご紹介することにします。

長いページを最後までお付き合いして頂きまして、ありがとうございました。お疲れ様でした。m(_ _;m

 

【ソフトウエア編TOPに戻る】


【表紙に戻る】