目次
前
次
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Ωでも問題なく動作しました。
目次
前
次