■ 簡介
AD5933阻抗變換模塊 是基於AD(ANALOG DEVICES)公司 的 AD5933 芯片的阻抗轉換器、網絡分析儀。此外,AD公司還提供了一款小型的 AD5934 。
▲ AD5933阻抗轉換器
該模塊在TMALL上的零售價格爲¥188。
D5933是一款高精度的阻抗轉換器系統解決方案,片上集成頻率發生器與12位、1 MSPS的模數轉換器(ADC)。用頻率發生器產生的信號來激勵外部復阻抗,外部阻抗的響應信號由片上ADC進行採樣,然後由片上DSP進行離散傅里葉變換(DFT)處理。DFT算法在每個頻率上返回一個實部®數據字和一個虛部(I)數據字。然後根據實部數據字與虛部數據字可計算出待測器件的阻抗值與相位值。
- 模塊特性
- 可編程輸出峯峯值激勵電壓,輸出頻率高可達100 kHz
- 可編程頻率掃描功能和串行I2C®接口
- 頻率分辨率:27位(<0.1 Hz)
- 阻抗測量範圍:1 kΩ至10 MΩ
- 利用附加電路可測量100Ω至1 kΩ阻抗
- 內部溫度傳感器(±2°C)
▲ AD5933內部結構圖
01模塊基本分析
1.I-V測量反饋電阻
從購買的網站上並沒有給出該模塊以下信息:
- RFB 的選擇與大小:因爲在模塊中只有一個VIN,並沒有顯示出RFB的接口大小。
這部分將模塊上的金屬殼頂蓋打開,便可以看到其中的內部主要電路。
▲ 將模塊金屬屏蔽盒打開之後,內部結構
通過測量,在AD5933上邊的電阻(22k歐姆)是連接在RBF(PIN4)和VIN(PIN5)之間的電阻。這說明反饋的電阻爲22kΩ。
▲ RFB電阻爲22kΩ
2.模塊工作電源
模塊供電端口的電源爲+5V。內部有AS1117-3.3V線性穩壓電源。AD5933工作電源爲3.3V。
3.模塊運放接口電路
在金屬屏蔽盒中包括有一個基於 AD8606 精密運放接口電路。
▲ 內部輔助電路
這部分電路與手冊中的參考輔助電路結構很相似。是在了AD5933的輸出和輸入部分增加了基於AD8606的運放緩衝。提高了電路對了的驅動能力。
▲ 手冊中的參考輔助電路
啓動這部分電路,需要將內部電路的幾個焊接點進行重新調整,將這部分的電路接入測量電路中。
02測試電路
1.硬件設計1
由於AD5933使用I2C總結接口,利用STC8G1K08所提供的I2C做接口芯片,完成與PC即連接。
▲ 測試單片機STC8G1K08原理圖
使用快速製版,設計實驗電路板並進行焊接。集成在麪包板上完成實驗。
▲ 實驗電路板
2.軟件設計2
工作頻率:35MHz
STC8G1K軟件設置:
- STC8G.H: #define PACKAGE_SOP8 1, #define I2C_EN 1
▲ 斜口鉗:28元人民幣
03實驗測試
1.AD5933基礎測試
- 供應工作電壓+5V,測量此時工作電流:5mA。
- 測量芯片周圍的工作電壓:3.296V;
- 測量內部AD8606運放的工作電壓:3.296V;兩個運放的靜態輸出爲1.64V。
▲ AD5933通電
2.I2C總線測試
下圖顯示連接AD5933的I2C總結對8G1K的I2C總線輸出波形的影響:
- 數據線的幅度在連接AD5399的時候降低到了3.3V。數據線的幅值沒有改變;
- 數據線在連接AD5933的時候,被主動拉高的一些變化。
▲ I2C總線波形測試
3.建立AD5933相關的模塊
-
建立AD5933.H, AD5933.C的相關模塊並定義一系列的相關底層函數
相應的模塊參見工程文件中的相應的文件。 -
基於串口的命令接口
這部分在serialtxt.c文件中實現。具體命令參加下面程序:
else IFARG0("setp") {
sscanf(SDA(1), "%x", &nNumber);
AD5933SetPointer((unsigned char)nNumber);
printf("Set Pointer:%d\r\n",nNumber);
} else IFARG0("readb") {
sscanf(SDA(1), "%x", &nNumber);
AD5933ReadBlock((unsigned char)nNumber, ucDim);
for(i = 0; i < nNumber; i ++) {
printf("%02bx ", ucDim[i]);
}
if(STD_NUM == 2) printf("\r\n");
} else IFARG0("readt") {
AD5933WriteByte(0x80, 0x90);
WaitTime(10);
AD5933SetPointer(0x92);
AD5933ReadBlock(2, ucDim);
nNumber = ucDim[0];
nNumber = nNumber * 256 + ucDim[1];
printf("%d\r\n", nNumber);
} else IFARG0("reada") {
AD5933SetPointer(0x80);
for(i = 0; i < 0x18; i ++) {
printf("%0bx ", AD5933ReadByte());
}
if(STD_NUM == 1) printf("\r\n");
} else IFARG0("writeb") {
sscanf(SDA(1), "%x", &nNumber);
ucAdd = (unsigned char)nNumber;
sscanf(SDA(2), "%x", &nNumber);
i = (unsigned char)nNumber;
AD5933WriteByte(ucAdd, i);
} else IFARG0("writei") {
sscanf(SDA(1), "%x", &nNumber);
ucAdd = (unsigned char)nNumber;
sscanf(SDA(2), "%x", &nNumber);
AD5933SetPointer(ucAdd);
AD5933WriteBlock(2,(unsigned char *)&nNumber);
} else IFARG0("writel") {
sscanf(SDA(1), "%x", &nNumber);
sscanf(SDA(2), "%lx", &lnNumber);
AD5933SetPointer((unsigned char)nNumber);
AD5933WriteBlock(3, ((unsigned char *)&lnNumber) + 1);
} else IFARG0("readd") {
AD5933SetPointer(0x94);
AD5933ReadBlock(4, ucDim);
printf("%0bx %0bx %0bx %0bx", ucDim[0], ucDim[1], ucDim[2], ucDim[3]);
if(STD_NUM == 1) printf("\r\n");
} else IFARG0("reads") {
AD5933SetPointer(0x8f);
printf("%0bx", AD5933ReadByte());
if(STD_NUM == 1) printf("\r\n");
}
04PYTHON程序測試
建立 ad5933.py,利用MCU的接口命令,完成對AD5933的操作。
1.讀取溫度
- ad5933temperature
Control registger(0x80) = 0x90
讀取:0x92,0x93:
數值處理:將讀取的數值乘以 0.03125.
▲ 溫度數值與轉換結果之間的關係
下面的曲線是從AD5933內部讀取的數值,在此過程中,使用手指觸摸芯片,可以引起芯片的溫度上下波動。所以芯片內的溫度傳感器對於環境溫度還是非常敏感的。
▲ 從AD5933內部讀取的溫度曲線
▲ 處於靜止狀態下,讀取的AD5933內部溫度傳感器的曲線。
2.設置輸出激勵信號
- setsweep(startf, incf, num, oscf)
如下是設置輸出頻率爲30kHz, 幅值爲2Vp-p的波形。
實際測量的參數:頻率:29.608; 電壓RSM= 0.695V。
設置輸出激勵電壓
- 頻率的偏差
設置100kHz, 實際使用DM3068輸出的頻率爲98.695kHz。原來假定的頻率。經過修規:
經過上述修正之後, 實際輸出聘用:99.993MHz。
3. 使用模塊的AD8606緩衝
將模塊的運放緩衝連接上。可以增加模塊對於低電阻的測量能力。相關的實驗在下一次的時候繼續驗證。
※ 結論
通過製作基於STC8G1(SOP8)的I2C接口板,可以使用上位機通過WiFi-UART來控制和讀取AD5933的內部寄存器。完成信號的輸出和測量結果。
更加詳細的測量和應用。需要按照使用手冊的要求進行標定和測量。相關的應用在後面的實驗中陸續給出。
- 相關的交叉引用文檔
//==============================================================================
// PROCESS THE DEBUG BUFFER
//------------------------------------------------------------------------------
void SerialDebugProcessBuffer(void) {
unsigned int nNumber;
unsigned char ucDim[8], i, ucAdd;
unsigned long lnNumber;
SerialDebugBuffer2Argument();
if(g_ucSDANumber == 0) return;
if(strcmp("hello", (char *)STD_ARG[0]) == 0)
printf("%s is ready !\r\n", VERSION_STRING);
else IFARG0("setp") {
sscanf(SDA(1), "%x", &nNumber);
AD5933SetPointer((unsigned char)nNumber);
printf("Set Pointer:%d\r\n",nNumber);
} else IFARG0("readb") {
sscanf(SDA(1), "%x", &nNumber);
AD5933ReadBlock((unsigned char)nNumber, ucDim);
for(i = 0; i < nNumber; i ++) {
printf("%02bx ", ucDim[i]);
}
if(STD_NUM == 2) printf("\r\n");
} else IFARG0("readt") {
AD5933WriteByte(0x80, 0x90);
WaitTime(10);
AD5933SetPointer(0x92);
AD5933ReadBlock(2, ucDim);
nNumber = ucDim[0];
nNumber = nNumber * 256 + ucDim[1];
printf("%d\r\n", nNumber);
} else IFARG0("reada") {
AD5933SetPointer(0x80);
for(i = 0; i < 0x18; i ++) {
printf("%0bx ", AD5933ReadByte());
}
if(STD_NUM == 1) printf("\r\n");
} else IFARG0("writeb") {
sscanf(SDA(1), "%x", &nNumber);
ucAdd = (unsigned char)nNumber;
sscanf(SDA(2), "%x", &nNumber);
i = (unsigned char)nNumber;
AD5933WriteByte(ucAdd, i);
g_ucTime0MS = 0;
g_ucTime0MS100 = 0;
if(STD_NUM > 3) {
for(;;) {
AD5933SetPointer(0x8F); // Set the pointer to status register address:0x8F
ucAdd = AD5933ReadByte();
if(ucAdd & 0x2) break;
}
i = g_ucTime0MS;
ucAdd = g_ucTime0MS100;
AD5933SetPointer(0x94);
AD5933ReadBlock(4, ucDim);
nNumber = ucDim[0];
nNumber = (nNumber << 8) + ucDim[1];
printf("%d ", nNumber);
nNumber = ucDim[2];
nNumber = (nNumber << 8) + ucDim[3];
printf("%d ", nNumber);
nNumber = ucAdd;
nNumber = (nNumber << 8) + i;
printf("%d\r\n", nNumber);
}
} else IFARG0("writei") {
sscanf(SDA(1), "%x", &nNumber);
ucAdd = (unsigned char)nNumber;
sscanf(SDA(2), "%x", &nNumber);
AD5933SetPointer(ucAdd);
AD5933WriteBlock(2,(unsigned char *)&nNumber);
} else IFARG0("writel") {
sscanf(SDA(1), "%x", &nNumber);
sscanf(SDA(2), "%lx", &lnNumber);
AD5933SetPointer((unsigned char)nNumber);
AD5933WriteBlock(3, ((unsigned char *)&lnNumber) + 1);
} else IFARG0("readd") {
AD5933SetPointer(0x94);
AD5933ReadBlock(4, ucDim);
nNumber = ucDim[0];
nNumber = (nNumber << 8) + ucDim[1];
printf("%d ", nNumber);
nNumber = ucDim[2];
nNumber = (nNumber << 8) + ucDim[3];
printf("%d", nNumber);
if(STD_NUM == 1) printf("\r\n");
} else IFARG0("reads") {
AD5933SetPointer(0x8f);
printf("%0bx", AD5933ReadByte());
if(STD_NUM == 1) printf("\r\n");
} else IFARG0("sweep") {
i = 0x1;
if(STD_NUM > 1) {
sscanf(SDA(1), "%x", &nNumber);
i = (unsigned char)nNumber;
}
for(nNumber = 0; nNumber < 10; nNumber ++) {
AD5933WriteByte(0x80, i | 0x20);
WaitTime(10);
for(;;) {
AD5933SetPointer(0x8F); // Set the pointer to status register address:0x8F
ucAdd = AD5933ReadByte();
if(ucAdd & 0x2) break;
}
if((ucAdd & 0x4)) continue;
}
AD5933SetPointer(0x94);
AD5933ReadBlock(4, ucDim);
nNumber = ucDim[0];
nNumber = (nNumber << 8) + ucDim[1];
printf("%d ", nNumber);
nNumber = ucDim[2];
nNumber = (nNumber << 8) + ucDim[3];
printf("%d ", nNumber);
lnNumber = 0;
for(;;) {
AD5933SetPointer(0x8F); // Set the pointer to status register address:0x8F
ucAdd = AD5933ReadByte();
if(ucAdd & 0x4) break;
lnNumber ++;
if(lnNumber >= 512) break;
AD5933WriteByte(0x80, i | 0x30);
for(;;) {
AD5933SetPointer(0x8F); // Set the pointer to status register address:0x8F
ucAdd = AD5933ReadByte();
if(ucAdd & 0x2) break;
}
AD5933SetPointer(0x94);
AD5933ReadBlock(4, ucDim);
nNumber = ucDim[0];
nNumber = (nNumber << 8) + ucDim[1];
printf("%d ", nNumber);
nNumber = ucDim[2];
nNumber = (nNumber << 8) + ucDim[3];
printf("%d ", nNumber);
}
printf("\r\n");
}
else printf("Error command : %s !\r\n", STD_ARG[0]);
}
#endif // SERIALTXT_EN
//==============================================================================
// END OF THE FILE : SERIALTXT.C
//------------------------------------------------------------------------------
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# AD5933.PY -- by Dr. ZhuoQing 2020-06-25
#
# Note:
#============================================================
from head import *
from tsmodule.tsstm32 import *
#------------------------------------------------------------
def init(settletime=100, extclock=0):
if extclock > 0:
stm32cmd('writeb 81 8')
else:
stm32cmd('writeb 81 0')
time.sleep(0.02)
stm32cmd('writeb 80 b1') # Enter standby mode
stm32cmd('writei 8a %x'%settletime)
time.sleep(0.02)
def temperature():
data = stm32cmdata('readt', wait=200)
if len(data) > 0:
return data[0] / 32
else: return 0
def setsweep(startf, incf, num=100, oscf=16.557):
startn = int(startf * (2**27) / (oscf*1e6/4))
incn = int(incf * (2**27) / (oscf*1e6/4))
# printff('%x %x %x'%(startn, incn, num))
stm32cmd('writel 82 %x'%startn)
time.sleep(.02)
stm32cmd('writel 85 %x'%incn)
time.sleep(.02)
stm32cmd('writei 88 %x'%num)
time.sleep(.02)
# stm32cmd('writeb 81 0') # D3: 0:Internal system clock 1:External
# time.sleep(.02)
stm32cmd('writeb 80 b1') # Standby
time.sleep(.02)
stm32cmd('writeb 80 11')
time.sleep(.02)
fdim = []
for n in linspace(startn, startn + incn * num, num+1, endpoint=True):
fdim.append(n * oscf * 1e6/4/(2**27))
return fdim
def startf(resultflag = 0):
if resultflag > 0:
stm32cmd('writeb 80 21 1')
else:
stm32cmd('writeb 80 21')
def incf(resultflag = 0):
if resultflag > 0:
stm32cmd('writeb 80 31 1')
else:
stm32cmd('writeb 80 31')
def repeatf(resultflag = 0):
if resultflag > 0:
stm32cmd('writeb 80 41 1')
else:
stm32cmd('writeb 80 41')
def readdata():
return stm32cmdata('readd', wait=100)
def sweep(code=0x1):
stm32cmd('CLEAR')
time.sleep(.02)
stm32cmd('sweep %x'%code)
#------------------------------------------------------------
if __name__ == '__main__':
tdim = []
for i in range(10):
data = temperature()
tdim.append(data)
time.sleep(.1)
printf(tdim)
#------------------------------------------------------------
# END OF FILE : AD5933.PY
#============================================================