ATMEGA16 ADC模數(shù)轉(zhuǎn)換示例程序
1. 開發(fā)語言
本范例使用 WinAVR/GCC20050214 版本開發(fā)
2. 范例描述
本程序簡單的示范了如何使用ATMEGA16的ADC模數(shù)轉(zhuǎn)換器
普通的單端輸入
差分輸入及校準
基準電壓的校準
查詢方式
中斷方式
數(shù)據(jù)格式的變換
出于簡化程序考慮,各種數(shù)據(jù)沒有對外輸出,學(xué)習(xí)時建議使用JTAGICE硬件仿真器
3.電路圖設(shè)計 :
為簡化線路設(shè)計,使用了本網(wǎng)站的ATMEGA16功能小板。
在范例中 選用內(nèi)部2.56V電壓基準作Vref ,差分通道 10倍放大
則 單端電壓測量范圍 02.56V, 分辨率2.5mV
差分電壓測量范圍 +/- 256mV 分辨率0.5mV
電流分辨率 = 50uA@10歐姆 電流采樣電阻
電流分辨率 =500uA@ 1歐姆 電流采樣電阻
程序中需要把實測的基準電壓代入 常量Vref中,以獲得更準確地結(jié)果
我手中的樣片實測為 2.556V@Vcc=5.0V
2.550V@Vcc=3.3V
*/
#include
#include
#include
#include
/*宏INTERRUPT的用法與SIGNAL類似,區(qū)別在于
SIGNAL執(zhí)行時全局中斷觸發(fā)位被清除、其他中斷被禁止
INTERRUPT執(zhí)行時全局中斷觸發(fā)位被置位、其他中斷可嵌套執(zhí)
另外avr-libc提供兩個API函數(shù)用于置位和清零全局中斷觸發(fā)位,它們是經(jīng)常用到的。
分別是:voidsei(void)和voidcli(void)由interrupt.h定義*/
//管腳定義
#definein_Single0//PA0(ADC0)
#definein_Diff_P3//PA3(ADC3)
#definein_Diff_N2//PA2(ADC2)
//常量定義
//單端通道,不放大
#defineAD_SE_ADC00x00//ADC0
#defineAD_SE_ADC10x01//ADC1
#defineAD_SE_ADC20x02//ADC2
#defineAD_SE_ADC30x03//ADC3
#defineAD_SE_ADC40x04//ADC4
#defineAD_SE_ADC50x05//ADC5
#defineAD_SE_ADC60x06//ADC6
#defineAD_SE_ADC70x07//ADC7
//差分通道ADC0作負端,10/200倍放大
#defineAD_Diff0_0_10x0x08//ADC0+ADC0-,10倍放大,校準用
#defineAD_Diff1_0_10x0x09//ADC1+ADC0-,10倍放大
#defineAD_Diff0_0_200x0x0A//ADC0+ADC0-,200倍放大,校準用
#defineAD_Diff1_0_200x0x0B//ADC1+ADC0-,200倍放大
//差分通道ADC2作負端,10/200倍放大
#defineAD_Diff2_2_10x0x0C//ADC2+ADC2-,10倍放大,校準用
#defineAD_Diff3_2_10x0x0D//ADC3+ADC2-,10倍放大
#defineAD_Diff2_2_200x0x0E//ADC2+ADC2-,200倍放大,校準用
#defineAD_Diff3_2_200x0x0F//ADC3+ADC2-,200倍放大
//差分通道ADC1作負端,不放大
#defineAD_Diff0_1_1x0x10//ADC0+ADC1-
#defineAD_Diff1_1_1x0x11//ADC1+ADC1-,校準用
#defineAD_Diff2_1_1x0x12//ADC2+ADC1-
#defineAD_Diff3_1_1x0x13//ADC3+ADC1-
#defineAD_Diff4_1_1x0x14//ADC4+ADC1-
#defineAD_Diff5_1_1x0x15//ADC5+ADC1-
#defineAD_Diff6_1_1x0x16//ADC6+ADC1-
#defineAD_Diff7_1_1x0x17//ADC7+ADC1-
//差分通道ADC2作負端,不放大
#defineAD_Diff0_2_1x0x18//ADC0+ADC2-
#defineAD_Diff1_2_1x0x19//ADC1+ADC2-
#defineAD_Diff2_2_1x0x1A//ADC2+ADC2-,校準用
#defineAD_Diff3_2_1x0x1B//ADC3+ADC2-
#defineAD_Diff4_2_1x0x1C//ADC4+ADC2-
#defineAD_Diff5_2_1x0x1D//ADC5+ADC2-
//單端通道,不放大
#defineAD_SE_VBG0x1E//VBG內(nèi)部能隙1.22V電壓基準,校準用
#defineAD_SE_GND0x1F//接地校準用
//注:
//差分通道,如果使用1x或10x增益,可得到8位分辨率。如果使用200x增益,可得到7位分辨率。
//在PDIP封裝下的差分輸入通道器件未經(jīng)測試。只保證器件在TQFP與MLF封裝下正常工作。
#defineVref2483//mV實測的Vref引腳電壓@5.0V供電
//#defineVref2464//mV實測的Vref引腳電壓@3.3V供電
//全局變量
unsignedintADC_SingleEnded;//單端輸入的ADC值
intADC_Diff;//差分輸入的ADC值
volatileunsignedintADC_INT_SE;
//中斷模式用的單端輸入ADC值,會在中斷服務(wù)程序中被修改,須加volatile限定
volatileunsignedcharADC_OK;//ADC狀態(tài),會在中斷服務(wù)程序中被修改,須加volatile限定
unsignedintLED_Volt;//變換后的電壓mV
intLED_Curr;//變換后的電流100uA
//仿真時在watch窗口,監(jiān)控這些全局變量。
unsignedintread_adc(unsignedcharadc_input)//查詢方式讀取ADC單端通道
{
ADMUX=(0xc0|adc_input);//adc_input:單端通道0x00~0x07,0x1E,0x1F
//0xc0:選擇內(nèi)部2.56V參考電壓
ADCSRA|=(1
ADCSRA|=(1
intread_adc_diff(unsignedcharadc_input)//查詢方式讀取ADC差分通道
{
unsignedintADC_FIX;
ADMUX=(0xc0|adc_input);//adc_input:差分通道0x08~0x1D
_delay_ms(1);//等待差分增益穩(wěn)定>125uS
ADCSRA|=(1
ADCSRA|=(1
//可正可負+/-9bit-512~+511
//即M16差分通道的ADC+輸入端的電壓可以大于ADC-,也可以小于ADC-。
//Tiny26就不行,ADC+輸入端的電壓必須大于或等于ADC-,為+10bit
if(ADC_FIX>=0x0200)//負數(shù)要變換,正數(shù)不用
{
ADC_FIX|=0xFC00;//變換成16位無符號整數(shù)
}
return(int)ADC_FIX;
}
SIGNAL(SIG_ADC)//ADC中斷服務(wù)程序
{
//硬件自動清除ADIF標志位
ADC_INT_SE=ADC;//讀取結(jié)果
ADC_OK=1;
}
intmain(void)
{
longteMP32;
ADC_SingleEnded=0;
ADC_Diff=0;
ADC_INT_SE=0;
//上電默認DDRx=0x00,PORTx=0x00輸入,無上拉電阻
PORTB=0xFF;//不用的管腳使能內(nèi)部上拉電阻。
PORTC=0xFF;
PORTD=0xFF;
PORTA=~((1<
ADCSRA=(1<分頻125KHz@8MHzsystemcLOCk
sei();//使能全局中斷
while(1)
{
//實測的Vref引腳電壓=2556mV
ADC_SingleEnded=read_adc(AD_SE_ADC0);
//查詢方式讀取ADC0
temp32=(long)ADC_SingleEnded*Vref;
LED_Volt=(unsignedint)(temp32/1024);
ADC_Diff=read_adc_diff(AD_Diff3_2_10x);
ADC_Diff-=read_adc_diff(AD_Diff2_2_10x);//校準OFFSET
temp32=(long)ADC_Diff*Vref;
LED_Curr=(unsignedint)(temp32/(512*10));//[單位為100uA]
//查詢方式讀取ADC3+,ADC2-10倍放大max+/-255.6mV
//10歐姆1mA=10mVmax+/-25.56mA
//分辨率約0.5mV=50uA,顯示取整為100uA單位
ADCSRA|=(1
ADCSRA|=(1
}
}