在一些時候我們需要使用精度更高的數字電位器來實現我們的應用。我們經常使用AD527x系列數字電位器來實現這類應用。在通常情況下,AD527x系列數字電位器完全能夠滿足要求。為了減少重復工作,在這里我們將分系并實現AD527x系列數字電位器的驅動。
1、功能概述
我們在這里討論的AD527x系列數字電位器包括:AD5270、AD5271、AD5272和AD5724,他們的功能是相同的,主要在數字位或通訊接口上有寫差別。
AD527x系列數字電位器集業界領先的可變電阻性能與非易失性存儲器(NVM)于一體,這些器件的端到端電阻容差誤差小于1%,并提供50次可編程(50-TP)存儲器。將電阻值編程寫入50-TP存儲器之前,可進行無限次調整。這些器件不需要任何外部電壓源來幫助熔斷熔絲,并提供50次永久編程的機會。在50-TP激活期間,一個永久熔斷熔絲指令會將游標位置固定
對于AD527x系列數字電位器,皆有一個16位寬的移位寄存器,一切對AD527x系列數字電位器的操作都是同過這個以為寄存器完成的。移位寄存器的格式如下所示。
該16位移位寄存器由兩個應設為0的未用位、四個控制位和10個RDAC數據位組成,并且數據以MSB優先方式加載。對于AD5271和AD5274只有8位數據,則最后兩位會被忽略。四個控制位決定軟件命令的功能,具體的功能碼如下所示:
我們對AD527x系列數字電位器的操作就是以這10個命令為基礎的,事實上NOP命令是可以忽略的,因為它不會有任何操作發生。其中有命令5和命令7需要說一下。
命令7則用于設置控制寄存器。控制寄存器僅后4為有效。C0用于設置50-TP的編程使能。C1用于設置RDAC的寫保護。C2用于電阻容差校準。C3則是指示50-TP的編程狀態。具體結構如下:
而命令5用于設置讀出的50-TP的內容。就是說這條命令用于設置我下次讀取50-TP時究竟是那一條的類容,因為總共有50條。具體的取值如下:
共50條需要50個編碼,使用了D0到DF5位,編號1開始一一對應50個編程位置。
2、驅動設計與實現
我們已經了解了AD527x系列數字電位器的基本情況,接下來我們就設計并實現AD527x系列數字電位器的驅動。
2.1、對象定義
同樣的我們將基于對象操作的思想來設計AD527x系列數字電位器的驅動。既如此,我們首先必須要定義AD527x系列數字電位器對象。
2.1.1、抽象對象類型
在抽象出AD527x系列數字電位器對象類型之前,我們先來分析一下AD527x系列數字電位器。一個對象最起碼包含屬性和操作兩個特性,我們來分析一下AD527x系列數字電位器對象包含有那些屬性和操作。
對于AD527x系列數字電位器包含有多種器件,不同的器件在通訊接口和檔位等方面會有差別,所以我們將設備的類型作為其屬性以分辯究竟是哪種器件,進而分辨接口和檔位差異。游標的當前位置以及控制寄存器的值我們也將其設置為屬性以確定設備當前的狀態。當設備時I2C接口時,需要有一個設備地址,所以我們將設備地址設置為屬性,這個屬性只在I2C接口模式時才起作用。而在使用SPI接口的器件時,需要一個片選信號,所以我們將操作片選信號作為AD527x系列數字電位器的一個操作,這個操作只在使用SPI接口的器件時才起作用。此外,AD527x系列數字電位器對象還需要實現數據的發送與接收以及操作過程中必要的延時函數,我們均將其作為對象的操作。據上述分析我們可以抽象出AD527x系列數字電位器對象類型如下:
/*定義用于SPI接口的對象類型*/
typedef struct AD527xObject {
AD527xType type;//設備類型
uint8_t devAddress;//設備地址,用于I2C接口
uint8_t conreg;//控制寄存器
uint16_t rdac;//游標寄存器現值
void (*ChipSelcet)(AD527xCSType en);//片選信號,用于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延時操作指針
}AD527xObjectType;
2.1.2、對象的初始化
一個對象我們需要對其初始化才能使用,初始化函數至少包含有2方面內容:一是為對象變量賦必要的初值;二是檢查這些初值是否是有效的。特別是一些操作指針錯誤的話可能產生嚴重的后果。基于這一原則,我們設計AD527x系列數字電位器的對象初始化函數如下:
/* 初始化AD527x對象,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)//硬件電路實現片選
{
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、對象操作
前面我們已經描述過,對AD527x系列數字電位器的操作命令有9個。這9個命令皆是對寄存器進行讀寫操作的,所以我們這里將這些操作分為讀寄存器操作和寫寄存器操作,并以此設計驅動程序。
2.2.1、寫寄存器操作
首先我們需要說明寫寄存器操作是針對對象的操作函數,而不是對象變量包含的操作,因為我們只在對象變量中放入依賴于外界平臺的基本操作。寫寄存器操作會以回調的方式調用對象變量包含的基本操作。
因為AD527x系列數字電位器對象包括不同接口和不同檔位的器件,所以我們設計寫寄存器操作時需要考慮AD527x系列數字電位器對象的類型。而這個類型已在初始化時賦予了對象變量。據此我們設計寫寄存器操作函數如下:
/* 寫寄存器操作 */
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、讀寄存器操作
與寫寄存器操作一樣,讀寄存器操作一樣要考慮到AD527x系列數字電位器對象的類型。在使用SPI接口的對象類型種需要考慮片選信號的處理。我們設計讀寄存器操作如下:
/* 讀寄存器操作 */
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、面向命令的操作
我們已經實現了對繼存存其的讀操作和寫操作,但我們并不想通過調用這兩個函數并傳遞命令來實現我們的應用。所以我們將不同的操作命令所要完成的功能封裝成函數,在這些函數中調用讀寫寄存器操作函數來完成。這樣使用驅動就變得更為簡便。例如我們設計讀寫RDAC的函數如下:
/* 設置AD527x游標位置 */
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游標寄存器的內容 */
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、驅動的使用
我們已經實現了AD527x系列數字電位器的驅動。接下來我們來考慮如何使用這一驅動實現我們的應用。
3.1、聲明并初始化對象
我們已經定義了AD527x系列數字電位器對象類型。所以我們先要使用對象類型聲明一個AD527x系列數字電位器對象變量。形式如下:
AD527xObjectType ad527x;
當然,這里定義的這個對象變量還不能直接使用。我們需要使用初始化函數對這個對象變量進行初始化。初始化函數前面已經說過,傳遞的參數皆是與對象變量相關的。初始化函數的參數如下:
AD527xObjectType *rx,待初始化的對象變量。
uint8_t address,采用I2C接口通訊是的設備地址。
AD527xType type,對象的設備類型。
AD527xReceive recieve,數據接收函數指針。
AD527xTransmit transmit,數據發送函數指針。
AD527xChipSelcet cs,使用SPI接口通訊時,片選操作函數指針。
AD527xDelayms delayms,毫秒延時操作函數指針。
對于這些參數,對象變量我們已經定義了。對象類型根據實際器件輸入即可。而設備地址在使用I2C接口時按要求輸入即可,如果是SPI接口則任意uint8_t類型的值均可。最主要的是我們需要定義幾個函數,并將函數指針作為參數。這幾個函數的類型圖下:
/*定義片選信號函數指針類型*/
typedef void (*AD527xChipSelcet)(AD527xCSType en);
/*定義接收數據函數指針類型*/
typedef void (*AD527xReceive)(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize);
/*定義發送數據函數指針類型*/
typedef void (*AD527xTransmit)(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize);
/*定義ms延時操作指針*/
typedef void (*AD527xDelayms)(volatile uint32_t nTime);
對于這幾個函數我們根據樣式定義就可以了,具體的操作可能與使用的硬件平臺有關系。片選操作函數只在使用SPI接口是需要定義,否則可以傳入NULL即可。具體函數定義如下:
/*定義片選信號函數*/
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);
}
}
/*定義接收數據函數*/
void AD527xReceiveData(struct AD527xObject *rx,uint8_t *rData,uint16_t rSize)
{
HAL_SPI_Receive (&hspi, rData, rSize, 1000);
}
/*定義發送數據函數*/
void AD527xTransmitData(struct AD527xObject *rx,uint8_t *wData,uint16_t wSize)
{
HAL_SPI_Transmit (&hspi, wData, wSize, 1000);
}
對于延時函數我們可以采用各種方法實現。我們曹勇的STM32平臺和HAL庫則可以直接使用HAL_Delay()函數。于是我們可以調用初始化函數如下:
AD527xInitialization(&ad527x,0x00,AD5270,AD527xReceiveData,AD527xTransmitData,AD527xCS,HAL_Delay);
這是使用SPI接口器件的初始化操作,使用I2C接口的初始化操作類似次操作即可。
3.2、基于對象進行操作
我們已經定義了對象變量并對其進行了初始化。接下來我們就要看看如何操作對象得到我們想要的結果。
我們在前面已經根據操作命令做了封裝,所以我們需要什么養的功能只需要調用相應的函數就可以了。如我們想要設置RDAC為最大值則:
SetValueToAd5270(&ad527x,1023);
其中第1個參數為要操作的對象指針,第2個參數為要設置的游標位置值。
4、應用總結
我們已經實現AD527x系列數字電位器的驅動及基于此驅動的應用,得到了與我們預期一致的結果,說明驅動的設計時符合需求的。
在使用驅動時需注意,采用I2C接口的器件需要考慮設備地址的問題。設備地址由ADDR引腳的狀態決定。由三種取值如下:
在使用驅動時需注意,采用SPI接口的器件需要考慮片選操作的問題。如果片選信號是通過硬件電路來實現的,我們在初始化時給其傳遞NULL值。如果是軟件操作片選則傳遞我們編寫的片選操作函數。
-
寄存器
+關注
關注
31文章
5369瀏覽量
121274 -
數字電位器
+關注
關注
4文章
267瀏覽量
83352 -
驅動設計
+關注
關注
1文章
111瀏覽量
15322
發布評論請先 登錄
相關推薦
AD8400系列數字電位器的驅動設計與實現
![AD8400<b class='flag-5'>系列</b><b class='flag-5'>數字</b><b class='flag-5'>電位器</b>的<b class='flag-5'>驅動</b>設計與<b class='flag-5'>實現</b>](https://file.elecfans.com/web2/M00/81/BE/poYBAGOS66-AJRGmAAGQ0d5LUhg601.jpg)
數字電位器的應用特性分析
用數字電位器替代機械電位器
![用<b class='flag-5'>數字</b><b class='flag-5'>電位器</b>替代機械<b class='flag-5'>電位器</b>](https://file1.elecfans.com//web2/M00/A4/D1/wKgZomUMNdOAE8RRAABjF8tMsgY203.gif)
評論