目次
前
次
SPI関係スケッチ
SPIインタフェースは、AVRのフラッシュROMに
プログラムコードを転送するときに使われる
ことが多く、ライターで利用されています。
RaspberryPiとArduinoを接続する前に、2つのArduino
マスターとスレーブの役割分担をし、接続しました。
1台のPCにUSB/シリアル変換器を2つ接続し、2つの
Arduinoと2つの仮想COMポートを使い、動作確認です。
SPIマスター側は、Personal Computer上の
端末ソフトで与えた文字列を受取り、SPI
インタフェースでスレーブ側に転送します。
端末ソフトとしてTeraTermを利用します。
コマンドは、2つだけにしました。
コマンドSでは、Sに続けて最大8文字まで
入力できるようにします。
仕様を固めたので、スケッチにします。
#include <SPI.h>
#include <MsTimer2.h>
#define OFF 0
#define ON OFF+1
#define LED_BIT 7
#define nSS_BIT 2
volatile byte sindex ;
volatile char sbuf[16] ;
volatile byte xspi;
volatile byte xcnt;
volatile byte uflag;
volatile byte eflag;
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 send_led(byte x)
{
if ( x ) { PORTD |= (1 << LED_BIT); }
else { PORTD &= ~(1 << LED_BIT); }
}
void update_trigger(void)
{
eflag = ON ;
}
void show_help()
{
rs_puts("? help"); crlf();
rs_puts("S send SPI data"); crlf();
}
void setup (void)
{
/* initialilze serial port */
Serial.begin(9600);
sindex = 0 ;
/* set I/O values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x01 ;
/* set port directions */
DDRB = 0x2f ;
DDRC = 0xff ;
DDRD = 0xfe ;
/* initialize SPI mode */
{
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
/* clear */
xcnt = 0 ;
/* clear flags */
uflag = OFF ;
eflag = OFF ;
/* LED handling */
MsTimer2::set(200,update_trigger);
/* enable */
MsTimer2::start();
}
void loop(void)
{
char cmd ;
byte i ;
char msg[8] ;
/* UART handling */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* new line */
crlf() ;
/* command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help() ; }
/* send data to SPI */
if ( cmd == 'S' ) {
/* clear buffer */
for ( i = 0 ; i < 8 ; i++ ) { *(msg+i) = 0 ; }
/* get data */
for ( i = 0 ; i < 8 ; i++ ) {
/* judge */
if ( *(sbuf+i+1) == '\r' ) break ;
/* store */
*(msg+i) = *(sbuf+i+1) ;
/* enable nSS */
PORTB &= ~(1 << nSS_BIT) ;
/* transfer */
SPI.transfer( *(msg+i) );
/* disable nSS */
PORTB |= (1 << nSS_BIT) ;
/* delay */
delay(1);
}
}
}
/* LED handling */
if ( eflag == ON ) {
/* clear flag */
eflag = OFF ;
/* impress */
send_led( xcnt & ON ) ;
/* update counter */
xcnt++ ;
}
}
/* 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では、次のように操作します。
スケッチの中では、setupの中に次の
パラメータを設定しています。
- モード
- MSBから出力するかLSBから出力するか
- 転送クロック周波数
マスター側は、SPI.hの中に定義されている
メソッドを使うだけなので、転送するときに
SSをイネーブルにすることに気をつけます。
スレーブ側は、SPIインタフェースで転送された
文字を2進数に変換後、接続PCに転送します。
接続PCでは、端末ソフトを利用しスレーブ側の
ArduinoがSPIインタフェースで受信したデータ
を確認します。
SPIスレーブとして利用するため、チップ内部に
あるレジスタでモードをスレーブにします。
setupの中に、次のコードを入れます。
SPCR |= (1 << SPE);
1バイトのデータ受信は、ハードウエアに任せ
受信終了を割込みによりloopに通知します。
ISR(SPI_STC_vect)
{
/* get 1 byte from SPI Data Register */
xspi = SPDR ;
/* set trigger flag */
sflag = ON ;
}
SPI.hの内容を見ると、attachInterruptがある
ので、外部割込みと等価な受信割込みを実現
できるようになっていました。
スレーブ側のスケッチは、以下。
#include <SPI.h>
#include <MsTimer2.h>
#define OFF 0
#define ON OFF+1
volatile byte xspi;
volatile byte sflag;
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 setup (void)
{
/* initialilze serial port */
Serial.begin(9600);
rs_puts("Hello!");
crlf();
/* set I/O values */
PORTD = 0x01 ;
PORTB = 0xef ;
PORTC = 0x00 ;
/* set port directions */
DDRD = 0xfe ;
DDRB = 0x10 ;
DDRC = 0xff ;
/* initialize SPI mode */
{
/* set SPI as slave */
SPCR |= (1 << SPE);
/* mode */
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV8);
/* enable SPI interrupt */
SPI.attachInterrupt();
}
/* clear flags */
sflag = OFF ;
}
/* SPI interrupt routine */
ISR(SPI_STC_vect)
{
/* get 1 byte from SPI Data Register */
xspi = SPDR ;
/* set trigger flag */
sflag = ON ;
}
void loop (void)
{
byte i ;
byte tmp ;
char msg[9] ;
/* flag handling */
if ( sflag == ON ) {
/* clear flag */
sflag = OFF ;
/* */
tmp = xspi ;
rs_putchar( tmp ) ;
rs_putchar( '\t' ) ;
/* clear */
for ( i = 0 ; i < 9 ; i++ ) { *(msg+i) = '\0' ; }
/* separate */
for ( i = 0 ; i < 8 ; i++ ) {
/* get bit code */
*(msg+i) = (tmp >> (7-i)) & ON ;
/* convert ASCII */
*(msg+i) += 0x30 ;
}
/* show */
rs_puts( msg ) ;
crlf() ;
}
}
スレーブ側Arduinoに接続したPCのTeraTermの
画面は、以下のようになりました。
文字をそのままASCIIコードで表示し、2進数表示に
なっているので、間違いなくSPIによるデータ転送で
あるとわかります。
マスターからスレーブにデータ転送するだけで充分な時も
ありますが、スレーブからデータを返すことが必要な場面
もあります。その場合の処理は、別ページで扱います。
目次
前
次