2010-04-24

加速度センサの情報を LED 表示

Arduino の工作で以前、加速度センサの情報をシリアル出力し、PC 側のソフトでセンサ情報を表示したり、MAX7219 という IC を使って、LED を制御したりしてみました。

今日は、加速度センサの情報を バー表示LED を使って表示するテストをしてみました。バー表示LED は 10個のLED が並んでいるだけのモノで、これを 2個(都合 LED 20 個)使います。
MAX7219 は LED を 8個単位で管理するので、Scan Limit レジスタの値は 「2」、つまり 3桁 (Display digits 0 1 2) になります。

さてさて、加速度センサの情報を LED 表示できるとなると、実際に車載して動きを確認したくなります。なので、車載前提で工作するため、2DIN に収まるサイズのブレッドボードを用意しました。EIC-108 というサイズのブレッドボードを一部バラして、2DIN のスケルトンシャシーに貼り付けたダケのものですが。

LED と MAX7219 との接続は、ブレッドボードに向かって、LED 左側から...

  • DIG-0 の SEG_A、SEG_B、SEG_C...SEG_G、SEG_DP (LED 8個)
  • DIG-1 の SEG_A、SEG_B、SEG_C...SEG_G、SEG_DP (LED 8個)
  • DIG-2 の SEG_A、SEG_B、SEG_C、SEG_D (LED 4個)
としてみました。
一番左側の LED が、DIG-0 の SEG-A。一番右側が DIG-2 の SEG_D となってます。





今回のスケッチ。
analogRead() した値を、左右 512 に振り分け、10段階で LED 表示。
ニュートラル位置のキャリブレーションは未考慮で、512 決め打ちです。

//-----------------------------------------------------
//
//  加速度センサの左右 G の変化をバーLED で表示する。
//
//    ・加速度センサ・シールド
//    ・バー表示LED x2
//                                       2010-04-24
//-----------------------------------------------------

// MAX7219 REGISTER ADDRESS MAP
#define   REG_NO-OP     0x00
#define   REG_DIG_0     0x01
#define   REG_DIG_1     0x02
#define   REG_DIG_2     0x03
#define   REG_DIG_3     0x04
#define   REG_DIG_4     0x05
#define   REG_DIG_5     0x06
#define   REG_DIG_6     0x07
#define   REG_DIG_7     0x08
#define   REG_DECODEMODE    0x09
#define   REG_INTENSITY   0x0A
#define   REG_SCANLIMIT   0x0B
#define   REG_SHUTDOWN    0x0C
#define   REG_DISPLAYTEST   0x0F

// MAX7219 DATA
#define   SEG_DP        0x80
#define   SEG_A       0x40
#define   SEG_B       0x20
#define   SEG_C       0x10
#define   SEG_D       0x08
#define   SEG_E       0x04
#define   SEG_F       0x02
#define   SEG_G       0x01

// MAX7219 PIN at Arduino
int   DIN  = 2;     // DATA IN
int   LOAD = 3;     // LATCH
int   CLK  = 4;     // CLOCK

// LED Map(バー表示 LED 2個 (20 LED) を 8個単位で管理する)
typedef struct{
  unsigned char ucLED_0;  // 8 LED (左側)
  unsigned char ucLED_1;  // 8 LED
  unsigned char ucLED_2;  // 4 LED
}LEDMAP;

// 点灯させる LED のマップ
static LEDMAP s_LedMap;

//-----------------------------------------------------
// 初期化
//
//-----------------------------------------------------
void setup()
{
  pinMode(DIN,  OUTPUT);
  pinMode(LOAD, OUTPUT);
  pinMode(CLK,  OUTPUT);

  // Scan Limit
  MAX7219_SendData(REG_SCANLIMIT, 2);     // 2: Display digits 0 1 2

  // Decode Mode
  MAX7219_SendData(REG_DECODEMODE, 0);    // 0: No decode for digits 7–0

  // Intensity
  MAX7219_SendData(REG_INTENSITY, 0x07);    // 7: Duty Cycle 15/32

  // Shutdown Mode
  MAX7219_SendData(REG_SHUTDOWN, 1);      // 1: Normal Operation.

  // Display Test
  MAX7219_SendData(REG_DISPLAYTEST, 0);   // 0: Normal Operation.

  // LED 0, 1, 2 -- OFF
  MAX7219_SendData(REG_DIG_0, 0x0);
  MAX7219_SendData(REG_DIG_1, 0x0);
  MAX7219_SendData(REG_DIG_2, 0x0);
  s_LedMap.ucLED_0 = 0;
  s_LedMap.ucLED_1 = 0;
  s_LedMap.ucLED_2 = 0;
}

//-----------------------------------------------------
// メイン
//
//-----------------------------------------------------
void loop()
{
  int   iValue;
  int   iDisplayValue;

#if 0
  iValue = analogRead(0);     // Analog 0 -- Accelerator
  iValue = analogRead(1);     // Analog 1 -- Brake
  iValue = analogRead(4);     // G-Force Z
#endif

  //ユニットの設置都合により、G 検出センサを切り替える
  if( 0 ){
    iValue = analogRead(2);     // G-Force X
  }else{
    iValue = analogRead(3);     // G-Force Y
  }

  //表示する LED の個数 (1--10)
  iDisplayValue = GetGForce(iValue);

  //左右の表示 LED をセット
  if(!GetGDirection(iValue)){
    GForce_left(iDisplayValue);
    GForce_Right(1);
  }else{
    GForce_left(1);
    GForce_Right(iDisplayValue);
  }

  // LED 点灯
  outLED();

  delay(10);
}

//-----------------------------------------------------
//  G の大きさを 10 段階の層値で返す
//戻り値:
//  int   G の大きさを表す層値 (1--10)
//
int GetGForce(int iNowForce)
{
  int   iNeutral = 512;
  double  dValue, dClass;

  dValue = (double)(iNeutral < iNowForce) ? (iNowForce - iNeutral) : (iNeutral - iNowForce);
  dClass = (dValue * 9.0L / 512.0L) + 1;

  return  (int)dClass;
}

//-----------------------------------------------------
// G の発生方向を返す
//
int GetGDirection(int iNowForce)
{
  int   iNeutral = 512;

  return  (iNeutral < iNowForce) ? 1 : 0;
}

//-----------------------------------------------------
// G-Force Left
//  点灯させるべき LED に対応する bit を ON する。
//
//引数:
//  iLevel    G レベル (1--10)
//
void GForce_left(int iLevel)
{

  if(iLevel < 1){
    s_LedMap.ucLED_0 = 0;
    s_LedMap.ucLED_1 &= ~(SEG_A | SEG_B);

  }else if(iLevel > 10){
    s_LedMap.ucLED_0 = 0xFF;
    s_LedMap.ucLED_1 |= (SEG_A | SEG_B);

  }else{
    s_LedMap.ucLED_0 = 0;
    s_LedMap.ucLED_1 &= ~(SEG_A | SEG_B);

    switch(iLevel){
    case 10:
      s_LedMap.ucLED_0 |= SEG_A;
    case 9:
      s_LedMap.ucLED_0 |= SEG_B;
    case 8:
      s_LedMap.ucLED_0 |= SEG_C;
    case 7:
      s_LedMap.ucLED_0 |= SEG_D;
    case 6:
      s_LedMap.ucLED_0 |= SEG_E;
    case 5:
      s_LedMap.ucLED_0 |= SEG_F;
    case 4:
      s_LedMap.ucLED_0 |= SEG_G;
    case 3:
      s_LedMap.ucLED_0 |= SEG_DP;
    case 2:
      s_LedMap.ucLED_1 |= SEG_A;
    case 1:
      s_LedMap.ucLED_1 |= SEG_B;
      break;
    }
  }
}

//-----------------------------------------------------
// G-Force Right
//  点灯させるべき LED に対応する bit を ON する。
//
//引数:
//  iLevel    G レベル (1--10)
//
void GForce_Right(int iLevel)
{
  if(iLevel < 1){
    s_LedMap.ucLED_2 = 0;
    s_LedMap.ucLED_1 &= ~(SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);

  }else if(iLevel > 10){
    s_LedMap.ucLED_2 |= (SEG_A | SEG_B | SEG_C | SEG_D);
    s_LedMap.ucLED_1 |= (SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);

  }else{
    s_LedMap.ucLED_2 = 0;
    s_LedMap.ucLED_1 &= ~(SEG_C | SEG_D | SEG_E | SEG_F | SEG_G | SEG_DP);

    switch(iLevel){
    case 10:
      s_LedMap.ucLED_2 |= SEG_D;
    case 9:
      s_LedMap.ucLED_2 |= SEG_C;
    case 8:
      s_LedMap.ucLED_2 |= SEG_B;
    case 7:
      s_LedMap.ucLED_2 |= SEG_A;
    case 6:
      s_LedMap.ucLED_1 |= SEG_DP;
    case 5:
      s_LedMap.ucLED_1 |= SEG_G;
    case 4:
      s_LedMap.ucLED_1 |= SEG_F;
    case 3:
      s_LedMap.ucLED_1 |= SEG_E;
    case 2:
      s_LedMap.ucLED_1 |= SEG_D;
    case 1:
      s_LedMap.ucLED_1 |= SEG_C;
      break;
    }
  }
}

//-----------------------------------------------------
// LED 点灯
//
void outLED()
{
  MAX7219_SendData(REG_DIG_0, s_LedMap.ucLED_0);
  MAX7219_SendData(REG_DIG_1, s_LedMap.ucLED_1);
  MAX7219_SendData(REG_DIG_2, s_LedMap.ucLED_2);
}

//-----------------------------------------------------
// MAX7219 の DIN へデータ (16bit) を送る
//
void MAX7219_SendData(unsigned char regAddress, unsigned char data)
{
  digitalWrite(LOAD, LOW);

  regAddress &= 0x0F;
  shiftOut(DIN, CLK, MSBFIRST, regAddress);
  shiftOut(DIN, CLK, MSBFIRST, data);

  digitalWrite(LOAD, HIGH);
}