[メモ] Digispark(ATTiny85)をI2CのA/D変換デバイスにして、RaspberryPiから使う。



前回、[Digispark(ATTiny85) をI2CのSlaveで使用(TinyWireS)して、RaspberryPi(Master)と通信してみる](http://qiita.com/mt08/items/46d73c4e1957c1eb55f5)　の続きで、
> \#ラズパイにADCがない! => 手元にあるATTiny85のADCの値をI2Cで受け渡せば... ってのが動機。

を解消。フォトセルを使って、電圧を適当にかえて、A/D変換して、値をとる。

## 準備
- [前回](http://qiita.com/mt08/items/46d73c4e1957c1eb55f5)と同様の環境

## ピン配
- Digisparkの`P4`をADCポートとして使用。
- 接続は
    - 5V - フォトセル -　P4 - 1Kオームの抵抗 - GND 
    - フォトセル と 1Kオームの抵抗 のあいだにDigispark::P4端子を接続 
- 5Vがリファレンスなので、0V=0, / 5V=1023くらいの値がかえってくるハズ。
- あとは前回と同じ。P0=I2C-SDA, P2=I2C-CLK

![IMG_5049VGA.jpg](https://qiita-image-store.s3.amazonaws.com/0/75594/c571ebaa-e1ce-d4df-f0e8-51d489329d37.jpeg)


## Digispark側のコード

- get_adcVal()という、P4の電圧値を読みとって、i2c_regs[0]と[1]に格納する関数追加。loop内で呼び続ける。 
    - ## データが要求される[requestEvent()]ときにget_adcVal()を呼ぶようにしたら、たまに、というかけっこうな頻度で、変な値がでてきた。ADCリードで遅延するから？？I2Cのレートをおとせば、いけるかも。
- あとは、前回とほぼ同じ。

<pre>
#define I2C_SLAVE_ADDRESS 0x5A // the 7-bit address
#define LED_PIN         1      // DigiSpark LED pin

#include "TinyWireS.h"

#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif

volatile uint8_t i2c_regs[] =
{
    0xDE, 
    0xAD, 
    0xBE, 
    0xEF, 
};

int get_adcVal() {
  analogReference(DEFAULT);  // Reference = 5V
  int adcValue = analogRead(2); // Read P4
  i2c_regs[0] = adcValue & 0xff;
  i2c_regs[1] = (adcValue>>8) & 0xff;
}


volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);

void requestEvent()
{  
    reg_position %= reg_size;
    TinyWireS.send(i2c_regs[reg_position]);
    reg_position++;
}

void receiveEvent(uint8_t howMany)
{
    // Sanity check
    if ((howMany &lt; 1) || (howMany > TWI_RX_BUFFER_SIZE)) return;
    
    reg_position = TinyWireS.receive();
    howMany--;

    while(howMany--)
    {
        reg_position %= reg_size;
        i2c_regs[reg_position] = TinyWireS.receive();
        reg_position++;
    }
}

void setup(){
    pinMode(4, INPUT);  // P4=ADC Input
    pinMode(LED_PIN,OUTPUT);
    mt08Blink(LED_PIN, 2);               //開始時LED点滅

    TinyWireS.begin(I2C_SLAVE_ADDRESS);
    TinyWireS.onReceive(receiveEvent);
    TinyWireS.onRequest(requestEvent);
}

void loop()
{
    TinyWireS_stop_check();
    get_adcVal();
}

void mt08Blink(byte led, byte times)
{
  times *= 2;
  while(times > 0) {
    digitalWrite(led,(times & 0x01) ? LOW : HIGH);
    delay (200);
    times--;
  }
}

</pre>

## 実行例

```shell-session
pi@raspberrypi ~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- 5a -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
pi@raspberrypi ~ $ i2cget -y 1 0x5a 0x00; i2cget -y 1 0x5a 0x01
0xed
0x02
pi@raspberrypi ~ $ i2cget -y 1 0x5a 0x00; i2cget -y 1 0x5a 0x01
0x59
0x00
```

|ADC(16進)|ADC(10進)|ADC電圧|電圧実測(テスタで計測)|
|:-:|--:|:-:|:-:|
| 0x02ED | 749 | 5V * 749/1024 = 3.66V | 3.64V| 
| 0x0059 | 89 |5V * 89/1024 = 0.43V |  0.412V |

## 予定は未定
- 一定間隔で値を読み出して、クらウドとかにデータ送って、グラフなんかつくったりしちゃうとかっこいいよね。