在開發臭氧發生器的時,我們需要一個高分辨率的AD采集,於是選擇了AD7192,選擇這款ADC的原因比較簡單。首先它是24位的符合我們的精度要求;其次它自帶時鍾,便於節省空間;第三他又4路單端或2路差分輸入,與我們需要三路采集相符。
1、AD7192簡介
AD7192是一款適合高精密測量應用的低噪聲完整模擬前端,內置一個低噪聲、 24 位Σ-Δ型模數轉換器 (ADC)。片內低噪聲增益級意味着可直接輸入小信號。
AD7192可配置為兩路差分輸入或四路偽差分輸入。片內通道序列器可以使能多個通道,AD7192 按順序在各使能通道上執行轉換,這可以簡化與器件的通信。 片內 4.92 MHz時鍾可以用作 ADC 的時鍾源; 或者也可以使用外部時鍾或晶振。 該器件的輸出數據速率可在 4.7 Hz 至 4.8 kHz 的范圍內變化。
AD7192提供兩種數字濾波器選項。 濾波器的選擇會影響以編程輸出數據速率工作時的均方根噪聲和無噪聲分辨率、建立時間以及 50 Hz/60 Hz 抑制。 針對要求所有轉換均需建立的應用, AD7192 具有零延遲特性。
其功能結構圖如下:
2、硬件設計
AD7192的串行接口包含四個信號:CS、DIN、SCLK 和DOUT/RDY。所以我們采用標准的SPI接口來實現AD7192的數據操作。具體的硬件設計圖如下:
4路輸入分別通過運算放大器做前端處理,然后以標准信號輸入到AD7192,數字輸入輸出則接到MCU的SPI接口。
3、軟件設計
AD7192內部具有多個寄存器,對AD7192的操作就是通過這些片內寄存器進行控制和數據寄存器/數據寄存器加狀態信息配置。這些寄存器包括:通信寄存器、狀態寄存器、模式寄存器、配置寄存器、ID寄存器、GPOCON寄存器、失調寄存器以及滿量程寄存器。其中通信寄存器和狀態寄存器共享地址,讀操作時針對的是狀態寄存器,寫操作時針對的是通訊寄存器。對任何寄存器的操作都是從寫通訊寄存器開始。
(1)、AD7192初始化
在使用AD719前先對其實先初始化。首先是軟件復位,連續寫入40個1就可對AD7192實現復位。復位完成后,對零點和量程進行較准。而后讀取各寄存器狀態。具體實現代碼如下:
/*AD7192初始化配置*/ void AD7192Initialization(void (*ReadWriteForAd7192)(uint8_t *,uint8_t *,uint16_t ),void (*ChipSelected)(bool),uint16_t (*GetReadyInput)(void)) { AD7192SoftwareReset(ReadWriteForAd7192,ChipSelected); AD7192InternalZeroScaleCalibration(ReadWriteForAd7192,ChipSelected,GetReadyInput); AD7192InternalFullScaleCalibration(ReadWriteForAd7192,ChipSelected,GetReadyInput); /*讀取並存儲全部寄存器的值*/ ReadAD7192Register(REG_COM_STA, 8, AD7192Registers, REG_COM_STA,ReadWriteForAd7192,ChipSelected); AD7192InternalZeroScaleCalibration(ReadWriteForAd7192,ChipSelected,GetReadyInput); AD7192InternalFullScaleCalibration(ReadWriteForAd7192,ChipSelected,GetReadyInput); }
零點和量程校准包括內部校准和外部校准,我們這里使用內部校准。
(2)、讀取轉換數據
讀取轉換的結果有2中方式:單次獲取和連續獲取。單次轉換模式下,AD7192 在完成轉換后處於關斷模式。 將模式寄存器中的MD2、MD1和MD0分別設置為0、0、1,便可啟動單次轉換,此時AD7192將上電,執行單次轉換,然后返回關斷模式。時序圖如下所示:
單次轉換數據獲取具體實現代碼如下:
uint32_t GetStartSingleConvertionValue(uint32_t Channels,void (*ReadWriteForAd7192)(uint8_t *,uint8_t *,uint16_t ),void (*ChipSelected)(bool),uint16_t (*GetReadyInput)(void)) { uint32_t dataCode=0; AD7192StartSingleConvertion(Channels,ReadWriteForAd7192,ChipSelected); dataCode = AD7192ReadConvertingData(ReadWriteForAd7192,ChipSelected,GetReadyInput); dataCode =dataCode & 0x00FFFFFF; ReadAD7192Register(REG_DATA, 1, AD7192Registers, REG_DATA,ReadWriteForAd7192,ChipSelected); return dataCode; }
連續轉換模式是上電后的默認轉換模式。AD7192連續轉換,每次完成轉換后,狀態寄存器中的RDY位變為低電平。如果CS為低電平,則完成一次轉換時,DOUT/RDY 線路也會變為低電平。若要讀取轉換結果,用戶需要寫入通信寄存器,指示下一操作為讀取數據寄存器。從數據寄存器中讀取數據字后,DOUT/RDY變為高電平。時序圖如下所示:
連續轉換數據獲取具體實現代碼如下:
void GettContinuousConvertionValue(uint32_t Channels,uint32_t *dataCodes,int number,void (*ReadWriteForAd7192)(uint8_t *,uint8_t *,uint16_t ),void (*ChipSelected)(bool),uint16_t (*GetReadyInput)(void)) { uint32_t dataCode=0; AD7192StartContinuousConvertion(Channels,ReadWriteForAd7192,ChipSelected); for(int i=0;i<number;i++) { dataCode = AD7192ReadConvertingData(ReadWriteForAd7192,ChipSelected,GetReadyInput); dataCode =dataCode & 0x00FFFFFF; dataCodes[i]=dataCode; } }
(3)、讀取內部溫度
AD7192內置一個溫度傳感器。利用配置寄存器中的CH2位可以選擇溫度傳感器。如果CH2位設置為1,就會使能溫度傳感器。使用溫度傳感器並選擇雙極性模式時,如果溫度為0K,器件應返回0x800000碼。為使傳感器發揮最佳性能,需要執行單點校准。因此,應記錄25°C 時的轉換結果並計算靈敏度。 靈敏度約為2815碼 /°C。溫度傳感器的計算公式為 :
溫度 (K) = ( 轉換結果 – 0x800000)/2815 K
溫度 (°C) = 溫度 (K) – 273
單點校准之后,內部溫度傳感器的精度典型值為 ±2°C。具體的實現代碼如下:
/*讀取內部溫度數據,返回攝氏度溫度*/ float GetTemperatureValue(void (*ReadWriteForAd7192)(uint8_t *,uint8_t *,uint16_t ),void (*ChipSelected)(bool),uint16_t (*GetReadyInput)(void)) { uint32_t temperatureCode=0; float temp = 0.0; AD7192Registers[REG_MODE] = 0; AD7192Registers[REG_CONF] = 0; AD7192Registers[REG_MODE] = MODE_SING|DAT_STA_DIS|INCLK_MCLK2EN|SINC_4|ENPAR_EN|CLK_DIV_DIS|SINGLECYCLE_DIS|REJ60_DIS|0x080; // AD7192Registers[REG_MODE] = MODE_CONT|DAT_STA_DIS|INCLK_MCLK2TRI|SINC_4|ENPAR_DIS|CLK_DIV_DIS|SINGLECYCLE_DIS|REJ60_DIS|0x060; WriteAD7192Register(REG_MODE, 1, AD7192Registers,ReadWriteForAd7192,ChipSelected); AD7192Registers[REG_CONF] = CHOP_DIS|REF_IN1|TEMP|BURN_DIS|REFDET_DIS|BUF_DIS|UB_BI|GAIN_1; WriteAD7192Register(REG_CONF, 1, AD7192Registers,ReadWriteForAd7192,ChipSelected); temperatureCode = AD7192ReadConvertingData(ReadWriteForAd7192,ChipSelected,GetReadyInput); temp = (temperatureCode-0x800000)/2815.0-273; return temp; }