関連:
シリアル通信関連記事一覧さすがにこのペースで説明資料を作成するのはキツイものがあります。
お盆最終日です。気合を入れていきましょう。
シリアル通信の設定(3)送受信フォーマットの取り決めで導入したSUMについて
送信するときに付加するだけだったので受信時に自動チェックするようにします。
受信した文字列を突っ込めば、OK:1 NG:0で結果が返ってくる関数を作ります。
文字列の処理
[HELLO WORLD1C]を受信した状況を考えてみます。
これが
_sci1_rx_data[0]~
_sci1_rx_data[14]に格納されます。
実際にSUMとして計算した部分は
[HELLO WORLD1C]この部分です。
また、
[HELLO WORLD1C]この部分のみを切り出して比較する必要があります。
これらの処理を行うために
文字列の切り出し処理と
文字列(16進数表記)を数字に変換する処理が必要になります。
文字列の切り出し処理には
strncpyを使用します。
文字列を数字に直す処理には
strtolを使用します。
strncpyの動作
strncpy(
コピー先の先頭アドレス,
コピー元の先頭アドレス,
コピーする文字数);
コピー先の先頭アドレスは置いといて、コピー元の先頭アドレスの指定が重要になってきます。
[HELLO WORLD1C]がこのように格納されているとします。
ポインタの解説で
bufと書くと先頭アドレスとして
buf[0]の番地が指定できるという説明をしました。今回の状況で指定したいのは
buf[1]の番地です。ではどうするのか。
buf+1と書くと
buf[1]の番地扱いになります。
15文字受信したうち、今回取得したいのは’
[’、’
]’、’
1’、’
C’の
4つを除外した
11文字です。今回使うSUMの方式では受信文字が増減したとしても切り出すべき文字数は
受信文字ー4となります。
ついでにSUM部分の切り出しも考えておきます。
切り出すべきはこの部分です。
これは結論だけ言えば、先頭アドレスは
buf+受信文字数-3となります。切り出すべき文字数は2で固定です。
strncpyは指定数分文字をコピー(上書き)する処理です。'
\0'が付加されない点に注意が必要です。
自前で'
\0'を付加してください。
strtolの使い方
文字を数字に直すのにstrtolを使用します。
strtol(
変換元の文字列,
変換できなかった文字のコピー場所,
10進数とか16進数とか);
変換できなかった文字のコピー場所は今回放置します。0を入れとけばコピーされなくなります。
10進数とか16進数とかには16表記の文字を変換したいので16としておきます。
ただ、毎回0とか16とか書くとめんどくさいので、intSCI.hで
#define strto0x(s) strtol(s,0,16)と定義してstrto0x(s)を使いまわします。
SUMチェック関数
上記文字列処理を踏まえて関数を作成します。
<設定>int check_sum(char *buf){
char check_buf[255];
//文字列部分のみ切り出し用 char sum_c[3];
//SUM部分のみ切り出し用 int len;
int sum1;
int sum2;
len=strlen(buf);
//文字数を取得 if(len<4)
//短すぎて計算できない return -2;
if(len>255)
//長すぎて計算できない return -2;
if( buf[0]!=STX0 && buf[0]!=STX1 )
//フォーマットが違う return -1;
if( buf[len-1]!=ETX0 && buf[len-1]!=ETX1 )
//フォーマットが違う return -1;
strncpy( check_buf, buf+1, len-4 );
//純粋な文字部分を切り出し check_buf[len-4]='\0'; sum1=calc_sum(check_buf);
//SUMを計算 strncpy( sum_c, buf+len-3, 2 );
//SUM部分を切り出し sum_c[2]='\0'; sum2=strto0x(sum_c);
//SUMを数値に変換 if(sum1==sum2)
//SUMが一致する return 1;
else
return 0;
}
<解説>
短すぎる、長すぎる場合は計算しないようにしています。
また、STX、ETXがフォーマットと異なる場合もSUMの計算を行いません。
strncpyの後には
自前で'\0'を追加しています。
intSCI.hでcheck_sum関数のプロトタイプ宣言が必要です。
メイン処理
受信した文字列に OK、NGの判定を付けて送り返します。
<設定>#include "iodefine.h"
#include <stdio.h>
#include "io_setup.h"
#include "intSCI.h"
void main(){
char recive_buf[255];
char trans_buf[255];
hardware_setup();
//汎用IOの初期化 init_SCI1();
//シリアル通信1の初期化 write_sci1_sum("HELLO WORLD");
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チェック合格 sprintf(trans_buf,"%s sum check OK\n",recive_buf);
else
//SUMチェック不合格 sprintf(trans_buf,"%s sum check NG\n",recive_buf);
write_sci1(trans_buf);
//受信した文字を送り返す }
//end get_recive_f }
//end while}
//end main<解説>if(check_sum(recive_buf)==1)にはカッコ
{ }がついていません。
カッコ
{ }を付けない場合
if文の
直後に書かれた1行のみが実行されます。
else文についても同様です。
途中で行数を増やすと動作しなくなったり、ビルドが通らなくなったりします。
余程簡略化したい時以外はカッコ
{ }を付けるように心がけましょう。
TMZで
[HELLO WORLD1C]を送信すると
[HELLO WORLD1C] sum check OKが返ってくれば成功です。
わざとSUMを変えて
[HELLO WORLD1D]等と送ると
[HELLO WORLD1D] sum check NGが返ってきます。
TMZで
NGが赤くなるのはTMZの仕様(設定)です。