在一些時(shí)候我們需要使用精度更高的數(shù)字電位器來(lái)實(shí)現(xiàn)我們的應(yīng)用。我們經(jīng)常使用AD527x系列數(shù)字電位器來(lái)實(shí)現(xiàn)這類(lèi)應(yīng)用。在通常情況下,AD527x系列數(shù)字電位器完全能夠滿(mǎn)足要求。為了減少重復(fù)工作,在這里我們將分系并實(shí)現(xiàn)AD527x系列數(shù)字電位器的驅(qū)動(dòng)。
1、功能概述
我們?cè)谶@里討論的AD527x系列數(shù)字電位器包括:AD5270、AD5271、AD5272和AD5724,他們的功能是相同的,主要在數(shù)字位或通訊接口上有寫(xiě)差別。
AD527x系列數(shù)字電位器集業(yè)界領(lǐng)先的可變電阻性能與非易失性存儲(chǔ)器(NVM)于一體,這些器件的端到端電阻容差誤差小于1%,并提供50次可編程(50-TP)存儲(chǔ)器。將電阻值編程寫(xiě)入50-TP存儲(chǔ)器之前,可進(jìn)行無(wú)限次調(diào)整。這些器件不需要任何外部電壓源來(lái)幫助熔斷熔絲,并提供50次永久編程的機(jī)會(huì)。在50-TP激活期間,一個(gè)永久熔斷熔絲指令會(huì)將游標(biāo)位置固定
對(duì)于A(yíng)D527x系列數(shù)字電位器,皆有一個(gè)16位寬的移位寄存器,一切對(duì)AD527x系列數(shù)字電位器的操作都是同過(guò)這個(gè)以為寄存器完成的。移位寄存器的格式如下所示。
該16位移位寄存器由兩個(gè)應(yīng)設(shè)為0的未用位、四個(gè)控制位和10個(gè)RDAC數(shù)據(jù)位組成,并且數(shù)據(jù)以MSB優(yōu)先方式加載。對(duì)于A(yíng)D5271和AD5274只有8位數(shù)據(jù),則最后兩位會(huì)被忽略。四個(gè)控制位決定軟件命令的功能,具體的功能碼如下所示:
我們對(duì)AD527x系列數(shù)字電位器的操作就是以這10個(gè)命令為基礎(chǔ)的,事實(shí)上NOP命令是可以忽略的,因?yàn)樗粫?huì)有任何操作發(fā)生。其中有命令5和命令7需要說(shuō)一下。
命令7則用于設(shè)置控制寄存器??刂萍拇嫫鲀H后4為有效。C0用于設(shè)置50-TP的編程使能。C1用于設(shè)置RDAC的寫(xiě)保護(hù)。C2用于電阻容差校準(zhǔn)。C3則是指示50-TP的編程狀態(tài)。具體結(jié)構(gòu)如下:
而命令5用于設(shè)置讀出的50-TP的內(nèi)容。就是說(shuō)這條命令用于設(shè)置我下次讀取50-TP時(shí)究竟是那一條的類(lèi)容,因?yàn)榭偣灿?0條。具體的取值如下:
共50條需要50個(gè)編碼,使用了D0到DF5位,編號(hào)1開(kāi)始一一對(duì)應(yīng)50個(gè)編程位置。
2、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
我們已經(jīng)了解了AD527x系列數(shù)字電位器的基本情況,接下來(lái)我們就設(shè)計(jì)并實(shí)現(xiàn)AD527x系列數(shù)字電位器的驅(qū)動(dòng)。
2.1、對(duì)象定義
同樣的我們將基于對(duì)象操作的思想來(lái)設(shè)計(jì)AD527x系列數(shù)字電位器的驅(qū)動(dòng)。既如此,我們首先必須要定義AD527x系列數(shù)字電位器對(duì)象。
2.1.1、抽象對(duì)象類(lèi)型
在抽象出AD527x系列數(shù)字電位器對(duì)象類(lèi)型之前,我們先來(lái)分析一下AD527x系列數(shù)字電位器。一個(gè)對(duì)象最起碼包含屬性和操作兩個(gè)特性,我們來(lái)分析一下AD527x系列數(shù)字電位器對(duì)象包含有那些屬性和操作。
對(duì)于A(yíng)D527x系列數(shù)字電位器包含有多種器件,不同的器件在通訊接口和檔位等方面會(huì)有差別,所以我們將設(shè)備的類(lèi)型作為其屬性以分辯究竟是哪種器件,進(jìn)而分辨接口和檔位差異。游標(biāo)的當(dāng)前位置以及控制寄存器的值我們也將其設(shè)置為屬性以確定設(shè)備當(dāng)前的狀態(tài)。當(dāng)設(shè)備時(shí)I2C接口時(shí),需要有一個(gè)設(shè)備地址,所以我們將設(shè)備地址設(shè)置為屬性,這個(gè)屬性只在I2C接口模式時(shí)才起作用。而在使用SPI接口的器件時(shí),需要一個(gè)片選信號(hào),所以我們將操作片選信號(hào)作為AD527x系列數(shù)字電位器的一個(gè)操作,這個(gè)操作只在使用SPI接口的器件時(shí)才起作用。此外,AD527x系列數(shù)字電位器對(duì)象還需要實(shí)現(xiàn)數(shù)據(jù)的發(fā)送與接收以及操作過(guò)程中必要的延時(shí)函數(shù),我們均將其作為對(duì)象的操作。據(jù)上述分析我們可以抽象出AD527x系列數(shù)字電位器對(duì)象類(lèi)型如下:
/*定義用于SPI接口的對(duì)象類(lèi)型*/
typedef struct AD527xObject {
AD527xType type;//設(shè)備類(lèi)型
uint8_t devAddress;//設(shè)備地址,用于I2C接口
uint8_t conreg;//控制寄存器
uint16_t rdac;//游標(biāo)寄存器現(xiàn)值
void (*ChipSelcet)(AD527xCSType en);//片選信號(hào),用于SPI接口
void (*Receive)(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize);
void (*Transmit)(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize);
void (*Delayms)(volatile uint32_t nTime); //ms延時(shí)操作指針
}AD527xObjectType;
2.1.2、對(duì)象的初始化
一個(gè)對(duì)象我們需要對(duì)其初始化才能使用,初始化函數(shù)至少包含有2方面內(nèi)容:一是為對(duì)象變量賦必要的初值;二是檢查這些初值是否是有效的。特別是一些操作指針錯(cuò)誤的話(huà)可能產(chǎn)生嚴(yán)重的后果?;谶@一原則,我們?cè)O(shè)計(jì)AD527x系列數(shù)字電位器的對(duì)象初始化函數(shù)如下:
/* 初始化AD527x對(duì)象,I2C接口必須初始化devAddress,SPI接口必需初始化void (*ChipSelcet)(bool) */
void AD527xInitialization(AD527xObjectType *rx,
uint8_t address,
AD527xType type,
AD527xReceive recieve,
AD527xTransmit transmit,
AD527xChipSelcet cs,
AD527xDelayms delayms)
{
if((rx==NULL)||(recieve==NULL)||(transmit==NULL)||(delayms==NULL))
{
return;
}
if((type==AD5270)||(type==AD5271))//使用SPI接口
{
if(cs==NULL)//硬件電路實(shí)現(xiàn)片選
{
rx->ChipSelcet=DefaultChipSelcet;
}
else
{
rx->ChipSelcet=cs;
}
rx->devAddress=0x00;
}
else//使用I2C接口
{
if((address==0x58)||(address==0x5C)||(address==0x5E))
{
rx->devAddress=address;
}
else if((address==0x2C)||(address==0x2E)||(address==0x2F))
{
rx->devAddress=(address<<1);
}
else
{
rx->devAddress=0x00;
}
rx->ChipSelcet=NULL;
}
rx->type=type;
rx->conreg=0x00;
rx->rdac=0x0000;
rx->Receive=recieve;
rx->Transmit=transmit;
rx->Delayms=delayms;
ReadControlRegister(rx);
SetSoftShutMode(rx,SOFT_NORMAL_MODE);
}
2.2、對(duì)象操作
前面我們已經(jīng)描述過(guò),對(duì)AD527x系列數(shù)字電位器的操作命令有9個(gè)。這9個(gè)命令皆是對(duì)寄存器進(jìn)行讀寫(xiě)操作的,所以我們這里將這些操作分為讀寄存器操作和寫(xiě)寄存器操作,并以此設(shè)計(jì)驅(qū)動(dòng)程序。
2.2.1、寫(xiě)寄存器操作
首先我們需要說(shuō)明寫(xiě)寄存器操作是針對(duì)對(duì)象的操作函數(shù),而不是對(duì)象變量包含的操作,因?yàn)槲覀冎辉趯?duì)象變量中放入依賴(lài)于外界平臺(tái)的基本操作。寫(xiě)寄存器操作會(huì)以回調(diào)的方式調(diào)用對(duì)象變量包含的基本操作。
因?yàn)锳D527x系列數(shù)字電位器對(duì)象包括不同接口和不同檔位的器件,所以我們?cè)O(shè)計(jì)寫(xiě)寄存器操作時(shí)需要考慮AD527x系列數(shù)字電位器對(duì)象的類(lèi)型。而這個(gè)類(lèi)型已在初始化時(shí)賦予了對(duì)象變量。據(jù)此我們?cè)O(shè)計(jì)寫(xiě)寄存器操作函數(shù)如下:
/* 寫(xiě)寄存器操作 */
static void AD527xWriteRegister(AD527xObjectType *rx,uint16_t cmd)
{
uint8_t tData[2];
tData[0]=(uint8_t)(cmd>>8);
tData[1]=(uint8_t)cmd;
if((rx->type==AD5270)||(rx->type==AD5271))//SPI接口
{
rx->ChipSelcet(AD527xCS_ENABLE);
rx->Delayms(1);
}
rx->Transmit(rx,tData,2);
if((rx->type==AD5270)||(rx->type==AD5271))//SPI接口
{
rx->Delayms(1);
rx->ChipSelcet(AD527xCS_DISABLE);
}
}
2.2.2、讀寄存器操作
與寫(xiě)寄存器操作一樣,讀寄存器操作一樣要考慮到AD527x系列數(shù)字電位器對(duì)象的類(lèi)型。在使用SPI接口的對(duì)象類(lèi)型種需要考慮片選信號(hào)的處理。我們?cè)O(shè)計(jì)讀寄存器操作如下:
/* 讀寄存器操作 */
static void AD527xReadRegister(AD527xObjectType *rx,uint16_t cmd,uint8_t *rData)
{
uint8_t tData[2];
if((rx->type==AD5270)||(rx->type==AD5271))//SPI接口
{
rx->ChipSelcet(AD527xCS_ENABLE);
rx->Delayms(1);
}
rx->Transmit(rx,tData,2);
rx->Receive(rx,rData,2);
if((rx->type==AD5270)||(rx->type==AD5271))//SPI接口
{
rx->Delayms(1);
rx->ChipSelcet(AD527xCS_DISABLE);
}
}
2.2.3、面向命令的操作
我們已經(jīng)實(shí)現(xiàn)了對(duì)繼存存其的讀操作和寫(xiě)操作,但我們并不想通過(guò)調(diào)用這兩個(gè)函數(shù)并傳遞命令來(lái)實(shí)現(xiàn)我們的應(yīng)用。所以我們將不同的操作命令所要完成的功能封裝成函數(shù),在這些函數(shù)中調(diào)用讀寫(xiě)寄存器操作函數(shù)來(lái)完成。這樣使用驅(qū)動(dòng)就變得更為簡(jiǎn)便。例如我們?cè)O(shè)計(jì)讀寫(xiě)RDAC的函數(shù)如下:
/* 設(shè)置AD527x游標(biāo)位置 */
void SetRDACForAd527x(AD527xObjectType *rx,uint16_t data)
{
uint16_t temp=0;
if((rx->type==AD5271)||(rx->type==AD5274))//256檔
{
temp=data>255?255:data;
}
else if((rx->type==AD5270)||(rx->type==AD5272))//1024檔
{
temp=data>1023?1023:data;
}
temp=COMMAND_W_RDAC|temp;
if(((rx->conreg)&0x02)!=0x02)
{
SetControlRegister(rx,PROGRAM_RDAC_ENABLE|rx->conreg);
}
AD527xWriteRegister(rx,temp);
}
/* 讀取RDAC游標(biāo)寄存器的內(nèi)容 */
uint16_t ReadRDACFromAd527x(AD527xObjectType *rx)
{
uint8_t rData[2];
uint16_t cmd=COMMAND_R_RDAC;
AD527xReadRegister(rx,cmd,rData);
rx->rdac=(rData[0]<<8)+rData[1];
return rx->rdac;
}
3、驅(qū)動(dòng)的使用
我們已經(jīng)實(shí)現(xiàn)了AD527x系列數(shù)字電位器的驅(qū)動(dòng)。接下來(lái)我們來(lái)考慮如何使用這一驅(qū)動(dòng)實(shí)現(xiàn)我們的應(yīng)用。
3.1、聲明并初始化對(duì)象
我們已經(jīng)定義了AD527x系列數(shù)字電位器對(duì)象類(lèi)型。所以我們先要使用對(duì)象類(lèi)型聲明一個(gè)AD527x系列數(shù)字電位器對(duì)象變量。形式如下:
AD527xObjectType ad527x;
當(dāng)然,這里定義的這個(gè)對(duì)象變量還不能直接使用。我們需要使用初始化函數(shù)對(duì)這個(gè)對(duì)象變量進(jìn)行初始化。初始化函數(shù)前面已經(jīng)說(shuō)過(guò),傳遞的參數(shù)皆是與對(duì)象變量相關(guān)的。初始化函數(shù)的參數(shù)如下:
AD527xObjectType *rx,待初始化的對(duì)象變量。
uint8_t address,采用I2C接口通訊是的設(shè)備地址。
AD527xType type,對(duì)象的設(shè)備類(lèi)型。
AD527xReceive recieve,數(shù)據(jù)接收函數(shù)指針。
AD527xTransmit transmit,數(shù)據(jù)發(fā)送函數(shù)指針。
AD527xChipSelcet cs,使用SPI接口通訊時(shí),片選操作函數(shù)指針。
AD527xDelayms delayms,毫秒延時(shí)操作函數(shù)指針。
對(duì)于這些參數(shù),對(duì)象變量我們已經(jīng)定義了。對(duì)象類(lèi)型根據(jù)實(shí)際器件輸入即可。而設(shè)備地址在使用I2C接口時(shí)按要求輸入即可,如果是SPI接口則任意uint8_t類(lèi)型的值均可。最主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類(lèi)型圖下:
/*定義片選信號(hào)函數(shù)指針類(lèi)型*/
typedef void (*AD527xChipSelcet)(AD527xCSType en);
/*定義接收數(shù)據(jù)函數(shù)指針類(lèi)型*/
typedef void (*AD527xReceive)(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize);
/*定義發(fā)送數(shù)據(jù)函數(shù)指針類(lèi)型*/
typedef void (*AD527xTransmit)(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize);
/*定義ms延時(shí)操作指針*/
typedef void (*AD527xDelayms)(volatile uint32_t nTime);
對(duì)于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺(tái)有關(guān)系。片選操作函數(shù)只在使用SPI接口是需要定義,否則可以傳入NULL即可。具體函數(shù)定義如下:
/*定義片選信號(hào)函數(shù)*/
void AD527xCS(AD527xCSType en)
{
if(AD527xCS_ENABLE==en)
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_SET);
}
}
/*定義接收數(shù)據(jù)函數(shù)*/
void AD527xReceiveData(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize)
{
HAL_SPI_Receive (&hspi, rData, rSize, 1000);
}
/*定義發(fā)送數(shù)據(jù)函數(shù)*/
void AD527xTransmitData(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize)
{
HAL_SPI_Transmit (&hspi, wData, wSize, 1000);
}
對(duì)于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們曹勇的STM32平臺(tái)和HAL庫(kù)則可以直接使用HAL_Delay()函數(shù)。于是我們可以調(diào)用初始化函數(shù)如下:
AD527xInitialization(&ad527x,0x00,AD5270,AD527xReceiveData,AD527xTransmitData,AD527xCS,HAL_Delay);
這是使用SPI接口器件的初始化操作,使用I2C接口的初始化操作類(lèi)似次操作即可。
3.2、基于對(duì)象進(jìn)行操作
我們已經(jīng)定義了對(duì)象變量并對(duì)其進(jìn)行了初始化。接下來(lái)我們就要看看如何操作對(duì)象得到我們想要的結(jié)果。
我們?cè)谇懊嬉呀?jīng)根據(jù)操作命令做了封裝,所以我們需要什么養(yǎng)的功能只需要調(diào)用相應(yīng)的函數(shù)就可以了。如我們想要設(shè)置RDAC為最大值則:
SetValueToAd5270(&ad527x,1023);
其中第1個(gè)參數(shù)為要操作的對(duì)象指針,第2個(gè)參數(shù)為要設(shè)置的游標(biāo)位置值。
4、應(yīng)用總結(jié)
我們已經(jīng)實(shí)現(xiàn)AD527x系列數(shù)字電位器的驅(qū)動(dòng)及基于此驅(qū)動(dòng)的應(yīng)用,得到了與我們預(yù)期一致的結(jié)果,說(shuō)明驅(qū)動(dòng)的設(shè)計(jì)時(shí)符合需求的。
在使用驅(qū)動(dòng)時(shí)需注意,采用I2C接口的器件需要考慮設(shè)備地址的問(wèn)題。設(shè)備地址由ADDR引腳的狀態(tài)決定。由三種取值如下:
在使用驅(qū)動(dòng)時(shí)需注意,采用SPI接口的器件需要考慮片選操作的問(wèn)題。如果片選信號(hào)是通過(guò)硬件電路來(lái)實(shí)現(xiàn)的,我們?cè)诔跏蓟瘯r(shí)給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫(xiě)的片選操作函數(shù)。
-
寄存器
+關(guān)注
關(guān)注
31文章
5336瀏覽量
120230 -
數(shù)字電位器
+關(guān)注
關(guān)注
4文章
267瀏覽量
83207 -
驅(qū)動(dòng)設(shè)計(jì)
+關(guān)注
關(guān)注
1文章
111瀏覽量
15285
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論