ゆるく楽しむプログラミング

Arduino同士をI2C接続 ~I2C SLAVE~

Arduino同士をI2C接続して、スレーブ側をOLED SSD1306のコントローラにしてみました。
SSD1306の描画処理をスレーブに持たせることで、SSD1306の描画処理に必要なメモリーを節約できます。



I2Cスレーブ設定

1) Wire.begin( )にI2Cアドレスを設定する事でスレーブになります。
2) 内蔵PULL UPを無効にする場合には Wire.begin()実行後にpinMode()を変更
3) 受信・送信要求の割り込み処理関数を定義
この3ステップだけでI2Cスレーブとして動作します。

※ <>を全角<>に置き換えています。コピペの際は注意してください。
#include<Wire,h>
void setup() {
  Wire.begin(SLAVE_ADDR);	// I2Cアドレスを設定

  pinMode(SDA, INPUT);		// 内蔵PULL UPを無効にする
  pinMode(SCL, INPUT);

  Wire.onReceive(i2cRecive);	// 受信割り込み関数定義
  Wire.onRequest(ic2Send);	// 送信要求割り込み関数定義
}

// 受信割り込み関数
// numBytes - 受信したデータバイト数
void i2cRecive(int numBytes) { }

//  送信要求割り込み関数
void ic2Send(int numBytes) { }


SSD1306コントローラ

描画コマンドを決めて、I2C受信時に該当するコマンドを実行するSSD1306コントローラを作成します。
描画さえできればよいので自由度は割と高めです。
描画コマンドは必要なら増やせばよいので適当に▼のように決めてみました。
コマンド パラメタ
0x01 CLS
0x02 SCROLL
0x03 LINE XS YS XE YE COLOR
0x04 RECT X Y W H COLOR
0x05 FILLRECT X Y W H COLOR
0x06 CIRCLE X Y R COLOR
0x07 FILLCIRCLE X Y R COLOR
0x08 LOCATE X Y
0x09 FONT COLOR COLOR
0x0A PRINT 文字列 MAX 16
0x0B PRINT X Y 文字列 MAX 16
0x0C 7SEG DISP X Y N COLOR
0xFE DEBUG MODE OFF
0xFF DEBUG MODE ON



I2C-SLAVE.zip
I2C-MASTER.zip (動作DEMO用)

※ <>を全角<>に置き換えています。コピペの際は注意してください。
#include <Wire.h>
#include "ssd1306SPI.h"

SSD1306SPI ssd1395spi ;
char str[128] ;
int count = 0 ;

#define SLAVE_ADDR 0x02   // 7-bit Slave Address
byte i2cRecvBuffLen;
byte i2cRecvBuff[32];
byte i2cSendBuffLen;
byte i2cSendBuff[32];
uint8_t busyFlag = 0 ;  // 0-Ready : 1-Busy
bool DEBUGMODE = false ;

// --- I2C 受信 ---
void i2cRecive(int numBytes){
  i2cRecvBuffLen = 0 ;
  while(Wire.available()){
    if(i2cRecvBuffLen < 32){
      i2cRecvBuff[i2cRecvBuffLen] = Wire.read();
      i2cRecvBuffLen++;
    }
  }

  busyFlag = 1 ;
  if (DEBUGMODE) {
    // -- DEBUG表示
    sprintf(str,"CMD %02X",i2cRecvBuff[0]) ;
    ssd1395spi.Print(0,4,str) ;
    for (int i=1;i<i2cRecvBuffLen;i++) {
      sprintf(str,"%02X",i2cRecvBuff[i]) ;
      ssd1395spi.Print((i-1)*3,6,str) ;
    }
   } else {
      execI2CCommand( ) ;
   }
  busyFlag = 0 ;
}

// --I2C 送信 ---
// Ready or Busyを返す
void ic2Send(){
  Wire.write(busyFlag);
}

// --- I2C 受信コマンド実行 ---
void execI2CCommand( ) {
  // COMMADN
  // [0] - COMMAND 
  // 0x01 : CLS
  // 0x02 : SCROLL
  // 0x03 : LINE [XS][YS][XE][YE][COLOR]
  // 0x04 : RECT [X][Y][W][H][COLOR]
  // 0x05 : FILLRECT [X][Y][W][H][COLOR]
  // 0x06 : CIRCLE [X][Y][R][COLOR]
  // 0x07 : FILLCIRCLE [X][Y][R][COLOR]
  // 0x08 : LOCATE [X] [Y]
  // 0x09 : FONT COLOR [COLOR]
  // 0x0A : PRINT [文字列 MAX 16]
  // 0x0B : PRINT [X][Y][文字列 MAX 16]
  // 0x0C : 7SEG DISP [X][Y][N][COLOR]
  // 0xFE : DEBUG MODE - OFF
  // 0xFF : DEBUG MODE - ON

   switch(i2cRecvBuff[0]) {
    case 1:  // 1 : CLS
      ssd1395spi.cls( ) ;
      break ;
    case 2:  // 2 : SCROLL
      ssd1395spi.scroll( ) ;
      break ;
    case 3:  // 3 : LINE [XS][YS][XE][YE][COLOR]
      ssd1395spi.drawLine((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(int)i2cRecvBuff[3],(int)i2cRecvBuff[4],i2cRecvBuff[5]) ;
      break ;
    case 4:  // 4 : RECT [X][Y][W][H][COLOR]
      ssd1395spi.drawRect((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(int)i2cRecvBuff[3],(int)i2cRecvBuff[4],i2cRecvBuff[5]) ;
      break ;
    case 5:  // 5 : FILLRECT [X][Y][W][H][COLOR]
      ssd1395spi.fillRect((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(int)i2cRecvBuff[3],(int)i2cRecvBuff[4],i2cRecvBuff[5]) ;
      break ;
    case 6:  // 6 : CIRCLE [X][Y][R][COLOR]
      ssd1395spi.drawCircle((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(int)i2cRecvBuff[3],i2cRecvBuff[4]) ;
      break ;
    case 7:  // 7 : FILLCIRCLE [X][Y][R][COLOR]
      ssd1395spi.fillCircle((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(int)i2cRecvBuff[3],i2cRecvBuff[4]) ;
      break ;
    case 8:  // 8 : LOCATE [X] [Y]
      ssd1395spi.locate((int)i2cRecvBuff[1],(int)i2cRecvBuff[2]) ;
      break ;
    case 9:  // 9 : FONT COLOR [COLOR]
      ssd1395spi.setFontColor(i2cRecvBuff[1]) ;
      break ;
    case 10:  // A : PRINT [文字列 MAX 16]
      i2cRecvBuff[i2cRecvBuffLen] = 0 ;
      ssd1395spi.Print((char *)&i2cRecvBuff[1]) ;
      break ;
    case 11:  // B : PRINT [X][Y][文字列 MAX 16]
      i2cRecvBuff[i2cRecvBuffLen] = 0 ;
      ssd1395spi.Print((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(char *)&i2cRecvBuff[3]) ;
      break ;
    case 12:  // C : 7SEG DISP [X][Y][N][COLOR]
      ssd1395spi.disp7SEG((int)i2cRecvBuff[1],(int)i2cRecvBuff[2],(int)i2cRecvBuff[3]) ;
      break ;
    case 0xFE:  // DEBUGMODE - OFF
      DEBUGMODE = false ;
      ssd1395spi.cls( ) ;
      break ;
    case 0xFF:  // DEBUGMODE - ON
      DEBUGMODE = true ;
      debugmode() ;
      break ;
   }
}

void debugmode( ) {
  ssd1395spi.cls( ) ;
  sprintf(str,"I2C ADDR") ;
  ssd1395spi.Print(0,2,str) ;
  ssd1395spi.disp7SEG(11,0, SLAVE_ADDR % 16 ) ;
  ssd1395spi.disp7SEG( 9,0, SLAVE_ADDR / 16 ) ;
}

void setup() {
  i2cRecvBuffLen = 0;
  i2cSendBuffLen = 0 ;

  ssd1395spi.init() ;
  ssd1395spi.cls( ) ;
 
  Wire.begin(SLAVE_ADDR);

  pinMode(SDA, INPUT); // disable internal pull-up
  pinMode(SCL, INPUT); // disable internal pull-up

  ssd1395spi.cls( ) ;
  debugmode( ) ;

  Wire.onReceive(i2cRecive);
  Wire.onRequest(ic2Send);
}

void loop() {
}

解説動画