逐次逼近原理
AD里面包含da,当输入电压Vin时,da的最高位是1,即为0.5Vref与输入信号比较,如果输入大于0.5Vref则比较器输出为1,同时da的最高位为1,反之DA最高位则为0,通过8次比较后得到8个01数据即完成ad转换。
现在说下程序中用到stc12单片机两个寄存器 ADC_CONTR;主要用来配置ad启动的工作模式;还有个result的寄存器
程序中的注意点:配置完ADC_CONTR后要延时4个时钟周期
先把程序附上
#include "stc12.h"
#include "intrins.h"
#include "ad.h"
uint ad;
#define ADC_POWER 0X80 //ADC最高位给adc部分供电,类似于片选
#define ADC_START 0X08 //模数转换启动控制位
#define ADC_FLAG 0x10 //ad转换需要时间,这个是转换完成标志位
#define ADC_SPEEDLL 0X00 //540 clock
#define ADC_SPEEDL 0X20 //360 clock
#define ADC_SPEEDH 0X40 //180 clock
#define ADC_SPEEDHH 0X60 //90 clock
uchar ADCresult(uchar aa) //这里的参数是哪个口来ad转换
{
P1ASF=0X01; //这里的选择和用哪一个P1口作为ad采样
ADC_CONTR=ADC_POWER|ADC_SPEEDLL|ADC_START|aa;
//ADC_CONTR=0X88|aa;
_nop_();
_nop_();
_nop_();
_nop_();//设置ADC_CONTR寄存器后需加4个CPU时钟周期的延时,才能保证值被写入ADC_CONTR寄存器
while (!(ADC_CONTR & ADC_FLAG)); //等待ADC_CONTR,这里的ADC_FLAG相当于一个常数,不是寄存器里面的某个位
//while(!ADC_FLAG);
//ADC_FLAG=0;
ADC_CONTR &= ~ADC_FLAG; //Close ADC 将标志位清零等待下次硬件置1
ad=(ADC_RES<<2)+ADC_RESL; //打开10位AD采集功能 如果用8位AD 屏掉这句 把下一句改为 Vo=(float)(ADC_RESL)*500/256; 即可
//ADC_RES结果寄存器的高2位;ADC_RES结果寄存器的低8位
ad=(float)(ad)*5*100/1024; //Return ADC result(为显示整数,这里将电压值扩大了十倍)
//10位AD采集 即2的10次方 满值为1024 这里用1024表示5伏的电压
//那么用采集到的数量值 除以1024 在乘以5 得到的值就是采集的电压数值
//这里 又*100 是为了扩大100倍 显示小数位
//ADC_RES*(5/256) 为采集的电压值 然后扩大10倍便于计算
return ad;
}
这里只是个ad.c源文件,这里有几个问题想说一下
1.怎么知道是10位还是8位的ad结果;你可以在ADCresult(uchar aa)最前面加一条AUXR1&=0x04;什么意思呢,转换结果的低2位放在ADC_RES,高8位ADC_RESL中
2为什么不用//while(!ADC_FLAG);
//ADC_FLAG=0;这两条因为ADC_FLAG相当于常量前面用宏定义
而头文件里只有ADC_CONTR的地址映射;但是如果在头文件中用sbit ADC_FLAG=ADC_CONTR^4会出现错误,具体原因还不清楚