シリアル通信でセンサー値をPCのモニターに出力しよう!:マイクロマウスで始める組み込み開発入門(11)(2/3 ページ)
市販の組み立てキットを用い、小さくて賢いロボット「マイクロマウス」の開発に取り掛かった北上くんとえみちゃんは、サンプルのソースコードに頼らない、オリジナルプログラムを作成中。今回は、前回取得したセンサーの値を「シリアル通信」でPCのモニターに表示させる。
それでは、いつものようにプログラムを作成していきましょう。
まずは「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.