Skip to content

Instantly share code, notes, and snippets.

@PiTshan
Last active October 7, 2015 03:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PiTshan/5025d7ba2e5985db494f to your computer and use it in GitHub Desktop.
Save PiTshan/5025d7ba2e5985db494f to your computer and use it in GitHub Desktop.
RaspPiとArduinoをI2C接続して、アナログセンサを最大4つ接続する
/*
* I2C SensorHub Ver1.0
* created 18 Sep. 2015
* function:
* communicate to AD converter(A0,A1,A2,and A3 port) on Aruduino UNO via I2C bus.
* based on SUMBus protocol (almost, uncertain)
* Editor : PiT
* 07 Oct. 2015 V1.1 A0_MSB,A0_LSB,..A3_MSB,A3_LSBをReadOnlyに変更
* 07 Oct. 2015 V1.0.1 コメント:レジスタマップの間違いを修正
* 01 Oct. 2015 V1.0 release
* 01 Oct. 2015 V0.5 I2Cのデータロストを防止するため、PWM機能のディセーブル。SDA,SCLの内部プルアップをディセーブル。
* レジスタマップ変更、Vddコントロールの仕様変更、デバイスディスクリプション”SHUB”バージョン、リビジョンレジ 追加 (動作確認用)
* 26 Sep. 2015 V0.4 レジスタを16→256に戻す。 余計なアドレス計算でRaspPi側からのアクセスに間に合わない模様 デバッグ用シリアルポートをコメントアウト
* 25 Sep. 2015 V0.3 スレーブIDを0x50→0x72に変更。13番PinをAD変換中に点灯させるように変更
* 25 Sep. 2015 V0.2 レジスタを256→16に変更。アドレス上位は不定になります。 コメントを少し変更。
* 18 Sep. 2015
*
* pin connection 1 to RaspberryPi
* Arduino - Master device (Laspberry Pi)
* A4(SDA) - I2C1SDA
* A5(SCL) - I2C1SCL
* GND - GND
*
* pin connection 2 (to analog sensor)
* センサのアナログ入力です
* Arduino - sensor
* A0 - A0Vo
* A1 - A1Vo
* A2 - A2Vo
* A3 - A3Vo
*
* pin connection 3 (to analog sensor Vdd)
* アナログセンサの電源をレジスタアクセスでON/OFFできるようにします。
* Arduino - sensor
* Digital13 - (A0Vdd)
* Digital12 - (A1Vdd)
* Digital11 - (A2Vdd)
* Digital10 - (A3Vdd)
*
* Register Map
* 0x00 A0_CTRL : 2'b00, vref[1:0], pondly[1:0], powctrl, enable(R/W)
* 0x01 A1_CTRL : 2'b00, vref[1:0], pondly[1:0], powctrl, enable(R/W)
* 0x02 A2_CTRL : 2'b00, vref[1:0], pondly[1:0], powctrl, enable(R/W)
* 0x03 A3_CTRL : 2'b00, vref[1:0], pondly[1:0], powctrl, enable(R/W)
* 0x04 - 0x07 reserved : 8'b0000_0000 (R/W)
* 0x08 A0_MSB : 4'b0, A0MSB[11:8] (R/W)
* 0x09 A0_LSB : A0LSB[ 7:0] (R/W)
* 0x0A A1_MSB : 4'b0, A1MSB[11:8] (R/W)
* 0x0B A1_LSB : A1LSB[ 7:0] (R/W)
* 0x0C A2_MSB : 4'b0, A2MSB[11:8] (R/W)
* 0x0D A2_LSB : A2LSB[ 7:0] (R/W)
* 0x0E A3_MSB : 4'b0, A3MSB[11:8] (R/W)
* 0x0F A3_LSB : A3LSB[ 7:0] (R/W)
* 0x10-0x13 DeviceDiscriptionID : "SHUB"
* 0x14 Version No.
* 0x15 Revision No.
*
* 0x00-0x03 : A0_CTRL, A1_CTRL, A2_CTRL, A3_CTRL
* 2'b00, vref[1:0] pondly[1:0], sleepmode, enable
* vref[1:0] : Vrefソースの選択 00:Vdd, 01:internal1V1, 10:Aref-pin, 11:Vdd 
* pondly : power on delay センサーの電源ONからADC開始までのディレイ(100mSec単位)
* 0~300mSecまで センサーが落ち着くのに時間がかかる場合に使う
* 100mSec(2'b01)を設定しておくとだいたい安定して測定できるようです。
* powctrl : センサの電源をディジタルピンから供給し、ADC中のみONにする。
* 常時ONにしたい場合は、ディジタルピンを使わずにVddに接続しておいたほうが良いです
* センサのドライブ電流に注意
* enable : ADCイネーブル 1のあいだ変換中で、変換終了後0に戻る
*
* 0x08-0x0F : AD変換された値はここに格納されます。
* 0x10-0x13 DeviceDiscriptionID : I2Cの接続確認などに使います。
* 0x14 Version : I2CSensorHubのバージョンです。インターフェイスの大幅な仕様変更など、RaspPiソフトウェア側の変更が必要な場合増えます。
* 0x15 Revision : I2CSensorHubのリビジョンです。RaspPiのソフトウェアに影響がない場合増えます。
*/
#include <Wire.h>
const char DEVICE_ID = 0x72; //slave device address
#define VERSION 01
#define REVISION 01
/* REG MAP define */
#define A0_CTRL 0x00
#define A1_CTRL 0x01
#define A2_CTRL 0x02
#define A3_CTRL 0x03
#define A0_RSVD 0x04
#define A1_RSVD 0x05
#define A2_RSVD 0x06
#define A3_RSVD 0x07
#define A0_MSB 0x08
#define A0_LSB 0x09
#define A1_MSB 0x0A
#define A1_LSB 0x0B
#define A2_MSB 0x0C
#define A2_LSB 0x0D
#define A3_MSB 0x0E
#define A3_LSB 0x0F
/* pin connection 3   センサーのパワーピン 
* アナログセンサの電源をコントロールしたい場合に使用します。
* AD変換中以外はセンサーの電源を落とします。 
* この機能が必要ない場合は、センサーの電源はVddなどに接続しておきます。
* Arduino - sensor
* 13 - (A0Vdd)
* 12 - (A1Vdd)
* 11 - (A2Vdd)
* 10 - (A3Vdd)
*/
#define A0_VDD_PIN 11
#define A1_VDD_PIN 10
#define A2_VDD_PIN 9
#define A3_VDD_PIN 8
#define ADC_ACT_LED 13
unsigned char deviceRegAddr; //SMBusレジスタのアドレス
#define MAX_REG_ADDR 256
unsigned char deviceReg[MAX_REG_ADDR]; //SMBus レジスタ
void setup() {
pinMode(A0_VDD_PIN, OUTPUT);
pinMode(A1_VDD_PIN, OUTPUT);
pinMode(A2_VDD_PIN, OUTPUT);
pinMode(A3_VDD_PIN, OUTPUT);
pinMode(ADC_ACT_LED, OUTPUT);
digitalWrite(ADC_ACT_LED, LOW);
Wire.begin(DEVICE_ID); // slave device address
digitalWrite(SDA, 0); // internal PullUp disable
digitalWrite(SCL, 0); // internal PullUp disable
Wire.onRequest(requestEvent); // tx event
Wire.onReceive(receiveEvent); // rx event
TIMSK0 = 0; //Timer0 interrupt disable, It means software PWM function also disable.
//its necessary for stable I2C communication
for (int i = 0; i < MAX_REG_ADDR; i++) deviceReg[i] = 0; //deviceReg initialize
deviceReg[0x10] = 'S';
deviceReg[0x11] = 'H';
deviceReg[0x12] = 'U';
deviceReg[0x13] = 'B';
deviceReg[0x14] = VERSION;
deviceReg[0x15] = REVISION;
}
int adcvalue;
void loop() {
if (deviceReg[A0_CTRL] & 0x01) { // A0_CTRL start flag is enabled
digitalWrite(ADC_ACT_LED, HIGH);
setARef(A0_CTRL);
digitalWrite(A0_VDD_PIN, HIGH); //sensor Vdd enable
powerondelay(A0_CTRL);
adcvalue = analogRead(A0);
deviceReg[A0_MSB] = (char)((adcvalue >> 8) & 0xFF);
deviceReg[A0_LSB] = (char)(adcvalue & 0xFF);
deviceReg[A0_CTRL] = deviceReg[A0_CTRL] & 0xFE;
}
if (deviceReg[A0_CTRL] & 0x02) digitalWrite(A0_VDD_PIN, HIGH); //sensor Vdd enable
else digitalWrite(A0_VDD_PIN, LOW); //sensor Vdd disable
if (deviceReg[A1_CTRL] & 0x01) { // A1_CTRL start flag
digitalWrite(ADC_ACT_LED, HIGH);
setARef(A1_CTRL);
digitalWrite(A1_VDD_PIN, HIGH); //sensor Vdd enable
powerondelay(A1_CTRL);
adcvalue = analogRead(A1);
deviceReg[A1_MSB] = (char)((adcvalue >> 8) & 0xFF);
deviceReg[A1_LSB] = (char)(adcvalue & 0xFF);
deviceReg[A1_CTRL] = deviceReg[A1_CTRL] & 0xFE;
}
if (deviceReg[A1_CTRL] & 0x02) digitalWrite(A1_VDD_PIN, HIGH); //sensor Vdd enable
else digitalWrite(A1_VDD_PIN, LOW); //sensor Vdd disable
if (deviceReg[A2_CTRL] & 0x01) { // A2_CTRL start flag
digitalWrite(ADC_ACT_LED, HIGH);
setARef(A2_CTRL);
digitalWrite(A2_VDD_PIN, HIGH); //sensor Vdd enable
powerondelay(A2_CTRL);
adcvalue = analogRead(A2);
deviceReg[A2_MSB] = (char)((adcvalue >> 8) & 0xFF);
deviceReg[A2_LSB] = (char)(adcvalue & 0xFF);
deviceReg[A2_CTRL] = deviceReg[A2_CTRL] & 0xFE;
}
if (deviceReg[A2_CTRL] & 0x02) digitalWrite(A2_VDD_PIN, HIGH); //sensor Vdd enable
else digitalWrite(A2_VDD_PIN, LOW); //sensor Vdd disable
if (deviceReg[A3_CTRL] & 0x02) digitalWrite(A3_VDD_PIN, HIGH); //sensor Vdd enable
if (deviceReg[A3_CTRL] & 0x01) { // A3_CTRL start flag
digitalWrite(ADC_ACT_LED, HIGH);
setARef(A3_CTRL);
digitalWrite(A3_VDD_PIN, HIGH); //sensor Vdd enable
powerondelay(A3_CTRL);
adcvalue = analogRead(A3);
deviceReg[A3_MSB] = (char)((adcvalue >> 8) & 0xFF);
deviceReg[A3_LSB] = (char)(adcvalue & 0xFF);
deviceReg[A3_CTRL] = deviceReg[A3_CTRL] & 0xFE;
}
if (deviceReg[A3_CTRL] & 0x02) digitalWrite(A3_VDD_PIN, HIGH); //sensor Vdd enable
else digitalWrite(A3_VDD_PIN, LOW); //sensor Vdd disable
digitalWrite(ADC_ACT_LED, LOW); //ADC active LED off
}
void powerondelay(int ControlRegIndex)
{
if (deviceReg[ControlRegIndex] & 0x04) delay(100); //power on delay 100ms
if (deviceReg[ControlRegIndex] & 0x08) delay(200); //power on delay 200ms
}
void setARef(int ControlRegIndex)
{
//vref[1:0] : Vrefソース 00:Vdd, 01:internal1V1 10:Aref-pin 11:Vdd
if ((deviceReg[ControlRegIndex] & 0x30) == 0x10) {
analogReference(INTERNAL); //use 1.1v reference
} else if ((deviceReg[ControlRegIndex] & 0x30) == 0x20) {
analogReference(EXTERNAL); //use ARef pin
} else {
analogReference(DEFAULT); //use Vdd=5V
}
analogRead(A0); //dmy 切り替えたあとに1回読む
}
//I2C interrupt ---------
void requestEvent() // I2C TX (i2cget)
{
Wire.write(deviceReg[deviceRegAddr]);
deviceRegAddr++; //auto increment
}
void receiveEvent(int howMany) // I2C RX 
{
deviceRegAddr = Wire.read();
while (0 < Wire.available()) // loop through all but the last
{
if (deviceRegAddr >= 0 && deviceRegAddr <= 0x07) //read and write reg
deviceReg[deviceRegAddr] = Wire.read(); // receive byte as a character
//other : read only
deviceRegAddr++; //auto increment
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment