« I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして | トップページ | 月の赤経・赤緯・地心距離を求める(海洋情報部の計算式) 2015年版 »

2014年11月25日 (火)

MCP3425のもうちょっと詳しい使い方(ソース付き)

I2Cで使えるADC(ADコンバータ)Microchip - MCP3425については

  「PICでI2C - ADコンバーター・MCP3425の使い方

に書きましたが、もう少し詳しいこととサンプルソースを書いておきます。
上の記事に書いたことを前提とした話になります。

MCP3425関連記事
  「PICでI2C - ADコンバーター・MCP3425の使い方
  「MCP3425のもうちょっと詳しい使い方(ソース付き)」 (この記事)

  「MCP3425の精度を調べてみた - 16bitADコンバータの分解能
  「じつはマイナスの電圧もちょっとは測れる16bitADコンバータMCP3425
  「ADコンバータでマイナスの電圧を測るとどうなるか? - MCP3425編
  「16bitADコンバータMCP3425とPICで作る白金抵抗温度計 - 1

=====

入力は差動入力になっています。だからブリッジの平衡をチェックするというようなことにも使えます。ですから

  「交流電圧計(ミリバル)の簡単な作り方

に書いたミリバルの表示部分として使うこともできます。

ただ当然のことながら入力はVSS-0.3V、VDD+0.3Vが絶対最大定格になりますので注意が必要です。電源電圧の同じところで使っていればまあまあ安心です(リアクタンスがあると電源電圧の範囲を超えることもあるので油断は禁物です)

16bitでフルスケールは±2.048V(この“-”というのは差動入力のマイナスです。マイナスの電圧を測ることはできません)ですので分解能は62.5μVです。x2、x4、x8のI2Cで制御可能な増幅器がついています。例えばx8とするとフルスケールは±256mVで分解能は8μVくらいになります(増幅器を使ったときの電圧は増幅率から自分で計算する必要があります(ソース参照)

とは言え上のリンクにあるようにマイナスの電圧がまったく測れないわけではないです。でもマイナスの電圧を測るときは注意が必要です。
  「
ADコンバータでマイナスの電圧を測ったときの内部抵抗の低下 - 16bitADC/MCP3425

これだけ分解能が高いとオフセットが気になりますが自動オフセット調整がされておりオフセットはとても小さいです。というかゼロです。実用上気になることはないと思います。
(ただ電源投入時基準電圧のドリフトらしきものは見られます。まあこれはなんでもおなじですが)

差動入力インピーダンスは2.25MΩを増幅率で割ったものになるので増幅率が最大の8のときは300kΩを切ります。用途によっては配慮が必要になります。

精度も分解能もなかなかのものですので測定には注意を払います。
白金薄膜抵抗を使った温度計だと次のような回路にしています。
Sample_3
基準電圧源から抵抗値が正確にわかる抵抗を通じて白金薄膜抵抗に小さめの電流を流します。そして白金薄膜抵抗による電圧降下を求めこれから白金薄膜抵抗の抵抗値を求めます。白金薄膜抵抗は100Ωくらいしかないのでシビアな条件での測定です。

これを次のようにしてしまうと違った(間違った)結果が得られます。
Sample1_2

1mAも流れていないのにこれらの違いがはっきりとわかるくらいに感度(+精度)がいいです(VSS付近の直線性も関係しているかもしれません)

この方法は間違っているわけではないですが結果に関係する要素多くて慣れないとなかなかうまくいかないかもしれません。次のように定電流回路を使う方法がおすすめです。
  「
思わぬところで見つけた負性抵抗 - 定電流回路(バイラテラル回路)

16bitのデータをXCコンパイラのfloat(何もしなければ24bit)に代入するのは心配になりますが、XCコンパイラのfloatは仮数部16bit、指数部8bitでギリギリで間に合っています。

温度特性はどうなのか、直線性は、増幅器の精度は、といろいろ気になってくると思いますがそういうのは「Microchip - MCP3425」に書いてあります。



ソースはmain.cとMCP3425lib.h、MCP3425lib.cのものです。これ以外のI2C通信とかLCD表示は

  「I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして

にあるソースがそのまま使えます。ソースには12F1822だったら、みたいな記述がありますが、実際にはそれなりのメモリが必要で12F1822くらいでは動きません。このソースは16F1938で動作を確認しています。

コンパイラは

  MPLAB X IDE v2.15 、Microchip MPLAB XC8 C Compiler (Free Mode) V1.32 Part Support Version: 1.32 (A)

を使っています。


関連

  「記事目次・趣味の電子工作

  「PIC18F26K22でSPI - 8ch/ADコンバータ MCP3208の使い方(ソース付き)
  「22ビット(20.6bit)ADコンバータMCP3553の使い方
  「22ビット(21.9bit)ADコンバータMCP3551の使い方 - MCP3553との分解能の比較

  「I2Cデバイス・アドレス一覧
  「同じアドレスのI2Cデバイスを使う
  「PICで平方根 - 白金薄膜抵抗で温度を測る
  「PICでI2C - 1 (温度計を作る)
  「PICでI2C - 液晶(LCD)ディスプレイ(ACM1602N1-FLW-FBW)に表示する
  「PICでI2C - LCD(液晶)ディスプレイによる違い
  「I2C大気圧センサーLPS331の驚くべき分解能
  「I2C大気圧温度センサーLPS331 - 海面更生気圧を気象庁とくらべてみた
  「炭素皮膜抵抗の温度係数を測定する話
  「サーミスタによる温度測定の精度
  「サーミスタ温度計の精度を調べる - 1
  「ミニ恒温槽の作成に向けて - 1

------

main.c

#include <xc.h>
#include <stdio.h>
#include <math.h>
#include "MyDef.h"
#include "I2CLib.h"
#include "ACM1602lib.h"
#include "MCP3425lib.h"
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\12f1822.html
#ifdef _12F1822
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#endif
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\16f1705.html
#ifdef _16F1705
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#endif
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\16f1938.html
#ifdef _16F1938
#pragma config FOSC = INTOSC
#pragma config WDTE = OFF
#endif
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html
#ifdef _18F26K22
#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF
#endif
void interrupt InterFunction( void )
{
     // I2C関連の割り込み処理
     InterI2C() ;
}
void main()
{
    float   fp;
    char    buf[20];
    short iPG=0;
    short i;
#ifdef _12F1822
    OSCCON = 0b01111010 ;  // 16MHz
    ANSELA = 0b00000000 ;
#endif
#ifdef _16F1705
    OSCCON = 0b01110010 ;  // 8MHz
    ANSELC = 0b00000000 ;
    RC0PPS = 0x10;
    RC1PPS = 0x11;
#endif
#ifdef _16F1938
    OSCCON = 0b01110010 ;  // 8MHz
#endif
#ifdef _18F26K22
    OSCCON = 0b01110010 ;  // 16MHz
    ANSELC = 0b00000000 ;
#endif
    InitI2C_Master() ;
   
    LCD_Init() ;
    LCD_Clear();
    while(1) {
        fp=getVltMCP3425(iPG);
        LCD_SetCursor(0, 0);
        sprintf(buf,"%9.6f",fp);  // 一桁余計に表示しています。
        LCD_Puts(buf);
        for( i=0; i < 12; i++ ) __delay_ms(40);
       
    }
}
------

MCP3425lib.h
/* 
* File:   MCP3425lib.h
* Author: Seppina
*
* Created on 2014/11/24, 21:57
*/
#ifndef MCP3425LIB_H
#define MCP3425LIB_H
#define ADRES_MCP3425   0x68
float getVltMCP3425(int iPG);
#endif /* MCP3425LIB_H */

------

MCP3425lib.c

#include <xc.h>
#include "MyDef.h"
#include "I2Clib.h"
#include "MCP3425lib.h"
float getVltMCP3425(int iPG)
{
    int ip_MCP3425[4];
    float fp;
    int ans;
    int i;
    //  MCP3425のデータを取り込む
    ans = I2C_Start(ADRES_MCP3425,RW_0);        // スタートコンディションを発行する
    if (ans == 0) {
        I2C_Send(0b10001000 | (iPG & 0x03 )) ;                     // configuration byte
    //  bit 7 RDY: Ready Bit
    //    Reading RDY bit with the read command:
    //      1 = Output register has not been updated.
    //      0 = Output register has been updated with the latest conversion data.
    //    Writing RDY bit with the write command:
    //      Continuous Conversion mode: No effect
    //      One-Shot Conversion mode:
    //        1 = Initiate a new conversion.
    //        0 = No effect.
    //  bit 6-5 C1-C0: Channel Selection Bits
    //    These are the Channel Selection bits, but not used in the MCP3425 device.
    //  bit 4 O/C: Conversion Mode Bit
    //    1 = Continuous Conversion Mode.
    //    0 = One-Shot Conversion Mode. The device performs a single conversion and enters a low power
    //  bit 3-2 S1-S0: Sample Rate Selection Bit
    //    00 = 240 SPS (12 bits),
    //    01 = 60 SPS (14 bits),
    //    10 = 15 SPS (16 bits)
    //  bit 1-0 G1-G0: PGA Gain Selector Bits
    //    00 = 1 V/V,
    //    01 = 2 V/V,
    //    10 = 4 V/V,
    //    11 = 8 V/V
    }
    I2C_Stop() ;                              // ストップコンディションを発行する
    __delay_ms(150) ;
    ans = I2C_Start(ADRES_MCP3425,RW_1);        // スタートコンディションを発行する
    if (ans == 0) {
        for( i=0;i<2;i++){
            ip_MCP3425[i] = I2C_Receive(ACK) ;
        }
        ip_MCP3425[i] = I2C_Receive(NOACK) ;
    }
    I2C_Stop() ;                              // ストップコンディションを発行する
    fp = ip_MCP3425[1];
    fp = (fp+ip_MCP3425[0]*256.0);
    if( ip_MCP3425[0] & 0x80 ) fp=fp-65536.0;
    fp = fp * 62.5E-6;
    switch(iPG) {
        case 1:
            fp /= 2.0;
            break;
        case 2:
            fp /= 4.0;
            break;
        case 3:
            fp /= 8.0;
            break;
    }
    return fp;
}


« I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして | トップページ | 月の赤経・赤緯・地心距離を求める(海洋情報部の計算式) 2015年版 »

趣味の電子工作」カテゴリの記事

趣味の電子工作」カテゴリの記事

コメント

こんにちは。
思ったよりあっけなく動いてしまいましたが、2つご質問が有ります。

せっぴーなさんのプログラムでは
AD conの設定条件を毎回送信して、毎回 150msec休止を入れていますね。
この2つって毎回必要なのでしょうか?最初の1回だけやればいいような気がしますが。。。

それから、表示桁数について、生の計算結果は小数点以下7桁になるときがありますが、LCDには常に小数点以下6桁で表示されますよね。7桁目はどのように処理されていますか?
1digit 0.0000625
2digits 0.000125
3digits 0.0001875
...

コメントありがとうございます m(._.)m
コンフィグレーションレジスタを毎回書き換えていることでしたら、このプログラム例は(一回データを取得したら省エネモードに入る)シングルコンバージョンモードで動作させていますので、毎回書き込みが必要なはずです。
このソースはこうすれば絶対動くという例と考えていただいて、あとは目的・必要に応じてやり方を変えていただければと思います。例えば別に記事を書いたMCP3551/MCP3553ではノイズを軽減する目的で連続コンバージョンを行い複数回データを取得しそれらを平均して測定値とするというようなことをやっています。
それから出力データはsprintf()のフォーマットで指定した桁数に四捨五入されています。
もし御質問の回答になっていないようでしたら、お手数ですが再度コメントいただければと思います。
今後ともよろしくお願いいたします。

セッピーナさん、さっそくのお返事有難う御座います。
ご説明を聞いて理解致しました。

今まで12bit AD con MCP3208、高速AD con AD7820などいろいろ試してきましたが
このAD conの安定度にはすごく満足しています。
もっともノイズに強くなるようフィルター回路を入れて、基板のパターンを考慮したからなのかもしれませんが。。。

MCP3425はお値段の割に解像度が高く、基準電圧源内蔵で使いやすいですね。
ノイズにも強そうですし、けっこうお気に入りでした。
入力インピーダンスがちょっと低めなので用途によっては工夫が必要ですが。

セッピーナさん、連続モードでやってみようと思い、
コンフィギュレーションをI2C_Send(0b10011000 | (iPG & 0x03 )) に変えて試してみましたが
時々変換がミスるようです。どうなおしたらよいのでしょうか?

コンフィギュレーションデータを読み取って、7bit目を調べれば変換が終わったかどうか分かるようですが、どのタイミングで読み取ったら良いのか分からなかったです。


プログラム例では変換が終わっていることを前提に2バイトしか読み込んでいませんが、変換終了をチェックするのであれば3バイト読み込めばいいはずです。
以下のような感じで書けばいいと思います。

ただ、変換が終わっていなければ最後の変換結果が残っているだけでとエラーとはならない、と思うので他に原因があるような気もします。

do {
ans = I2C_Start(ADRES_MCP3425,RW_1); // スタートコンディションを発行する
if (ans == 0) {
for( i=0;i<3;i++){   // コンフィグレーションバイトまで読み込む
ip_MCP3425[i] = I2C_Receive(ACK) ;
}
ip_MCP3425[i] = I2C_Receive(NOACK) ;
}
I2C_Stop() ; // ストップコンディションを発行する

} while ( ( ip_MCP3425[2] & 0x80 ) != 0 )

※ 3バイト受信した後も(NOACKでなく)ACKを送り続ければコンフィグレーションバイトだけが繰り返し送信されてきますので厳密にはコンビ不レーションバイトを受信し続け変換が終了した時点(最上位ビットが0になった時点)で再度データを読み込むというやり方が正しいのかもしれません。

whileの()の後に ; が必要ですね。で直して、ちゃんと動きました!
data sheetの中に、3つめのbyteを読んで調べるように図が書かれていましたが、ふつうはbusyでなくなった後で変換値を読みに行くので、ちょっとおかしいなと思ってました。

あるとき表示桁がおかしくなったのは電源かPICのICピンの接触がわるくなったときにノイズを読み込んだのではないかと思います(one shotモードでも基盤を動かしているとそうなりましたから)。

うまく行きましたので、次回はごかんさんの記事を読んで、PIC24でトライしてみようと思います。これで動けば、8bitのfloat処理が遅いという問題が解決できていいかもしれません。。

”;”の件、ご指摘ありがとうございます。
きちんと動作したとのことで安心しました。
コンフィグレーションバイトを3バイト目におくのはちょっとどうかと思うのですが、利便性(?)を優先したんでしょうね。
デバイスの仕様書を隅から隅まで読んだわけでもないのであんまり無責任なことは書けませんが....

ご無沙汰しております。
あれから16bitPIC24Fで同じことをやってみようとお盆休みの大半をつぶして格闘した結果、いくつかの落とし穴を回避して、なんとかAD変換するところまでは行けたんですが、AD変換値の計算がうまくいかないので困っています。他の方の記事で大変恐縮ですが、もし分かったらお教えいただけると有り難いです。
下のウェブのメインプログラムでAD変換値を16進数 1FFFFで除算していますが、イメージがつかめないです。ちなみにこちらは18bit ADコンなので1 byte変換データが多くなっています。これをこちらの16bit ADコンで使用しています(1 byte少ない)。

http://www.picfun.com/PIC24F/AP/app24F03.html

セッピーナさん、自己レスです。
1FFFFは10進数で131071で、 18bit ADコンの表現範囲 -131072 ~ +131071の正の最大値ですので計算式がなんとなく分かってきました。なんでもすぐに聞いてしまってすいません。

ご無沙汰しております。
ソースをのぞいて見たのですが、おっしゃるとおりフルスケールを1.0に正規化するために0x1FFFFで割ってあるようですね。
自己解決されたようでよかったです。

有難うございます。お陰様で16 bit PICでもAD conを動かすことができました。^^


セッピーナさん、こんにちは。
上のmain.cというプログラムでI2C関連の割り込み処理というのが記述されていますが、割り込み許可を出してないので、ここに飛んでくることはないという解釈で合っていますか?

無事動作したとのことおめでとうございます。

I2C関連の割り込み処理はご指摘のとおり実際には使われていません。
仮に割り込み処理に入ってもフラグをクリアするだけで何もやっていないです。

このあたりは(あちこちでリンクしていますが)
  きむ茶工房ガレージハウス
  http://www.geocities.jp/zattouka/GarageHouse/Top.htm
が参考になると思います。

有難うございます。^^

そうですね、I2Cの割り込み処理は使用されてませんね。

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1994983/58082620

この記事へのトラックバック一覧です: MCP3425のもうちょっと詳しい使い方(ソース付き):

« I2Cのソース - PIC12F1822/16F1705/16F1938/18F26K22 - LCD(ACM1602)を例にして | トップページ | 月の赤経・赤緯・地心距離を求める(海洋情報部の計算式) 2015年版 »

フォト

サイト内検索

  • 記事を探されるんでしたらこれがいちばん早くて確実です。私も使ってます (^^;; 検索窓が表示されるのにちょっと時間がかかるのはどうにかしてほしいです。

新着記事

リンク元別アクセス数

  • (アクセス元≒リンク元、原則PCのみ・ドメイン別、サイト内等除く)

人気記事ランキング

  • (原則PCのみ、直近2週間)
無料ブログはココログ