關(guān)于ADC我們已經(jīng)討論過不少了,但在不同的應(yīng)用需求下,我們會(huì)選擇不同的原件。在這里我們將討論ADS111x系列ADC驅(qū)動(dòng)的設(shè)計(jì)與實(shí)現(xiàn)。
1、功能概述
??ADS1113、 ADS1114 和 ADS1115 器件 (ADS111x)是兼容 I2C 的 16 位高精度低功耗模數(shù)轉(zhuǎn)換器。ADS111x 器件采用了低漂移電壓基準(zhǔn)和振蕩器。ADS1114 和 ADS1115 還采用可編程增益放大器(PGA) 和數(shù)字比較器。憑借這些特性加之較寬的工作電源電壓范圍,使得ADS111x非常適合功率受限和空間受限的傳感器測(cè)量應(yīng)用。其引腳定義及封裝如下:
??ADS111x 可在數(shù)據(jù)速率高達(dá)每秒 860 個(gè)樣本 (SPS)的情況下執(zhí)行轉(zhuǎn)換。PGA 可提供從 ±256mV 到±6.144V 的輸入范圍,從而實(shí)現(xiàn)精準(zhǔn)的大小信號(hào)測(cè)量。ADS1115具有一個(gè)輸入多路復(fù)用器 (MUX),可實(shí)現(xiàn)兩路差分輸入測(cè)量或四路單端輸入測(cè)量。
1.1、通訊接口
??ADS111x通過I2C接口進(jìn)行通信。ADS111x有一個(gè)地址引腳ADDR,用來配置設(shè)備的I2C地址。這個(gè)引腳可以連接到GND、VDD、SDA或SCL,允許用一個(gè)引腳選擇四個(gè)不同的地址,具體如下:
??器件會(huì)對(duì)地址引腳的狀態(tài)進(jìn)行連續(xù)采樣。優(yōu)先使用GND,VDD和SCL來設(shè)置期間地址。如果使用SDA設(shè)置設(shè)備地址,需要在SCL線路低電平后,至少保持SDA線路低電平100 ns,以確保I2C通信時(shí)設(shè)備正確解碼該地址。
1.2、寄存器
??ADS111x有四個(gè)寄存器,可以通過使用地址指針寄存器的I2C接口訪問。轉(zhuǎn)換寄存器包含最后一次轉(zhuǎn)換的結(jié)果。配置寄存器用于改變ADS111x的工作模式和查詢?cè)O(shè)備狀態(tài)。另外兩個(gè)寄存器Lo_thresh和Hi_thresh設(shè)置了用于比較器函數(shù)的閾值,在ADS1113中不可用。
1.2.1、地址指針寄存器
??對(duì)ADS111x寄存器的操作都是通過寄存器地址指針寄存器來實(shí)現(xiàn)的,其數(shù)據(jù)結(jié)構(gòu)如下:
??對(duì)于做后兩位的定義為:00,轉(zhuǎn)換寄存器;01,配置寄存器;10,低門限值寄存器;11,高門限值寄存器。
1.2.2、轉(zhuǎn)換寄存器
??16位轉(zhuǎn)換寄存器以二進(jìn)制補(bǔ)碼格式存放最后一次轉(zhuǎn)換的結(jié)果。其格式如下:
??在上電之后,轉(zhuǎn)換寄存器被清除為0,并保持0直到第一次轉(zhuǎn)換完成。
1.2.3、配置寄存器
??16位配置寄存器用于控制操作模式,輸入選擇,數(shù)據(jù)速率,滿量程和比較器模式。其格式如下:
??多路選擇器用于配置當(dāng)前需要采集的通道,只有ADS1115具有該功能。PGA用于配置采集的增益大小,DR用于配置蘇劇的輸出速率。
1.2.4、門限值寄存器
??比較器使用的上下限閾值以二進(jìn)制補(bǔ)碼格式存儲(chǔ)在兩個(gè)16位寄存器中。比較器實(shí)現(xiàn)為數(shù)字比較器;因此,當(dāng)PGA設(shè)置發(fā)生更改時(shí),這些寄存器中的值必須更新。具體的數(shù)據(jù)格式如下:
??通過設(shè)置高閾值寄存器MSB為1和低閾值寄存器MSB為0,可以啟用ALERT/RDY引腳的轉(zhuǎn)換準(zhǔn)備函數(shù)。要使用ALERT/RDY引腳的比較器函數(shù),高閾值寄存器的值必須總是大于低閾值寄存器的值。當(dāng)設(shè)置為RDY模式時(shí),ALERT/RDY引腳在單發(fā)模式下輸出OS位,在連續(xù)轉(zhuǎn)換模式下提供連續(xù)轉(zhuǎn)換就緒脈沖。
2、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
在前述中我們已經(jīng)梳理了ADS111x系列模數(shù)轉(zhuǎn)換器的相關(guān)技術(shù)特性。接下來我們需要依據(jù)我們了解的這些技術(shù)數(shù)據(jù)設(shè)計(jì)并設(shè)計(jì)ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動(dòng)程序。
2.1、對(duì)象定義
??與以前的驅(qū)動(dòng)設(shè)計(jì)一樣,我們依然是基于對(duì)象來設(shè)計(jì)ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動(dòng)程序。所以我們要先抽象并定義ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象類型。一般來講對(duì)象包括屬性與操作兩方面,我們將據(jù)此逐一分析ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象的屬性與操作。
??先考慮ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象的屬性。ADS111x系列模數(shù)轉(zhuǎn)換器采用I2C接口總線,而每臺(tái)I2C的從站都有一個(gè)設(shè)備地址,該地址表示了每臺(tái)設(shè)備的身份,所以我們將器作為ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象的一個(gè)屬性。此外為了查看當(dāng)前ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象的配置情況,我們希望記錄配置寄存器的當(dāng)前值,所以我們?cè)O(shè)定一個(gè)屬性來記錄它。每次讀取回來的個(gè)通道的數(shù)據(jù)實(shí)際表示了各通道的當(dāng)前狀態(tài)所以我們也將其作為ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象的屬性來記錄之。
??再來考慮ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象的操作。我們對(duì)ADS111x系列模數(shù)轉(zhuǎn)換器所要進(jìn)行的操作主要有下發(fā)命令、讀取數(shù)據(jù)等,這些動(dòng)作都需要依據(jù)具體的軟硬件平臺(tái)來實(shí)現(xiàn),我們以對(duì)象操作的方式來處理它。為了控制時(shí)序,我們需要延時(shí)操作函數(shù),而延時(shí)操作也需要基于具體的平臺(tái)來實(shí)現(xiàn),所以我們將延時(shí)函數(shù)也作為對(duì)象的一個(gè)操作。
??根據(jù)上述對(duì)ADS111x系列模數(shù)轉(zhuǎn)換器對(duì)象屬性和操作的分析,我們可以抽象出ADS111x系列模數(shù)轉(zhuǎn)換器的對(duì)象類型如下:
/*定義ADS111x對(duì)象類型*/
typedef struct Ads111xObject {
uint8_t devAddress; //設(shè)備地址
uint16_t dataCode[8]; //讀取的數(shù)據(jù)值
uint16_t config; //配置寄存器值
void (*Transmit)(struct Ads111xObject *ads,uint8_t *tData,uint16_t tSize);
void (*Receive)(struct Ads111xObject *ads,uint8_t *rData,uint16_t rSize);
void (*Delayus)(volatile uint32_t nTime); //實(shí)現(xiàn)us延時(shí)操作
}Ads111xObjectType;
??抽象了對(duì)象類型后就可聲明對(duì)象變量,可是這個(gè)對(duì)象變量必須作必要的初始化才能使用。所以我們需要一個(gè)初始化函數(shù)來對(duì)其進(jìn)行初始化。在此函數(shù)中,我們將檢測(cè)變量的有效性和初始狀態(tài)賦值,并對(duì)設(shè)備進(jìn)行必要的配置。根據(jù)這些要求我們?cè)O(shè)計(jì)ADS111x系列模數(shù)轉(zhuǎn)換器的對(duì)象初始化函數(shù)如下:
/*ADS111x初始化配置*/
void Ads111xInitialization(Ads111xObjectType *ads, //ADS111x對(duì)象變量
uint8_t devAddress, //設(shè)備地址
Ads111xGainType gain, //增益
Ads111xDataRateType dr, //輸出速率
Ads111xTransmit transmit,//發(fā)送函數(shù)指針
Ads111xReceive receive, //接收函數(shù)指針
Ads111xDelayus delayus //us延時(shí)函數(shù)指針
)
{
uint16_t channels[]={0x0000,0x1000,0x2000,0x3000,0x4000,0x5000,0x6000,0x7000};
uint16_t gains[]={0x0000,0x0200,0x0400,0x0600,0x0800,0x0A00};
uint16_t dataRates[]={0x0000,0x0020,0x0040,0x0060,0x0080,0x00A0,0x00C0,0x00E0};
uint16_t config=0x8103;
if((ads==NULL)||(transmit==NULL)||(receive==NULL)||(delayus==NULL))
{
return ;
}
ads->Transmit=transmit;
ads->Receive=receive;
ads->Delayus=delayus;
Ads111xReset(ads);
if((devAddress==0x48)||(devAddress==0x49)||(devAddress==0x4A)||(devAddress==0x4B))
{
ads->devAddress=(devAddress<<1);
}
else if((devAddress==0x90)||(devAddress==0x92)||(devAddress==0x94)||(devAddress==0x96))
{
ads->devAddress=devAddress;
}
else
{
ads->devAddress=0x00;
}
config=config|channels[ADS111X_AIN0_AIN1]|gains[gain]|dataRates[dr];
Ads111xWriteRegister(ads,ConfigRegister,config);
ads->Delayus(200);
ads->config=Ads111xReadRegister(ads,ConfigRegister);
}
2.2、對(duì)象操作
??為了從ADS111x訪問特定的寄存器,必須先向地址指針寄存器中寫一個(gè)適當(dāng)?shù)闹祦碇甘疽L問的寄存器地址。也就是說不論讀寫那個(gè)寄存器都需要首先寫地址指針寄存器才能實(shí)現(xiàn)。
2.2.1、讀寄存器
??當(dāng)從ADS111x讀取數(shù)據(jù)時(shí),先前寫入到地址指針寄存器的值決定了被讀取的是哪一個(gè)寄存器。要想改變所要度的寄存器需要先修改地址指針寄存器的值。也就是說都一個(gè)寄存器的值分為兩步完成,首先寫地址指針寄存器,然后再讀所指向的寄存器的值。具體的操作時(shí)序圖如下:
??根據(jù)前面的分析以及上述的時(shí)序圖我們可以實(shí)現(xiàn)讀ADS111x系列模數(shù)轉(zhuǎn)換器寄存器的操作函數(shù)如下:
/*讀ADS111x寄存器*/
static uint16_t Ads111xReadRegister(Ads111xObjectType *ads,Ads111xRegisterType reg)
{
uint8_t wData;
uint8_t rData[2];
uint16_t result=0;
wData=(uint8_t)reg;
ads->Transmit(ads,&wData,1);
ads->Delayus(200);
ads->Receive(ads,rData,2);
result=rData[0];
result=(result<<8)+rData[1];
return result;
}
??需要說明一下的是,如果是連續(xù)多次讀取同一個(gè)寄存器則不需要先修改地址指針寄存器的值。
2.2.2、寫寄存器
??對(duì)于ADS111x系列模數(shù)轉(zhuǎn)換器來說,寫一個(gè)寄存器也是從寫地址指針寄存器開始的。但是與讀寄存器不同的是并不是兩步完成的,而是一次全部完成,即先寫地址指針寄存器接著就寫所要寫的寄存器。具體的操作時(shí)序如下:
??根據(jù)我們前述的分析以及上面的時(shí)序圖,我們可以實(shí)現(xiàn)寫ADS111x系列模數(shù)轉(zhuǎn)換器的函數(shù)如下:
/*寫ADS111x寄存器*/
static void Ads111xWriteRegister(Ads111xObjectType *ads,Ads111xRegisterType reg,uint16_t regValue)
{
uint8_t wData[3];
wData[0]=(uint8_t)reg;
wData[1]=(uint8_t)(regValue>>8);
wData[2]=(uint8_t)regValue;
ads->Transmit(ads,wData,3);
}
3、驅(qū)動(dòng)的使用
??我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動(dòng)程序,為了驗(yàn)證驅(qū)動(dòng)程序的正確性,這一節(jié)我們將來討論基于驅(qū)動(dòng)程序設(shè)計(jì)一個(gè)簡(jiǎn)單的應(yīng)用驗(yàn)證。
3.1、聲明并初始化對(duì)象
??我們是基于對(duì)象實(shí)現(xiàn)的ADS111x系列模數(shù)轉(zhuǎn)換器驅(qū)動(dòng)程序,所以我們先來聲明一個(gè)ADS111x系列模數(shù)轉(zhuǎn)換器的對(duì)象變量。
Ads111xObjectType ads1115;
??聲明了這個(gè)對(duì)象變量后,我們還需要使用前面實(shí)現(xiàn)的初始化函數(shù)Ads111xInitialization對(duì)這個(gè)對(duì)象變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入參數(shù)如下:
Ads111xObjectType *ads, //ADS111x對(duì)象變量
uint8_t devAddress, //設(shè)備地址
Ads111xGainType gain, //增益
Ads111xDataRateType dr, //輸出速率
Ads111xTransmit transmit,//發(fā)送函數(shù)指針
Ads111xReceive receive, //接收函數(shù)指針
Ads111xDelayus delayus //us延時(shí)函數(shù)指針
??在這些參數(shù)中,第一個(gè)為我們想要初始化的對(duì)象變量。devAddress就是ADS111x系列模數(shù)轉(zhuǎn)換器的設(shè)備地址,根據(jù)實(shí)際輸入即可。增益和數(shù)據(jù)輸出均為枚舉量,根據(jù)實(shí)際需要選擇輸入即可。還有三個(gè)函數(shù)指針是我們需要實(shí)現(xiàn)的參數(shù),這幾個(gè)函數(shù)的原型定義如下:
typedef void (*Ads111xTransmit)(struct Ads111xObject *ads,uint8_t *tData,uint16_t tSize);
typedef void (*Ads111xReceive)(struct Ads111xObject *ads,uint8_t *rData,uint16_t rSize);
typedef void (*Ads111xDelayus)(volatile uint32_t nTime); //實(shí)現(xiàn)us延時(shí)操作
??這些函數(shù)的實(shí)現(xiàn)依賴于具體的軟硬件平臺(tái),這里我們基于STM32F103硬件平臺(tái)和HAL庫(kù)來實(shí)現(xiàn)的相關(guān)操作函數(shù)。
/*通過I2C2發(fā)送數(shù)據(jù)到ADS115*/
static void BmcbAds111xTransmit(struct Ads111xObject *ads,uint8_t *tData,uint16_t tSize)
{
HAL_I2C_Master_Transmit(&hi2c2,ads->devAddress,tData,tSize,1000);
}
/*通過I2C2端口從ADS1115接收數(shù)據(jù)*/
static void BmcbAds111xReceive(struct Ads111xObject *ads,uint8_t *rData,uint16_t rSize)
{
HAL_I2C_Master_Receive(&hi2c2,ads->devAddress,rData,rSize,1000);
}
??而延時(shí)函數(shù)采用我們?cè)赟TM32系統(tǒng)下實(shí)現(xiàn)的通用函數(shù)即可。于是我們可以使用初始化函數(shù)實(shí)現(xiàn)對(duì)象變量初始化如下:
Ads111xInitialization(&ads1115, //ADS111x對(duì)象變量
0x90, //設(shè)備地址
ADS111X_GAIN_8, //增益
ADS111X_DR_128, //輸出速率
BmcbAds111xTransmit, //發(fā)送函數(shù)指針
BmcbAds111xReceive, //接收函數(shù)指針
Delayus //us延時(shí)函數(shù)指針
);
3.2、基于對(duì)象進(jìn)行操作
??我們初始化了對(duì)象變量就可一使用它來實(shí)現(xiàn)相應(yīng)的操作,所以我們含需要實(shí)現(xiàn)相關(guān)的應(yīng)用函數(shù)。事實(shí)上,這款驅(qū)動(dòng)程序我們已經(jīng)應(yīng)用到實(shí)際的工程應(yīng)用中,所以我們節(jié)選其中關(guān)于讀取差分通道的操作。
Ads111xChannelType Channel[sChCount]={ADS111X_AIN0_AIN1,ADS111X_AIN2_AIN3};
if(sCh>=sChCount)
{
sCh=0;
}
Ads111xGetDataCode(&ads1115,Channel[sCh]);
sCh++;
aPara.phyPara.pressure=Ads111xCalcPhysicalValue(&ads1115,ADS111X_AIN0_AIN1,PRES_RANGE,PRES_ZERO);
aPara.phyPara.vacuum=Ads111xCalcPhysicalValue(&ads1115,ADS111X_AIN2_AIN3,VACU_RANGE,VACU_ZERO);
4、應(yīng)用總結(jié)
??我們就已經(jīng)完成了ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動(dòng)設(shè)計(jì)與驗(yàn)證。在我們的實(shí)際使用過程中運(yùn)行穩(wěn)定,效果也很好。
??在使用驅(qū)動(dòng)程序時(shí)需要注意,此驅(qū)動(dòng)只適用于ADS1113、 ADS1114 和 ADS1115 器件。
評(píng)論