我們的經(jīng)常需要采集一些精度要求較高的模擬信號,使用MCU集成的ADC難以達(dá)到要求、所以我們需要獨(dú)立的ADC芯片。這一節(jié)我們就來設(shè)計(jì)并實(shí)現(xiàn)AD7705芯片的驅(qū)動、并探討驅(qū)動的使用方法。
1 、功能概述
AD7705/AD7706是用于低頻測量的完整模擬前端??梢灾苯訌?a target="_blank">傳感器接收低電平輸入信號,并產(chǎn)生串行數(shù)字輸出。
1.1 、硬件結(jié)構(gòu)
AD7705和AD7706均為完整16位、低成本、Σ-Δ型ADC,適合直流和低頻交流測量應(yīng)用。其具有低功耗(3 V時(shí)最大值為1 mW)特性,因而可用于環(huán)路供電、電池供電或本地供電的應(yīng)用中。片內(nèi)可編程增益放大器提供從1至128的增益設(shè)置,無需使用外部信號調(diào)理硬件便可接受低電平和高電平模擬輸入。
AD7705擁有兩個(gè)差分通道,而AD7706則擁有一個(gè)差分通道和兩個(gè)偽差分通道。在定制比率應(yīng)用器件時(shí),差分基準(zhǔn)電壓輸入還能提供極大的靈活性。采用16引腳封裝,具體的定義及結(jié)構(gòu)如下:
AD7705/AD7706設(shè)備的工作電壓從2.7 V到3.3 V或4.75 V到5.25 V不等。在VDD為5v和參考電壓為2.5 V的情況下,輸入信號范圍從0 mV到20 mV,從0 V到2.5 V,都可以在這兩種設(shè)備上使用。在VDD為3v和參考電壓為1.25 V的情況下,可以處理0 mV到10 mV到0 V到1.225 V的單極輸入信號范圍。
1.2 、片上寄存器
AD7705/AD7706每個(gè)包含8個(gè)片上寄存器,可以通過串口訪問。第一個(gè)是通信寄存器,第二個(gè)是配置寄存器,第三個(gè)是時(shí)鐘寄存器,第四個(gè)是數(shù)據(jù)寄存器,余下的是校準(zhǔn)寄存器。具體如下:
需要說明的是測試寄存器,不要改變此寄存器中的任何位的狀態(tài),這個(gè)寄存器用于設(shè)備測試。
1.2.1 、通信寄存器
通信寄存器用于控制通道選擇,并決定下一個(gè)操作是讀操作還是寫操作,并決定下一個(gè)讀操作或?qū)懖僮髟L問哪個(gè)寄存器。通訊寄存器各位含義如下:
所有到AD7705/AD7706的通信都必須從通信寄存器的寫操作開始。寫入該寄存器的數(shù)據(jù)決定下一個(gè)操作是讀操作還是寫操作,以及該操作發(fā)生在哪個(gè)寄存器。其中RS2–RS0三位決定下一操作是針對哪一個(gè)寄存器進(jìn)行的。
而CH1, CH0兩位決定是針對哪一通道的操作。
1.2.2 、配置寄存器
配置寄存器是一個(gè)8位寄存器,可以從中讀取或?qū)懭霐?shù)據(jù),用于確定校準(zhǔn)模式、增益設(shè)置、雙極/單極操作和緩沖模式。
1.2.3 、時(shí)鐘寄存器
時(shí)鐘寄存器是一個(gè)8位寄存器,可以從中讀取或?qū)懭霐?shù)據(jù),,并包含篩選器選擇位和時(shí)鐘控制位。
1.2.4 、數(shù)據(jù)寄存器
數(shù)據(jù)寄存器是一個(gè)16位的只讀寄存器,它包含來自AD7705/AD7706的最新轉(zhuǎn)換結(jié)果。如果通信寄存器為該寄存器的寫操作設(shè)置了部件,則必須執(zhí)行寫操作才能將部件返回到其默認(rèn)狀態(tài)。然而,寫入該部分的16位數(shù)據(jù)將被AD7705/AD7706忽略。
1.2.5 、校準(zhǔn)寄存器
校準(zhǔn)寄存器是一系列的寄存器對,用于存儲通道校準(zhǔn)數(shù)據(jù)。每對包括一個(gè)零標(biāo)度校準(zhǔn)寄存器和一個(gè)滿標(biāo)度校準(zhǔn)寄存器,并對應(yīng)一個(gè)通道。當(dāng)開啟系統(tǒng)零點(diǎn)或量程校準(zhǔn)時(shí),將根據(jù)對應(yīng)通道上的數(shù)據(jù)來校準(zhǔn)。當(dāng)然如果有必要,也可以通過數(shù)字接口來讀寫這些寄存器。
2 、驅(qū)動設(shè)計(jì)與實(shí)現(xiàn)
我們已經(jīng)了解了AD7705模數(shù)轉(zhuǎn)換器的結(jié)構(gòu)及內(nèi)部寄存器配置,接下來我們將根據(jù)我們的了解設(shè)計(jì)并實(shí)現(xiàn)AD7705模數(shù)轉(zhuǎn)換器的驅(qū)動。
2.1 、對象定義
我們對AD7705模數(shù)轉(zhuǎn)換器的操作依然是基于對象的,所以我們要先得到對象。首先的工作當(dāng)然是抽象得到對象的特性進(jìn)而得到我們需要的對象。
2.1.1 、抽象對象類型
一個(gè)對象最起碼包含屬性和操作兩方面內(nèi)容,我們先來分析一下AD7705模數(shù)轉(zhuǎn)換器對象需要包含哪些屬性和操作。
對于AD7705模數(shù)轉(zhuǎn)換器來說,總共有8個(gè)寄存器,這些寄存器是實(shí)現(xiàn)操作的基礎(chǔ),我們要配置并了解這些寄存器的狀態(tài),所以我們將這些寄存器抽象為對象的屬性,以便隨時(shí)掌握操作的目標(biāo)。
進(jìn)而我們考慮AD7705模數(shù)轉(zhuǎn)換器對象的操作。首先我們要操作AD7705模數(shù)轉(zhuǎn)換器就是向其發(fā)送命令和讀取數(shù)據(jù),所以我們將向AD7705模數(shù)轉(zhuǎn)換器發(fā)送命令和讀取數(shù)據(jù)作為對象的一個(gè)操作。AD7705模數(shù)轉(zhuǎn)換器采用SPI通訊接口,有時(shí)需要在軟件中對片選信號進(jìn)行操作,所以我們將片選型號的操作作為對象的另一個(gè)操作。在一些情況下,有些針對對象的活動需要延時(shí)進(jìn)行,而在不同的平臺中采取的延時(shí)方式不盡相同,為了操作方便我們將延時(shí)操作作為對象的一個(gè)操作。此外AD7705模數(shù)轉(zhuǎn)換器有一個(gè)轉(zhuǎn)換數(shù)據(jù)就緒檢測的功能,我們將讀取就緒信號作為它的另一個(gè)操作。
據(jù)以上的分析我們可以抽象AD7705模數(shù)轉(zhuǎn)換器的對象類型如下:
/* 定義AD7705對象類型 */
typedef struct AD7705Object {
uint8_t registers[3]; //用于存儲通訊、配置和時(shí)鐘寄存器
uint8_t(*ReadWriteByte)(uint8_t data); //讀寫操作
uint8_t(*CheckDataIsReady)(void); //就緒信號檢測
void(*ChipSelect)(AD7705CSType cs); //實(shí)現(xiàn)片選
void(*Delayms)(volatile uint32_t nTime); //實(shí)現(xiàn)ms延時(shí)操作
void(*Delayus)(volatile uint32_t nTime); //實(shí)現(xiàn)us延時(shí)操作
}AD7705ObjectType;
2.1.2 、對象初始化
我們雖然得到了是對象,但對象不能直接使用,我們需要對其進(jìn)行初始化方能使用。所以接下來我們考慮AD7705模數(shù)轉(zhuǎn)換器對象的初始化函數(shù)。
初始化函數(shù)至少包含有2方面內(nèi)容:一是為對象變量賦必要的初值;二是檢查這些初值是否是有效的。特別是一些操作指針錯(cuò)誤的話可能產(chǎn)生嚴(yán)重的后果?;谶@一原則,我們設(shè)計(jì)AD7705模數(shù)轉(zhuǎn)換器的對象初始化函數(shù)如下:
/* AD7705對象初始化函數(shù) */
void AD7705Initialization(AD7705ObjectType*ad,
AD7705GainType gain,
AD7705MclkType mclk,
AD7705OutRateType rate,
AD7705ReadWriteByteType spiReadWrite,
AD7705CheckDataIsReadyType checkReady,
AD7705ChipSelect cs,
AD7705Delay msDelay,
AD7705Delay usDelay)
{
if((ad==NULL)||(spiReadWrite==NULL)||(checkReady==NULL)||(msDelay==NULL)||(usDelay==NULL))
{
return;
}
ad->CheckDataIsReady=checkReady;
ad->ReadWriteByte=spiReadWrite;
ad->Delayms=msDelay;
ad->Delayus=usDelay;
if(cs==NULL) //硬件電路實(shí)現(xiàn)片選
{
ad->ChipSelect=DefaultChipSelect;
}
else
{
ad->ChipSelect=cs;
}
//設(shè)置成單極性、無緩沖、增益為1、濾波器工作、自校準(zhǔn)
ad->registers[REG_SETUP]=SelfCalibration|Unipolar|BufferDisable|FSYNCEnable|gains[gain];
ad->registers[REG_CLOCK]=CLKEnable; //默認(rèn)主時(shí)鐘輸出
if((mclk==Mclk4915200)||(mclk==Mclk2000000))
{
ad->registers[REG_CLOCK]|=CLKDIVEnable;
}
else
{
ad->registers[REG_CLOCK]|=CLKDIVDisable;
}
if(((mclk<=Mclk4915200)&&(rate<=Rate200Hz))||((mclk>=Mclk1000000)&&(rate>=Rate50Hz)))
{
ad->registers[REG_CLOCK]|=updateRate[rate];
}
else
{
ad->registers[REG_CLOCK]=0x00;
return;
}
}
2.2 、對象操作
我們獲取對象的目的就是希望通過對象來得到我們想要的數(shù)據(jù)。對于AD7705模數(shù)轉(zhuǎn)換器來說,我們想要得到的就是各個(gè)通道的輸入信號。所以我們對AD7705模數(shù)轉(zhuǎn)換器對象的操作就是得到通道的模數(shù)轉(zhuǎn)換值。據(jù)此我們設(shè)計(jì)讀取AD7705模數(shù)轉(zhuǎn)換器單個(gè)通道的值的函數(shù)如下:
//讀取AD7705單個(gè)通道的值
uint16_t GetAD7705ChannelValue(AD7705ObjectType*ad,AD7705ChannelType channel)
{
ad->ChipSelect(AD7705CS_Enable);
//初始化通道
AD7705ChannelConfig(ad,channel);
ad->Delayms(20);
ad->registers[REG_COMM]=DataRegister|ReadOperation|OperatingMode|channels[channel];
ad->ReadWriteByte(ad->registers[REG_COMM]);
//等待數(shù)據(jù)準(zhǔn)備好
while(ad->CheckDataIsReady()==1)
{
}
uint16_t dataLowByte;
uint16_t dataHighByte;
dataHighByte = ad->ReadWriteByte(0xFF); //讀數(shù)據(jù)寄存器
ad->Delayus(200);
dataLowByte = ad->ReadWriteByte(0xFF); //讀數(shù)據(jù)寄存器
ad->Delayus(200);
dataHighByte = dataHighByte << 8;
uint16_t value;
value = dataHighByte | dataLowByte;
ad->ChipSelect(AD7705CS_Disable);
return value;
}
其中設(shè)置寄存器和時(shí)鐘寄存器的值,在初始化函數(shù)中已經(jīng)記錄下來,在配置時(shí),我們只需要下發(fā)數(shù)據(jù)就好了。
3 、驅(qū)動的使用
我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了AD7705模數(shù)轉(zhuǎn)換器的驅(qū)動,接下來我們考慮如何使用這一驅(qū)動程序?qū)崿F(xiàn)AD7705模數(shù)轉(zhuǎn)換器的應(yīng)用。
3.1 、聲明并初始化對象
應(yīng)用的設(shè)計(jì)一如既往,我們需要使用AD7705模數(shù)轉(zhuǎn)換器對象類型聲明一個(gè)對象變量。形式如下:
AD7705ObjectTypead7705;
聲明了這個(gè)對象變量并不能用于操作AD7705模數(shù)轉(zhuǎn)換器,我們還需要使用初始化函數(shù)對對象變量進(jìn)行初始化。初始換函數(shù)所需參數(shù)如下:
AD7705ObjectType*ad,要初始化的AD7705對象
AD7705GainTypegain,增益系數(shù)
AD7705MclkTypemclk,主時(shí)鐘頻率
AD7705OutRateTyperate,輸出更新速率
AD7705ReadWriteByteTypespiReadWrite,SPI口讀寫操作函數(shù)
AD7705CheckDataIsReadyTypecheckReady,就緒檢測函數(shù)
AD7705ChipSelectcs,片選操作函數(shù)
AD7705DelaymsDelay,毫秒延時(shí)函數(shù)
AD7705DelayusDelay,微秒延時(shí)函數(shù)
對于這些參數(shù),對象變量我們已經(jīng)定義了。采用的增益倍數(shù)根據(jù)實(shí)際情況選擇,為枚舉。AD7705采用的數(shù)字時(shí)鐘則根據(jù)我們的實(shí)際使用情況輸入,為枚舉。而輸出更新速率根據(jù)需要選擇,為枚舉。主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類型如下:
/*定義讀寫AD7705函數(shù)指針類型*/
typedef uint8_t(*AD7705ReadWriteByteType)(uint8_t data);
/*定義就緒檢測函數(shù)指針類型*/
typedef uint8_t(*AD7705CheckDataIsReadyType)(void);
/*定義片選信號函數(shù)指針類型*/
typedef void(*AD7705ChipSelect)(AD7705CSType cs);
/*定義延時(shí)操作函數(shù)指針類型*/
typedef void(*AD7705Delay)(volatile uint32_t nTime);
對于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺有關(guān)系。片選操作函數(shù)用于多設(shè)備需要軟件操作時(shí),如采用硬件片選可以傳入NULL即可。具體函數(shù)定義如下:
/*定義片選信號函數(shù)*/
void AD7705CS(AD7705CSType en)
{
if(AD7705CS_Enable==en)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_SET);
}
}
/* 定義就緒信號讀取函數(shù) */
uint8_t AD7705CheckReady(void)
{
returnHAL_GPIO_ReadPin(GPIOC,GPIO_PIN_0);
}
/*定義發(fā)送數(shù)據(jù)函數(shù)*/
uint8_t AD7705WriteReadData(uint8_twData)
{
uint8_trxData=0;
HAL_SPI_TransmitReceive(&ad7705hspi,&wData,&rxData,1,1000);
return rxData;
}
對于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
AD7705Initialization(&ad7705,Gain_1,Mclk2457600,Rate200Hz,AD7705WriteReadData,AD7705CheckReady,AD7705CS,HAL_Delay,Delayus);
3.2 、基于對象進(jìn)行操作
我們定義了對象變量并使用初始化函數(shù)給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數(shù)據(jù)。在驅(qū)動中我們已經(jīng)封裝了獲取某一通道模數(shù)轉(zhuǎn)換數(shù)據(jù)的函數(shù),這里我們將調(diào)用這一函數(shù)獲取AD7705兩個(gè)通道的模數(shù)轉(zhuǎn)換值。
/*獲取通道數(shù)據(jù)*/
void GetChannelValue(void)
{
uint16_tdataCode[2];
dataCode[0]=GetAD7705ChannelValue(&ad7705,Channel1);
dataCode[1]=GetAD7705ChannelValue(&ad7705,Channel2);
}
獲取了ADC的數(shù)據(jù)后就可以根據(jù)每個(gè)通道所對應(yīng)的物理量量程范圍計(jì)算得到物理量值。
4 、應(yīng)用總結(jié)
我們實(shí)現(xiàn)了AD7705模數(shù)轉(zhuǎn)換器的驅(qū)動并使用驅(qū)動實(shí)現(xiàn)了簡單的應(yīng)用,得到了AD7705兩個(gè)通道的模數(shù)轉(zhuǎn)換數(shù)據(jù),結(jié)果與預(yù)期一致。
在使用驅(qū)動時(shí)需注意,采用SPI接口的器件需要考慮片選操作的問題。如果片選信號是通過硬件電路來實(shí)現(xiàn)的,我們在初始化時(shí)給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數(shù)。
完整的源代碼可在GitHub下載 :https://github.com/foxclever/ExPeriphDriver
評論