A-Dコンバータ その5 12ビットSPI MCP3208-(2)
前回のスケッチはチャネル0の読み取りを行いました。8チャネル全部を読み出すように修正します。また、読み取り部分を関数にして使いやすくします。
#include <SPI.h>
#define SS 10
float Vref = 5.0 ;
SPISettings settings( 1000000 , MSBFIRST , SPI_MODE0 );
void setup() {
pinMode(SS, OUTPUT);digitalWrite(SS, HIGH);
Serial.begin(9600);
SPI.begin();
}
int adcRead(byte ch) { // 0 .. 7
byte channelDataH2 = ((ch & 0xf) + 8) >> 2 ;
byte channelDataL2 = ch & 0x03;
Serial.println(" ch= " + String(ch) + " "+ String(channelDataH2,BIN) + " "+ String(channelDataL2,BIN));
SPI.beginTransaction(settings);
digitalWrite(SS, LOW);
SPI.transfer(channelDataH2 + 4); // Start bit 1 + D2bit
byte highByte = SPI.transfer(channelDataL2 << 6); // singleEnd D1,D0 bit
byte lowByte = SPI.transfer(0x00); // dummy
digitalWrite(SS, HIGH);
SPI.endTransaction();
return ((highByte & 0x0f) << 8) + lowByte ;
}
void loop(){
for (byte channel = 0 ; channel <8 ; channel++ ) {
unsigned int dataCh = adcRead(channel) ;
float volts = dataCh*Vref /4096 ;
Serial.println("CH" + String(channel) +": " + String(volts,3) + "V") ;
}
delay(1000);
}
シングルエンドでチャネルを指定する4ビットは最初のバイトが、シングルエンドとD2ビット、次のバイトの先頭でD1、D0を指定するように泣き別れになります。adcRead()の最初で、チャネルの指定である0から7を分離する作業をしています。上位2ビットがchannelDataH2、下位2ビットがchannelDataL2です。実際の送信では、1バイト目は、StartビットをONするためにchannelDataH2 + 4とし、2バイト目は指定の2ビットをMSB側にもっていくためにchannelDataL2 << 6しています。もっとすっきりした指定方法があるかもしれません。
マスタから送っているデータです。
コンソールの出力です。入力のCH0は5V、CH1はGND、CH2は1.0000Vをつないでいます。
●電源を工夫
スケッチを走らせると、出力がある程度の範囲でばらつきます。ばらつきが見たいので、CH0を表示するスケッチを修正して小数点第4位まで表示しました。
次のフィルタを5VとVrefの間に入れました。
5VとMCP3208のVddの間にコモン・モード・フィルタを入れました。
Vrefにエネループを電源に使ったTL431の出力2.49228Vを入れ、Vrefを5Vからその値に変更しました。
いずれの方法も、三つの数値にばらついています。ブレッドボードの環境ではこのようなばらつきが起こるのが普通なのか、もっと抜本的な対策があるのでしょうか。
プリント基板に実装された12ビットA-DコンバータADS7042を利用した記事でも、小数点第3位は三つの数値にばらついていました。
A-Dコンバータの確度が±1LSBであれば、三つの数値にばらつくのはICの性能そのものだと考えられます。そうであれば、ブレッドボードでの計測は十分な性能が出ているとも考えられます。最後の桁を安定な表示にするには、10回ぐらいの測定値の平均もしくは最頻値を選ぶのがよいでしょう。A-DコンバータICのなかには、平均値を出力できる製品もあるかもしれません。