忍者ブログ

Fグループ電子工作講座

秋月電子SH7125ボードで始めるマイコン開発

シリアル通信の設定(5)SUMチェック

関連:シリアル通信関連記事一覧

さすがにこのペースで説明資料を作成するのはキツイものがあります。
お盆最終日です。気合を入れていきましょう。

シリアル通信の設定(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の仕様(設定)です。
PR

コメント

プロフィール

HN:
ぼんどF博士
性別:
男性
自己紹介:

最新コメント