RX621でシリアル通信したcsvファイルを分割したい

お世話になっております。現在、PCとRX621間でBluetoothを用いたシリアル通信を行っています。

今、PC側に保存された5つのエクセルデータ(~.csv  //1秒ごとに値が更新されます。)

 

をTeraTermを用いてRX621に送信し、callbackでPC側に表示させることができました。(PC側のTeraterm上には -0.0611,0.0109,0.048,0.1388,0.3029と表示されていることから、シリアル通信はできていると思っています。)

次に、RX621が受信した上記のデータをカンマごとに区切り、A,B,C,D,Eのそれぞれに分けて計算をしたいと思っていますが、受信したデータを分割して配列するために、どのようなコードを記述すればよいか分かりません。ご教授お願いいたします。

 

念のために、以下にシリアル通信のプログラムを貼ります。RX621が受信したデータは "ch"に入れています。

unsigned char sci_recv(void)
{
unsigned char ch;

#ifdef USE_IR
while (IR(SCI1,RXI1) == 0) ;
#else
while (SCI1.SSR.BIT.RDRF == 0) ;
#endif

ch =SCI1.RDR;

#ifdef USE_IR
IR(SCI1,RXI1) = 0;
#endif
return ch;
}

 void sci_send(unsigned char ch)
{
#ifdef USE_IR
while (IR(SCI1,TXI1) == 0) ;
IR(SCI1,TXI1) = 0;
#else
while (SCI1.SSR.BIT.TDRE == 0) ;
#endif

SCI1.TDR = ch;
}

  • sscanf() が使えればそれを使うだけですね。

    $ cat -n test.c
         1  #include <stdio.h>
         2
         3  int main(void)
         4  {
         5      float a, b, c, d, e;
         6      const char data[] = "-0.0611,0.0109,0.048,0.1388,0.3029";
         7      sscanf(data, "%f,%f,%f,%f,%f", &a, &b, &c, &d, &e);
         8      printf("a = %f, b = %f, c = %f, d = %f, e = %f\n", a, b, c, d, e);
         9  }
    
    $ gcc -Wall -Wextra -O2 test.c ; ./a
    a = -0.061100, b = 0.010900, c = 0.048000, d = 0.138800, e = 0.302900
    
    $
  • わわいです
    CSVデータの分割、集計はSCIの動作とは関係ないですね
    SCIでは1行分のデータを受信し、そのデータをバッファに展開するところまでです。
    その後、バッファに溜まっているデータをCSVとして分解、集計という処理をすることになります
  • >fujita様、わわい様
    上記のサンプルを参考にプログラムを修正してみました。

    シリアル通信で受信したデータの内、1つだけ取り出して送信するというプログラムです。
    ①.シリアル通信で受信したcvsデータをdataに格納する。
    ②.配列Data[ ] に dataを代入する。
    ③.Data[ ] に入れたcvsデータをカンマ区切りにしてa~eの5つに分割する。
    ④.XにData[0] (=a)を代入する。
    ⑤.シリアル通信でXを送信する。

    配列?で間違ってると思うのですが、初心者なので、何がどう間違っているのかよく分かりません。

    エラーとしては156、157、159行で「実行文の後、宣言が現れないかもしれない」、警告としては161行で引数が非対応、144行でdataが設定されたが使われていない。

    144行目の警告ですが、while文内で使っているので、なぜこの警告が出るのか分かりません。


      void main(void)//メイン関数
      {
    144    unsigned char data; //受信データを格納する変数の宣言

       setup_clock();
       setup_port(); //ポートの振り分け
       setup_sci(); //シリアル通信の初期設定

       while(1){
       data = sci_recv(); //①受信したデータをdataに格納する

    156    float a, b, c, d, e;
    157  const char Data[] = "data" ; //②
    158  sscanf(Data,"%f,%f,%f,%f,%f", &a, &b, &c, &d, &e); //③
    159  float X= Data[0]; //④

    161  sci_send(X);  //⑤

       }

      }

  • CSV は 1行(=char の配列)にカンマで区切られて情報が配置されるので、1文字ごとに入力される文字を配列にまとめる必要があります。

    例えば

        const int CsvDataSize = 100;        // CSV データの最大文字数を 100と仮定
        char csvData[CsvDataSize + 1];
        int i;
    
        for (i = 0; i < CsvDataSize;) {
            int recievedChar;
            recievedChar = sci_recv();
            if (recievedChar == '\r' || recievedChar == '\n') {
                if (i > 0) {
                    break;
                }
            } else {
                csvData[i++] = (char)recievedChar;
            }
        }
        csvData[i] = '\0';
    

    こんな感じですね。

    > 配列?で間違ってると思うのですが、初心者なので、何がどう間違っているのかよく分かりません。

    Amazon 辺りで評判の良い C の入門書でも調べて読まれたらいかがですか。

  • ミントさん、こんにちは。NoMaYと申します。

    投稿されていたソースを見たのですが、最初の投稿時のソースは以下のスレッドを参照されたものかな、と思ったのですが、そこにfujitaさんのソースを嵌め込んだものを投稿されたのですよね。

    初歩の質問ですみません。シリアル通信ができません。
    RX621マイコンでのSCI通信について

    この嵌め込んだソースなのですが、動かないのは承知の上でコンパイル出来るかどうか見ようとしたら見知らぬワーニングが出たので質問をされた、というのではなくて、きっとこれで動くだろうと思ってコーディング/コンパイルしたらワーニングが出たので質問をされた、という経緯でしょうか? 後者だとすると、藤田さんが仰ったように、入門書を読まれた方が良いように思います。

    一応、もしかするとArduinoやmbedは経験済みで、その時のやり方が出てしまったのだろうか、とは思いましたので、それらのAPIを見てみたのですが、どうもそうでもないようですし、、、

    Arduino シリアルAPI
    garretlab.web.fc2.com/arduino_reference/.../serial/
    以下はGitHubにあるヘッダファイルです(上級者向けかと思うので灰色文字にしました)
    GitHub: HardwareSerial.h
    GitHub: Stream.h
    GitHub: Print.h

    mbed API
    docs.mbed.com/.../Serial/
    以下はGitHubにあるヘッダファイルです(上級者向けかと思うので灰色文字にしました)
    GitHub: SerialBase.h
    GitHub: Stream.h

    それで、144行目の「dataが設定されたが使われていない」というワーニングですが、注意して読むと気付くのですが、単に「使われていない」という警告では無く、「設定されたが使われていない」という警告であり、この時の「使われていない」というのは「参照されていない」という意味なのです。(⑤は元々はsci_send(data);だったかと思いますが、それに戻すと「参照されていない」状態が解消されるので出なくなります。もっとも、今度は④のfloat X= Data[0];のXが「参照されていない」状態になりますので、Xに対して同じ警告が出るようになりますが、、、)

    [余談]

    思うところあって、以下のソース(inoファイル)をArduino 1.8.3でArduino UNO用にコンパイルしてみたところ、インストール(私の場合は習慣でZIPファイルをダウンロードして解凍)した直後のArduino IDEの設定では、ワーニング無し、エラー無し、でコンパイルが通りました。

    void my_main(void)//メイン関数
    {
        unsigned char data; //受信データを格納する変数の宣言

        setup_clock();
        setup_port(); //ポートの振り分け
        setup_sci(); //シリアル通信の初期設定

        while(1){
            data = sci_recv(); //①受信したデータをdataに格納する

            float a, b, c, d, e;
            const char Data[] = "data" ; //②
            sscanf(Data,"%f,%f,%f,%f,%f", &a, &b, &c, &d, &e); //③
            float X= Data[0]; //④

            sci_send(X);  //⑤
         }
    }
    void setup() {my_main();}
    void loop() {}
    void setup_clock() {}
    void setup_port() {}
    void setup_sci() {}
    unsigned char sci_ch = '*';
    unsigned char sci_recv() {return sci_ch;}
    void sci_send(unsigned char ch) {sci_ch = ch;}

    画面コピー



    ただし「dataが設定されたが使われていない」というワーニングは、Arduino IDEの設定を変えてコンパイラの警告の設定を[より多く]もしく[全て]にすると、出るようになりました。とは言え、この設定を[全て]にした場合でも、出るワーニングは以下のこれのみでした。

    C:\Temp\UserName\arduino_modified_sketch_623403\sketch_jun10a.ino: In function 'void my_main()':

    C:\Temp\UserName\arduino_modified_sketch_623403\sketch_jun10a.ino:3:19: warning: variable 'data' set but not used [-Wunused-but-set-variable]

         unsigned char data; //受信データを格納する変数の宣言

                       ^

    画面コピー



  • こんにちは。

    本を買うしかなかった昔と違って、今ならウェブサイトも選択肢かと思い、少し探してみました。

    Google検索: C言語 入門 OR 学習 サイト

    パラパラっと見た印象では、以下の2つの昔ながらのウェブサイトが良さげでした。(ウェブサイトとしては、動画サイトやスライドサイトもあったのですが、有料コンテンツの一部を無料公開しているような雰囲気でしたので、そちらは全く見ませんでした。)


    苦しんで覚えるC言語
    9cguide.appspot.com/

    「苦しんで覚えるC言語(苦C)は、初心者を対象としたC言語入門サイトです。
    C言語の基本機能を体系立てて解説しており、市販書籍と同等以上の完成度です。」

    scanf関数(sscanf関数の同類)についてのページ

    strtok関数を利用する方法についてのページ

    Rulzのスレッドでのstrtok関数についてのトピックス(上級者向け)


    0から始めるC言語学習帳
    effy.ldw.jp/c/

    「本サイトは、ソフトバンク・パブリッシング(現ソフトバンク・クリエイティブ)より
    発刊されていた雑誌「Cマガジン」で私が2002年4月から1年間にわたって連載してきた
    C言語入門の記事を、編集部より許可を頂き加筆訂正し公開するものです。」

    scanf関数(sscanf関数の同類)についてのページ


    上に書いたウェブサイトの他にも、Rulzのページ上部のリンクを辿って、ルネサスさんの半導体セミナのテキストを閲覧出来るページへも行ったのですが、立ち読みコーナーというところで公開されていた以下のテキスト(PDF)を見た印象では、上に書いたウェブサイトが良さげでした。


    基礎技術セミナー(一部のみ公開)

    ・ プログラムを書くためのロジック思考入門
    ・ 組み込みC言語入門 ~文法編~
    ・ 組み込みC言語入門 ~実装編~
    ・ ポインタ徹底活用
    ・ C言語アドバンス

    はじめてシリーズ(一部のみ公開)

    ・ はじめてのC言語プログラミング

  • >fijitaさん、NoMaYさん

    C言語の本の紹介ありがとうございます。初心者向けの本を購入して読みました。

    CSVが文字列であるというヒントをうけて、まずは受信した文字列をカンマ区切りで配列に格納しようと考えました。

    sscanf(s, " " , …) ; の引数sの定義がconst char *というのは本で調べました。しかし、私のプログラムの場合、sに対応するのがdata = sci_recv()であるため、const char* 型にすることができません。


    unsigned char sci_recv(void)//シリアル通信受信関数
    {
    unsigned char data1; //受信したデータを格納する変数の宣言

    #ifdef USE_IR
    while (IR(SCI1,RXI1) == 0) ;
    #else
    while (SCI1.SSR.BIT.RDRF == 0) ;
    #endif

    data1 =SCI1.RDR; //格納したデータをdataに格納する

    #ifdef USE_IR
    IR(SCI1,RXI1) = 0;
    #endif

    return data1; //受信したデータを返す
    }


    void sci_send(char data)//シリアル通信送信関数
    {
    #ifdef USE_IR
    while (IR(SCI1,TXI1) == 0) ;
    IR(SCI1,TXI1) = 0;
    #else
    while (SCI1.SSR.BIT.TDRE == 0) ;
    #endif

    SCI1.TDR =data; //トランスミットデータレジスタに送信データを格納
    }


    void main(void)//メイン関数
    {
    char data; // 受信データ(文字列)を格納する変数の宣言
    char Data[5]; // 文字列をカンマ区切りした後に格納する配列の宣言

    setup_clock();
    setup_port(); // ポートの振り分け
    setup_sci(); // シリアル通信の初期設定

    while(1){
    data = sci_recv(); // シリアル通信で受信したデータ(文字列)をdataに格納する

    sscanf(data, "%c,%c,%c,%c,%c", &Data[0], &Data[1], &Data[2], &Data[3], &Data[4]); // 文字列dataをカンマで区切り、配列Dataに格納する

    sci_send(data); //dataをシリアル通信で送信する
    }

    }
  • > CSVが文字列であるというヒントをうけて、まずは受信した文字列をカンマ区切りで配列に格納しようと考えました。

        while(1){
           data = sci_recv();	// シリアル通信で受信したデータ(文字列)をdataに格納する
    

    「文字」と「文字列」が異なることに理解が及んでない様見受けられます。購入された本でその辺りの説明を良く読み直されることをお勧めします。

    なお、受信した「文字」を「文字列(=文字の配列)」に格納する方法は既に例示しています。

    japan.renesasrulz.com/.../22828

  • >fujitaさん
    japan.renesasrulz.com/.../22828

    ご教授いただいた上記のプログラムで疑問があります。
    char csvData[CsvDataSize + 1];
    が「式の値が定数ではない」というエラーがでたのですが、なぜ、char型の配列csvDataをだた宣言しただけであるのにエラーがでるのですか?
  • > なぜ、char型の配列csvDataをだた宣言しただけであるのにエラーがでるのですか?

    C 言語の仕様によっては配列の大きさを変数で指定できないので

        const int CsvDataSize = 100;        // CSV データの最大文字数を 100と仮定
    

        #define CsvDataSize 100        // CSV データの最大文字数を 100と仮定
    

    と修正してください。