關(guān)于ADC我們已經(jīng)討論過不少了,但在不同的應(yīng)用需求下,我們會選擇不同的原件。在這里我們將討論ADS111x系列ADC驅(qū)動的設(shè)計與實現(xiàn)。
1、功能概述
??ADS1113、 ADS1114 和 ADS1115 器件 (ADS111x)是兼容 I2C 的 16 位高精度低功耗模數(shù)轉(zhuǎn)換器。ADS111x 器件采用了低漂移電壓基準(zhǔn)和振蕩器。ADS1114 和 ADS1115 還采用可編程增益放大器(PGA) 和數(shù)字比較器。憑借這些特性加之較寬的工作電源電壓范圍,使得ADS111x非常適合功率受限和空間受限的傳感器測量應(yīng)用。其引腳定義及封裝如下:
??ADS111x 可在數(shù)據(jù)速率高達(dá)每秒 860 個樣本 (SPS)的情況下執(zhí)行轉(zhuǎn)換。PGA 可提供從 ±256mV 到±6.144V 的輸入范圍,從而實現(xiàn)精準(zhǔn)的大小信號測量。ADS1115具有一個輸入多路復(fù)用器 (MUX),可實現(xiàn)兩路差分輸入測量或四路單端輸入測量。
1.1、通訊接口
??ADS111x通過I2C接口進(jìn)行通信。ADS111x有一個地址引腳ADDR,用來配置設(shè)備的I2C地址。這個引腳可以連接到GND、VDD、SDA或SCL,允許用一個引腳選擇四個不同的地址,具體如下:
??器件會對地址引腳的狀態(tài)進(jìn)行連續(xù)采樣。優(yōu)先使用GND,VDD和SCL來設(shè)置期間地址。如果使用SDA設(shè)置設(shè)備地址,需要在SCL線路低電平后,至少保持SDA線路低電平100 ns,以確保I2C通信時設(shè)備正確解碼該地址。
1.2、寄存器
??ADS111x有四個寄存器,可以通過使用地址指針寄存器的I2C接口訪問。轉(zhuǎn)換寄存器包含最后一次轉(zhuǎn)換的結(jié)果。配置寄存器用于改變ADS111x的工作模式和查詢設(shè)備狀態(tài)。另外兩個寄存器Lo_thresh和Hi_thresh設(shè)置了用于比較器函數(shù)的閾值,在ADS1113中不可用。
1.2.1、地址指針寄存器
??對ADS111x寄存器的操作都是通過寄存器地址指針寄存器來實現(xiàn)的,其數(shù)據(jù)結(jié)構(gòu)如下:
??對于做后兩位的定義為: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ǔ)碼格式存儲在兩個16位寄存器中。比較器實現(xiàn)為數(shù)字比較器;因此,當(dāng)PGA設(shè)置發(fā)生更改時,這些寄存器中的值必須更新。具體的數(shù)據(jù)格式如下:
??通過設(shè)置高閾值寄存器MSB為1和低閾值寄存器MSB為0,可以啟用ALERT/RDY引腳的轉(zhuǎn)換準(zhǔn)備函數(shù)。要使用ALERT/RDY引腳的比較器函數(shù),高閾值寄存器的值必須總是大于低閾值寄存器的值。當(dāng)設(shè)置為RDY模式時,ALERT/RDY引腳在單發(fā)模式下輸出OS位,在連續(xù)轉(zhuǎn)換模式下提供連續(xù)轉(zhuǎn)換就緒脈沖。
2、驅(qū)動設(shè)計與實現(xiàn)
在前述中我們已經(jīng)梳理了ADS111x系列模數(shù)轉(zhuǎn)換器的相關(guān)技術(shù)特性。接下來我們需要依據(jù)我們了解的這些技術(shù)數(shù)據(jù)設(shè)計并設(shè)計ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動程序。
2.1、對象定義
??與以前的驅(qū)動設(shè)計一樣,我們依然是基于對象來設(shè)計ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動程序。所以我們要先抽象并定義ADS111x系列模數(shù)轉(zhuǎn)換器對象類型。一般來講對象包括屬性與操作兩方面,我們將據(jù)此逐一分析ADS111x系列模數(shù)轉(zhuǎn)換器對象的屬性與操作。
??先考慮ADS111x系列模數(shù)轉(zhuǎn)換器對象的屬性。ADS111x系列模數(shù)轉(zhuǎn)換器采用I2C接口總線,而每臺I2C的從站都有一個設(shè)備地址,該地址表示了每臺設(shè)備的身份,所以我們將器作為ADS111x系列模數(shù)轉(zhuǎn)換器對象的一個屬性。此外為了查看當(dāng)前ADS111x系列模數(shù)轉(zhuǎn)換器對象的配置情況,我們希望記錄配置寄存器的當(dāng)前值,所以我們設(shè)定一個屬性來記錄它。每次讀取回來的個通道的數(shù)據(jù)實際表示了各通道的當(dāng)前狀態(tài)所以我們也將其作為ADS111x系列模數(shù)轉(zhuǎn)換器對象的屬性來記錄之。
??再來考慮ADS111x系列模數(shù)轉(zhuǎn)換器對象的操作。我們對ADS111x系列模數(shù)轉(zhuǎn)換器所要進(jìn)行的操作主要有下發(fā)命令、讀取數(shù)據(jù)等,這些動作都需要依據(jù)具體的軟硬件平臺來實現(xiàn),我們以對象操作的方式來處理它。為了控制時序,我們需要延時操作函數(shù),而延時操作也需要基于具體的平臺來實現(xiàn),所以我們將延時函數(shù)也作為對象的一個操作。
??根據(jù)上述對ADS111x系列模數(shù)轉(zhuǎn)換器對象屬性和操作的分析,我們可以抽象出ADS111x系列模數(shù)轉(zhuǎn)換器的對象類型如下:
/*定義ADS111x對象類型*/
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); //實現(xiàn)us延時操作
}Ads111xObjectType;
??抽象了對象類型后就可聲明對象變量,可是這個對象變量必須作必要的初始化才能使用。所以我們需要一個初始化函數(shù)來對其進(jìn)行初始化。在此函數(shù)中,我們將檢測變量的有效性和初始狀態(tài)賦值,并對設(shè)備進(jìn)行必要的配置。根據(jù)這些要求我們設(shè)計ADS111x系列模數(shù)轉(zhuǎn)換器的對象初始化函數(shù)如下:
/*ADS111x初始化配置*/
void Ads111xInitialization(Ads111xObjectType *ads, //ADS111x對象變量
uint8_t devAddress, //設(shè)備地址
Ads111xGainType gain, //增益
Ads111xDataRateType dr, //輸出速率
Ads111xTransmit transmit,//發(fā)送函數(shù)指針
Ads111xReceive receive, //接收函數(shù)指針
Ads111xDelayus delayus //us延時函數(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、對象操作
??為了從ADS111x訪問特定的寄存器,必須先向地址指針寄存器中寫一個適當(dāng)?shù)闹祦碇甘疽L問的寄存器地址。也就是說不論讀寫那個寄存器都需要首先寫地址指針寄存器才能實現(xiàn)。
2.2.1、讀寄存器
??當(dāng)從ADS111x讀取數(shù)據(jù)時,先前寫入到地址指針寄存器的值決定了被讀取的是哪一個寄存器。要想改變所要度的寄存器需要先修改地址指針寄存器的值。也就是說都一個寄存器的值分為兩步完成,首先寫地址指針寄存器,然后再讀所指向的寄存器的值。具體的操作時序圖如下:
??根據(jù)前面的分析以及上述的時序圖我們可以實現(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ù)多次讀取同一個寄存器則不需要先修改地址指針寄存器的值。
2.2.2、寫寄存器
??對于ADS111x系列模數(shù)轉(zhuǎn)換器來說,寫一個寄存器也是從寫地址指針寄存器開始的。但是與讀寄存器不同的是并不是兩步完成的,而是一次全部完成,即先寫地址指針寄存器接著就寫所要寫的寄存器。具體的操作時序如下:
??根據(jù)我們前述的分析以及上面的時序圖,我們可以實現(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ū)動的使用
??我們已經(jīng)設(shè)計并實現(xiàn)了ADS111x系列模數(shù)轉(zhuǎn)換器的驅(qū)動程序,為了驗證驅(qū)動程序的正確性,這一節(jié)我們將來討論基于驅(qū)動程序設(shè)計一個簡單的應(yīng)用驗證。
3.1、聲明并初始化對象
??我們是基于對象實現(xiàn)的ADS111x系列模數(shù)轉(zhuǎn)換器驅(qū)動程序,所以我們先來聲明一個ADS111x系列模數(shù)轉(zhuǎn)換器的對象變量。
Ads111xObjectType ads1115;
??聲明了這個對象變量后,我們還需要使用前面實現(xiàn)的初始化函數(shù)Ads111xInitialization對這個對象變量進(jìn)行初始化。這個初始化函數(shù)所需要的輸入參數(shù)如下:
Ads111xObjectType *ads, //ADS111x對象變量
uint8_t devAddress, //設(shè)備地址
Ads111xGainType gain, //增益
Ads111xDataRateType dr, //輸出速率
Ads111xTransmit transmit,//發(fā)送函數(shù)指針
Ads111xReceive receive, //接收函數(shù)指針
Ads111xDelayus delayus //us延時函數(shù)指針
??在這些參數(shù)中,第一個為我們想要初始化的對象變量。devAddress就是ADS111x系列模數(shù)轉(zhuǎn)換器的設(shè)備地址,根據(jù)實際輸入即可。增益和數(shù)據(jù)輸出均為枚舉量,根據(jù)實際需要選擇輸入即可。還有三個函數(shù)指針是我們需要實現(xiàn)的參數(shù),這幾個函數(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); //實現(xiàn)us延時操作
??這些函數(shù)的實現(xiàn)依賴于具體的軟硬件平臺,這里我們基于STM32F103硬件平臺和HAL庫來實現(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ù)采用我們在STM32系統(tǒng)下實現(xiàn)的通用函數(shù)即可。于是我們可以使用初始化函數(shù)實現(xiàn)對象變量初始化如下:
Ads111xInitialization(&ads1115, //ADS111x對象變量
0x90, //設(shè)備地址
ADS111X_GAIN_8, //增益
ADS111X_DR_128, //輸出速率
BmcbAds111xTransmit, //發(fā)送函數(shù)指針
BmcbAds111xReceive, //接收函數(shù)指針
Delayus //us延時函數(shù)指針
);
3.2、基于對象進(jìn)行操作
??我們初始化了對象變量就可一使用它來實現(xiàn)相應(yīng)的操作,所以我們含需要實現(xiàn)相關(guān)的應(yīng)用函數(shù)。事實上,這款驅(qū)動程序我們已經(jīng)應(yīng)用到實際的工程應(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ū)動設(shè)計與驗證。在我們的實際使用過程中運(yùn)行穩(wěn)定,效果也很好。
??在使用驅(qū)動程序時需要注意,此驅(qū)動只適用于ADS1113、 ADS1114 和 ADS1115 器件。
評論
查看更多