プロが教えるわが家の防犯対策術!

UARTから送られてきたデータとチェックサム(16進2桁)をPIC側で計算して、
間違えがないかチェックしたいのですが、
sscanfをPIC18F26K22, MPLAB X IDE v5.20とXC8 v2.05にて動くか書いてみましたが、
ビルドが通りませんでした。

sscanfをコメントアウトするとビルドが通るのでPICでサポートしていないみたいです。

本題です。

例えば、送られてきたデータとチェックサムが下記のように配列に格納されていて、
チェックサムの文字をそのまま16進の文字として扱うにはどのようにすればいいでしょうか?
よろしくお願いします。

配列:char deta[6] = {"GGAE2E"}; // 最後の2文字がチェックサムです。

質問者からの補足コメント

  • うーん・・・

    >16進文字(char) → 対応するint への1桁だけ変換する関数

    この処理部はできましたが、int型の変数、例:「int tmp;」に変換して、
    char deta[6] = {"GGAE2E"}; のGGAEから算出したチャックサムが入っている
    int型の変数、例:「int check = 0x7e;」と比較したいです。

    sprintfだと配列に数値が入りますので、単純にifで比較できませんでした。

    ここの処理がうまくゆけば完成なのですが・・・

    大変恐縮ですが、ご教示いただけないでしょうか。

    No.1の回答に寄せられた補足コメントです。 補足日時:2019/07/25 16:41
  • 訂正します。
    >この処理部はできましたが、2つのint型の変数を1つの変数、例:「int tmp;」に変換して。

      補足日時:2019/07/25 17:09

A 回答 (5件)

「結合前」の値を見ればわかるはずなんだけど, 「文字コード」と「数値としての値」が違うということは理解できていますか?

    • good
    • 0
この回答へのお礼

あ、数字の部分は、2は数値で0x32ですね!
アルファベットの部分は大文字のEは数値では、0x45で、
数値に変換するには、0x37を引けばいいんですね!

こんな単純なことに気が付かないとは(^_^;)

お礼日時:2019/07/26 16:44

文字コードが ASCII であると仮定したうえでたぶんだいたい余計な話.



文字をその文字コードで比較するなら
if (deta[len - 2] >= 0x30 && deta[len - 2] <= 0x39)
よりも
if (deta[len - 2] >= '0' && deta[len - 2] <= '9')
あるいは
if ('0' <= deta[len - 2] && deta[len - 2] <= '9')
のように文字定数を使った方がいい.

さらに, 「おかしなデータがやってくることはない」という前提で話をするなら
if (deta[len - 2] >= 0x30 && deta[len - 2] <= 0x39) {
tmp1 = deta[len - 2];
}else{
tmp1 = deta[len - 2] + 0x20; // 大文字を小文字に変換
}
(を適当になおすことにして) よりも
tmp1 = deta[len-2];
if (tmp1 > '9') {
tmp1 += 10 - 'A';
}
tmp1 &= 0x0f;
の方が (じっと見ないとわからないけど) 簡単かもしれない.

ちなみに「データ」は英語で
data
と書く (ふだん使わないけど単数形は datum).
    • good
    • 0

上位1桁目をint tmp1に


下位1桁目をint tmp0に
代入したら、 2桁の16進数は tmp1 * 0x10 + tmp0 (あるいは、シフト演算を使って tmp1 << 4 + tmp0) になる、ということはご理解いただけますか?


10進数 で 十の位 が4 一の位が 7 なら、 4 × 10 + 7 = 47 です。
16進数でも考えは同じです。


> sprintfだと配列に数値が入りますので、単純にifで比較できませんでした。

何の事を言っているのか、何故急にsprintfが出てきたのかわかりませんが。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
VC2017上で書いてみましたが出力が、0x385となってしまいます。

ソースを記載しますので誤っている箇所をご指摘願います。

int main() {

char deta[7] = { "GGAE2E" }; //0x32:0x45(小文字は0x65)

int len = 0;

int tmp1 = 0;
int tmp0 = 0;
int tmp2 = 0;


len = strlen(deta);


if (deta[len - 2] >= 0x30 && deta[len - 2] <= 0x39) {
tmp1 = deta[len - 2];
}else{
tmp1 = deta[len - 2] + 0x20; // 大文字を小文字に変換
}

if (deta[len - 1] >= 0x30 && deta[len - 1] <= 0x39) {
tmp0 = deta[len - 1];
}else{
tmp0 = deta[len - 1] + 0x20; // 大文字を小文字に変換
}

printf("len:%d\n\n",len);
printf("結合前:0x%x:0x%x\n",tmp1,tmp0);
tmp2 = (tmp1 * 0x10) + tmp0;
printf("結合:0x%x\n\n",tmp2);

while (1) {}

}

お礼日時:2019/07/25 23:24

なければ作ればいい.



今の場合は sscanf ほどの汎用性は必要じゃないだろうし, そもそもこのデータだと sscanf は使えないはず.
    • good
    • 0
この回答へのお礼

回答有難うございます。
質問には記載していませんが、チェックサム部だけを別配列に代入する処理があります。

お礼日時:2019/07/25 16:27

変換関数を自作しましょう。



16進文字(char) → 対応するint への1桁だけ変換する関数が作れれば、それを組合せれば2桁の16進数文字列から整数に変換できます。
この回答への補足あり
    • good
    • 0
この回答へのお礼

回答有り難うございます。
補足いたしましたのでよろしくお願いします。

お礼日時:2019/07/25 16:42

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!