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