CAN通信の送信時に関して

お世話になります。

RX71MでCAN通信の環境構築をしようとしているものです。

今回CANの送信時にいくつかの疑問が生じてしまったので、お力添えいただいただけないかと投稿させていただきました。

 

まず、今回使用しているmain関数のPCへのCAN送信部分を以下に示させていただきます。

//送信処理(キーボード0-7がMB[0]-[7]に対応)
  xc=sciRead();
  s_mb=0xff;
  switch(xc)
  {
   case '0':
    s_mb=0;  //使用するメールボックス番号
    s_dlc=1; //送信バイト数
    break;
   case '1':
    s_mb=1;
    s_dlc=2;
    break;
   case '2':
    s_mb=2;
    s_dlc=3;
    break;
   case '3':
    s_mb=3;
    s_dlc=4;
    break;
   case '4':
    s_mb=4;
    s_dlc=5;
    break;
   case '5':
    s_mb=5;
    s_dlc=6;
    break;
   case '6':
    s_mb=6;
    s_dlc=7;
    break;
   case '7':
    s_mb=7;
    s_dlc=8;
    break;
#if (LED_PORT_NUM > 0)
   case 'z':
    //ボード識別向けLED点滅
    sciPrintBuf("LED blink test(for board identify).\n");
    led=LED1_PORT;
    for(l=0; l<3; l++)
    {
     LED1_PORT=1;
     for(x=0; x<1000000; x++) nop();
     LED1_PORT=0;
     for(x=0; x<1000000; x++) nop();
    }
    LED1_PORT=led;
    break;
#endif
   case 'c':
    for(l=0; l<CAN_CH; l++)
    {
     send_can_ch++;
     if(send_can_ch>=CAN_CH) send_can_ch=0;
     if(varid_can_ch[send_can_ch] == 1) break;
    }
    sciPrintBuf("CAN send channel -> CAN");
    sciWriteBuf(send_can_ch+0x30);
    sciPrintBuf("\n");
    break;
   default:
    break;
  }
  
  if(s_mb != 0xff)
  {
   switch(send_can_ch)
   {
    case 0:
#if (CAN0_VALID == 1)
     s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 1:
#if (CAN1_VALID == 1)
     s_ret = can1_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 2:
#if (CAN2_VALID == 1)
     s_ret = can2_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    default:
     break;
   }
   
   sciPrintBuf("CAN");
   sciWriteBuf(send_can_ch+0x30);
   sciPrintBuf(" data send,     MB=0x");
   sciPrintByteBuf(s_mb);
   sciPrintBuf(" ret=0x");
   sciPrintWordBuf(s_ret);
    
   if(s_ret==0)
   {
    sciPrintBuf(" id=MB    ");
    sciPrintBuf(" data=0x");
    for(j=0; j<s_dlc; j++)
    {
     if(j>=8) break;
     sciPrintByteBuf(s_data[j]);
    }
   }
   sciPrintBuf("\n");
  }

 

ざっくりいうと

もともと用意していたデータを用意していたメールボックスにいれ(送信処理前に行っています)

switch関数を用いてキーボードの0~7に対応するメールボックスの番号とデータ量を指定

・switch文を抜けた後に、s_retで送信関数を呼び出してPCへの送信を行う

というような流れになっていると理解しています。

送信用の関数は以下のようになっています。

int can0_send(unsigned char mb, unsigned char dlc, unsigned char *data)
{
 //CAN0 送信関数
 
 //戻り値
 // 0  : 正常終了
 // -1 : 引数チェックエラー
 // -2 : レジスタ値設定変更タイムアウト
 // -3 : メールボックスが受信に設定されている
 // -4 : メールボックス送信中
 
 //引数
 // mb    : メールボックス番号(0-31)
 // dlc   : 送信バイト数(1-8)
 // *data : 送信データ
 
 unsigned short i, loop;
 unsigned char reg8;
 
 if(mb>31) return -1;
 if((dlc == 0) || (dlc>8)) return -1;
 
 //メールボックスが受信モードに設定されているときはエラーとする
 if(CAN0.MCTL[mb].BIT.RX.RECREQ == 1)
 {
  return -3;
 }
 
 if(CAN0.MCTL[mb].BIT.TX.TRMACTIVE == 1)
 {
  //メールボックス送信中
  return -4;
 }
 
 //TRMREQ=0
 reg8 = CAN0.MCTL[mb].BYTE;
 reg8 &= ~0x80;
  CAN0.MCTL[mb].BYTE = reg8;
 
 loop=0;
 while(CAN0.MCTL[mb].BIT.TX.TRMREQ != 0)
 {
  loop++;
  if(loop > CAN_LOOP_TIMEOUT) return -2;
 }
 
 //SENTDATA=0
 reg8 = CAN0.MCTL[mb].BYTE;
 reg8 &= ~0x01;
 CAN0.MCTL[mb].BYTE = reg8;
 
 loop=0;
 while(CAN0.MCTL[mb].BIT.TX.SENTDATA != 0)
 {
  loop++;
  if(loop > CAN_LOOP_TIMEOUT) return -2;
 }
 
 //メールボックスにデータセット
 for(i=0; i<dlc; i++)
 {
  CAN0.MB[mb].DATA[i] = *data++;
 }
 
 CAN0.MB[mb].DLC = dlc;
 
 CAN0.MCTL[mb].BIT.TX.TRMREQ = 1;   //メールボックスを送信モードに設定
 
 return 0;
}

 

キーボードを押すと、それに対応したCAN通信先のPCで送られてきたデータに対する応答用の表示が確認できています。

ここでキーボード入力をしないとデータ送信ができないとなるとなにかと不便ではないかと考え、まずswitch文を用いないでデータの送信をやろうと考え以下のようしました。

//送信処理(キーボード0-7がMB[0]-[7]に対応)
  s_mb=0xff;
  s_mb=0;
  s_dlc=1;
  
  s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
  
  /*xc=sciRead();
  
  switch(xc)
  {
   case '0':
    s_mb=0;  //使用するメールボックス番号
    s_dlc=1; //送信バイト数
    break;
   case '1':
    s_mb=1;
    s_dlc=2;
    break;
   case '2':
    s_mb=2;
    s_dlc=3;
    break;
   case '3':
    s_mb=3;
    s_dlc=4;
    break;
   case '4':
    s_mb=4;
    s_dlc=5;
    break;
   case '5':
    s_mb=5;
    s_dlc=6;
    break;
   case '6':
    s_mb=6;
    s_dlc=7;
    break;
   case '7':
    s_mb=7;
    s_dlc=8;
    break;
#if (LED_PORT_NUM > 0)
   case 'z':
    //ボード識別向けLED点滅
    sciPrintBuf("LED blink test(for board identify).\n");
    led=LED1_PORT;
    for(l=0; l<3; l++)
    {
     LED1_PORT=1;
     for(x=0; x<1000000; x++) nop();
     LED1_PORT=0;
     for(x=0; x<1000000; x++) nop();
    }
    LED1_PORT=led;
    break;
#endif
   case 'c':
    for(l=0; l<CAN_CH; l++)
    {
     send_can_ch++;
     if(send_can_ch>=CAN_CH) send_can_ch=0;
     if(varid_can_ch[send_can_ch] == 1) break;
    }
    sciPrintBuf("CAN send channel -> CAN");
    sciWriteBuf(send_can_ch+0x30);
    sciPrintBuf("\n");
    break;
   default:
    break;
  }*/
  
  /*if(s_mb != 0xff)
  {
   switch(send_can_ch)
   {
    case 0:
#if (CAN0_VALID == 1)
     s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 1:
#if (CAN1_VALID == 1)
     s_ret = can1_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 2:
#if (CAN2_VALID == 1)
     s_ret = can2_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    default:
     break;
   }
   */
   sciPrintBuf("CAN");
   sciWriteBuf(send_can_ch+0x30);
   sciPrintBuf(" data send,     MB=0x");
   sciPrintByteBuf(s_mb);
   sciPrintBuf(" ret=0x");
   sciPrintWordBuf(s_ret);
    
   if(s_ret==0)
   {
    sciPrintBuf(" id=MB    ");
    sciPrintBuf(" data=0x");
    for(j=0; j<s_dlc; j++)
    {
     if(j>=8) break;
     sciPrintByteBuf(s_data[j]);
    }
   }
   sciPrintBuf("\n");
  //}

 

最初にメールボックスの番号とデータ量を指定し、送信関数を呼び出してしてswitch文をコメントアウトしました。

しかし、ここで以前のような表示がCAN通信先のPCで見られなくなり、一回分だけ表示ができる時とできない場合があったりします。

ここで疑問なのですが、

・switch文のcase0と私が書いたコードは同義ではないのでしょうか

・そもそもmain自体がwhile(1)でまわっている(まわしています)のに一回分しか送信されないことはどこか私が書いたコードに問題があるのでしょうか

 

初歩的なプログラムの疑問ですみません、どなたかお力添えいただけないでしょうか。

よろしくお願い致します。

 

 

Parents
  • makiさん、こんにちは。NoMaYと申します。

    以下でs_mb=0としていますが、

    //送信処理(キーボード0-7がMB[0]-[7]に対応)
      s_mb=0xff; ← 不要ですね。
      s_mb=0;
      s_dlc=1;

    それに対して、以下を丸ごとコメントアウトしては拙いのではないでしょうか?

      /*if(s_mb != 0xff)
      {
       switch(send_can_ch)
       {
        case 0:
    #if (CAN0_VALID == 1)
         s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
    #endif
         break;
        case 1:
    #if (CAN1_VALID == 1)
         s_ret = can1_send(s_mb, s_dlc, &s_data[0]);
    #endif
         break;
        case 2:
    #if (CAN2_VALID == 1)
         s_ret = can2_send(s_mb, s_dlc, &s_data[0]);
    #endif
         break;
        default:
         break;
       }
       */

    上記は、初期化の部分を以下のようにして、コメントアウトせずにおくものではないですか?

    //送信処理(キーボード0-7がMB[0]-[7]に対応)
      s_mb=0;
      s_dlc=1;
      send_can_ch=0; ← 値は一例です。適切な値にして下さい。

     

Reply
  • makiさん、こんにちは。NoMaYと申します。

    以下でs_mb=0としていますが、

    //送信処理(キーボード0-7がMB[0]-[7]に対応)
      s_mb=0xff; ← 不要ですね。
      s_mb=0;
      s_dlc=1;

    それに対して、以下を丸ごとコメントアウトしては拙いのではないでしょうか?

      /*if(s_mb != 0xff)
      {
       switch(send_can_ch)
       {
        case 0:
    #if (CAN0_VALID == 1)
         s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
    #endif
         break;
        case 1:
    #if (CAN1_VALID == 1)
         s_ret = can1_send(s_mb, s_dlc, &s_data[0]);
    #endif
         break;
        case 2:
    #if (CAN2_VALID == 1)
         s_ret = can2_send(s_mb, s_dlc, &s_data[0]);
    #endif
         break;
        default:
         break;
       }
       */

    上記は、初期化の部分を以下のようにして、コメントアウトせずにおくものではないですか?

    //送信処理(キーボード0-7がMB[0]-[7]に対応)
      s_mb=0;
      s_dlc=1;
      send_can_ch=0; ← 値は一例です。適切な値にして下さい。

     

Children
  • NoMaYさん

    ご回答ありがとうございます。

    説明が少なくなってしまい申し訳ございません。

    send_can_ch=0はmain関数の最初のほうに定義をしています。

    NoMayさんのおっしゃるとおりにコメントアウトの部分を訂正してみたのですが、まだ、問題解決しなさそうです、、、

    if(s_mb != 0xff)

     {

      switch(send_can_ch)

      {

       case 0:

    #if (CAN0_VALID == 1)

        s_ret = can0_send(s_mb, s_dlc, &s_data[0]);

    #endif

        break;

       case 1:

    #if (CAN1_VALID == 1)

        s_ret = can1_send(s_mb, s_dlc, &s_data[0]);

    #endif

        break;

       case 2:

    #if (CAN2_VALID == 1)

        s_ret = can2_send(s_mb, s_dlc, &s_data[0]);

    #endif

        break;

       default:

        break;

      }

    ここから始まるif文が0xffじゃない場合に通り、main関数が一回まわったときにmbの値が0xffになるので単にswitch文を削除しただけでは何度も送信が行えなくなりそうなのは

    コードをよく読んで見たらわかりました。

     

    毎回毎回送信処理の時に

    //送信処理(キーボード0-7がMB[0]-[7]に対応)
      s_mb=0xff; ← 不要ですね。
      s_mb=0;
      s_dlc=1;

    以上の動作を行っていれば先ほどのif文の中にもはいれて、送信もその度にできそうな気もするのですが、いまいちまだよくわかりません。

    この考えって間違っていたりするのでしょうか?