天天看點

外設驅動庫開發筆記42:DAC8552 DAC驅動

  模拟信号輸出是經常會遇到的應用需求,解決的辦法應多種,但我們使用最多的還是數模轉換。對于不同的數模轉換器我們需要為其編寫适用的驅動程式,在這一篇中我們就來考慮如何實作DAC8552高精度模數轉換器的驅動程式。

1、功能概述

  該DAC8552是一個16位,雙通道,電壓輸出數模轉換器(DAC)提供低功率操作和靈活的串行主機接口。每個晶片上的精确輸出放大器允許軌到軌輸出擺動,以實作在2.7V到5.5V的供應範圍。該裝置支援标準三線串行接口,能夠操作與輸入資料時鐘頻率高達30MHz的VDD = 5V。

1.1、功能結構

  DAC8552這種裝置在正常情況下的低功耗使得它非常适合便攜式、電池驅動裝置和其他低功耗應用。采用SOIC-8的封裝形式,引腳定義如下:

外設驅動庫開發筆記42:DAC8552 DAC驅動

  DAC8552需要一個外部參考電壓來設定每個DAC通道的輸出範圍。DAC8552還包括一個電源上電複位電路,以確定DAC輸出功率能夠輸出到零,并保持在那裡,直到擷取一個有效的寫入值。DAC8552擁有一個SPI串行接口,該接口提供了靈活的功能。

外設驅動庫開發筆記42:DAC8552 DAC驅動

  從上述結構圖可知,DAC8552每次僅能操作一路輸出,因為全部的操作都是通過同一個移位寄存器來實作的。

1.2、移位寄存器

  DAC8552有一個24位的輸入移位寄存器,前面8位用來作控制位,後面16位用作資料位。具體如下圖所示:

外設驅動庫開發筆記42:DAC8552 DAC驅動

  在前面的8位控制位中,DB23和DB22是保留位必須為“0”,DB21(LDB)位和DB20(LDA)用于控制後面的16位資料适用于加載哪一個輸出通道還是Power_Down指令。DB19沒有定義,DAC8552不關心該位的具體數值。DB18為緩沖器選擇位,用于控制資料的目标通道是DAC A還是DAC B。後續的DB17(PD1)和DB16(PD0)用于選擇Power_Down的模式。具體的指令如下表中描述:

外設驅動庫開發筆記42:DAC8552 DAC驅動

  至于Power_Down的模式有幾種選擇,如下表所示:

外設驅動庫開發筆記42:DAC8552 DAC驅動

2、驅動設計與實作

  我們已經了解了DAC8552的基本結構及寄存器指令,接下來我們将根據這些認知設計DAC8552的驅動程式。

2.1、對象定義

  在設計DAC8552的驅動程式之前,我們先來考慮一下DAC8552的對象定義問題。我們作為一個對象一般會包括屬性和操作兩個方面的内容。我們先來分析DAC8552對象應該包含有哪些屬性。屬性用于辨別對象的某些特性,DAC8552通過SPI總線下發資料和指令,我們沒有發現什麼需要特别标記的特性,是以我們不需要為DAC8552對象設計屬性。

  我們再來看一看,DAC8552對象需要實作哪些操作。首先DAC8552使用SPI總線進行通訊,而SPI總線采用片選信号來區分不同的節點,是以我們需要操作DAC8552的片選信号,而片選型号的操作顯然依賴于特定的操作平台,是以我們将控制其片選信号作為DAC8552對象的一個操作。另外,DAC8552作為模拟量輸出對象,我們需要向其發送指令和資料,而向其發送資料和指令也依賴于具體的操作平台,是以應将其作為對象的一個操作來實作。據此我們可以定義DAC8552的對象類型如下:

/* 定義DAC8552對象類型 */
typedef struct DAC8552Object {
  void (*WriteDataToDAC)(uint8_t *tData,uint16_t tSize);        //向DAC發送資料
  void (*ChipSelcet)(DAC8552CSType cs);     //片選信号
}DAC8552xObjectType;      

  我們定義了DAC8552的對象類型,但當我們使用其聲明一個對象時,并不能直接使用,我們需要對對象進行初始化,這就需要我們設計一個對象初始化的函數。對象初始化函數處理對象相關的屬性和操作的配置,具體實作如下:

/*初始化DAC8552對象*/
void DAC8552Initialization(DAC8552xObjectType *dac,     //DAC8552對象變量
                           DAC8552WriteType write,      //寫資料函數指針
                           DAC8552ChipSelectType cs             //片選操作函數指針
                          )
{
  if((dac==NULL)||(write==NULL))
  {
    return;
  }
  
  if(cs!=NULL)
  {
    dac->ChipSelcet=cs;
  }
  else
  {
    dac->ChipSelcet=DefaultChipSelect;
  }
}      

2.2、對象操作

  我們已經定義了DAC8552的對象類型并為DAC8552對象設計了初始化函數,接下來我們看一看DAC8552所要實作的操作。對于DAC8552對象來說,我們對其操作無非就是寫其移位寄存器以實作指令和資料的下發。從其資料表中我們可以看到操作移位寄存器的時序如下所示:

外設驅動庫開發筆記42:DAC8552 DAC驅動

  根據我們前面對DAC8552相關資料的了解以及上述時序圖,我們可以封裝對其移位寄存器的操作函數如下:

/*操作DAC8552輸出通道*/
void SetDAC8552ChannelValue(DAC8552xObjectType *dac,DAC8552LDType ld,DAC8552BSType bs,DAC8552PDType pd,uint16_t data)
{
  uint32_t inputShiftData=0;
  uint8_t sData[3];
  
  inputShiftData=data;
  
  inputShiftData=inputShiftData|(ld<<20);
  inputShiftData=inputShiftData|(bs<<18);
  inputShiftData=inputShiftData|(pd<<16);
   
  sData[0]=(uint8_t)(inputShiftData>>16);
  sData[1]=(uint8_t)(inputShiftData>>8);
  sData[2]=(uint8_t)inputShiftData;
  
  dac->ChipSelcet(DAC8552CS_Enable);
  dac->WriteDataToDAC(sData,3);
  dac->ChipSelcet(DAC8552CS_Disable);
}      

3、驅動的使用

  我們設計了DAC8552的對象驅動,但這個驅動是否正确我們需要驗證一下。是以接下來我們設計一個簡單的例子來實作對驅動程式的驗證。

3.1、聲明并初始化對象

  我們使用設計的驅動程式操作DAC8552時,首先需要使用我們定義的對象類型聲明一個DAC8552對象。

DAC8552xObjectType dac8552;      

  聲明了這個對象變量之後,我們還需要使用初始化函數對其進行初始化方可使用。這一初始化函數擁有3個參數:

DAC8552xObjectType *dac,     //DAC8552對象變量
DAC8552WriteType write,      //寫資料函數指針
DAC8552ChipSelectType cs     //片選操作函數指針      

  第一個參數正是我們要初始化的對象變量;第二個參數為向DAC8552寫指令和資料的函數指針;第三個參數是片選信号操作函數指針。這兩個函數指針需要我們實作。它們的原型如下:

/* 向DAC發送資料函數指針類型 */
typedef void (*DAC8552WriteType)(uint8_t *tData,uint16_t tSize);
/* 片選操作函數指針類型 */
typedef void (*DAC8552ChipSelectType)(DAC8552CSType cs);      

  我們根據函數原型定義,在具體的實作平台上實作它們,如我們在STM32平台上實作如下:

/*定義片選信号函數*/
void DAC8552CS(DAC8552CSType en)
{
  if(DAC8552CS_Enable==en)
  {
    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_RESET);
  }
  else
  {
    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_4, GPIO_PIN_SET);
  }
}

/*定義發送資料函數*/
void DAC8552TransmitData(uint8_t *wData,uint16_t wSize)
{
  HAL_SPI_Transmit (&dac8552hspi, wData, wSize, 1000);
}      

  我們将對象變量以及上面實作的2個函數的函數指針作為參數傳遞給DAC8552對象初始化函數來實作對象變量的初始化。具體如下:

DAC8552Initialization(&dac8552,               //DAC8552對象變量
                   DAC8552TransmitData,    //寫資料函數指針
                   DAC8552CS               //片選操作函數指針
                   );      

3.2、基于對象進行操作

  初始化對象變量後,我們就可以基于該對象變量實作我們對DAC8552的操作了。我們已經封裝了對其移位寄存器操作的函數,直接調用該函數來說實作我們的操作。一個簡單的實作函數如下:

/* 修改DAC8552的通道輸出 */
void DAC8552Operation(void)
{
  uint16_t wData=0;
  
  wData=(uint16_t)(65535*tValueA/100);
  
  SetDAC8552ChannelValue(&dac8552,              //所操作的DAC對象
                         DAC8552_LoadA,         //加載的通道
                         DAC8552BS_BufferA,     //選擇的緩存
                         DAC8552PD_Normal,      //Power-Down設定
                         wData                  //所寫的資料
                         );
  
  wData=(uint16_t)(65535*tValueB/100);
  
  SetDAC8552ChannelValue(&dac8552,              //所操作的DAC對象
                         DAC8552_LoadB,         //加載的通道
                         DAC8552BS_BufferB,     //選擇的緩存
                         DAC8552PD_Normal,      //Power-Down設定
                         wData                  //所寫的資料
                         );
}      

  在這個例子中我們分别通過百分比設定值調整了A、B通道的輸出,實作在正常模式下操作A或者B通道,并更新指定的緩存。

4、應用總結

  我們設計并實作了DAC8552模數轉換器的驅動程式,并且設計了一個簡單的應用來驗證這一驅動程式的正确性。所得到的結果證明驅動的設計是沒有問題的,實際上我們已經将其運用到實際的項目中,效果良好。

  在使用驅動程式時需要注意,片選信号并非必須實作。因為有些時候我們可能需要在硬體上直接将其選中,此時添加片選操作函數是沒有什麼意義的,我們可以在初始化時傳入NULL來完成。

歡迎關注:

繼續閱讀