单片机/MCU论坛
直播中

送你一把好柴刀

8年用户 71经验值
私信 关注
[问答]

用pcf8591采样电压不准确,总是比电压表上的数值小,求更精确的算法

#include
#include
#define uchar unsigned char
#define uint unsigned int
#define  _Nop()  _nop_()  //定义空指令
#define AddWr 0x90   //写数据地址
#define AddRd 0x91   //读数据地址                       
bit ack;                      //应答标志位
***it RS=P2^6;
***it RW=P2^5;
***it E=P2^7;
***it SDA=P2^1;
***it SCL=P2^0;
uchar code table[]="0123456789 V";
void delay(uint z)
{
        uint x,y;
                for(x=z;x>0;x--)
                        for(y=110;y>0;y--);
}


void write_com(uchar com)
{
        RS=0;
        delay(1);
        E=1;
        P0=com;
        E=0;
}
void write_dat(uchar dat)
{
        RS=1;
        delay(1);
        E=1;
        P0=dat;
        E=0;
}
void Start_I2c()
{
  SDA=1;   //发送起始条件的数据信号
  _Nop();
  SCL=1;
  _Nop();    //起始条件建立时间大于4.7us,延时
  _Nop();
  _Nop();
  _Nop();
  _Nop();   
  SDA=0;     //发送起始信号
  _Nop();    //起始条件锁定时间大于4μ
  _Nop();
  _Nop();
  _Nop();
  _Nop();      
  SCL=0;    //钳住I2C总线,准备发送或接收数据
  _Nop();
  _Nop();
}
/*------------------------------------------------
                    结束总线
------------------------------------------------*/
void Stop_I2c()
{
  SDA=0;    //发送结束条件的数据信号
  _Nop();   //发送结束条件的时钟信号
  SCL=1;    //结束条件建立时间大于4μ
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  _Nop();
  SDA=1;    //发送I2C总线结束信号
  _Nop();
  _Nop();
  _Nop();
  _Nop();
}
void  SendByte(unsigned char c)
{
unsigned char BitCnt;

for(BitCnt=0;BitCnt<8;BitCnt++)  //要传送的数据长度为8位
    {
     if((c<        else  SDA=0;               
     _Nop();
     SCL=1;               //置时钟线为高,通知被控器开始接收数据位
      _Nop();
      _Nop();             //保证时钟高电平周期大于4μ
      _Nop();
      _Nop();
      _Nop();         
     SCL=0;
    }

    _Nop();
    _Nop();
    SDA=1;               //8位发送完后释放数据线,准备接收应答位
    _Nop();
    _Nop();   
    SCL=1;
    _Nop();
    _Nop();
    _Nop();
    if(SDA==1)ack=0;     
       else ack=1;        //判断是否接收到应答信号
    SCL=0;
    _Nop();
    _Nop();
}       
unsigned char  RcvByte()
{
  unsigned char retc;
  unsigned char BitCnt;

  retc=0;
  SDA=1;             //置数据线为输入方式
  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        _Nop();           
        SCL=0;       //置时钟线为低,准备接收数据位
        _Nop();
        _Nop();      //时钟低电平周期大于4.7us
        _Nop();
        _Nop();
        _Nop();
        SCL=1;       //置时钟线为高使数据线上数据有效
        _Nop();
        _Nop();
        retc=retc<<1;
        if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
        _Nop();
        _Nop();
      }
  SCL=0;   
  _Nop();
  _Nop();
  return(retc);
}

void NoAck_I2c(void)
{

  SDA=1;
  _Nop();
  _Nop();
  _Nop();      
  SCL=1;
  _Nop();
  _Nop();              //时钟低电平周期大于4μ
  _Nop();
  _Nop();
  _Nop();  
  SCL=0;                //清时钟线,钳住I2C总线以便继续接收
  _Nop();
  _Nop();   
}
unsigned char ReadADC(unsigned char Chl)
{
   unsigned char Val;
   Start_I2c();               //启动总线
   SendByte(AddWr);             //发送器件地址
     if(ack==0)return(0);
   SendByte(0x40|Chl);            //发送器件子地址
     if(ack==0)return(0);
   Start_I2c();
   SendByte(AddWr+1);
      if(ack==0)return(0);
   Val=RcvByte();
   NoAck_I2c();                 //发送非应位
   Stop_I2c();                  //结束总线
  return(Val);
}
void Ini()
{
        E=0;
        RW=0;
        write_com(0x38);
        write_com(0x0c);//设置光标
        write_com(0x06);
        write_com(0x01);//清屏
        write_com(0x80);
}
main()
{
unsigned char num=0;
uint a,b,c;
Ini();

while (1)         //主循环
  {
num=ReadADC(0);
a=num/51;
num=num%51*10 ;
b=num/51;
c=num%51*10/51;
write_com(0x80);
write_dat(table[a]);
write_dat('.');
write_dat(table[b]);
write_dat(table[c]);
delay(500);
  }
}


已退回5积分

回帖(2)

星痕舞动

2016-11-5 10:21:47
首先你要确认,你所使用的万用表的类型到底能不能精确测量实际所需要的电压值。万用表的精度是不是达标,如果你万用表达不到你所需要测量的值,那么你用万用表测量出来的值,是没有任何参考意义的,按照你所使用的这款芯片,是8位的AD,所以你要是用的万用表的精度等级就必须高于8位AD采样的值的最小精度。所以一般要比AD高一到两个等级的万用表测量。这样才能真正确认,是哪个问题。然后才好找问题所在。
举报

一书生

2016-11-12 21:22:33
测直流哪有可言,值会是外围电路不够好,比如芯片的基准不稳或不精确
举报

更多回帖

发帖
×
20
完善资料,
赚取积分