それでは、いつものようにプログラムを作成していきましょう。
まずは「init.h」に、通信の初期化設定に関する記述を追加します(ソースコード1)。
void init_sci(void); //通信初期化
続いて「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; //受信許可
}
void init_all(void)
{
……(中略)……
init_sci(); //SCIの初期化
}
SCIの初期化設定は、項目が多く複雑です。フローチャート(画像4)とソースコード2を照らし合わせながら、理解を深めてください。
フローチャートには記述されていませんが、シリアル通信の設定の前に、必ずスタンバイコントロールレジスタ(STB.CR)の_SCI1ビットを「0」にクリアしておきましょう。これは、マイコンの消費電力を抑えるために、デフォルトではクロックが使える状態になっていないからです。
もう1つ分かりにくいのが、通信速度の設定です。シリアル通信の通信速度は、周辺クロック「PΦ」に依存します。Pi:Co Classicに搭載されているCPUボード(STK-7125)の仕様を確認すると、周辺クロックは24MHzです。
通信速度はビットレートレジスタ(SCBRR)に設定します。この時、Tera Termに表示していた38400ビットの値ではなく、ルネサス エレクトロニクスのWebサイトからダウンロードしたデータシートの表にある「N(ボーレートジェネレータのSCBRRの設定値)」を設定します。すなわち、今回の場合は「19」になります(画像5)。
画像5の表には38400ビットまでしか記述されていないので、それよりも速い通信速度を設定したい場合は、データシートに記載されている計算方法で設定値を算出してください。
通信ステータスをどこからでも呼び出せるように「common.h」へ定義すれば、シリアル通信の設定は完了です(ソースコード4)。
//通信ステータス #define COM_OK 0 //送信OK #define COM_ERR -1 //送信ERROR
通信ドライバの作成の前に、データ表示の仕様を決めておきましょう。
今回は、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 //送信タイムアウトカウンタ
「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; //タイムアウト
}
「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;
}
そこで、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;
}
/************************************************/
/* 通信処理(数値送信) (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;
}
よし! これでPC側へデータを送信できるようになったよ。
今度こそ、PCのモニターにセンサー値を表示できますね!
そうだね。前回作ったアプリケーションに、通信コントローラを追加するだけだから、カンタンだよ。
なら、すぐに作って、動かしてみましょうよ!
Copyright © ITmedia, Inc. All Rights Reserved.
組み込み開発の記事ランキング
コーナーリンク