目次

CANコントローラ利用

 ArduinoProMiniをユニバーサル基板に実装して
 CANコントローラを接続し、通信してみました。



 各基板の回路図は、以下。



 CANコントローラは、MCP2515を利用していますが
 CAN通信の前に、このデバイスとSPIで通信できる
 のかを、テストするスケッチを作成。

#include <SPI.h>
#include <MsTimer2.h>

#define OFF 0
#define ON  OFF+1

#define nSS 10

// global variables
boolean uflag ;
boolean aflag ;
boolean tflag ;

char sbuf[4];
byte sindex ;

char cmd ;

byte state ;
byte lpat[4] ;
byte tmp ;

// function prototype
void update_trigger();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();
void perform();
void snd_spi(byte x);
void init_lpat();

void setup()
{
  // serial debug
  Serial.begin(115200);
  sindex = 0;
  rs_puts("test LED blight");
  crlf();
  show_help();

  // initialize pin
  pinMode(nSS,OUTPUT);
  // set values
  digitalWrite(nSS,HIGH);

  // clear flags
  uflag = OFF ;
  aflag = OFF ;

  // clear state machine
  state = 0 ;
  SPI.begin();
  // reset MCP2515
  snd_rst();

  /* 1000ms period */
  MsTimer2::set(1000,update_trigger);
  /* enable */ 
  MsTimer2::start();

  // others
  init_lpat();
}

void loop()
{
  // command interpreter
  if ( uflag ) {
    // clear flag
    uflag = OFF ;
    // get command 
    cmd = *(sbuf+0) ;
    // help
    if ( cmd == '?' ) { show_help(); }
    // command 'A' begin timer handling
    if ( cmd == 'A' ) {
      aflag = ON ;
      state = 0 ; 
    }
    // command 'a' exit timer handling
    if ( cmd == 'a' ) {
      aflag = OFF ;
      snd_spi( 0x0C );
    }
    // test
    if ( cmd == 'T' ) { perform_led(); }
    // new line
    crlf();
  }
  // timer interrupt
  if ( tflag ) {
    tflag = OFF ;
    // handling
    if ( aflag ) {
      // impress
      tmp = *(lpat+state);
      snd_spi( tmp );
      // debug
      Serial.print( state );
      rs_putchar(' ');
      // update state
      state++ ;
      state &= 3 ;
    }
  }
}

void update_trigger()
{
  tflag = ON ;
}

void rs_putchar(char x)
{
  Serial.write( x );
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help()
{
  rs_puts("? help");             crlf();
  rs_puts("A enable sequence");  crlf();
  rs_puts("a disable sequence"); crlf();
  rs_puts("T test LED") ;        crlf();
  rs_puts("T0 stop LED blight"); crlf();
  rs_puts("T1 LED #A blight");   crlf();
  rs_puts("T2 LED #B blight");   crlf();
  rs_puts("T3 both LED blight"); crlf();
}

void perform_led()
{
  byte cmdp ;
  // get parameter
  cmdp = *(sbuf+1) ;
  // perform
  if ( cmdp == '0' ) { snd_spi( 0x0C ); }
  if ( cmdp == '1' ) { snd_spi( 0x1C ); }
  if ( cmdp == '2' ) { snd_spi( 0x2C ); }
  if ( cmdp == '3' ) { snd_spi( 0x3C ); }
}

void snd_rst()
{
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
  // enable SPI device
  digitalWrite(nSS, LOW);
  // reset
  SPI.transfer( 0xC0 );
  // disable SPI device
  digitalWrite(nSS, HIGH);
  //
  SPI.endTransaction();
}

void snd_spi(byte x)
{
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
  // enable SPI device
  digitalWrite(nSS, LOW);
  SPI.transfer(0x02); // write mode
  SPI.transfer(0x0C); // address
  SPI.transfer( x ) ; // parameter
  // disable SPI device
  digitalWrite(nSS, HIGH);
  //
  SPI.endTransaction();
}

void init_lpat()
{
  *(lpat+0) = 0x0C ;
  *(lpat+1) = 0x1C ;
  *(lpat+2) = 0x3C ;
  *(lpat+3) = 0x2C ;
}

/* receive interrupt */
void serialEvent()
{
  char ch;

  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 MCP2515のRX0BF、RX1BFの2ピンをデジタル出力にし
 接続しているLEDを点滅させます。

 Teratermを使い、シリアルインタフェースで
 次のようにタイプして、基板上の2つのLEDの
 点灯、消灯を確認。



 送信側のファームウエア、次の仕様で作成しました。

3秒ごとに、CANに次のコマンドを順次送信
 #A0*
 #A1*
 #A2*
 #A3*
 #A4*
 #A5*
 #A6*
 #A7*
 #A8*
 #A9*
 #A0*
 #A1*
 :

 Arduinoスケッチは、以下。

#include <mcp_can.h>

#define OFF 0
#define ON  OFF+1

#define TIM_MAX 3000

// CAN0 CS: pin 10
MCP_CAN CANS(10);

// global variables
boolean uflag ;
boolean aflag ;

char sbuf[4];
byte sindex ;

char cmd ;

byte state ;
byte lpat[4] ;
byte tmp ;

unsigned long pre_millis ;

byte sndBuf[4] ;

// function prototype
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();
void perform();

void init_txbuf();

void setup()
{
  // serial debug
  Serial.begin(115200);
  sindex = 0;
  crlf();
  rs_puts("test CAN send with MCP2515");
  crlf();

  // init CANS bus, baudrate: 250kbps@16MHz
  if( CANS.begin(MCP_ANY, CAN_250KBPS , MCP_16MHZ) == CAN_OK ) {
    rs_puts("CANS: Init OK!");
    CANS.setMode(MCP_NORMAL);
  } else{ 
    rs_puts("CANS: Init Fail!");
  }
  crlf();

  // clear flags
  uflag = OFF ;
  aflag = ON  ;

  // clear state machine
  state = 0 ;

  // others
  init_txbuf();

  // current time counter
  pre_millis = millis() ;
}

void loop()
{
  // period 3 seconds
  if( (millis() - pre_millis) > TIM_MAX ) {
    // update time count
    pre_millis = millis();
    // update
    perform();
  }
  // command interpreter
  if ( uflag ) {
    // clear flag
    uflag = OFF ;
    // get command 
    cmd = *(sbuf+0) ;
    // help
    if ( cmd == '?' ) { show_help(); }
    // command 'A' begin timer handling
    if ( cmd == 'A' ) {
      crlf();
      aflag = ON ;
      state = 0 ; 
      // initialize command
      *(sndBuf+2) = state + '0' ;
      // message
      rs_puts("begin to send");
    }
    // command 'a' exit timer handling
    if ( cmd == 'a' ) {
      crlf();
      aflag = OFF ; 
      // message
      rs_puts("exit to send");
    }
    // new line
    crlf();
  }
}

void rs_putchar(char x)
{
  Serial.write( x );
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help()
{
  rs_puts("? help");             crlf();
  rs_puts("A enable sequence");  crlf();
  rs_puts("a disable sequence"); crlf();
}

void init_txbuf()
{
  *(sndBuf+0) = '#' ;
  *(sndBuf+1) = 'A' ;
  *(sndBuf+2) = '0' ;
  *(sndBuf+3) = '*' ;
}

void perform()
{
  byte i ;
  // exit
  if ( aflag == OFF ) return ;
  // send command
  CANS.sendMsgBuf( 0x100, 0 , 4, sndBuf ) ;
  rs_puts("Tx(ID:0x100) Cmd");
  rs_putchar('(');
  for ( i = 0 ; i < 4 ; i++ ) {
    rs_putchar( *(sndBuf+i) );
  }
  rs_putchar(')');
  crlf();
  // update state
  state++ ;
  if ( state == 10 ) { state = 0 ; }
  // update command
  *(sndBuf+2) = state + '0' ;
}

/* receive interrupt */
void serialEvent()
{
  char ch;

  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 Teratermでは、次のように送信していることを
 モニタします。



 受信側のファームウエア、次の仕様で作成しました。

 MCP2515からの割込み信号がイネーブルになったら
 受信バッファからデータを引き抜いて、シリアル
 インタフェースで内容を表示。

 Arduinoスケッチは、以下。

#include <mcp_can.h>

#define OFF 0
#define ON  OFF+1

#define CAN_INT 2   // CAN interrupt

// CAN CS: pin 10
MCP_CAN CANR(10);

// global variables
boolean uflag ;
boolean sflag ;

char sbuf[4];
byte sindex ;
char cmd ;

unsigned long rcvID  ; // receive ID
byte rcvLen          ; // receive data length
byte rcvBuf[4]       ; // receive buffer

// function prototype
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void show_help();
void init_rxbuf();
void show_string();
void show_param();
void trigger();

void setup()
{
  // serial debug
  Serial.begin(115200);
  sindex = 0;
  crlf();
  rs_puts("test CAN receive with MCP2515");
  crlf();

  // init CANS bus, baudrate: 250kbps@16MHz
  if( CANR.begin(MCP_ANY, CAN_250KBPS , MCP_16MHZ) == CAN_OK ) {
    rs_puts("CANR: Init OK!");
    CANR.setMode(MCP_NORMAL);
  } else{ 
    rs_puts("CANR: Init Fail!");
  }
  crlf();

  // enable CAN interrupt
  pinMode(CAN_INT,INPUT_PULLUP);

  // INT0 interrupt
  attachInterrupt(0, trigger , FALLING );

  // clear flags
  uflag = OFF ;
  sflag = OFF ;

  // initialize receive buffer
  init_rxbuf();
}

void loop()
{
  // receive CAN signal INT : ~~|__
  if ( sflag ) {
    // clear flag
    sflag = OFF ;
    // get data from receive buffer
    CANR.readMsgBuf( &rcvID , &rcvLen , rcvBuf );
    // show
    show_param();
    // perform
  }
  // command interpreter
  if ( uflag ) {
    // clear flag
    uflag = OFF ;
    // get command 
    cmd = *(sbuf+0) ;
    // help
    if ( cmd == '?' ) { show_help(); }
    // command 'S' show receive buffer context
    if ( cmd == 'S' ) { 
      crlf();
      show_string();
    }
    // new line
    crlf();
  }
}

void rs_putchar(char x)
{
  Serial.write( x );
}

void rs_puts(char *ptr)
{
  while ( *ptr ) {
    rs_putchar( *ptr );
    ptr++;
  }
}

void crlf()
{
  rs_putchar('\r');
  rs_putchar('\n');
}

void show_help()
{
  rs_puts("? help");                 crlf();
  rs_puts("S show receive context"); crlf();
}

void init_rxbuf()
{
  byte ii ;
  for ( ii = 0 ; ii < 4 ; ii++ ) {
    *(rcvBuf+ii) = '@' ;
  }
}

void show_string()
{
  byte ii ;
  //
  for ( ii = 0 ; ii < 4 ; ii++ ) {
    rs_putchar( *(rcvBuf+ii) );
  }
}

void show_param()
{
  rs_puts("ID : 0x"); Serial.print( rcvID , HEX);
  rs_puts(" Length : "); Serial.print(rcvLen);
  rs_puts(" Data : ");
  show_string();
  crlf();
}

void trigger()
{
  sflag = ON ;
}

/* receive interrupt */
void serialEvent()
{
  char ch;

  if ( Serial.available() > 0 ) {
    /* get 1 character */
    ch = Serial.read();
    /* store */
    *(sbuf+sindex) = ch ;
    /* increment */
    sindex++ ;
    /* judge */
    if ( ch == '\r' ) {
      sindex = 0 ; 
      uflag  = ON ;
    }
  }
}

 Teratermでは、次のように受信していることを
 モニタします。



 シリアルインタフェースで、送信側が出力した
 コマンドが受け取れているか判断します。

 IDは、送信側で0x100。受信側で、IDが0x100と
 表示されたので、確実に受信と判断できます。


 送信側と受信側は、2ピンのワイヤーで接続。



 終端抵抗は、120Ωを利用していますが
 100Ωでも問題なく動作しました。


目次

inserted by FC2 system