ADS1115 STM32 HAL
STM32F103(blue pill):12ビットのADC搭載
読み取り精度が必要な時に16ビットなどが欲しい。1chならMCP3425が有名で秋月で簡単に購入できる。一方いくつもとなるとMultiplexerが搭載されているマルチチャンネルが読めるものが必要
入手性から ADS1115 を購入してみた。アマゾンでADCを調達しようとするとこれが出てくる。MCP3425から比べると大きい(4ADC分あるからといえば)。
また16ビットとなっているが、フルスケールがプラスマイナスなので実際は正側だけ使う場合は、15ビットの分解能になるとはいえ、フルスケールも選択できるので分解能はFSが狭ければ稼ぐ事もできる。
使い方のメモ。
【動作】
動作させる主な手順
1.レジスタとしてAddress Pointer registerに書き込みConfig Registerを指定する。
2.Config Registerに設定を書き込む
3.レジスタとしてAddress Pointer registerに書き込みConversion Registerを指定する。
(Conversion Register:16ビットのAD変換の結果が格納されるレジスタ)
4. Conversion Registerの内容を読み込む
上記で書き込み時には、 R/Wビットはゼロ(LOW)で、読み込む時は、1(HIGH)にする。
【アドレス】I2Cのアドレスは4種類から選べ、メカで(ハードの時点で)ADDR Pinをどこに接続するかで決められる。1つの4ch分を使うのであれば、GNDにでも繋いでおく。
レジスタとして、
Conversion Register:16ビットのAD変換の結果が格納されるレジスタ
Config Register:各種の設定をするレジスタ
Lo thresh Register/ Hi thresh Register:コンパレーターの機能をもっていて閾値を設定できる(ここで指定した値に入るとALERT/RDYのピンの出力を変動させる事ができる。モードが通常とコンパレーターとWindowモードがあり、出力を制御できる。このあたりはデータシートを参照。)
まず設定をしたいので、Address Pointer registerに01を書き込む。前の6つは常にゼロなので0B0000001となる。
実際の書き込みは、7ビットのアドレス(ここではADDR PinはGND接続で説明)1001000を一つ左にシフトさせてR/WビットをLOW(書き込み)を指定(シフトした時点でゼロが入っているので何かする訳ではない)してB10010000を送信。
具体的には、
ADS1115_address (0x48 << 1) と1ビットずらしておいて、
HAL_I2C_Master_Transmitを呼び出すと最初の8ビットはHALがアドレスを指定(1ビット人によりずらしてあげたアドレス)すると自動で送られるので、こちらで意図的に送る必要はなくて残る3バイト(24ビット分)を送付する。
その後続けて、Address Pointer register Config Registerを編集したいので0B00000001を送信。
【手順2】Config Registerの内容を決めて送信する
それぞれは、データシートを見るとして、要約。
OS:寝ている子を起こす。後で出てくるが、連続取得ではなくシングルショットで取得すると電力削減のためにスリープする。その場合起こすのに1とする。MUX:出力を差動で取り出す(この場合実質2チャンネル)か、GND基準にして4チャンネル取得するか?を決め、どのチャンネルを読むかを指定する
000 : AINP = AIN0 and AINN = AIN1 (default)
001 : AINP = AIN0 and AINN = AIN3
010 : AINP = AIN1 and AINN = AIN3
011 : AINP = AIN2 and AINN = AIN3
100 : AINP = AIN0 and AINN = GND
101 : AINP = AIN1 and AINN = GND
110 : AINP = AIN2 and AINN = GND
111 : AINP = AIN3 and AINN = GND
GNDに対して、チャンネル1~4まで順番に読みたい場合はここのビットを変更していく事になる。
PGA:これはPGA。ゲイン。デフォルトで010 : FSR = ±2.048 V (default)
000 : FSR = ±6.144 V
(1)
001 : FSR = ±4.096 V
(1)
010 : FSR = ±2.048 V (default)
011 : FSR = ±1.024 V
100 : FSR = ±0.512 V
101 : FSR = ±0.256 V
110 : FSR = ±0.256 V
111 : FSR = ±0.256 V
(1) VDDがこの値を超える時に使える。つまり3.3V電源だと4.096Vのレンジでは測定できない。
MODE:連続取得するか?シングルショットで取得(シングルは取得後寝る)か?
0 : Continuous-conversion mode
1 : Single-shot mode or power-down state (default)
DR:サンプリングレート:ノイズとの兼ね合いで決める。デフォルトの128が早くてかつノイズもあらゆる条件で低い。遅くしたからと言ってノイズも減らないので、128基本かな。
000 : 8 SPS
001 : 16 SPS
010 : 32 SPS
011 : 64 SPS
100 : 128 SPS (default)
101 : 250 SPS
110 : 475 SPS
111 : 860 SPS
COMP_MODE~COMP_QUE:コンパレーター機能を使う時に指定する。ただ値を読むだけだったら、COMP機能を無効化するために、最後の2ビットには”11”とする。
コンペアを使わない場合でシングルショット、AINP = AIN0 and AINN = AIN1の差を見て、128SPSの場合
↓
MSB:(OS)1 (MUX)000 (PGA)010 (MODE)0 LSB:(DR)100 (COMP)00011
と上で送信したAddress Pointer register 0B0000001に続けて、MSB,LSBを送信する。
MUXの部部bンは読みたいチャンネルにあわせて変更していく。
【手順3】Conversion Registerを指定する。
7ビットのアドレス1001000にR/WビットをLOW(書き込み)を指定してB1010000を送信した後、手順1では、Address Pointer register 0B0000001を送ったが、ここをConversion Registerを指定のAddress Pointer register 0B0000000を送る。
これも上と同じでHALを呼び出せば、アドレス部分は自動で書き込みするので、後者の0B0000000だけを送付する。
【手順4】Conversion Registerの内容を読み込む
7ビットのアドレス1001000にR/WビットをHIGH(読み込み)を指定してB1010001を送る。続くビット16ビット分を読みめば、ADCの値を取り込める。
HALの場合は、読み込み時に、わざわざR/Wを指定しなくても勝手に1にしてくれるので、HAL_I2C_Master_Receive(&hi2c1, (uint16_t)ADS1115_address, &ADS1115_buffer, 2, 100);
といったように読み取る16ビット分を(上では2バイト)読んであげればよい。
実際のコード
mainの中で、
Vads1115=ADS1115_read(0);
を呼び出す。
CH3は常にGNDに接続して、CH0、CH1,CH2の間の差分を見るようにした。
1ch分減るが、精度はこちらの方が高そうだから。
ADS1115_readの関数:
float ADS1115_read(uint8_t num_ch) {
#define ADS1115_address (0x48 << 1) //ADDR Pin connect to GND
int16_t ADCread; //16 bit signed integer to show minus value
uint8_t ADS1115_ConfREG[3];
float Vads1115;
/*******Write to Config register:***********/
ADS1115_ConfREG[0]=0B00000001;//Address Pointer register
switch(num_ch){
//MSB:(OS)1 (MUX)000 (PGA)010 (MODE)0
case(0):
ADS1115_ConfREG[1]=0B10010100;
break;
case(1):
ADS1115_ConfREG[1]=0B10100100;
break;
case(2):
ADS1115_ConfREG[1]=0B10110100;
break;
case(3):
ADS1115_ConfREG[1]=0B11110100;
break;
}
//LSB:(DR)100 (COMP)00011
ADS1115_ConfREG[2]=0B10000011;
HAL_I2C_Master_Transmit(&hi2c1,(uint16_t) ADS1115_address, ADS1115_ConfREG, 3, 100);
/*******Write to Conversion Register***********/
ADS1115_ConfREG[0]=0B00000000;//Address Pointer register
HAL_I2C_Master_Transmit(&hi2c1,(uint16_t) ADS1115_address, &ADS1115_ConfREG[0], 1, 100);
/*******Read form Conversion Register***********/
HAL_I2C_Master_Receive(&hi2c1, (uint16_t)ADS1115_address, ADS1115_buffer, 2, 100);
ADCread=(ADS1115_buffer[0]) <<8 | ADS1115_buffer[1];
/*******Convert to voltage***********/
float Vref_ads1115=2.048;//Full scale (you should change to other)
Vads1115=Vref_ads1115/32768.0*ADCread;
// Return Voltage
return Vads1115;
}
コメント
コメントを投稿