ATMEGA16 ADC模数转换示例程序
扫描二维码
随时随地手机看文章
ATMEGA16 ADC模数转换示例程序
1. 开发语言
本范例使用 WinAVR/GCC20050214 版本开发
2. 范例描述
本程序简单的示范了如何使用ATMEGA16的ADC模数转换器
普通的单端输入
差分输入及校准
基准电压的校准
查询方式
中断方式
数据格式的变换
出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAGICE硬件仿真器
3.电路图设计 :
为简化线路设计,使用了本网站的ATMEGA16功能小板。
在范例中 选用内部2.56V电压基准作Vref ,差分通道 10倍放大
则 单端电压测量范围 02.56V, 分辨率2.5mV
差分电压测量范围 +/- 256mV 分辨率0.5mV
电流分辨率 = 50uA@10欧姆 电流采样电阻
电流分辨率 =500uA@ 1欧姆 电流采样电阻
程序中需要把实测的基准电压代入 常量Vref中,以获得更准确地结果
我手中的样片实测为 2.556V@Vcc=5.0V
2.550V@Vcc=3.3V
*/
#include
#include
#include
#include
/*宏INTERRUPT的用法与SIGNAL类似,区别在于
SIGNAL执行时全局中断触发位被清除、其他中断被禁止
INTERRUPT执行时全局中断触发位被置位、其他中断可嵌套执
另外avr-libc提供两个API函数用于置位和清零全局中断触发位,它们是经常用到的。
分别是: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内部能隙1.22V电压基准,校准用
#defineAD_SE_GND0x1F//接地校准用
//注:
//差分通道,如果使用1x或10x增益,可得到8位分辨率。如果使用200x增益,可得到7位分辨率。
//在PDIP封装下的差分输入通道器件未经测试。只保证器件在TQFP与MLF封装下正常工作。
#defineVref2483//mV实测的Vref引脚电压@5.0V供电
//#defineVref2464//mV实测的Vref引脚电压@3.3V供电
//全局变量
unsignedintADC_SingleEnded;//单端输入的ADC值
intADC_Diff;//差分输入的ADC值
volatileunsignedintADC_INT_SE;
//中断模式用的单端输入ADC值,会在中断服务程序中被修改,须加volatile限定
volatileunsignedcharADC_OK;//ADC状态,会在中断服务程序中被修改,须加volatile限定
unsignedintLED_Volt;//变换后的电压mV
intLED_Curr;//变换后的电流100uA
//仿真时在watch窗口,监控这些全局变量。
unsignedintread_adc(unsignedcharadc_input)//查询方式读取ADC单端通道
{
ADMUX=(0xc0|adc_input);//adc_input:单端通道0x00~0x07,0x1E,0x1F
//0xc0:选择内部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);//等待差分增益稳定>125uS
ADCSRA|=(1
ADCSRA|=(1
//可正可负+/-9bit-512~+511
//即M16差分通道的ADC+输入端的电压可以大于ADC-,也可以小于ADC-。
//Tiny26就不行,ADC+输入端的电压必须大于或等于ADC-,为+10bit
if(ADC_FIX>=0x0200)//负数要变换,正数不用
{
ADC_FIX|=0xFC00;//变换成16位无符号整数
}
return(int)ADC_FIX;
}
SIGNAL(SIG_ADC)//ADC中断服务程序
{
//硬件自动清除ADIF标志位
ADC_INT_SE=ADC;//读取结果
ADC_OK=1;
}
intmain(void)
{
longteMP32;
ADC_SingleEnded=0;
ADC_Diff=0;
ADC_INT_SE=0;
//上电默认DDRx=0x00,PORTx=0x00输入,无上拉电阻
PORTB=0xFF;//不用的管脚使能内部上拉电阻。
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
}
}