在產(chǎn)品設(shè)計過程中,我們經(jīng)常會遇到數(shù)模轉(zhuǎn)換的應(yīng)用需求。在本篇種我們就來討論一下MCP4725單通道數(shù)模轉(zhuǎn)換器的驅(qū)動設(shè)計與實現(xiàn)。
1、功能概述
??MCP4725是一個低功耗,高精度,單通道,12位緩沖電壓輸出數(shù)字到模擬轉(zhuǎn)換器(DAC)與非易失性存儲器(EEPROM)。它的板載精度輸出放大器允許它實現(xiàn)軌到軌模擬輸出擺動。
??DAC輸入和配置數(shù)據(jù)可以被編程到非易失性存儲器(EEPROM)由用戶使用I2C接口命令。非易失性存儲器特性使DAC設(shè)備能夠在斷電時保存DAC輸入代碼,并且在通電后立即提供DAC輸出。當(dāng)DAC設(shè)備被用作網(wǎng)絡(luò)中其他設(shè)備的支持設(shè)備時,這個特性非常有用。MCP4725的引腳定義及排布如下:
??MCP4725有一個外部A0地址位選擇引腳。這個A0引腳可以綁定到用戶應(yīng)用PCB板的VDD或VSS上。這個引腳被用戶用來選擇A0地址位。用戶可以將這個引腳綁定到VSS(邏輯' 0 '),或VDD(邏輯' 1 '),或可以由數(shù)字邏輯級別主動驅(qū)動,如I2C主輸出。
??MCP4725的地址字節(jié)由兩個部分組成,第一部分為4位設(shè)備代碼,固定設(shè)置為1100的,設(shè)備代碼后面是三位為地址位(A2, A1, A0),如下圖所示:
??A2和A1位的選擇可由客戶提供,作為訂購過程的一部分。兩位在出廠前設(shè)定好,如果客戶沒有特別要求的話,A2和A1會默認編程為“00”。而A0位則由A0引腳的邏輯狀態(tài)決定。
??MCP4725設(shè)備包括一個上電復(fù)位(POR)電路,以確??煽康纳想?,以及一個用于EEPROM編程電壓的板載電荷泵。DAC引用是直接從VDD驅(qū)動的。在down模式下,輸出放大器可以配置為已知的低、中或高阻輸出負載,如下圖。
??MCP472的寫命令用于將配置位和DAC輸入碼加載到DAC寄存器,或?qū)懭朐O(shè)備的EEPROM。寫命令類型由三個寫命令類型位(C2、C1、C0)定義。寫命令類型及其作用如下表所示。
2、驅(qū)動設(shè)計與實現(xiàn)
??在前一節(jié)中,我們梳理了MCP4725單通道數(shù)模轉(zhuǎn)換器的基本技術(shù)參數(shù)。在這一節(jié)中,我們將依據(jù)這些技術(shù)參數(shù)來設(shè)計MCP4725單通道數(shù)模轉(zhuǎn)換器的驅(qū)動程序。我們依然是基于對象的思想來實現(xiàn)之。
2.1、對象定義
??我們基于對象來實現(xiàn)驅(qū)動程序,所以我們就需要先得到對象,在這里我們首先將抽象出MCP4725單通道數(shù)模轉(zhuǎn)換器的對象類型。一版來說,對象皆包含屬性與操作兩個方面的內(nèi)容。在抽象對象類型的過程中,我們需要分析MCP4725單通道數(shù)模轉(zhuǎn)換器都有哪些屬性和操作。
??我們先來分析MCP4725單通道數(shù)模轉(zhuǎn)換器的對象的屬性。每一臺I2C從設(shè)備都有一個設(shè)備地址,這個地址實際上標(biāo)識了總線上設(shè)備的身份,MCP4725亦如此,所以我們將設(shè)備地址作為對象的一個屬性。對于MCP4725單通道數(shù)模轉(zhuǎn)換器,有一個掉電處理模式是需要配置的,為了掌握其配置狀態(tài)我們將其作為對象的一個屬性記錄下來。
??接下來分析MCP4725單通道數(shù)模轉(zhuǎn)換器的對象的操作。MCP4725單通道數(shù)模轉(zhuǎn)換器的基本操作無非就是讀寫數(shù)據(jù),而要實現(xiàn)讀和寫則依賴于具體的軟硬件平臺,所以我們將讀和寫MCP4725單通道數(shù)模轉(zhuǎn)換器都作為對象的操作來實現(xiàn)。
??根據(jù)上述關(guān)于MCP4725單通道數(shù)模轉(zhuǎn)換器對象屬性和操作的分析,我們可以抽象得到其對象類型如下:
/*定義MCP4725對象類型*/
typedef struct Mcp4725Object {
uint8_t devAddress;
Mcp4725PDModeType pdMode;
void (*Write)(struct Mcp4725Object *mcp,uint8_t *wData, uint16_t wSize);
void (*Read)(struct Mcp4725Object *mcp,uint8_t *rData, uint16_t rSize);
}Mcp4725ObjectType;
??抽象了對象類型后就可聲明對象變量,可是這個對象變量必須作必要的初始化才能使用。所以我們需要一個初始化函數(shù)來對其進行初始化。在此函數(shù)中,我們將檢測變量的有效性和初始狀態(tài)賦值,并對設(shè)備進行必要的配置。根據(jù)這些要求我們設(shè)計MCP4725單通道數(shù)模轉(zhuǎn)換器的對象初始化函數(shù)如下:
/*MCP4725初始化配置*/
void Mcp4725Initialization(Mcp4725ObjectType *mcp, //MCP4725對象變量
uint8_t slaveAddress, //從站設(shè)備的地址
Mcp4725PDModeType pdMode,//掉電操作模式
Mcp4725Write write, //寫數(shù)據(jù)函數(shù)指針
Mcp4725Read read //讀數(shù)據(jù)函數(shù)指針
)
{
if((mcp==NULL)||(write==NULL)||(read==NULL))
{
return;
}
mcp->Write=write;
mcp->Read=read;
if((slaveAddress==0x60)||(slaveAddress==0x61))
{
mcp->devAddress=(slaveAddress<<1);
}
else if((slaveAddress==0xC0)||(slaveAddress==0xC2))
{
mcp->devAddress=slaveAddress;
}
else
{
mcp->devAddress=0x00;
}
mcp->pdMode=pdMode;
}
2.2、對象操作
??有了對象變量,也完成了初始化,那么我們就可以用其來操作MCP4725單通道數(shù)模轉(zhuǎn)換器了。所以我們來看看實現(xiàn)對MCP4725單通道數(shù)模轉(zhuǎn)換器的讀寫操作。
首先我們來看看寫MCP4725單通道數(shù)模轉(zhuǎn)換器的實現(xiàn)。寫MCP4725單通道數(shù)模轉(zhuǎn)換器有兩種模式:快速模式和正常模式。快速模式就是將命令與數(shù)據(jù)結(jié)合在一起,這要只需發(fā)送三個字節(jié)就可完成寫數(shù)據(jù)的過程。具體的操作時序如下:
??而正常模式則是命令是單獨的字節(jié),數(shù)據(jù)是另外的2個字節(jié),所以正常模式一次發(fā)送4個字節(jié)才能完成寫的過程。正常模式可以操作寄存器也可操作EEPROM,這一點與快速模式是不一樣的。具體的操作時序如下:
??根據(jù)前面的描述和時序圖,我們可以設(shè)計寫MCP4725單通道數(shù)模轉(zhuǎn)換器的函數(shù)。下面的函數(shù)可以快速模式和普通模式,有命令類型來決定最終的操作方式。
/*設(shè)置MCP4725輸出*/
void Mcp4725SetDatas(Mcp4725ObjectType *mcp,Mcp4725CommandType cmd,uint16_t data)
{
uint8_t wData[3];
uint8_t pdMode=0;
uint16_t wSize=0;
uint8_t command[]={Fast_Mode,Write_DAC_Register,Write_DAC_Register_EEPROM};
pdMode=(uint8_t)(mcp->pdMode);
if(cmd==Mcp4725_Fast_Mode) //快速模式
{
wData[1]=(uint8_t)data;
wData[0]=(uint8_t)(data>>8);
wData[0]=wData[0]|command[cmd];
wData[0]=wData[0]|(pdMode<<4);
wSize=2;
}
else //普通模式
{
wData[0]=command[cmd];
wData[0]=wData[0]|(pdMode<<1);
wData[1]=(uint8_t)(data>>4);
wData[2]=(uint8_t)(data<<4);
wSize=3;
}
mcp->Write(mcp,wData,wSize);
}
??MCP4725單通道數(shù)模轉(zhuǎn)換器不斷可以寫數(shù)據(jù)也可以讀數(shù)據(jù)。讀回來的數(shù)據(jù)包括狀態(tài)命令字、DAC寄存器數(shù)據(jù)以及EEPROM數(shù)據(jù),總共是5個字節(jié)。具體的操作時序如下:
??根據(jù)前速的分析以及時序圖,我們可以簡單實現(xiàn)讀操作如下:
/*讀取MCP4725數(shù)據(jù)*/
void Mcp4725GetDatas(Mcp4725ObjectType *mcp,uint8_t *rData)
{
mcp->Read(mcp,rData,5);
}
3、驅(qū)動的使用
??我們已經(jīng)實現(xiàn)了MCP4725單通道數(shù)模轉(zhuǎn)換器的驅(qū)動程序。我們還需要將這一驅(qū)動程序?qū)嶋H應(yīng)用一下以確認驅(qū)動程序的正確性。
3.1、聲明并初始化對象
??同樣,我們先聲明一個MCP4725單通道數(shù)模轉(zhuǎn)換器對象變量。前面我們已經(jīng)抽象了對象類型,使用MCP4725單通道數(shù)模轉(zhuǎn)換器對象類型聲明如下:
Mcp4725ObjectType mcp4725;
??對于這個對象變量,我們還需要使用Mcp4725Initialization函數(shù)對它進行初始化才能使用。這個初始化函數(shù)有多個輸入參數(shù):
Mcp4725ObjectType *mcp, //MCP4725對象變量
uint8_t slaveAddress, //從站設(shè)備的地址
Mcp4725PDModeType pdMode,//掉電操作模式
Mcp4725Write write, //寫數(shù)據(jù)函數(shù)指針
Mcp4725Read read //讀數(shù)據(jù)函數(shù)指針
??這些參數(shù)中,第一個參數(shù)是我們要初始化的對象變量,已經(jīng)在前面聲明了。slaveAddress是指MCP4725單通道數(shù)模轉(zhuǎn)換器的設(shè)備地址。掉電操作模式是枚舉類型,根據(jù)使用需要選擇就可以了。最后兩個讀寫操作函數(shù)指針則需要我們實現(xiàn)相應(yīng)的函數(shù)。這兩個函數(shù)的原型定義如下:
typedef void (*Mcp4725Write)(struct Mcp4725Object *mcp,uint8_t *wData, uint16_t wSize);
typedef void (*Mcp4725Read)(struct Mcp4725Object *mcp,uint8_t *rData, uint16_t rSize);
??讀寫操作函數(shù)的實現(xiàn)與具體的軟硬件平臺是相關(guān)的,這里我們實現(xiàn)STM32F103硬件平臺和HAL庫的對應(yīng)函數(shù):
/*通過I2C1端口寫MCP4725*/
static void BmcbMcp4725Write(struct Mcp4725Object *mcp,uint8_t *wData, uint16_t wSize)
{
HAL_I2C_Master_Transmit(&hi2c1,mcp->devAddress,wData,wSize,1000);
}
/*通過I2C1端口讀MCP4725*/
static void BmcbMcp4725Read(struct Mcp4725Object *mcp,uint8_t *rData, uint16_t rSize)
{
HAL_I2C_Master_Receive(&hi2c1,mcp->devAddress,rData,rSize,1000);
}
有了這些參數(shù)后,我們就可以使用這些參數(shù)來初始化MCP4725單通道數(shù)模轉(zhuǎn)換器的對象變量了。
Mcp4725Initialization(&mcp4725, //MCP4725對象變量
0xC0, //從站設(shè)備的地址
MCP4725_Normal, //掉電操作模式
BmcbMcp4725Write, //寫數(shù)據(jù)函數(shù)指針
BmcbMcp4725Read //讀數(shù)據(jù)函數(shù)指針
);
3.2、基于對象進行操作
??關(guān)于對象的應(yīng)用這塊,我們將實際工程中的應(yīng)用代碼節(jié)選過來。具體很簡單就是計算當(dāng)前應(yīng)該下發(fā)的數(shù)字編碼并將其下發(fā)給MCP4725單通道數(shù)模轉(zhuǎn)換器就可以了。
uint16_t code=0;
code=(uint16_t)((aPara.phyPara.presControl/100.0)*4095.0);
Mcp4725SetDatas(&mcp4725,Mcp4725_Write_DAC,code);
4、應(yīng)用總結(jié)
??我們設(shè)計并實現(xiàn)了MCP4725單通道數(shù)模轉(zhuǎn)換器的驅(qū)動程序,而且將其運用到了實際的工程當(dāng)中,使用情況符合我們的預(yù)期。
源碼下載:https://github.com/foxclever/ExPeriphDriver
評論
查看更多