22ビット(20.6bit)ADコンバータMCP3553の使い方
16bitのADコンバータMCP3425に飽きたらず22bitのADコンバータMCP3553に手を出してみました。22bitとは言ってもタイトルにあるとおり実質的(Effective Resolution)には20.6bitですが。
本家のデータシート(PDF、日本語)はここにあります。
「Microchip - MCP3550/1/3 低電力、単チャネル、22ビット デルタ-シグマADC」
MCP3425がI2Cなのに対しこちらはSPIです。
サンプリング・レートは60/sとけっこう速いです。
電源は2.7V~5.0Vが標準(?)のようです。かなり広い範囲で使えます。
Vrefは外部から与えます。ここはMCP3425とは違います。
せっかくだから内蔵してくれればいいのにと思うのですが、さすがに22bitともなるとそれに見合う基準電圧源がないのでしょうか。
私の場合は抵抗比を求めるのが目的なので電圧計に要求するは不確かさではなく分解能と(温度や電源電圧に対する)安定性なのでどうにかなるでしょう。
なおこのシリーズには3550、3551というのがあります。そちらは高級品で電源ノイズの除去機能(50/60 Hz Rejection)なんてものがついていますしEffective Resolutionはなんと21.9bitになります。
==> 「22ビット(21.9bit)ADコンバータMCP3551の使い方 - MCP3553との分解能の比較」
=======
なぜこういうのに手を出したかというといろいろ理由やきっかけがあるのですが、それは別の記事に書く予定なのでさっそく本題に入ります。
インターフェースはSPIなんですが使い方によってはI2Cなみというかそれ以上に簡単です。
SDIピンがありません。PICのSDOの接続は不要です。
他にSPIデバイスを使わなければ(あるいは他のデバイスがあってもSDカードI/Fのときにやったようにアナログスイッチでデバイスを切り替えるような使い方であれば)/CSはLowにおとしっぱなしという使い方ができます。
この場合連続変換モード(Continuous Conversion Mode)になります。特に/CSをLowにおとっしっぱなしのときは2-WIRE CONTINUOUS CONVERSION OPERATIONと言うようです。
この連続変換モードのときはクロックを送れば最新の(直近の)測定値がもどってきます。“クロックを送れば”というのは0x00を送信すればという意味です(もちろん0xFFでもなんでもいいです。このデータはMCP3553は受け取っていないのですから)
SPIのモードは Mode 0,0とMode 1,1が使えるのですが、モードによって測定値のバイト数が異なります。つまり送信すべきバイト数が異なりますので注意が必要です。
「記事一覧(測定、電子工作、天文計算)」
==> 測定
==> 電圧
==> ADコンバータ
==> 「16bitADコンバータMCP3425の使い方と特性」
==> MCP3353
==> この記事
==> 「熱電対起電力を直接測定できる22bit(20.6bit)ADコンバータMCP3553」
--------
実験風景
PICはI2CとSPIが使えるいつものPIC18F26K22です。SPIにMCP3553、I2CにLCDを接続してあります。
基準電圧源はREF5030(3.0V)です(温度係数が小さそうなのでこれにしたのですが最悪ミニ恒温槽に入れてしまうつもりです)
-------
実験中のソースです。
上の写真にあるようにPICと同じブレッドボードの載せてやっつけでやっているのでノイズ対策らしきものはまだ何もやっていません。というかどう見ても近くにノイズ源があります。
この状態での実質的な分解能を下の結果から逆算すると悲しいことに16.7bit 17.6bitです (^^;;
(16 + 3.3 - 1.6 = 17.7、 3.3は分解能の一桁向上分、1.7というのは測定回数10の平方根から)
ノイズが原因なら(本来の分解能は高いので)平均をとれば改善するのではないかと思い)私が必要とする)MCP3425の10倍くらいの分解能が得られるまで平均をとる測定回数をふやしてみました。
そうすると10回の平均でMCP3425の10倍くらいの分解能が得られました。つまり16bit+3.3bitで19.3bitになりました。分解能が悪化している原因を見つけ一つ一つクリアして一回の測定でこの程度の実質的な分解能が得られるようにするのが今後の課題です。
-----
ソースはMode 0,0のときにあわせて作ってあります。
この場合データのバイト数は4になります。最初のバイトの頭3bitは測定データではありません。4bit目から22bitがデータです(Mode 1,1のときはデータは3バイトになり、全体的に1bit左にずれます)
最初のバイトの2bit目と3bit目はオーバーフローフラッグです。下のプログラムではオーバーフローのデータは(あんまり意味はありませんが)無視するようにしてあります。
コンパイルするときはdoubleを32bitにします。floatだと仮数部は16bitしかありません。
ウェイトのかけ方を変更しました(プログラムの最後の方の取り消し線と赤字のところです)またSPIモード設定を2回行っていたので一回ですませました。 2015.05.22)
電圧が負のときの計算方法が間違ってましたので修正しました。すみません m(._.)m 2015.05.26
I2Cに関しては
「I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして」
今回使っているLCDはこれとは別のものです。
「I2C薄型液晶ディスプレイ(LCD)・AQM1602XAの使い方」
SPIに関しては
「PICでSPI SDカードを読み書きする」
「このブログのPIC/SPIソースのきむしげさんの新しいskSPILIB.c対応 - MCP3553を例に」
// PIC18F26K22
// 01 /MCLR .....(1), Pull-up 10k
// 02 RA0/AN0
// 03 RA1/AN1
// 04 RA2/AN2/DACOUT
// 05 RA3/AN3
// 06 RA4
// 07 RA5/AN4
// 08 VSS
// 09 RA7
// 10 RA6/OSC2/CLKO
// 11 RC0
// 12 RC1
// 13 RC2
// 14 RC3/SCL1.....I2C Clock / Pull-up 2.7k(この値に特別な意味はありません)
// 15 RC4/SDA1.....I2C Data / Pull-up 2.7k(この値に特別な意味はありません)
// 16 RC5/SDO1
// 17 RC6/TX1
// 18 RC7/RX1
// 19 VSS .....(3)
// 20 VDD .....(2)
// 21 RB0/INT0
// 22 RB1/SCL2.....SPI Clock
// 23 RB2/SDA2.....SPI Data In
// 24 RB3/SDO2.....SPI Data Out <== MCP3553では使いません。
// 25 RB4.....SPI CS MCP3553 <== このプログラムでは使用していません
// 26 RB5
// 27 RB6/TX2/PGC .....(5)
// 28 RB7/RX2/PGD .....(4)#include <xc.h>
#include <stdio.h>
#include "MyDef.h"
#include "I2CLib.h"
#include "SPILIB.h"
#include "AQM1602lib.h"
#define COUNT 10
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html
#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF
// センサーから読み込んだデータをLCDに16進表示するため
// sprintf()を使いたくないとき用
void putLCDhex(unsigned char ch)
{
char hex[]="0123456789ABCDEF";
LCD_Putc(hex[ch>>4]) ;
LCD_Putc(hex[ch & 0x0f]) ;
}
void interrupt InterFunction( void )
{
// I2C関連の割り込み処理
InterI2C() ;
}
void main()
{
unsigned short i=0;
unsigned short j;
unsigned char ct[4];
double V, Vref=3.0, Vs=0.0;
char buf[20];
OSCCON = 0b01110010 ; // 16MHz
// for I2C
ANSELCbits.ANSC3 = 0;
ANSELCbits.ANSC4 = 0;
// for SPI
ANSELBbits.ANSB2 = 0;
ANSELBbits.ANSB1 = 0;
TRISB1 = 0;
TRISB3 = 0;
// OUTPUT
// MCP3553の/CS ..... このプログラムでは使いません。
// TRISB4 = 0;
// CS_3553 = 1;
//
SPIはひとまずmode 2として初期化します。
//SPI_Init(SPI_MODE2,SPI_CLOCK_DIV16) ;
// SPIはmode 0として初期化します。
SPI_Init(SPI_MODE0,SPI_CLOCK_DIV16) ;
InitI2C_Master() ;
LCD_Init() ;
LCD_Clear();
LCD_Putc(0x30);
for( j=0; j < 12; j++ ) __delay_ms(40);
//
SPI MODE 0
//SSP2STAT &= 0xBF;
//SSP2CON1 &= 0xEF;
while(1) {
for( j =0; j < 4; j++ ) {
ct[j]=SPI_transfer(0x00) ;
}
if( (ct[0] & 0x40) || (ct[0] & 0x20) ) continue;
V=(((double)ct[3]/256.0+ct[2])/256+ct[1])/256+(ct[0]&0x1F);
V =V / 16 * Vref;
if( ct[0] & 0x10 ) V = Vref - V;
if( ct[0] & 0x10 ) V = V - Vref * 2.0;
if( i == COUNT ) {
LCD_SetCursor(0, 0);
for( j =0; j < 4; j++ ) {
putLCDhex(ct[j]) ;
}
sprintf(buf,"%9.5f",Vs/COUNT);
LCD_SetCursor(0, 1);
LCD_Puts(buf);
//for( j=0; j < 5; j++ ) __delay_ms(40);
i=0;
Vs = 0.0;
}
Vs += V;
i++;
//__delay_ms(20);
// まれにループから抜け出せなくことがあるので何回かループして
// PORTBbits.SDA2がLOWに落ちなかったら抜けるようにした方がいいかも
while(PORTBbits.SDA2 );
}
}
« ADコンバータMCP3425と計装アンプLT1167で作るK熱電対温度計 - オフセットの自動補正 | トップページ | このブログのPIC/SPIソースのきむしげさんの新しいskSPILIB.c対応 - MCP3553を例に »
「趣味の電子工作」カテゴリの記事
- PICで作る100MHz周波数カウンタ検証用XOR(エクスクルーシブオア)逓倍器(2016.03.08)
- 150MHz(~200MHz?)周波数カウンター用プリスケーラー(1/4分周器)(2016.03.06)
- 測温抵抗体(Pt100、白金薄膜温度センサー)の抵抗値を温度に変換する(平方根を使わない)計算式(2016.03.01)
- GPS/JJY(標準電波)を基準周波数源とするためのPLLの詳細(2016.02.27)
- GPS受信モジュール1PPS対決 - GE-612T vs GM-5157A(2016.02.21)
この記事へのコメントは終了しました。
« ADコンバータMCP3425と計装アンプLT1167で作るK熱電対温度計 - オフセットの自動補正 | トップページ | このブログのPIC/SPIソースのきむしげさんの新しいskSPILIB.c対応 - MCP3553を例に »
コメント