メイン処理で動作を確認してみます。
<設定>#include "iodefine.h"
#include <stdio.h>
#include "io_setup.h"
#include "intSCI.h"
void main(){
short data[16]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
char recive_buf[255];
char trans_buf[255];
short ID;
short DLC;
hardware_setup();
//汎用IOの初期化 init_SCI1();
//シリアル通信1の初期化 send_data_sci1(0x10,10,data);
//専用フォーマットでデータ送信 while(1){
//無限ループ開始 if(get_recive_f(1)){
//SCI1で新しく受信したか確認 get_recive_buf(1,recive_buf);
//受信データをrecive_bufにコピー clr_recive_f(1);
//受信完了フラグをリセット if(check_sum(recive_buf)==1){
//SUMチェック合格 ID=
str_to_num(recive_buf,1,2);
//IDを取得 DLC=
str_to_num(recive_buf,3,2);
//DLCを取得 sprintf(trans_buf,"%s sum check OK ID:%02X DLC:%02X\n",recive_buf,ID,DLC);
}else{
//SUMチェック不合格 sprintf(trans_buf,"%s sum check NG\n",recive_buf);
}
write_sci1(trans_buf);
//受信した文字を送り返す }//end get_recive_f
}
//end while}
//end main<解説>フォーマットから外れているデータを解析すると危険なので、SUMチェックが合格した
もののみ解析を行います。
IDのある場所とDLCのある場所は決まっているので直接指定してあります。
TMZで動作確認してみます。
[100A00010203040506070809BF]を送信しすると
[100A00010203040506070809BF] sum check OK ID:10 DLC:0Aが返ってきて正常に変換できたことが分かります。
試しに
[HELLO WORLD1C]を送信すると
[HELLO WORLD1C] sum check OK ID:00 DLC:00が返ってきました。
16進数以外の文字は変換できずに変換結果は0になります。
データ保存用変数
受信した文字データを数値化しますが、数値化したデータを保存する変数を作っておきます。
<設定>#define MAX_RECIVE_DATA 10
//とりあえず10 ID分のデータを記録するstatic unsigned char
_recive_dlc[MAX_RECIVE_DATA];
//DLCstatic unsigned char
_recive_data[MAX_RECIVE_DATA][20];
//受信データ 20個static unsigned long
_recive_time[MAX_RECIVE_DATA];
//最終受信時刻static unsigned char
_recive_timeout[MAX_RECIVE_DATA];
//受信タイムアウト<解説>受信データ
_recive_data以外にも最終受信時刻
_recive_timeを記録します。
また、最終受信から一定時間(500ms)経過して次の受信が無い場合はデータをリセットするようにします。
最終受信時刻から
一定時間経過した場合はタイムアウトフラグ
_recive_timeoutを
1にします。
本当は
構造体で作りたかったのですが、構造体の説明を用意していなかったので、グローバル変数で作成しておきます。
これらの
変数の初期化関数を以下とします。
<設定>//受信データ1セット分を初期化void init_recive_data(int data_num){
int i;
_recive_dlc[data_num]=0;
_recive_time[data_num]=0;
_recive_timeout[data_num]=1;
for(i=0;i<20;i++){
_recive_data[data_num][i]=0;
}
}
//受信データ全部を初期化void init_recive_data_all(void){
int i;
for(i=0;i<MAX_RECIVE_DATA;i++){
init_recive_data(i);
}
}
また、タイムアウトのチェックには
タイマ割り込み(
intCMT.c、
intCMT.h)にて作成した関数
getsystime()を使用します。
<設定>//各データごとのタイムアウトチェックvoid check_timeout(int data_num){
if(_recive_timeout[data_num]==1)
//元々タイムアウトしている場合 return;
if(_recive_time[data_num]+500<
getsystime()){
init_recive_data(data_num);
_recive_timeout[data_num]=1;
}
}
//全データのタイムアウトチェックvoid check_timeout_all(void){
int i;
for(i=0;i<MAX_RECIVE_DATA;i++){
check_timeout(i);
}
}
_recive_data、
_recive_dlc、
_recive_timeoutをそれぞれ呼び出す関数も作成します。
//受信データを指定して取得unsigned char get_recive_data(int data_num,int data_pos){
if(_recive_dlc[data_num]<data_pos)
return -1;
//ありえない位置を参照した return
_recive_data[data_num][data_pos];
}
//受信データ長を取得unsigned char get_recive_dlc(int data_num){
return
_recive_dlc[data_num];
}
//タイムアウト状態を取得unsigned char get_recive_timeout(int data_num){
return
_recive_timeout[data_num];
}
これでデータ保存先の準備ができました。
解析関数
冒頭でテストした
if(get_recive_f(1)){}の中身は
main関数内で見える必要はありません。
そこでSUMチェックやら数値変換やらをひとまとめに実行する関数を作成します。
先ほど通信に使ったIDをdefineしておきます。
<設定>#define ID_OPE 0x10 //操作情報用通信ID
#define DATA_NUM_OPE 0 //操作データ保管No.
<設定>//受信データの解析(定期的に実行されることが前提)short analysys_sci(short port){
char recive_buf[255];
short len;
//文字列長 short rtn;
//関数の戻り値 short ID;
short DLC;
check_timeout_all();
//タイムアウトをチェックする if(get_recive_f(port)){
//SCI1で新しく受信したか確認 get_recive_buf(port,recive_buf);
//受信データをrecive_bufにコピー clr_recive_f(port);
//受信完了フラグをリセット if(check_sum(recive_buf)==1){
//SUMチェック合格 len=strlen(recive_buf);
ID=str_to_num(recive_buf,1,2);
//IDを取得 DLC=str_to_num(recive_buf,3,2);
//DLCを取得 if(ID==0x00)
return 0;
//文字列を受信した if(len!=(1+2+2+DLC*2+2+1))
//文字数が一致しないSTX+ID+DLC+データ+SUM+ETX return -2;
switch(ID){
//この中に各IDにおける解析処理を追加していく case ID_OPE:
rtn=
analysys_0x10(recive_buf,ID,DLC); //ID:0x10に対する解析処理 break;
default:
rtn=ID;
break;
}
//end ID return rtn;
}
//end check_sum return -1;
//受信したけどSUMチェックが不合格 }
//end get_recive_f return 0;
//受信していない}
メインの解析処理を以下とします。
<設定>short analysys_0x10(char *buf,int id,int dlc){
int i;
int data_num=DATA_NUM_OPE;
if(id!=
ID_OPE) return -3;
//一致しないはずがないのでプログラムミス _recive_dlc[data_num]=dlc;
//DLCを格納 _recive_time[data_num]=getsystime();
//最終受信時刻を更新 _recive_timeout[data_num]=0;
//タイムアウトフラグを解除 for(i=0;i<dlc;i++){
if(i>20)
return ID_OPE;
//多すぎたら終了 _recive_data[data_num][i]=str_to_num(buf,1+2+2+i*2,2);
//受信データを順次格納 }
return
ID_OPE;
}
<解説>この関数を実行できた時点で正常受信が成功しているので、最終受信時刻を更新して、タイムアウトフラグを解除します。
send_data_sci1と対になる関数
(2017/08/16追記)
send_data_sci1で送信したデータをrecv_data_sci1で取得できるようにしてみます。
//専用フォーマットでデータをまるごと取得void recv_data_sci1(int id,int dlc,short*data){
int data_num;
int i;
if(id>255) return;
//IDがおかしいので終了 if(id<0) return;
if(dlc<0) return;
//DLCがおかしいので終了 if(dlc>100) return;
switch(id){
//この中に各IDに対するデータ番号を追記していく case ID_OPE:
data_num=DATA_NUM_OPE;
break;
default:
//登録が無いので終了 return;
break;
}//end ID
if(get_recive_timeout(data_num)==0){
//操作情報がタイムアウトしていない for(i=0;i<dlc;i++){
data[i]=get_recive_data(data_num,i);
//受信したデータを取得0-255 }
//end for }else{
//操作情報がタイムアウトしている for(i=0;i<dlc;i++){
data[i]=0;
//0に設定する }
//end for }
//end get_recive_timeout}
<解説>
名前にsci1が入っていますが、あまり関係ありません。送信側と名前を統一したかっただけです。
ここまで作成した関数はすべてintSCI.hでプロトタイプ宣言しておく必要があります。
かなり時間がかかりましたが、
以上でシリアル通信を使ったデータ送受信の設定は終わります。
最終的にできたファイルは以下となります。
シリアル通信ソースファイル:
intSCI.cシリアル通信ヘッダファイル:
intSCI.h
動作確認
とりあえず正常に受信データの解析ができるか試してみます。
<設定>#include "iodefine.h"
#include <stdio.h>
#include "io_setup.h"
#include "intSCI.h"
#include "intCMT.h"
void main(){
short data[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
char transbuf[255];
int rtn;
hardware_setup();
//汎用IOの初期化 init_SCI1();
//シリアル通信1の初期化 send_data_sci1(ID_OPE,10,data);
//専用フォーマットでデータ送信 while(1){
//無限ループ開始 rtn=analysys_sci(1);
//受信チェック if(rtn==ID_OPE){
sprintf(transbuf,"recive ID:0xX%02X DLC:%d %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X"
,rtn
,get_recive_dlc(DATA_NUM_OPE)
,get_recive_data(DATA_NUM_OPE,0)
,get_recive_data(DATA_NUM_OPE,1)
,get_recive_data(DATA_NUM_OPE,2)
,get_recive_data(DATA_NUM_OPE,3)
,get_recive_data(DATA_NUM_OPE,4)
,get_recive_data(DATA_NUM_OPE,5)
,get_recive_data(DATA_NUM_OPE,6)
,get_recive_data(DATA_NUM_OPE,7)
,get_recive_data(DATA_NUM_OPE,8)
,get_recive_data(DATA_NUM_OPE,9)
);
write_sci1(transbuf);
//解析結果を送り返す }
//end ID_OPE }
//end while}
//end main起動時に送られてくるデータ
[100A00010203040506070809BF]はフォーマット通りに設定された電文です。
これをTMZからSH7125へ送り返せば解析ができます。
recive ID:0x10 DLC:10 00 01 02 03 04 05 06 07 08 09正常に解析できていれば成功です。
次回はマイコン同士で通信を行い、遠隔操作をやってみます。