Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page

シリアル通信の方法

はじめまして。以前にRX231を使ってPWM波形を出力する方法で質問させていただいたものです。

今度はシリアル通信(Uart)に挑戦しようと思って、まずは1バイトの文字を送ってその文字を受信する、

その次に任意のバイト数の文字列を送信し、それに応じてマイコンを動かすということを行いたいと考えているのですが、

1バイトの送受信が出来ずつまづいています。スマートコンフィグレータを使って生成されたコードを使って書いてますが、

ハードウェアマニュアルを読んでも具体的な書き方が分かりません。

下記どなたかご教授頂けないでしょうか?

何卒よろしくお願いします。

 

 

①自動生成された下記の関数の意味と使い分け

※SCI5を使用 

<Config_SCI5.c>

MD_STATUS R_Config_SCI5_Serial_Receive(uint8_t * const rx_buf, uint16_t rx_num)→受信データの処理関数?

MD_STATUS R_Config_SCI5_Serial_Send(uint8_t * const tx_buf, uint16_t tx_num)→送信データの処理関数?

<Config_SCI5_user.c>

static void r_Config_SCI5_receive_interrupt(void)→受信割り込み時の処理関数?

static void r_Config_SCI5_receiveerror_interrupt(void)→受信割り込みエラー時の処理関数?

static void r_Config_SCI5_transmit_interrupt(void)→送信割り込み時の処理関数?

static void r_Config_SCI5_transmitend_interrupt(void)→送信割り込み完了時?の処理関数?(上記の関数と何が違う?)

static void r_Config_SCI5_callback_transmitend(void)→送信完了時の何らかの関数?

static void r_Config_SCI5_callback_receiveend(void)→受信完了時の何らかの関数?

static void r_Config_SCI5_callback_receiveerror(void)→受信エラー時の何らかの関数?

 

②下記のようにプログラムを書きましたが、Teraterm上から送った1バイトの文字が無数に帰ってきます。

一旦受信したデータをバッファに置いて、送信する、という趣旨の書き方をしたいのですが、どのように

書けばよいのかも分かりません。

 

#define BUFFERSIZE 32

static int RxBuffer [BUFFERSIZE ];

void main(void)

{

      //InitとSCI5スタート

       R_Config_SCI5_Start(void)

       while(1)

       {

                receive();

                transmit();

        }

}

void recive(void)

{

      R_Config_SCI5_Serial_Receive(&RxBuffer ,1);

void transmit(void)

{

      R_Config_SCI5_Serial_Send(&RxBuffer, 1);

}

-----------------------------------------------------

下記自動生成されたコードの一部を編集してます。

static void r_Config_SCI5_receive_interrupt(void)
{
//if (g_sci5_rx_length > g_sci5_rx_count)
//{
//*gp_sci5_rx_address = SCI5.RDR;
//gp_sci5_rx_address++;
//g_sci5_rx_count++;
//}

  SCI5.TDR = SCI5.RDR;  //TDRにRDRを挿入し、受信データを返す。

//if (g_sci5_rx_length <= g_sci5_rx_count)
//{
/* All data received */
SCI5.SCR.BIT.RIE = 0U;
SCI5.SCR.BIT.RE = 0U;
r_Config_SCI5_callback_receiveend();
//}
}

 

static void r_Config_SCI5_transmitend_interrupt(void)
{
/* Set TXD5 pin */
PORTA.PMR.BYTE &= 0xEFU;

SCI5.SCR.BIT.TIE = 0U;
SCI5.SCR.BIT.TE = 0U;
SCI5.SCR.BIT.TEIE = 0U;

r_Config_SCI5_callback_transmitend();
}

 

  • 生成されたコードの続きです。

    MD_STATUS R_Config_SCI5_Serial_Receive(uint8_t * const rx_buf, uint16_t rx_num)
    {
    MD_STATUS status = MD_OK;

    if (1U > rx_num)
    {
    status = MD_ARGERROR;
    }
    else
    {
    g_sci5_rx_count = 0U;
    g_sci5_rx_length = rx_num;
    gp_sci5_rx_address = rx_buf;
    SCI5.SCR.BIT.RIE = 1U;
    SCI5.SCR.BIT.RE = 1U;
    }

    return (status);
    }

    MD_STATUS R_Config_SCI5_Serial_Send(uint8_t * const tx_buf, uint16_t tx_num)
    {
    MD_STATUS status = MD_OK;

    if (1U > tx_num)
    {
    status = MD_ARGERROR;
    }
    else
    {
    gp_sci5_tx_address = tx_buf;
    g_sci5_tx_count = tx_num;

    /* Set TXD5 pin */
    PORTA.PMR.BYTE |= 0x10U;

    SCI5.SCR.BIT.TIE = 1U;
    SCI5.SCR.BIT.TE = 1U;
    }

    return (status);
    }
  • R_Config_SCI5_Serial_Receive() に関する認識に問題があると思われます。
    この関数は、あくまで「受信設定(受信したデータ保存する場所と受信するバイト数の設定)」のみで、受信するまで待つことは有りません。

    したがって、main関数内のwhile文の中では、「受信した時の設定 → 送信開始」を常に繰り返しているので、受信したデータを延々と送信している状況です(最初のデータを受信する前は'\0"を出していたのでは?)。

    目的のプログラムにするには、while文の中を「受信設定 → 1バイト受信するまでWait → 受信した時に1度だけ送信を実施」とすれば良いと考えます。
  • In reply to YPekl39:

    チョコです。
    RXは使ったことがありませんが、ハードウェアから見た処理方法については、コメントできると考えて、コメントします。
    単に、受信したデータを送信するだけの処理であれば、全て受信割り込み処理だけで十分だと思います。
    提示された受信割り込みの中で受信データを送信用レジスタに書き込んで、その後に以下の処理を残していますが、この3行を削除すれば十分ではないでしょうか。
    SCI5.SCR.BIT.RIE = 0U;
    SCI5.SCR.BIT.RE = 0U;
    r_Config_SCI5_callback_receiveend();


    それと、main関数では単純にループするだけで、以下の処理は不要かと思います。
    receive();
    transmit();

    以上
  • YPekl39さん、こんにちは。NoMaYです。

    いろいろアドバイスがあると思いますが、私は、以下の投稿のようなコードを追加するのが良いのではないかなぁ、と思います、、、(以下はIICでの例ですがUARTでも同様です。また、RXスマートコンフィグレータでも同様です。)

    RX231のコード生成を用いた簡易IIC通信について
    japan.renesasrulz.com/cafe_rene/f/002-2095199602/6169/rx231-iic/34171#34171
    japan.renesasrulz.com/cafe_rene/f/002-2095199602/6169/rx231-iic/34173#34173
     「
    今回、送信完了/受信完了を待つ送信関数名/受信関数名の末尾に _UWT を付けてみました。(unlimited wait timeの意。また、先頭を R_ ではなくて U_ にしてあります。ちなみに、STM32CubeMXでは送信完了/受信完了を待たない関数の名前の末尾に _IT を付けるようでしたので、逆向きに(?)真似てみました。)


    以下は私のチョンボですね。


  • In reply to チョコ:

    チョコさん
    ご指摘ありがとうございます、やってみましたが駄目でした。デバッガーでブレークポイントを当てながら
    確認しましたが、R_Config_SCI5_Serial_Receive(uint8_t * const rx_buf, uint16_t rx_num)の関数を呼ばないと受信データが割り込みで呼ばれないようです。そのため何も受信されず、送信もされない状況です。
  • In reply to YPekl39:

    チョコです。
    おそらく、以下の2行を実行させることで受信と受信割り込みが許可されると思うのですが。
    これを最初にやっておけば、受信で割り込みが発生するのではないでしょうか。
    SCI5.SCR.BIT.RIE = 1U;
    SCI5.SCR.BIT.RE = 1U;

    同様に、送信は以下の処理を最初にやっておけば、送信動作が許可されるのでは。
    SCI5.SCR.BIT.TE = 1U;

    これで、データを受信すれば、受信割り込みが起動されるかと思います。後は、この状態が
    続いていれば、いいのではないでしょうか。
    (R_Config_SCI5_Serial_Receiveでのデータポインタやデータカウンタを使わなければ、上記の
    2行のだけでいいと思います。)
  • In reply to 吉光屋の次男坊:

    吉光屋の次男坊さん

    デバッガーで変数をウォッチ式で見ながら確認しました。

    >R_Config_SCI5_Serial_Receive() に関する認識に問題があると思われます。
    確かに、この関数は受信データのアドレスとバイト数を設定しているようです。

    >1バイト受信するまでWait → 受信した時に1度だけ送信を実施
    これはどう書けば良いのでしょうか?初心者すぎる質問ですみません。

    まず、受信割り込み処理関数を下記のように元の生成コードに戻しました。
    static void r_Config_SCI5_receive_interrupt(void)
    {
    if (g_sci5_rx_length > g_sci5_rx_count)
    {
     *gp_sci5_rx_address = SCI5.RDR;
     gp_sci5_rx_address++;
     g_sci5_rx_count++;
    }

    if (g_sci5_rx_length <= g_sci5_rx_count)
    {
     /* All data received */
     SCI5.SCR.BIT.RIE = 0U;
     SCI5.SCR.BIT.RE = 0U;
     r_Config_SCI5_callback_receiveend();
    }
    次に、メインの処理で

       unsigned int counter = 0;
    if ( MD_OK == R_Config_SCI5_Serial_Receive(&rBuff, 1) )
    {
    counter++;

    if ( counter == 1 )
    {
    R_Config_SCI5_Serial_Send(&rBuff, 1);
    counter = 0;
    }

    }
    のように設定しました。
    受信割り込みはかかり、static void r_Config_SCI5_receive_interrupt(void)の
    if (g_sci5_rx_length > g_sci5_rx_count)
    {
     *gp_sci5_rx_address = SCI5.RDR;
     gp_sci5_rx_address++;
     g_sci5_rx_count++;
    }
    の箇所にSCI5.RDRの値が入ることを確認しました。
    が、ここからが分からないところです。1バイト受信するまでWaitという書き方がこれらの関数を
    使ってどう書けばよいかわからないため、依然として送った1バイトのデータが無数に帰ってきたままです。
    送信割り込み関数の
    static void r_Config_SCI5_transmit_interrupt(void)
    {
    if (0U < g_sci5_tx_count)
    {
    SCI5.TDR = *gp_sci5_tx_address;
    gp_sci5_tx_address++;
    g_sci5_tx_count--;
    }
    else
    {
    SCI5.SCR.BIT.TIE = 0U;
    SCI5.SCR.BIT.TEIE = 1U;
    }
    }
    のelseに処理が移れば止まると思うのですが・・。
  • In reply to チョコ:

    チョコさん
    SCI5.SCR.BIT.RIE = 1U;
    SCI5.SCR.BIT.RE = 1U;
    SCI5.SCR.BIT.TE = 1U;
    もやってみましたが、TDRにRDRの値が入っている(デバッガーで確認)にも関わらず
    何もデータが返って来ない状況です。
  • In reply to YPekl39:

    r_Config_SCI5_callback_receiveend()が呼ばれたら、受信完了です。
    R_Config_SCI5_Serial_Receive()で指定したバッファに、長さ分のデータが格納された事になります。

    受信完了フラグを用意(要volatile宣言)して、receive()を以下のようにすれば、1バイトの受信ができます。

    receive()
    {
     受信完了フラグクリア
     R_Config_SCI5_Serial_Receive();
     受信完了フラグセット待ち
    }

    r_Config_SCI5_callback_receiveend()
    {
     受信完了フラグセット
    }

    なお、コード生成されたソースは元の状態に戻す必要があります。

    スマートコンフィグレータのAPIマニュアルを見てみましたが、1文字送信の使用例があるだけで、初心者が使うには、ちょっと使う敷居が高いですね。

  • Higetakaさん、皆様
    受信完了フラグをセットすることにより無事1バイトの送受信が出来るようになりました。
    これで次は文字列の送信に移れると思います。大変ありがとうございました。
    ただ仰られるようにAPI関数の使い方についてはサンプルコード等が無いと私のような初心者
    には時間だけ浪費して全く進まないという状況になってしまう可能性もあると感じました。
  • In reply to YPekl39:

    チョコです。
    何か食い違いがあるのではないかと思います。

    「スマートコンフィグレータ ユーザーズマニュアル RX API リファレンス編」(R20UT4360JJ0104)を参照しながらコメントを書いています。最初の書き込みにあった各関数の機能はこのマニュアルに記載されているので、参照してみてください。

    SCI5はスマートコンフィグレータのR_Config_SCI5_Createで初期設定を行います
    (これは、R_Systeminitから呼ばれるとマニュアルに書かれています)。
    その後main関数でR_Config_SCI5_Startを呼び出すことで動作準備状態(?)になります。

    その上で、R_Config_SCI5_Serial_Receiveでバッファやデータ数を設定して、SCI5の受信動作と、SCI5の受信割り込みを許可します。これで、SCI5はシリアル信号の受信待ちが始まります。決して、受信が完了して関数から戻るわけではありません。

    その後、シリアル信号のスタートビットを検出すると、受信動作が始まります。
    ストップビットまで1キャラクタの受信が完了すると、受信割り込みが発生し、r_Config_SCI5_receive_interruptが起動されます。割り込み処理では、バッファに受信データを格納し、データ数をカウントして、目的のデータ数の受信が完了したら、受信割り込みを禁止(SCI5.SCR.BIT.RIE = 0U;)し受信動作を停止(SCI5.SCR.BIT.RE = 0U;)してからr_Config_SCI5_callback_receiveend()を呼び出すことで、受信完了を通知できるようにしています。
    ここらは、Higetakaさんがコメントしています。

    送信の方は、R_Config_SCI5_Serial_Sendを呼ぶことで、送信が開始します。ここも、関数から戻っても送信が完了したわけではありません。1キャラクタの送信が完了してr_Config_SCI5_transmitend_interruptが起動し、データ数をカウントして残り送信データがあれば、それをバッファから読み出して、送信するはずです。
    データ数で指定されたデータの送信が完了した場合には、送信動作を禁止(SCI5.SCR.BIT.TE = 0U;)送信割り込み禁止(SCI5.SCR.BIT.TIE = 0U;)等を行い、r_Config_SCI5_callback_transmitend()を呼び出すことで、送信が終わったことを示せるようになっています。

    とにかく、送信中/送信完了や受信中/受信完了を示すようなフラグが準備されていないので、初心者には使いにくいのはRL78のコード生成と同じですね。


    前回の私のコメントは、main関数でR_Config_SCI5_Startを呼び出した後で、以下の処理を行えば、受信と送信が許可され、受信割り込みも許可された状態になるはずです。
    SCI5.SCR.BIT.RIE = 1U;
    SCI5.SCR.BIT.RE = 1U;
    SCI5.SCR.BIT.TE = 1U;

    そこで、受信完了割り込みの中で、単純に受信したデータを送信してしまうだけで、受信データのコールバックができるのではというものです。受信割り込み処理の中ではそれ以外の処理は行わない、main関数は単に無限ループで処理できるはずというものです。つまり、単純にハードウェア(と割り込み)だけで処理しようというものです。単純な動作なのですが、拡張性は全くありません。いろいろと機能拡張するならば、きちんとスマートコンフィグレータのAPIの使い方を理解してください。

    スマートコンフィグレータのAPI関数を使った処理は、上でも述べたように、フラグを準備して、1キャラクタ受信完了するまでループし、受信完了したら、受信したデータを送信します。ループして次の1キャラクタの受信を起動します。受信のボーレートが同じなら、次のデータ受信の間に送信は完了するはずなので、送信完了を待つ必要はないはずです。
    偉そうにいろいろと言いましたが、最初に書いたように、RX231は(というかRXは)使ったことはありません。単に、ハードウェアの動作とRL78のコード生成のAPIと比較しながらコメントしているだけです。最後の確認は自分でやってください。
  • In reply to YPekl39:

    すみません。週末は家族サービスで、こちらの方は見ていませんでした。
    Higetaka さんが答えていただいたおかげで解決に至り、良かったです。

    さて、サンプルプログラムですが、ルネサスのホームページにある各マイコンシリーズのサンプルコードを参照されてはいかがでしょうか(「マイクロコンピュータの周辺」-「通信機能」)。
    スマートコンフィグレータのコードとは異なる点があると思いますが、考え方(設計思想)は同じなので多いに参考になると思います。
  • In reply to チョコ:

    ありがとうございます、マニュアルをよく読んで理解することに努めたいと思います。
  • In reply to 吉光屋の次男坊:

    吉光屋の次男坊さん
    ありがとうございます、でもどこにサンプルコードがあるのか分かりません。
    お手数ですがURLなど貼って頂けると幸いです。
  • In reply to 吉光屋の次男坊:

    吉光屋の次男坊さん
    ありがとうございます、でもどこにサンプルコードがあるのか分かりません。
    お手数ですがURLなど貼って頂けると幸いです。

Top Page [◀◀]  2   3   4   5   6   7   8   9   ... [▶▶Last Page