質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.06%

CAN.init_Mask()について

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 751

Alyn

score 38

質問

下記ソースコードを書き込んだ後、別のArduinoから1ms間隔で0x000~0x7ffのIDのCAN信号を送信すると、
IDが4,5,6,7,8,9,404,405,405,406,407,408,409だけ受信できました。

IDが4,5,6,7,8,9はCAN.init_Filt()関数により完全一致するIDのため受信できたとわかるのですが、
404,405,405,406,407,408,409がなぜ受信できたのかわかりません。
CAN.init_Mask()関数によるものだとはわかるのですが、その関数の仕組みがわかりません。

なぜID:404,405,405,406,407,408,409が受信できたのか教えてください。
またCAN.init_Mask()関数の使い方を教えてください。

ソースコード

// demo: CAN-BUS Shield, receive data with interrupt mode, and set mask and filter
//
// when in interrupt mode, the data coming can't be too fast, must >20ms, or else you can use check mode
// loovee, 2014-7-8

#include <SPI.h>
#include "mcp_can.h"

/*SAMD core*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
  #define SERIAL SerialUSB
#else
  #define SERIAL Serial
#endif

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin

const byte interruptPin = 0;
unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void setup()
{
    SERIAL.begin(115200);

    while (CAN_OK != CAN.begin(CAN_500KBPS))              // init can bus : baudrate = 500k
    {
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");

    attachInterrupt(digitalPinToInterrupt(interruptPin), MCP2515_ISR, FALLING); // start interrupt


    /*
     * set mask, set both the mask to 0x3ff
     */
    CAN.init_Mask(0, 0, 0x3ff);   // there are 2 mask in mcp2515, you need to set both of them
    CAN.init_Mask(1, 0, 0x3ff);


    /*
     * set filter, we can receive id from 0x04 ~ 0x09
     */
    CAN.init_Filt(0, 0, 0x04);                          // there are 6 filter in mcp2515
    CAN.init_Filt(1, 0, 0x05);                          // there are 6 filter in mcp2515

    CAN.init_Filt(2, 0, 0x06);                          // there are 6 filter in mcp2515
    CAN.init_Filt(3, 0, 0x07);                          // there are 6 filter in mcp2515
    CAN.init_Filt(4, 0, 0x08);                          // there are 6 filter in mcp2515
    CAN.init_Filt(5, 0, 0x09);                          // there are 6 filter in mcp2515

}

void MCP2515_ISR()
{
    flagRecv = 1;
}

void loop()
{
    if(flagRecv)                   // check if get data
    {

        flagRecv = 0;                // clear flag
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

        SERIAL.println("\r\n------------------------------------------------------------------");
        SERIAL.print("Get Data From id: ");
        SERIAL.println(CAN.getCanId(), HEX);
        for(int i = 0; i<len; i++)    // print the data
        {
            SERIAL.print("0x");
            SERIAL.print(buf[i], HEX);
            SERIAL.print("\t");
        }
        SERIAL.println();

    }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

追記

CAN.init_Mask(0, 0, 0x300);
CAN.init_Mask(1, 0, 0x3ff);

マスク関数の引数を上記に変更したところ、受信したIDは以下のようになりました。
この関数の結果、どういった計算で受信できるIDが変化したのか教えてください。

<受信したID>
0x000~0x0ff、0x400~0x4ff

追記2

マスクとフィルタの演算内容をC言語で書き直してみました。
こんな感じでしょうか?

#include <stdio.h>

#define MASK0 0x3ff
#define MASK1 0x3ff

#define FILT0 0x004
#define FILT1 0x005
#define FILT2 0x006
#define FILT3 0x007
#define FILT4 0x008
#define FILT5 0x009

int main(void)
{
    int cnt = 0;

    printf("<受信可能CAN-ID>\n");

    for (int id = 0x000; id <= 0x7ff; id++)
    {
        if (((MASK0 & FILT0) == (MASK0 & id)) || ((MASK0 & FILT1) == (MASK0 & id)))
        {
            printf("%.3x ", id);
            cnt++;
        }
        else if (((MASK1 & FILT2) == (MASK1 & id)) || ((MASK1 & FILT3) == (MASK1 & id))
            || ((MASK1 & FILT4) == (MASK1 & id)) || ((MASK1 & FILT5) == (MASK1 & id)))
        {
            printf("%.3x ", id);
            cnt++;
        }

        if (cnt == 0x10)
        {
            printf("\n");
            cnt = 0;
        }
    }

    char end = getchar();
    return 0;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

MCP2515のデータシートによると、CANフレームの受信にはマスクとフィルタが関係してきます。
基本的には、届いたCANフレームのIDとフィルタに設定しているIDを比較して値が完全に一致していれば受信格納しますが、このID比較の際、マスクのビットが1になっている部分のみをチェックし0の部分は一致しなくてもOK(don't care)になります。
maskとフィルタの関係
たとえば、mask = 0x300, filter0 = 0x004 の場合、以下のように
IDの最上位側から2,3ビット目が0になっているかどうかだけをチェックすることになります。

mask:  b'011_0000_0000
filt0: b'000_0000_0100
--------------------------------
       b'x00_xxxx_xxxx (x: don't care)

ID 0x000~0x0ff、0x400~0x4ffのみ受信格納された件については以下のように考えれば説明できると思います。

0x00f: b'000_0000_1111 2,3ビット目が0なので一致
0x100: b'001_0000_0000 × 3ビット目が1なので不一致
0x400: b'100_0000_0000 2,3ビット目が0なので一致
0x501: b'101_0000_0001 × 3ビット目が1なので不一致
0x7ff: b'111_1111_1111 × 2,3ビット目が0なので一致

実際のMCP2515では以下の2系統の受信設定があるのでもう少し複雑です。
完全に理解するにはMCP2515のデータシートを読む必要があります。

  • マスクの0(RXM0) と フィルタの0, 1(RXF0, RXF1)のペア
  • マスクの1(RXM1) と フィルタの2-5(RXF2-RXF5)のペア

受信部ブロック図


追記2に関して

実機を持っていないので動作確認はできませんが、合っていると思います。
あとは実際に使用するIDに合わせて以下のようなイメージで設定するだけです。

#define MASK0 0x7f0
#define MASK1 0x7ff

#define FILT0 0x000
#define FILT1 0x280
#define FILT2 0x501
#define FILT3 0x601
#define FILT4 0x602
#define FILT5 0x73f
<受信可能CAN-ID>
000 001 002 003 004 005 006 007 008 009 00a 00b 00c 00d 00e 00f  /* FILT0 */
280 281 282 283 284 285 286 287 288 289 28a 28b 28c 28d 28e 28f  /* FILT1 */
501 601 602 73f  /* FILT2-5 */

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/15 16:57

    ありがとうございます!ちなみに質問と同じ0x3ffでマスクした際に、0x000と0x400がAcceptしないのはなぜでしょうか?

    キャンセル

  • 2019/11/15 17:32

    table 4-2にあるようにマスク値が0x3ffの場合、CAN IDの最上位ビット以外全ての一致を確認することになります。ご質問のソースではフィルタの値が0x004~0x009になっているので、フィルタ設定と受信CAN IDが完全に一致している0x004~0x009とIDの最上位ビットが1になっている部分だけが違う0x404~0x409は受信格納できます。0x000, 0x400は一致するフィルタ条件が無いため受信格納できません。

    キャンセル

  • 2019/11/18 21:31

    ありがとうございます。マスクとフィルタは追記2の計算で大丈夫でしょうか?

    キャンセル

  • 2019/11/19 01:04

    ありがとうございます!

    キャンセル

+1

CAN.init_Mask(0, 0, 0x3ff);

第三引数はIDの判定マスク値です
マスクビットが1のところのみがID値の比較対象となります

4,5,6,7,8,9のみを通したいのであれば、ここは0x7ffとするべきです

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/14 22:32

    CANバスは1つしかありませんが、チャンネル番号とは何を示しているのでしょうか?

    キャンセル

  • 2019/11/14 22:34

    1つしか無いのであれば、1は無効となります

    キャンセル

  • 2019/11/15 10:45

    チャンネル番号ではないっぽいです。追記に記載します

    キャンセル

0

404,405,405,406,407,408,409がなぜ受信できたのか

ちょっと分からないのですが、、、この 404 とかは、16進数の 404 (0x404) でしょうか?
もし、そうならば、0x3FFでマスクしているので、 0x404 & 0x3FF => 0x004 なので、一致すると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/11/14 22:23

    16進数です!CAN.init_Mask()関数の第一引数が0と1があるのですが、どちらの0x3FFでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.06%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る