シリアル通信でセンサー値をPCのモニターに出力しよう!マイクロマウスで始める組み込み開発入門(11)(2/3 ページ)

» 2013年03月05日 10時00分 公開
[三月兎,MONOist]

 それでは、いつものようにプログラムを作成していきましょう。

 まずは「init.h」に、通信の初期化設定に関する記述を追加します(ソースコード1)。


void init_sci(void);        //通信初期化
ソースコード1 「init.h」に通信の初期化設定を追加する

 続いて「init.c」に、SCIの初期化設定(ソースコード2)を記述し、全てのハードウェアの初期化を行うinit_all関数に通信の初期化(ソースコード3)を追加します。

void init_sci(void){
    //
    STB.CR3.BIT._SCI1 = 0;        //SCIのスタンバイを解除
    //
    SCI1.SCSCR.BIT.RIE  = 0;      //受信割り込み
    SCI1.SCSCR.BIT.TIE  = 0;      //送信割り込み
    SCI1.SCSCR.BIT.TEIE = 0;      //送信終了割り込み
    SCI1.SCSCR.BIT.MPIE = 0;      //MP割り込みイネーブル
    SCI1.SCSCR.BIT.TE   = 0;      //送信動作
    SCI1.SCSCR.BIT.RE   = 0;      //受信動作
    //
    SCI1.SCSCR.BIT.CKE  = 0;
    //
    SCI1.SCSMR.BIT.CA   = 0;      //調歩同期式モード
    SCI1.SCSMR.BIT.CHR  = 0;      //8ビット
    SCI1.SCSMR.BIT._PE  = 0;      //パリティ禁止
    SCI1.SCSMR.BIT.OE   = 0;      //偶数
    SCI1.SCSMR.BIT.STOP = 0;      //1ストップビット
    SCI1.SCSMR.BIT.MP   = 0;      //マルチプロセッサモード禁止
    SCI1.SCSMR.BIT.CKS  = 0;      //クロックセレクト
    //
    SCI1.SCBRR = 19;              //PΦ=24MHz ボー・レート=38400bps
    //
    PFC.PACRL2.BIT.PA4MD = 1;     //TXDポート設定
    PFC.PACRL1.BIT.PA3MD = 1;     //RXDポート設定
    //
    SCI1.SCSCR.BIT.TE    = 1;     //送信許可
    SCI1.SCSCR.BIT.RE    = 1;     //受信許可
}
ソースコード2 「init.c」に、SCIの初期化設定関数init_sciを作成する。1ビット期間経過の部分は省略。また、割り込みを使用しないので、画像4のフローチャート[5]の部分も一部省略している

void init_all(void)
{
 
 ……(中略)……
 
    init_sci();        //SCIの初期化
}
ソースコード3 「init.c」のinit_all関数にSCIの初期化を追加

 SCIの初期化設定は、項目が多く複雑です。フローチャート(画像4)とソースコード2を照らし合わせながら、理解を深めてください。

SCIの初期化フローチャート 画像4 SCIの初期化フローチャート(SH7125グループハードウェアマニュアルより抜粋)

 フローチャートには記述されていませんが、シリアル通信の設定の前に、必ずスタンバイコントロールレジスタ(STB.CR)の_SCI1ビットを「0」にクリアしておきましょう。これは、マイコンの消費電力を抑えるために、デフォルトではクロックが使える状態になっていないからです。

 もう1つ分かりにくいのが、通信速度の設定です。シリアル通信の通信速度は、周辺クロック「PΦ」に依存します。Pi:Co Classicに搭載されているCPUボード(STK-7125)の仕様を確認すると、周辺クロックは24MHzです。

 通信速度はビットレートレジスタ(SCBRR)に設定します。この時、Tera Termに表示していた38400ビットの値ではなく、ルネサス エレクトロニクスのWebサイトからダウンロードしたデータシートの表にある「N(ボーレートジェネレータのSCBRRの設定値)」を設定します。すなわち、今回の場合は「19」になります(画像5)。

ビットレートに対するSCBRRの設定例 画像5 ビットレートに対するSCBRRの設定例(SH7125グループハードウェアマニュアルより抜粋)

 画像5の表には38400ビットまでしか記述されていないので、それよりも速い通信速度を設定したい場合は、データシートに記載されている計算方法で設定値を算出してください。


 通信ステータスをどこからでも呼び出せるように「common.h」へ定義すれば、シリアル通信の設定は完了です(ソースコード4)。

//通信ステータス
#define    COM_OK        0        //送信OK
#define    COM_ERR      -1        //送信ERROR
ソースコード4 「common.h」に通信ステータスを記述

 通信ドライバの作成の前に、データ表示の仕様を決めておきましょう。

 今回は、A/D変換したセンサー値をPCのモニターに出力させますが、数値だけを表示しても、それがどのセンサーの値なのか分かりません。そのため、フォーマットを「文字列:00000」とし、4つあるセンサーの区別が付くようにします。

 ここで作る通信ドライバと通信コントローラは、センサー値だけでなく、マイクロマウスのバッテリー残量、デバッグモードで走行中のモータ速度や回転角度の表示にも使用します。そのため、データの表示を5桁にしてあります。

 データ表示の仕様を決定したところで、通信ドライバの作成に入ります。「drv.h」に、通信ドライバと通信ポートの送受信フラグ、送信タイムアウトカウンタの定義を追加します(ソースコード5)。

int  drv_com_send(char);    //通信ドライバ(1文字送信)
 
//通信ポート
#define    COM_SEND_FLG        SCI1.SCSSR.BIT.TDRE   //送信フラグ
#define    COM_SEND_DATA       SCI1.SCTDR            //送信データ
#define    COM_RECV_FLG        SCI1.SCSSR.BIT.RDRF   //受信フラグ
#define    COM_RECV_DATA       SCI1.SCRDR            //受信データ
//通信用定数
#define    COM_TO_COUNT        2000000               //送信タイムアウトカウンタ
ソースコード5 「drv.h」に通信ドライバ、送受信フラグ、送信タイムアウトカウンタを定義する

 「drv.c」に1文字ずつデータを送信する通信ドライバ「drv_com_send」を作成します(ソースコード6)。

/************************************************/
/*  通信ドライバ(1文字送信) (drv_com_send)  */
/************************************************/
/*  1文字送信する                               */
/*----------------------------------------------*/
/*  IN :char i_char …… 送信する文字           */
/*  RET:int …… 通信ステータス                 */
/*  COM_OK (0):正常                           */
/*  COM_ERR (-1):エラー                      */
/************************************************/
int drv_com_send(char i_char)
{
    //通信ドライバ(1文字送信)
    int i;
    //
    for(i = 0; i < COM_TO_COUNT; i++)
    {
        if(COM_SEND_FLG)                    //フラグ確認
        {
            COM_SEND_DATA = i_char;         //送信データ書き込み
            COM_SEND_FLG = 0;               //フラグクリア
            return COM_OK;
        }
    }
    return COM_ERR;                         //タイムアウト
}
ソースコード6 1文字ずつデータを送信する通信ドライバ関数を作成

 「ctrl.c」に、データを通信ドライバに渡すctrl_com_send関数を作成します(ソースコード7)。先ほど、データ表示の仕様で定めたように、送信データは文字列と数字で構成されています。A/D変換したセンサー値はint型なので、文字として表示するためにstring型に変換する必要があります。

/************************************************/
/* 通信処理(文字列、数値送信)(ctrl_com_send)*/
/************************************************/
/*  文字列を送信する                            */
/*----------------------------------------------*/
/*  IN:char *i_string …… 文字列              */
/*  int   i_int        …… 数値                */
/*  RET:int           …… COM_OK(0):正常   */
/*  COM_ERR(-1):エラー                       */
/************************************************/
int ctrl_com_send(char *i_string, int i_int)
{
    //通信処理(文字列、数値送信)
    int stat = COM_OK;
    //
    stat = ctrl_com_string(i_string);
    if(stat == COM_OK)
    {
        stat = ctrl_com_int(i_int);
    }
    //
    return stat;
}
ソースコード7 ここでは文字列と数値を分けて、それぞれの通信処理関数を呼び出している

 そこで、ctrl_com_send関数内では、文字列と数値を分けて送信します(ソースコード8ソースコード9

/************************************************/
/*  通信処理(文字列送信) (ctrl_com_string)  */
/************************************************/
/*  文字列を送信する                            */
/*----------------------------------------------*/
/*  IN:char *i_string …… 文字列              */
/*  RET:int …… COM_OK(0):正常             */
/*  COM_ERR(-1):エラー                       */
/************************************************/
int ctrl_com_string(char *i_string)
{
    //通信処理(文字列送信)
    int i;
    int stat = COM_OK;
    //
    for(i = 0; i < 1024; i++)
    {
        if(*i_string == 0)
        {
            //\0で終了
            break;
    }
        stat = drv_com_send(*i_string);    //1文字送信
        if(stat == COM_ERR)
        {
            break;
        }
        i_string++;
    }
    return stat;
}
ソースコード8 文字データを1文字分ずつ分け、drv_com_send関数でPC側へ送信

/************************************************/
/*  通信処理(数値送信) (ctrl_com_int)       */
/************************************************/
/*  intを文字に変換して送信する                 */
/*----------------------------------------------*/
/*  IN:int i_int …… 数値                     */
/*  RET:int …… COM_OK(0):正常             */
/*  COM_ERR(-1):エラー                       */
/************************************************/
int ctrl_com_int(int i_int)
{
    //通信処理(数値送信)
    int i;
    int stat = COM_OK;
    char buf[6];
    int sign;
    char numStr[10] = "0123456789";
    //
    if(i_int < 0)
    {
        sign = -1;
    }
    else
    {
    sign = 1;
    }
    i_int = i_int * sign;
    //
    if(sign >= 0)
    {
        buf[0] = ' ';
    }
    else
    {
    buf[0] = '-';
    }
    buf[1] = numStr[(int)(i_int / 10000)];
    buf[2] = numStr[(int)((i_int % 10000) / 1000)];
    buf[3] = numStr[(int)((i_int % 1000) / 100)];
    buf[4] = numStr[(int)((i_int % 100) / 10)];
    buf[5] = numStr[(int)(i_int % 10)];
    //
    for(i = 0; i < 6; i++)
    {
        stat = drv_com_send(buf[i]);        //1文字送信
        if(stat == COM_ERR)
        {
            break;
        }
    }
    //
    return stat;
}
ソースコード9 int型のデータをstring型に変換した後に、1文字分ずつ分け、drv_com_send関数でPC側へ送信

表示アプリケーションの作成

北上

よし! これでPC側へデータを送信できるようになったよ。


えみ

今度こそ、PCのモニターにセンサー値を表示できますね!


北上

そうだね。前回作ったアプリケーションに、通信コントローラを追加するだけだから、カンタンだよ。


えみ

なら、すぐに作って、動かしてみましょうよ!



Copyright © ITmedia, Inc. All Rights Reserved.