少々謎の残るシリアル通信(UART)を設定します。
関連:
・
コード生成(準備編)・
コード生成(PWM編)・
コード生成(AD編)・I2Cスレーブ(
現象、
対策)
UARTについて、送信のみ、受信のみの設定もできる様ですが
今回は送受信両方設定します。
通信設定は好みに合わせて調整してください。
今回はいつも通り
38400,Even,8,1
にします。
送信と受信で独立した設定になっているので設定忘れに注意
生成されたコードの実行
例によって生成されたコードを見てみます。
ファイル→コード生成→r_cg_sau.c
PWMのコード生成により6つの関数が作成されました。
void R_SAU0_Create(
void)
・シリアル全般の初期化
・自動実行される
void R_UART0_Create(
void)
・UARTの初期化
・自動実行される
void R_UART0_Start(void)・UART開始
void R_UART0_Stop(
void)
・UART停止
MD_STATUS R_UART0_Send(uint8_t * const tx_buf, uint16_t tx_num)・データ送信
・
送信データ(文字列)と
送信データ数を指定
MD_STATUS R_UART0_Receive(uint8_t * const rx_buf, uint16_t rx_num)・データ受信
・
受信データ格納先と
受信文字数を指定?
受信機能に謎が残りますが、とりあえずは送信機能を試してみます。
<設定:送信テスト>#include "iodefine.h"
//端子の基本設定読み込み#include "r_cg_macrodriver.h"
//uint16_tとか読み込み#include "r_cg_wdt.h"
//ウォッチドッグタイマー#include "r_cg_sau.h" //UART設定void user_main(void){
char trans_buf[50]="RL78G10 connected\n";
//送信バッファ long i;
R_UART0_Start(); //UART開始
R_UART0_Send((unsigned char *)trans_buf,18); //送信
while(1){
for(i=0;i<100000;i++);
//空ループ trans_buf[0]='t';
trans_buf[1]='e';
trans_buf[2]='s';
trans_buf[3]='t';
trans_buf[4]='\r';
trans_buf[5]='\n';
R_UART0_Send((unsigned char *)trans_buf,6); //送信 R_WDT_Restart();
//ウォッチドッグタイマーリセット }
}
送信はいたって素直。
受信動作の確認
少々謎の残る受信動作をテストします。
MD_STATUS R_UART0_Receive(uint8_t * const rx_buf, uint16_t rx_num)実際にこの関数を使ってみると分かりますが、これは
受信したデータを取得する関数
ではありません。従って、この関数を
定期的に実行しても受信できません。
この関数は受信データの格納先を指定する関数です。
uint8_t * const rx_buf格納先の先頭アドレス
uint16_t rx_num格納可能な最大データ数
ウォッチ機能を使って受信バッファがどうなるか確認してみます。
<受信設定>#include "iodefine.h"
//端子の基本設定読み込み#include "r_cg_macrodriver.h"
//uint16_tとか読み込み#include "r_cg_wdt.h"
//ウォッチドッグタイマー#include "r_cg_sau.h" //UART設定char recv_buf[50]={0};
//受信バッファvoid user_main(
void){
R_UART0_Start(); //UART開始 R_UART0_Receive((unsigned char *)recv_buf,50); //受信格納先設定 while(1){
R_WDT_Restart();
//ウォッチドッグタイマーリセット }
}
メインループに入る前に受信設定を行います。
メインループではウォッチドッグタイマークリア以外何もしません。
これを実行して動作を確認します。
USBシリアル変換モジュールといつもの
TMZを使ってPCからRL78へデータを送信します。
TMZの通信設定もUARTの設定に合わせて
38400,
Even,8,1とします。
また、改行コードとして送信の終わりにCR(\r:0x0d)とLF(\n:0x0a)を付加します。
TMZを使ってPCから"test1" "test2"という電文を送ります。
ウォッチで受信バッファを確認すると
メインループで何も処理をしなくても、PCから電文を送る度に受信データが自動的に
バッファへ格納されていきます。
実際の受信処理はr_cg_sau_user.cのstatic void __near r_uart0_interrupt_receive(void)にて
行われている様です。
受信処理の作成
受信動作は確認できましたが、このままでは受信バッファが埋まってしまいます。
r_uart0_interrupt_receiveを改造すればSH等で作成した受信処理を
一時的には再現
できるのですが、r_uart0_interrupt_receiveにはユーザー用の編集領域が無いため
UARTとは全く関係ない機能であっても
コード生成を実行すると強制的に初期状態に戻されてしまいます。場合によってはUART部分はコード生成機能を一切使用せず、
独自でコードを作成した方が良いかもしれません。
今回RL78は
ちょっと利用する程度に考えており、なるべくコード生成を使う方向で
プログラムを作成してみます。
SHやRXでは
stdio.hをincludeして
sprintfを使っていました。小型マイコン向けに
sprintf_tinyという軽量版が用意されているのですが、RL78の場合
sprintf_tinyを使
おうとするとそれだけで10Y47なら
ROMの約40%、10Y16だと
ROMの約80%も消費
してしまいます。
流石にこれだけ消費されると他に何もできません
従って、sprintfを使わない処理方法が必要です。
動作の方針
文字列の送受信を前提として改行コード(\n)を受信した時点で受信完了と判定し、
受信文字を取得する事を目的として作成してみます。
また、ついでに文字列のみを指定して送信する関数も作っておきます。
初期化処理1)UART開始
2)受信処理を初期化
連続処理3)1文字以上受信したことを確認
4)最終受信データが改行コード(\n)であるか確認
5)受信文字数分のデータをバッファから別のバッファへコピー
6)受信処理を初期化
とします
これに対して
1)はR_UART0_Startを使用
2)6)はR_UART0_Receiveおよびmemset(string.h)を使用
3)はg_uart0_rx_countを利用
4)受信バッファのg_uart0_rx_count-1番目のデータと比較
5)はmemcpy(string.h)を使用
とします。
本当は
移植するときに困るのですが、g_uart0_rx_countに対しての処理が必要なので
とりあえずr_cg_sau_user.cへ記述します。
受信データの格納バッファは_recv_bufとしました。
<設定>/* Start user code for include. Do not edit comment generated here */#include <string.h>
/* End user code. Do not edit comment generated here */・
・
・
/* Start user code for global. Do not edit comment generated here */char _recv_buf[50];
//受信バッファ/* End user code. Do not edit comment generated here */・
・
・
/* Start user code for adding. Do not edit comment generated here *///受信バッファを設定する関数void init_recv_buf(
void){
memset(_recv_buf,0,50);
//受信バッファクリア R_UART0_Receive((
unsigned char *)_recv_buf,50);
//受信設定}
//受信文字数を取得する関数int get_recv_len(
void){
return g_uart0_rx_count;
//受信文字数を戻す}
//最終文字を取得する関数char get_char_last(
void){
return _recv_buf[g_uart0_rx_count-1];
//最終受信文字を戻す}
//受信完了を確認する関数(戻り値:受信完了文字数)int check_recv_fin(
void){
char ch_last;
//最終受信文字格納先 int count=get_recv_len();
//受信文字数を取得 if(count<=0)
return 0;
//受信していない ch_last=get_char_last();
//最終受信文字を取得 if(ch_last=='\n')
return count;
//受信完了 return 0;
//受信完了していない}
//受信データを取得する関数(戻り値:受信完了文字数)int get_recv_buf(
char* buf){
int recv_len=check_recv_fin();
if(recv_len>0){
//受信完了時 memset(buf,0,50);
//格納先バッファクリア memcpy(buf,_recv_buf,recv_len);
//コピー init_recv_buf();
//受信バッファを再設定 return recv_len;
//受信文字数を戻す }
return 0;
}
//送信関数void send_buf(
char* buf){
int send_len=strlen(buf);
//文字数を取得 R_UART0_Send((
unsigned char *)buf,send_len);
//送信}
/* End user code. Do not edit comment generated here */プロトタイプ宣言はとりあえずr_cg_sau.hへ記述しておきます。
/* Start user code for function. Do not edit comment generated here */void init_recv_buf(
void);
int get_recv_len(
void);
char get_char_last(
void);
int check_recv_fin(
void);
int get_recv_buf(
char* buf);
void send_buf(
char* buf);
/* End user code. Do not edit comment generated here */E1を使わなくても動作確認ができるようにメイン関数での処理にて受信した文字列を
そのまま送り返してみます。(ループバック)
#include "iodefine.h"
//端子の基本設定読み込み#include "r_cg_macrodriver.h"
//uint16_tとか読み込み#include "r_cg_wdt.h"
//ウォッチドッグタイマー#include "r_cg_sau.h"
//UART設定void user_main(
void){
char buf[50];
//受信バッファ R_UART0_Start();
//UART開始 init_recv_buf(); while(1){
if(
get_recv_buf(buf)>0){
//受信処理 send_buf(buf); //送り返す }
R_WDT_Restart();
//ウォッチドッグタイマーリセット }
}
PCから送信した文字列(改行コードLF付)がそのまま戻ってくれば成功です。
今回はざっくり作ったので汎用性はありませんが、文字列の送受信機能を確認
することができました。
気が向いたらXBeeのAPI受信プログラムを公開します。