[硬體]為什麼ADS1115輸出只有12 bit? Arduino實作16bit ADC偵測

     因為工作的關係,常常看到IC的參考線路上會有一個用來量測電流精密電阻,這個阻值通常都非常小,常見的規格是10mOhm。這個級別的電阻可以串連在電源的路徑上,不會影響電路的正常工作,又能夠用來量測電流,不過體積明顯較大,常見在開發版上,比較少在量產品上看見。而這次我想要透過自製的Arduino搭配16bit ADS1115高精度ADC來做這個電流的偵測。

ADS1115


    雖然常常看到這個設計,也常常拿到有這種精密電阻的板子,但是工作了這麼多年卻沒看過有人真的透過這個電阻的跨壓來量測電流。其原因不外乎是因為需要很搭配高精度的電表,設備取得不易,或者是電壓太小,小電流量不準等原因。在公司裡比較常見的還是透過傳統串連電表的方式來量測,雖然準確,但是當電源數量一多,量測時間與複雜度也會瞬間提高很多。


為什麼ADS1115實際上使用只有12bit的資料輸出?

    首先說到ADS1115的取得方式。ADS1115是德州儀器TI的產品,只有SMT Type的封裝方式,對於我們沒有辦法走正常SMT流程的業餘玩家,這種封裝大致上束手無策,只能上網找現成已經打在板子上的模組。最容易的取得管道不外乎就是淘寶、蝦皮等等的網路賣場。


    如果有嘗試在各大拍賣網站像是蝦皮、淘寶、露天等等的賣場找過商品,應該會發現很多ADS1115的模組,一塊板子大約台幣100-200元不等價格販售,貨源很多,大多看起來是來自中國的產品。我隨機買了四組,基本上問題都差不多,就是可以正常的讀寫資料,但是精度都只有12bit,沒有TI官方Datasheet宣稱的16bit.


蝦皮購買的ADS1115模組(偽造品)


    相信大家如果是從網路平台蝦皮、淘寶或是露天等等來歷不明的賣家手中買到的中國製ADS1115模組,都是宣稱16bit高精度模組,但是買回來後,不外乎就是遇到以下幾件事情:

1. 實際ADC偵測範圍只有12bit精度。雖然讀取的總長度是16bit但是最後4個bit永遠是0000,也就是剩下12個有效位元。

2. 偶爾可能會買到瑕疵品,例如我就遇到了一個無法使用的模組,總共4個就遇到1個,在我手中的不良率就是1/4 (25%),買到壞掉的東西機率應該還滿高的。通電後會直接讓VDD變成0V。實際上從外部量不到短路的狀況,應該是IC內部有異常或是損傷的狀況。

3. 如果懷疑產品料號,檢查IC表面的Marking,確實是有TI的LOGO,且文字確實是ADS1115的識別文字「BOGI」。看起來像正品,但已經脫離IC原始膠捲包裝進行SMT後的物料,Marking很有可能被事後偽造。

 

    關於ADS1115是不是假貨的問題,在台灣的網站上討論不多,Google也不容易找到相關的問題,但如果到百度或是國外網站搜尋類似案例,還是可以找到少數遇到類似問題的玩家。最後得到的結論就是買到假貨,換一個正版的就好了。猜測是有不肖廠商把ADS1015表面的文字擦除,印上ADS1115的文字,藉此賺取暴利,通常這種方式容易發生在已經SMT後的IC上。在市面上非原廠保固的水貨造假也是常有的事情,尚在膠捲內的料可能就是日期(Date code)標籤被動手腳,或是受潮的元件重新放入新的濕敏標籤二次包裝,已經過爐的IC則可能更進一步被串改Marking。


    最後我決定找一個比較值得信賴的供應商購買,從貿澤電子的平台上購買,這裡就會發現貿澤產品型錄上ADS1115相關商品售價都比蝦皮上的價格高了2倍以上,甚至有樣貌相似的商品價格差距有4倍之多(100元->400元),這也怪不得市面上會有仿冒品產出。網路上比較知名的電子零件零售平台有貿澤電子DigiKey,應該都是能夠買到正品的平台,雖然比較有保障,但是價格偏高。只要到該平台網站搜尋關鍵字「ADS1115」就可以找到很多相關商品。


    從貿澤網路下單,會有免運費的低消,因為運費真的很貴,建議是滿足低消購買會比較划算,而且除了商品售價與運費之外,收到貨的當下還要支付關稅。我的帳單金額約台幣2265元,收到貨時需要支付關稅約台幣112元。最麻煩的地方除了海外配送時間較長,需要約1周的時間,且因為關稅問題,取貨時需要本人付款,不方便找代收處理,下單前需要特別注意。


從貿澤電子購買的ADS1115正品

    我在貿澤下單的ADS1115模組共有兩款,由於運費實在太高了,所以就把清單上其中兩款看起來應該很容易使用的模組都放入購物車湊免運門檻。一款式是Adafruit品牌的模組,一款是Grove品牌的模組,兩款價格雖然也有不小的差距,但是都比蝦皮上來歷不明的模組貴上很多。這兩款模組的版型與IO接口的位置與形式都不太一樣,但是上面的IC與周邊電路是一樣的,IC接腳的名稱都有印刷在PCB表面的絲文字,使用時只要按照文字接線即可。

    經過我實際接上Arduino測試,兩款模組都能夠達到16bit的偵測範圍,跟Datasheet上標示的性能一致。不論是真假的ADS1115模組,他們的I2C Address、操作方式、資料格式、電器規格都是一模一樣的,所以如果在蝦皮、淘寶買的假貨已經可以在Arduino溝通,換上正品之後同樣也能夠操作,且讀取到的數值更精準。

Adafruit ADS1115 Module

   

Grove ADS1115 Module

Grove ADS1115 Module


Arduino + ADS1115 I2C


    使用ADS1115的目的主要是要量測更精準的電壓範圍。以Arduino MEGA2560為例,內建ADC的刻度為10bit,雖然量測電壓不是問題,但如果是量測精密的小電壓就非常不夠用,且都是單通道Single-end ADC,無法量測一個串聯在電源線上的電阻跨壓。若以內建INTERNAL1V1的參考電壓計算,最小刻度約是1.1V/1024=1.074mV,看起來已經很精細了,不過跟16bit位元相比就是小巫見大巫。

    TI ADS1115的ADC刻度來到16bit,扣除最高位元的符號位元,有效位數有15bit,而且內部還能夠調整偵測範圍,讓量測的最小刻度可以來到256mV/32767=7.812uV,如此小的刻度,如果搭配0.01歐姆的(10mOhm)精密電阻,即可以量測到0.7812mA的小電流,對於系統分析來說是非常有吸引力的工具。

電壓量測範圍(可調):256mV/ 512mV/ 1.024V/ 2.048V/ 4.096V/ 6.144V

16bit刻度範圍:-32768~32767

    系統的電流分析通常會在電源線上串聯一個很小的精密電阻,在不影響系統的狀況下量測電阻的跨壓換算成電流值,當電源組數非常多的時候可以透過多通道的ADC量測加速分析時間。通常使用的電阻值會根據待測電流大小使用0.01~1 ohm不等的阻值。選用電阻大小的準則是(1)通過的電流換算功率(P=I^2*R)不能超過電阻的承受功率,避免過熱燒毀。(2)待測電流產生的跨壓會造成的V_drop,這個電壓的浮動不能夠影響系統的運作。

    至於電阻的大小,會與量測電流的精細程度有關,通常量測0.01ohm,能夠量測>1mA的電流。若要量測<1mA的電流,為了量到更精準的電流就要選用0.1ohm或是1ohm的電阻。

>> 最小電流刻度 = (ADC量測範圍 / ADC量測刻度)/量測電阻  

1 ohm:

    使用ADS1115最小量測刻度=(256mV /32767) / 1ohm =7.812uA

0.1 ohm:

    使用ADS1115最小量測刻度=(256mV /32767) / 0.1ohm =78.12uA

0.01 ohm:

    使用ADS1115最小量測刻度=(256mV /32767) / 0.01ohm =0.7812mA


ADS1115


    ADS1115與Arduino溝通介面是I2C,由於ADS1115模組上已經放置了Pull-up電阻,若將模組的VDD與Arduino同樣使用5V,就可以直接對接SCL與SDA使用,使用上可說是非常的簡便。電源的部分,因為ADS1115模組本身耗電量低, 所以直接接上Arduino的5V就足夠了,單純接上USB就能驅動,可說相當的便利。

Arduino Mega2560
 


ADC + 放大器的架構

    在ADS1115的Datasheet中會有一個使用範例是透過OPA333進行放大的範例:Low-Side Current Shunt Monitoring。這個範例可以進一步把待測端訊號放大,透過訊號放大的方式量測到更精細的刻度值。因為手邊沒有OPA333,剛好有一組常見的LM358,因此就按照電路上的說明用麵包版兜一組來試試看。下面也分享一下我的心得。

    在範例中串組是接在靠近GND的一端,不是接在Power Source,與我的使用情境不太相同。最後我發現使用LM358,並且把待測端的串流電阻接在power Source端的時候,會有一個很大的量測偏差,且這個偏差的數值會隨著Power Source提供的電壓高低有所不同,推測是LM358本身的漏電造成一個隨電壓改變的偏壓,如果經過校正應該是可以解決這個偏壓的影響。然而,我的量測情境是需要針對不同電壓準位的Power Source量測他的的負載電流,在這個架構下我的使用狀況需要根據每一次的量測電壓進行校正,使用起來比較不人性化,因此我就放棄這個方案了。


ADC讀取範例

    最後分享Arduino操作ADS1115的簡略程式碼。

    在這個範例程式裡面採用Single Conversion的模式,我們下一次指令,才會讀取一筆資料,大致上一次完整讀取ADC值的操作流程:

(1)寫入config rigister位置→
(2)寫入config內容→
(3)等待擷取→
(4)寫入conversion register位置→
(5)讀取conversion內容。


#include<Wire.h>

#define pConverReg 0

#define pConfigReg 1

#define pLo_thReg 2

#define pHi_thReg 3

#define R10mOhm 0.01


int adcRcv1=0;

int adcRcv2=0;

double adcCal_mV1=0;

double adcCal_mV2=0;

double adcCal_mA1=0;

double adcCal_mA2=0;

double cal_bias=0;

int adcAddr=72;

unsigned char adcConfigCh1[2]={0x8F, 0x83};   //sizeof(int)=2  A0=P, A1=N

unsigned char adcConfigCh2[2]={0xBF, 0x83};

double adcVcm=0;

//ADS1115 i2c addr(GND) = 1001000(7bit) = 72

//ADS1115 i2c addr(VDD) = 1001001(7bit) = 73

//ADS1115 i2c addr(SDA) = 1001010(7bit) = 74

//ADS1115 i2c addr(SCL) = 1001011(7bit) = 75

int i=0;

unsigned char i2cReadVal[2]={0};

char i2cDataLen=2;   //read length



void setup() 

{

    // initial I2C 

    Wire.begin(); //to be a Master

}


void loop() 

{


   

    //point to config Read ch1=======================

    Wire.beginTransmission(adcAddr);

    Wire.write(pConfigReg);

    Wire.write(adcConfigCh1,sizeof(adcConfigCh1));

    Wire.endTransmission();

    

    delay(10);  // 1s/128SPS=7.8ms 中間間隔的時間必須大於單次擷取的週期

   

    //read conversion - assign pointer

    Wire.beginTransmission(adcAddr);

    Wire.write(pConverReg);

    Wire.endTransmission();

    //read conversion - read 2 byte value

    Wire.requestFrom(adcAddr, i2cDataLen);

    i=0;

    while (Wire.available()) 

    {   // slave may send less than requested

        i2cReadVal[i] = Wire.read(); // receive a byte as character

        i++;

    }

    //combine to int

    adcRcv1=( ((i2cReadVal[0] & 0x00FF) <<8) | (i2cReadVal[1]& 0x00FF))  ; 

    //adcCal_mV1=( (((double)adcRcv1+cal_bias) /32768.0) *256.0) ;  

    adcCal_mV1= (double)adcRcv1/128.0;  //   /32767*256 => /128

    adcCal_mA1=adcCal_mV1/R10mOhm; //V=IR


    delay(1);  

           

    //point to config Read ch2=======================

    Wire.beginTransmission(adcAddr);

    Wire.write(pConfigReg);

    Wire.write(adcConfigCh2,sizeof(adcConfigCh2));

    Wire.endTransmission();

    

    delay(10);  // 1s/128SPS=7.8ms

   

    //read conversion - assign pointer

    Wire.beginTransmission(adcAddr);

    Wire.write(pConverReg);

    Wire.endTransmission();

    //read conversion - read 2 byte value

    Wire.requestFrom(adcAddr, i2cDataLen);

    i=0;

    while (Wire.available()) 

    {   // slave may send less than requested

        i2cReadVal[i] = Wire.read(); // receive a byte as character

        i++;

    }

    //combine to int

    adcRcv2=( ((i2cReadVal[0] & 0x00FF) <<8) | (i2cReadVal[1]& 0x00FF))  ; 

    //adcCal_mV2=( (((double)adcRcv2+cal_bias) /32768.0) *256.0) ; 

    adcCal_mV2=(double)adcRcv2 /128.0;    //   /32767*256 => /128

    adcCal_mA2=adcCal_mV2/R10mOhm; //V=IR

    

    delay(100);  

}




留言

  1. 大陸的很多很便宜不要買,不然就是要有買過的店家

    回覆刪除
    回覆
    1. 是的,很多便宜的都是假貨,不要浪費錢。

      刪除

張貼留言

Facebook

這個網誌中的熱門文章

[房屋]裝潢紀錄分享- 基本包冷氣管包梁工程。把冷氣管隱藏得無影無蹤

[心得]天作之合音樂劇「阿堯 Shemenayha」 at 台北表演藝術中心 大劇院

[台北]台北小巨蛋 冰上迪士尼。迪士尼主題花式溜冰的視覺饗宴

[印尼]印尼 巴淡島 旅遊 TOP 100量販超市必買商品推薦。咖啡、生活用品、泡麵

[工具]線上模擬器。簡單的硬體電路模擬小工具Falstad: Circuit Simulatior Applet

[食記]將捷金鬱金香酒店- 河畔餐廳 主餐+自助餐吃到飽心得

[軟體]PDFill - 功能強大的免費PDF處理與編輯軟體。常用功能教學

為您推薦