前言:使用A/D轉換器模擬電壓表功能
1. 基礎
(1)模/數(A/D)轉換器
轉換的功能是把模擬量電壓轉換爲N位數字量電壓。A/D轉換器主要性能指標有分辨率、誤差、轉換精度、轉換速度等。
按轉換原理分類,有逐次逼近式、雙積分式、並行式等。雙積分轉換精度高,轉換時間長,大約需要幾百毫秒;並行式轉換速度最高,能達到2G次,即轉換時間僅50ns,但價格昂貴,產品的分辨率不高;逐次逼近式兼顧了轉換速度和轉換精度,是應用廣泛的A/D轉換器。
逐次逼近式的各類很多,分辨率從8位到16位,轉換時間從100μs到幾微秒,精度有不同等級。常用的幾種A/D轉換器:8位通用型ADC0808/0809、12位的AD574A和雙積分型5G14433。
(2)ADC0808/0809的主要性能指標
分辨率爲8位;總的非調整誤差:0808爲± LSB,0809爲±1 LSB;具有鎖存控制功能的8路模擬開關,能對8路模擬電壓信號進行轉換;輸出電平與TTL電平兼容;單電源+5V供電;工作時序,完成一次轉換所需要的時候爲66~73個時鐘週期;
轉換結束信號的處理方式。當A/D轉換結束,ADC輸出一個轉換結束信號,通知主要A/D轉換已經結束,可以讀取結果,可以讀取結果。主機檢查判斷A/D轉換是否結束的方法主要有四種:中斷方式、查詢方式、延時方式、DMA方式。
2. 仿真電路設計
(1)元件:
單片機(AT89C51)、4位共陰極數碼管(7SEG-MPX4-CC-BLUE)、ADC0808、變阻器、電壓表。
(2)內容:
對於數碼管,P1段控,P2位控;P3控制ADC;P0接收ADC轉換結果;變阻器控制ADC輸入模擬電壓值;示波器與計數器監控P3^3輸出方波/時鐘。
(3)電路連線:
3. 程序設計
(1)內容:
以查詢方式監控EOC;將ADC結果換算成電壓值,並循環顯示轉換結果;使用T1定時器控制P3^3輸出方波頻率(用於ADC輸入時鐘),輸入方波週期爲20μs(即T1以10μs轉換電平),即10^6/20μs=50kHz;用for/delay控制數碼管顯示延時。
(2)代碼:
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
// ADC控制
sbit START = P3^0;
sbit OE = P3^1;
sbit EOC = P3^2;
sbit CLK = P3^3;
// ADC輸入-地址碼
sbit P34 = P3^4;
sbit P35 = P3^5;
sbit P36 = P3^6;
// 控制小數點段碼位
sbit P17 = P1^7;
void Delay(uint);
void LedScan(uint);
void T1_Init(void);
// common cathode(共陰極)
// Led code, "0~9, A~F"
uchar LedOfNum[] =
{
0x3f, 0x06, 0x5b, 0x4f,0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f,
0x77, 0x7c, 0x39, 0x5e,0x79, 0x71
};
uchar ADC_data;
uint temp;
/******************** Main function ********************/
void main(void)
{
T1_Init();
while (1)
{
START = 0;
OE = 0;
START = 1;
START = 0;
P34 = 0;
P35 = 0;
P36 = 0;
do
{}while(!EOC); // 查詢方式,確認EOC的狀態
OE = 1; // ADC輸出使能
ADC_data = P0; // 獲得ADC結果
OE = 0; // ADC關輸出使能
temp = ADC_data *1.0 / 255 * 500; // 將數字結果換算成模擬量
LedScan(temp);
}
}
/******************** Led scan ********************/
// P1控制段碼顯示
// P2位控(共陰極)
void LedScan(uint num)
{
uchar g, s, b, q;
uchar k;
g = num%10;
s = num/10%10;
b = num/100%10;
q = num/1000;
for (k=0; k<150; k++)
{
P1 = LedOfNum[q];
P2 = 0x0E; // 0000 1110B
Delay(1);
P1 = 0x00; // 0000 0000B
P1 = LedOfNum[b];
P17 = 1;
P2 = 0x0D; // 0000 1101B
Delay(1);
P1 = 0x00; // 0000 0000B
P1 = LedOfNum[s];
P2 = 0x0B; // 0000 1011B
Delay(1);
P1 = 0x00; // 0000 0000B
P1 = LedOfNum[g];
P2 = 0x07; // 0000 0111B
Delay(1);
P1 = 0x00; // 0000 0000B
}
}
/******************** Delay function ********************/
void Delay(uint x)
{
uchar k;
while (x--)
for(k=0;k<125; k++) ;
}
/******************** T1_Init function ********************/
void T1_Init(void)
{
TMOD = 0X10;
TH1 = (65536-10) / 256;
TL1 = (65536-10) % 256;
EA = 1; // 開中斷
ET1 = 1; // 允許T1中斷
TR1 = 1; // 啓動T1
}
/******************** T1_Init function ********************/
void T1_Timer(void) interrupt 3
{
TH1 = (65536-10) / 256; // 相當於半週期爲10us,全週期爲20us的方波;即10^6/20us=50kHz
TL1 = (65536-10) % 256;
CLK = ~CLK;
}
4. 仿真操作
(1)裝入HEX文件,運行。
(2)運行結果:
a. ADC轉換結果與電壓表相當,存在轉換誤差
b. 計數器監控P3^3輸出方波頻率;因設置下降沿有效,所以頻率少一半;又for/delay佔用CPU時間,頻率誤差加大。
c. 示波器監控P3^3;因設置上升沿有效,所以週期長一倍;週期接近40μs。
5. 實物確認
還是用以上程序,實物連線確認,實際電壓和轉換結果還是有差異,就如Proteus裏仿真一般。這個問題還得繼續摸索。
下一步:
for/delay改T0定時器以減少對CPU佔用;實物電路做成,以確認實際運行結果、以及ADC0808輸入時鐘真實要求。
參考:《單片機C語言與Proteus仿真技能實訓》、《Proteus入門實用教程》