MCP2515モジュールでCAN通信の実験2(PIC)

〔マイコンのトップに戻る〕

CAN通信の基礎概要
PIC18F26K80のECANレジスタ内容
MCC操作でECAN 2.0Bプログラムを生成する
PICとPICでECAN通信の実験
MCP2515モジュールでCAN通信の実験1(Arduino)

前ページMCP2515 モジュール簡単な説明はしておきましたね、
前ページはArduinoUNOと接続しましたが今回はPICと接続します、なのでMCP2515モジュール+PIC
組み合わせをノード4と しておきます。

《配線図》

MCP2515モジュールとPIC配線図左図がPIC16F1829とのノード4配線図です
電源は5.0Vです。
ノード4、"PICとPICでECAN通信の実験"
回路のノード2と1 対1で繋ぎます。
(下記実験風景の写真参照)
但し、ノード2のMCP2561トランシーバは
MCP2562と交換しています。
これは終端抵抗を120Ωにしたかったので
交換しました。

SPIはMSSP1(SCK1/SDI1/SDO1) を使い、
I2CはMSSP2(SCL2/SDA2)を使い ました、
I2Cプルアップは前回の回路を利用したので
外付けとしています、PIC内蔵でもOKです。
SWのプルアップはPIC内蔵を使っています。

J1ジャンパーピン
このピンを短絡させるとCANバスの終端抵抗
120Ωが施されます。
今回、1対1で行うのでジャンパーピンを短絡
させ終端抵抗を生かしましょう。


 I2Cを使わないならMSSP(SPI)が1個のPICでも良いでしょう、但し8Kword以上のメモリ 容量を
 勧めます、今回のコンパイルで3.5Kだったので4Kwordでは厳しいかもね。

MCP2562ピン構成図
MCP2561との違いは5番ピンで後は同じ使い方だが、
終端抵抗は60Ωの分割回路でなく120ΩをCANH/CANLに並列に取り付けます。
詳しい内容は日本語データシートを見ましょう。

VIOピンはI/Oの操作用VDD電源でPICの VDD電源と同じにします、今回は5.0Vに配線します。
 尚、MCP2562の動作電源(3番ピン)は5.0Vですよ。
STBYピンは、LOWで通常動作モードで、HIGHで消費電力を抑える為の スタンバイモード。
 バスのアクティビティで復帰する様です。

何らかの回路に組み込む場合は、PICとMCP2562には 0.1uFのパスコンを取り付けましょう

《ノード2プログラムについて》

ノード2のプログラ ムについては、前回までの実験を行っている人はおそらくそのままだと思います。
"PICとPICでECAN通信の実験"の「リモートフレーム」実験で使った"node2R.c"を使います。
このプログラムは、リモートフレーム(0x123)を受信したら、データフレームで半固定抵抗値を送信します

《ノード4プログラムについて》

↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
MCP2515.zip

プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.40コンパイラを使用しています。

ダウンロードファイルを解凍すると下記の様なファイル構成です。
 node4.c・・・・・・・・・・・・・・・CANバスに接続されるノード4機器のサンプルプログラム
 skMCP25xx.c・・・・・・・・・・・MCP2515/25625用関数ライブラリ
 skMCP25xx.h・・・・・・・・・・・MCP2515/25625用関数ライブラリのヘッダファイル
 mcp_can_dfs.h・・・・・・・・・MCP2515/25625用関数ライブラリの定数定義ファイル
 skI2CLCDlib.c・・・・・・・・・・I2C接続LCD関数ライブラリの ソースファイル
 skI2CLCDlib.h・・・・・・・・・・I2C接続LCD関数ライブラリの ヘッダファイル
 skI2Clib.c・・・・・・・・・・・・・・I2C関数ライブラリの ソースファイル
 skI2Clib.h・・・・・・・・・・・・・・I2C関数ライブラリの ヘッダファイル
 skSPIlib.c・・・・・・・・・・・・・・SPI通信を行う関数ソースファイル
 skSPIlib.h・・・・・・・・・・・・・・SPI通信を行う関数のヘッダファイル

 尚、CPUのクロックは32MHzを想定しています。
 なので通信速度等(I2C/SPI)はシステムクロック32MHzで計算されています。

 ※ "skMCP25xx"ライブラリは、GitHubの
   "CAN_BUS_Shield-master(https://github.com/Seeed-Studio/CAN_BUS_Shield)" の
   Arduino用をPIC用に移植した物です。

 ※ "MCP2515/25625 用関数ライブラリ"となっていま すがぁ、これはMCP25625のデータシートを
   眺めていたらMCP2515と同じ様な操作に思えたので記述したのですがぁ、実際は未実験です。
      (MCP25625動作します、実験しました。) *1)

node4.c

ノード4は、スイッチを押したらリモートフレーム(ID=0x123)を送信します。
ノード2からデータフレーム(半固定抵抗値)を受け取りLCDに内容を表示します。

起動させるとLCDに、
[CAN BUS ]
と1行目に表示され、MCP2515の初期化後に
[Init OK!] が2行目に表示されたら正常で す。
[InitFail]  と表示されたら初期化失敗で す、プログラム終了
後はスイッチをポチッとな、リモートフレーム(ID=0x123)を送信します。
[     ????]
と1秒後、LCDの2行目に半固定抵抗の値が表示されます。
(1秒後は、スイッチのチャタリング防止で入れています)

skI2CLCDlib.c
skI2CLCDlib.h
skI2Clib.c
skI2Clib.h

この内容は”秋月電子I2C接続小型LCDモジュールに表 示を行う”を参照下さい。

skSPIlib.c
skSPIlib.h

この内容は、こちらのペー ジを参照下さい。

mcp_can_def.h

MCP2515/25625用関数ライブラリで使用する定数の定義を行っているファイルです。

// MCP25XXデバイスをセレクトする為のPIC側ポートを指定します。
#define MCP25XX_SPI_CS        LATCbits.LATC6      // RC6をCSとする
と記述ヶ所が有りますので、必ずスレーブデバイスを選択する為のピンを 設定しましょう

skMCP25xx.h

MCP2515/25625用関数ライブラリのヘッダファイルです。
関数のプロトタイプ宣言を行っています。

skMCP25xx.c

MCP2515/25625と通信を行う為のドライバ関連の関数集です。
この関数自体は、XC8/XC16コンパイラで利用出来ると思います。
(XC16 v1.3 でコンパイルは通っています、但し動作はさせていません)
(尚、ここの"skSPIlib"/"skI2Clib"はXC8用です)

このライブラリを利用する場合は、"skSPIlib.c"を使って います、
メインプログラムでこの関数を呼び出す前に、必ず"SPI_Init( )"関数でSPIを初期化します
例)
 SPI_Init(SPI_MODE0,SPI_CLOCK_DIV4,0) ;
 mcp_begin(CAN_100KBPS,MCP_8MHz) ;

CAN通信を行う関数の使い方を説明します。

 ans = mcp_begin(speedset, clockset)
  mcp2515/25625の初期化を行います。
  初期化は、RX0IFとRX1IFの割り込みを有効に 設定し、RXB0がオーバフローしたらRXB1に書込むで
  設定しています、又、標準/拡張識別子がフィルタに一致した全てのメッセージを受信で初期化
  しています。
  speedset : CANバスの通信速度を指定する
  clockset  : デバイスのクロックを指定する(8/16/20MHz)
  ans        : CAN_OK - 初期化正常終了
                     CAN_FAILINIT - 初期化失敗

 ans = mcp_init_Mask(num, ext, ulData)
  マスクレジスタの初期化を行います。
  マスクレジスタは、RXM0とRXM1の2個が有ります。
  num  : 設定するマスクレジスタの番号(0-1)
  ext    : 0 = 標準フォーマット  1 = 拡張フォーマット
  ulData : マスクに設定するデータ
  ans     : MCP25XX_OK - 正常終了
                  MCP25XX_FAIL - 初期化失敗

 ※ マスクレジスタの話は、"PIC18F26K80のECANレジスタ内容" を参照下さい。

 ans = mcp_init_Filt(num, ext, ulData)
  フィルタレジスタの初期化を行います。
  フィルタレジスタは、RXF0/RXF1とRXF2/RXF3/RXF4/RXF5の6個が有ります。
  num  : 設定するフィルタレジスタの番号(0-5)
  ext    : 0 = 標準フォーマット  1 = 拡張フォーマット
  ulData : フィルタに設定するデータ
  ans     : MCP25XX_OK - 正常終了
                  MCP25XX_FAIL - 初期化失敗

 ans = mcp_sendMsgBuf(id, ext, rtrBit, len, *buf, wait_sent)
  メッセージデータを送信します。
  3つの送信バッファ、TXB0-TXB1-TXB3のバッファの空きを順番に調べて空きが有れば
  書き込み送信します。
  id           : 識別子ID(HEXで指定する)
  ext          : 0 = 標準フォーマット  1 = 拡張フォーマット
  rtrBit       : 0 = データフレーム    1 = リモートフレーム
  len          : 送信するデータの長さ(0-8)
  *buf        : 送信するデータの格納先アドレスを設定する(送信データはMAX8byte)
  wait_sent : 1 = 送信終了まで待つ  0 = 待たない(送信要求を行ったら直ぐにRETURNする)
  ans          : CAN_OK - 送信正常終了
                       CAN_GETTXBFTIMEOUT - 500ms経っても送信バッファに空きがない
                       CAN_SENDMSGTIMEOUT - 500ms経ってもデータが送信されない

 ※ 500msは変更可能です、"mcp_can_dfs.h"記述の"TIMEOUTVALUE    50"を変えます。

 ans = mcp_readMsgBuf(*len, *buf)
  受信したメッセージデータを読み込みます。
  lenとbuf以外の情報は、getCanId()/isRemoteRequest()/isExtendedFrame() 関数で調べます。
  読み込んだ後に、RX0IF/RX1IFフラグはクリアしています。
  *len : 受信したデータの長さ(0-8)を返す
  *buf : 受信したデータの格納先アドレスを設定する(受信データはMAX8byte)
  ans  : CAN_OK - 正常に受信した
               CAN_NOMSG - 受信メッセージは無い

 ans = mcp_checkReceive(void)
  メッセージデータを受信しているのかを調べます。
  "状態読み込みコマンド"で RX0IF / RX1IF を見ているだけですので、
  INT割り込みが有った時にこの関数で調べるか、
  もしINT割り込みを使わないなら常にこの関数をループ処理で実行させます。
  尚、この関数では RX0IF / RX1IF の何方が受信したかまでは判らない。
  ans  : CAN_MSGAVAIL - メッセージを受信しています
               CAN_NOMSG - メッセージを受信していない
  例)
          // "CAN_NOMSG"になるまで繰り返す
          while (CAN_MSGAVAIL == mcp_checkReceive()) {
               mcp_readMsgBuf(&len, RcvBuf) ;
                             :
          }

 ans = mcp_getCanId(void)
  受信したメッセージデータの識別子IDを得ます。
  ans  : 識別子ID(11ビット又は29ビット長)を返します

 ans = mcp_isRemoteRequest(void)
  受信したメッセージデータが、リモートフレームかどうかを確認する事が出来ます。
  ans  : 0 = データフレーム、1 = リモートフレーム

 ans = mcp_isExtendedFrame(void)
  受信したメッセージデータが、標準の11ビットフレーム又は拡張29ビットか調べます。
  ans  : 0 = 標準、1 = 拡張

 ※ mcp_getCanId() / mcp_isRemoteRequest() / mcp_isExtendedFrame() 関数共に、
   mcp_readMsgBuf( ) 関数を実行した後に使用出来ます。
   例)
          mcp_readMsgBuf(&len, RcvBuf);
          // データフレームなら処理する
          if (mcp_isRemoteRequest() == 0) {
               id = mcp_getCanId() ;    // 識別子IDを得る
               if (id == 0x123) {
                    // ID=0x123なら処理する
                    :
               }
          }

 mcp_reset(void)
  デバイスをリセットします。
  電源がオンした後は必ずリセットを行いましょう。

 割り込み処理の記述方法

 PICのRA2をMCP2515のINTピンと接続して状態変化割り込み(IOC)とした場合の設定例です。
 MCP2515のINTピンは割り込みが有ればLOWにドライブするのでPICのIOC設定は
 "立ち下げエッジで割り込み発生"とします。
 void interrupt InterFunction( void )
 {
      // MCP2515のINTピン割り込み
      if (IOCIF == 1) {
           IOCIF = 0 ;
           if (IOCAF2 == 1) {
IOCAF2 = 0 ;
flagRecv = 1 ;
           }
      }
 }
 void main()
 {
       :
      // MCP2515のINTピン割り込みの設定
      IOCAN2 = 1 ;   // RA2をIOCで設定(立ち下げエッジで割り込み発生)
      IOCAF2 = 0 ;   // フラグをクリアする
      IOCIF  = 0 ;
      IOCIE  = 1 ;   // 状態変化割り込みを有効にする
  GIE = 1 ; // 全割り込み処理を許可する
       :
  while(1) {
  // INTピン割り込みが有れば処理する
  if (flagRecv) {
  flagRecv = 0 ; // 割り込みフラグをクリアする
  while (CAN_MSGAVAIL == mcp_checkReceive()) {
  // 受信したメッセージを読み込む
  mcp_readMsgBuf(&len, RcvBuf);
:
}
}
  }
 }


《その他》

実験風景
実験時の風景写真です。
左上のPICがノード2、
MCP2561からMCP2562に変更したので抵抗1本となりスッキリしました。
右上のPICがノード4その上がMCP2515モジュールです。
CANバス通信速度は100Kbps
今回のCAN通信実験の為に色々部品を買い込んでしまった....
本当はこちらのMCP25625を使用した製品を買い"skMCP25xx"ライブラリが使用出来るか
検証したいのですが...
今は懐に余裕がない...早く検証しないとぉ頭からCAN通信のデータがこぼれてしまうがぁ...
PS. *1)
"MCP25625:Pmod CAN"動作確認しました、動作可能です、Pmod CANはクロックを20MHzに変更要。




MCP2565動作確認追記(*1) 2018/12/26


【きむ茶工房ガ レージハウス】
Copyright (C) 2006-2018 Shigehiro Kimura All Rights Reserved.