昨天有人反应我写的错别字太多,那我恭喜你看明白了我想表达的意思,只要是我偏科偏得厉害。
言归正传啊! 最近做的这个基于卫星定位的便携式污染源监测系统,对温湿度要有高了些,对价格也比较敏感,所以对温湿度的选择比较慎重了些。顺便我有分析了下,AD的精度和分辨率的问题:
很多人对于精度和分辨率的概念不清楚,这里我做一下总结,希望大家不要混淆。
像我们搞电子的,经常跟“精度”与“分辨率”打交道。简单点说,“精度”是用来描述物理量的准确程度的,而“分辨率”是用来描述刻度划分的。从定义上看,这两个量应该是风马牛不相及的。我是这么理解的,“精度”就是描述物理量 的精确程度的,也就是我们常说的准不准的问题,或者说与真实值差多少的问题;“分辨率”是用来表述分辨能力的,分辨能力强的未必测试的准确,比如说温度变化多少时它能分辨出来。 在简单做个比喻:有这么一把常见的塑料尺(中学生用的那种),它的量程是10厘米,上面有100个刻度,最小能读出1毫米的有效值。那么我们就说这把尺子的分辨率是1毫米,或者量程的1%;而它的实际精度就不得而知了(算是0.1毫米吧)。当我们用火来烤一下它,并且把它拉长一段,然后再考察一下它。我们不难发现,它还有有100个刻度,它的“分辨率”还是1毫米,跟原来一样!然而,您还会认为它的精度还是原来的0.1毫米么?(这个例子是引用网上的,个人觉得比喻的很形象!)
回到电子技术上, 所以很多朋友一谈到精度,马上就和分辨率联系起来了,包括有些项目负责人,只会在那里说:这个系统精度要求很高啊,你们AD的位数至少要多少多少啊
其实,仔细浏览一下AD的数据手册,会发现跟精度有关的有两个很重要的指标:DNL和INL。似乎知道这两个指标的朋友并不多,所以在这里很有必要解释一下。
DNL:Differencial NonLiner——微分非线性度
INL:Interger NonLiner——积分非线性度(精度主要用这个值来表示)
他表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。当然,像有的AD如△—∑系列的AD,也用Linearity error来表示精度。
分辨率的计算:测量电压范围/(2^AD位数-1)
就HTU20D温湿度传感器来说: 温度部分:
由上图不难看出,在14bit时,HTU20D传感器的温度部分的分辨率是0.01°C,在12bit时,温度的分辨率是0.04°C。这里的14bit与12bit就是设定的AD转换的位数啊。但是大家看看表中给出的温度的“精度(Temperature Accuracy@25°C)”是±0.3°C,不管你在设置AD转换位数是14位还是12位时,传感器本身的精度数不变的,0.3就是0.3°C。所以精度和分辨率是两个完全不同的我概念。
下面再看看湿度吧
HTU20D湿度的的“分辨率”是,在12bits时为0.04%RH; 在8bits时 0.7%RH, 那么他的“精度”总是±3%RH, 如此看来分辨率和精度真的是不同了,呵呵 大家再想想,同是在一个传感器中的温度和湿度两个物理量的温度的精度是±0.3,而湿度的精度是±3 。对吧 你在看看上面的两个表格,如果吧温度和湿度都设置是12bit时,他们的分辨率是相同的,都是0.04,不是吗?你在仔细看看 至于0.04这个数是如何来的呢! 你知道吗? 考虑考虑吧,
下面我给出我的读写HTU20D/HTU21D的程序仅供参考,不过我在项目中应用过了,还没发现有什么问题呢 /*================================================================
【名 称】void I2CDelay (unsigned char t)
【功 能】模拟IIC用的短延时
【备 注】
【作 者】
【时 间】2015年10月18日
================================================================*/
void I2CDelay (unsigned char t)
{
while(t--);
} /*================================================================
【名 称】void I2CInit(void)
【功 能】I2C初始化,空闲状态
【备 注】
【作 者】
【时 间】2015年10月18日
================================================================*/
void I2CInit(void)
{
SDA = 1;
SCL = 1;
}
/*================================================================
【名 称】void I2CStart(void)
【功 能】I2C起始信号
【备 注】SCL、SDA同为高,SDA跳变成低之后,SCL跳变成低
【作 者】
【时 间】2015年10月18日
================================================================*/
void I2CStart(void)
{
SDA = 1;
SCL = 1;
I2CDelay(10);
SDA = 0;
I2CDelay(20);
SCL = 0;
I2CDelay(20);
} /*================================================================
【名 称】void I2CStop(void)
【功 能】I2C停止信号
【备 注】SCL、SDA同为低,SCL跳变成高之后,SDA跳变成高
【作 者】
【时 间】2015年10月18日
================================================================*/
void I2CStop(void)
{
SDA = 0;
SCL = 0;
I2CDelay(10);
SCL = 1;
I2CDelay(10);
SDA = 1;
I2CDelay(10);
}
/*================================================================
【名 称】unsigned char I2CWRByte(unsigned char WRByte)
【功 能】I2C写一个字节数据,返回ACK或者NACK
【备 注】从高到低,依次发送
【作 者】
【时 间】2015年10月18日
================================================================*/
unsigned char I2CWRByte(unsigned char WRByte)
{
unsigned char i;
SCL = 0;
for(i=0;i<8;i++)
{
if(WRByte&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
I2CDelay(10);
SCL=1; //输出SDA稳定后,拉高SCL给出上升沿,从机检测到后进行数据采样
I2CDelay(50);
SCL=0;
I2CDelay(10);
WRByte <<= 1;
}
SDA = 1;
SCL = 1;
I2CDelay(20);
if(SDA==1) //SDA为高,收到NACK
{
SCL=0;
I2CDelay(50);
return NACK;
}
else //SDA为低,收到NACK
{
SCL=0;
I2CDelay(50);
return ACK;
}
}
/*================================================================
【名 称】unsigned char I2CRDByte(unsigned char AckValue)
【功 能】I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK
【备 注】从高到低,依次接收
【作 者】
【时 间】2015年10月18日
================================================================*/
unsigned char I2CRDByte(unsigned char AckValue)
{
unsigned char i,RDByte=0;
SCL = 0;
SDA = 1; //释放总线
for (i=0;i<8;i++)
{
RDByte <<= 1; //移位
SCL = 1; //给出上升沿
I2CDelay(30); //延时等待信号稳定
if(SDA==1) //采样获取数据
{
RDByte |= 0x01;
}
else
{
RDByte &= 0xfe;
}
SCL = 0; //下降沿,从机给出下一位值
I2CDelay(10);
}
SDA = AckValue; //应答状态
I2CDelay(10);
SCL = 1;
I2CDelay(50);
SCL = 0;
SDA = 1;
I2CDelay(1);
return RDByte;
} /*================================================================
【名 称】void HTU21Init(void)
【功 能】HTU21初始化函数,主函数中调用
【备 注】从高到低,依次接收
【作 者】
【时 间】2015年10月18日
================================================================*/
void HTU21Init(void)
{
I2CInit();//I2C初始化
I2CStart();//启动I2C
I2CWRByte(HTU21ADDR&0xfe);//写HTU21I2C地址
I2CWRByte(0xfe);
I2CStop();//停I2C
Delay(600);//短延时
}
/*================================================================
【名 称】long ReadHtu21(char whatdo)
【功 能】读取函数函数
【备 注】
【作 者】
【时 间】2015年10月18日
================================================================*/
long ReadHtu21(char whatdo)
{
unsigned long temp;
unsigned char Humidity,HumidityH,HumidityL;
unsigned long wendu; I2CStart();
if(I2CWRByte(HTU21ADDR&0xfe)==ACK)
{
if(I2CWRByte(whatdo)==ACK)
{
do
{
Delay(30);
I2CStart();
}while(I2CWRByte(HTU21ADDR|0x01)==NACK); HumidityH = I2CRDByte(ACK);
HumidityL = I2CRDByte(ACK);
I2CRDByte(NACK);
I2CStop();
HumidityL &= 0xfc;
temp = HumidityH*256+HumidityL;
if (whatdo==((char)0xf5))
{
Humidity = (unsigned char)((temp*125)/65536-6)%0xff;
return Humidity;
}
else
{
temp=((long)17572)*temp;
temp=temp/((long)65536);
wendu =temp-((long)4685);
return wendu; //输出
}
}
}
return 0;
} 你如果感觉有收获就分享给更多的朋友吧,或者你把你的心得体会也分享给我和他。
|