找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 746|回复: 4
收起左侧

关于ADC0832的误差有疑问

[复制链接]
ID:1159547 发表于 2025-10-20 10:22 | 显示全部楼层 |阅读模式
我现在用ADC0832采集数据,0832的基准电压测出来实际是4.95V,刚开始是采集后的数据显示到数码管上,但是有误差,于是就改为将电压值发送到串口进行显示,现在串口显示数据为4.51V的时候,输入电压测出来实际值为4.77V,有0.2v的误差,有没有大神知道这误差怎么来的,以及如何解决呢。感谢。
这是我的程序,写的有点乱,因为修改了好多次,见谅。

#include<reg52.h>
#include<intrins.h>

/***********ad0832与单片机的接口定义**********************/
sbit CS =P3^2;                 
sbit CLK=P3^3;
sbit OUT=P3^4;
sbit DI=P3^5;

float key;
unsigned char code tab[]={        0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
                                        0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};
unsigned char temdat[]={0,0,0};  



unsigned char adc0832(void);
void display(unsigned char *pl);
void delayms(unsigned char t);
void uart_init(void);
void send_string(unsigned char *str);



void main(void)
{
        float tep;
        unsigned char string[10];  // "X.XXV\r\n"共6个字符
        unsigned int integer_part;  // 整数部分(0~5)
        unsigned int decimal_part;  // 小数部分(0~99,代表0.00~0.99)
        uart_init();
       
       
       
        while(1)
        {
               
                tep = (5.0 / 255.0) * adc0832();  // 正确计算电压值
                integer_part = (unsigned int)tep;  // 提取整数部分(如3.85→3)
                decimal_part = (unsigned int)((tep - integer_part) * 100 + 0.5);  // 提取两位小数(+0.5是四舍五入)

                // 构造字符串(例如 "3.85V\r\n")
                string[0] = integer_part + '0';       // 整数位(3→'3')
                string[1] = '.';                      // 小数点
                string[2] = (decimal_part / 10) + '0'; // 小数第一位(85/10=8→'8')
                string[3] = (decimal_part % 10) + '0'; // 小数第二位(85%10=5→'5')
                string[4] = 'V';
                string[5] = '\r';
                string[6] = '\n';
                string[7] = '\0';
               
               
                send_string(string);
        
        delayms(1000);// 间隔1秒
        }
}
/*********************************************
**函数描述:AD采样函数
**写入参数:无
**返回参数:电压0-5V对应的8位二进制数即0—255
************************************************/
unsigned char adc0832(void)
{
        unsigned char i;
        unsigned int l_key;
       
        OUT=1;
    CLK=0;
        _nop_();_nop_();       
       
        CS=0;
        DI=1;
        _nop_();_nop_();//大于等于500ns       
        _nop_();_nop_();
        _nop_();_nop_();
        CLK=1;
        _nop_();_nop_();
        CLK=0;
        DI=1;
        _nop_();_nop_();               
        CLK=1;
        _nop_();_nop_();
        CLK=0;
        DI=0;
        _nop_();_nop_();               
        CLK=1;
        _nop_();_nop_();
       
        CLK=0;
        _nop_();_nop_();
        CLK=1;
        _nop_();_nop_();       
        CLK=0;
               
        for(i=0;i<8;i++)
        {
                l_key<<=1;
                if(OUT)
                        l_key++;
                CLK=1;
                _nop_();_nop_();
                CLK=0;
                _nop_();_nop_(); //两个时钟下降延后就输出第一个数据,是一个同步串行通信协议
        }
        CS=1; //结束读取
       
       
        return l_key;
}
/********************************************************
**名称:显示子函数      
**功能:动态扫描P2口做为位选,P0口送段码
**输入:pl指向要显示数据的地址,最后3位
**返回:无
*******************************************************/
void display(unsigned char *pl)
{
        P2=0x04;
        P1=tab[*pl];                     //低
        delayms(3);
        P1=0xff;
       
        P2=0x02;
        P1=tab[*(pl+1)];                    //中
        delayms(3);
        P1=0xff;
       
        P2=0x01;
        P1=tab[*(pl+2)]&0x7f;   //高        //高位数码管总是带小数,因为电压的范围:0—5V
        delayms(3);
        P1=0xff;                 
}

void delayms(unsigned char t)
{
        unsigned char x,y;
        for(x=t;x>0;x--)
                for(y=110;y>0;y--);
}



//串口配置
void uart_init(void)
{
       
       
       
        PCON |= 0x80;                //使能波特率倍速位SMOD
        SCON  = 0x50;       //允许接收中断,其中包括REN=1
        TMOD &= 0x0F;                //设置定时器模式
        TMOD |= 0x20;            //设置定时器1为方式2自动重载
        TH1   = 0xf3;       //波特率4800 (11.0592MHz晶振)
        TL1   = 0xf3;
        ET1   = 0;              //禁止定时器1自身中断
        TR1   = 1;                        //启动定时器1
        EA    = 1;          //打开总中断
        ES    = 1;          //打开串口中断
       
       


}

// 发送一个字节
void sendbyte(unsigned char byte)
{
        SBUF = byte;
        while(TI == 0);    //等待发送完成
        TI = 0;            //清除发送标志
}

// 发送字符串
void send_string(unsigned char *str)        //*str表示这是一个字符型指针,用于接收要发送的字符串的首地址
{
    while(*str != '\0')
    {
        sendbyte(*str);
        str++;  
    }
}
回复

使用道具 举报

ID:332444 发表于 2025-10-20 11:28 | 显示全部楼层
作为单通道模拟信号输入时ADC0832的输入电压是0~5V,且8位分辨率时的电压精度为19.53mV。注意需要处理小数。
回复

使用道具 举报

ID:879809 发表于 2025-10-20 16:57 | 显示全部楼层
应该是这句 tep = (5.0 / 255.0) * adc0832(); 把误差放大了。
回复

使用道具 举报

ID:1133081 发表于 2025-10-20 17:20 | 显示全部楼层
计算方法不佳导致扩大误差。以下结果是mV。
        ADC = adc0832();  // 读取ADC
        tep = (5000 * (long)ADC / 256) ;  // 计算电压值 (mV)
回复

使用道具 举报

ID:469589 发表于 2025-10-20 18:15 | 显示全部楼层
只有8位分辨率的片子,有这误差非常好了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表