打印
[51单片机]

模拟IIC时,AD芯片用差分输入时,输出补码时出错

[复制链接]
2386|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 guizhong282 于 2014-3-11 09:10 编辑

我用的是ADS1115,采集正电压工作正常,想来采集负电压,于是用差分输入,正常情况会输出补码,但是在补码开头,SDA总是在SCL高电平时出现上升沿,造成错误的停止信号,就是第二个红点,还有在这红点前一个高电平,不知道是什么原因造成的,明明正电压时这些都没有,

相关帖子

沙发
guizhong282|  楼主 | 2014-3-10 23:15 | 只看该作者
本帖最后由 guizhong282 于 2014-3-10 23:16 编辑

/*------------------------------------------------------------------------------------------------------------------------------------------*/ /*--*************************功能:   【ADS1115单端输入检测电压】********************--*/
/*--*************************CPU:    【STC12C5A60S2】*******************************--*/
/*--*************************ADC芯片:【ADS1115(2差分输入或4单端输入)】***********--*/
/*--*************************液晶:   【LCD1602】************************************--*/
/*--*************************ADC与单片机连接:【SCL:P1.0 , SDA:P1.1】*******************--*/
/*--*************************检测范围:【0.00~4.99V】*********************************--*/
/*----------------------------------------------------------------------------------------------------------------------------------------*/
#include <reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define _Nop() _nop_()


/*------------------------以下为LCD1602显示模块端口定义及函数声明-----------------------*/
sbit lcd_rs_port = P2^5;                          /*定义LCD控制端口*/
sbit lcd_rw_port = P2^6;
sbit lcd_en_port = P2^7;
#define lcd_data_port P0

unsigned char num_char_table[] = {"0123456789ABCDEF -"};
unsigned char Lcd_Dis1_table[] = {"Volt:         V "};                        //电压显示框架
unsigned char pos_char_table[] = {"        .     V "};                        //电压显示位置

void lcd_delay(uchar ms);                                                                                        //LCD1602 延时
void lcd_busy_wait();                                                                                                 //LCD1602 忙等待
void lcd_command_write(uchar command);                                                         //LCD1602 命令字写入
void lcd_system_reset();                                                                                                //LCD1602 初始化
void lcd_char_write(uchar x_pos,y_pos,lcd_dat);                                                 //LCD1602 字符写入
void lcd_bad_check();                                                                                                 //LCD1602 坏点检查
void Num_to_Disp(uint Num);                                                                                //LCD1602 数据处理
void LcdDisp(uint num);                                                                                                //LCD1602 数据显示
void delay_1ms(uchar x);                                                                                        //LCD1602 延时1ms

/*------------------------以下为ADS1115模块端口定义及函数声明--------------------------*/

sbit SCL = P3^1;
sbit SDA = P3^0;

#define TRUE             1
#define FALSE            0

unsigned int Config;
unsigned char Writebuff[4],Readbuff[3];
unsigned int Result[2];
int D_ADS;                                  //转换的数字量
#define Accuracy 32768      //定义ADC精度,ADS1115单端输入时15位
float VCC = 4.096;                     //VCC,电压参考值

#define ADDRESS_0  0x90   //ADDR PIN ->GND
#define ADDRESS_1  0x92   //ADDR PIN ->VDD
#define ADDRESS_2  0x94   //ADDR PIN ->SDA
#define ADDRESS_3  0x96   //ADDR PIN ->SCL

/************POINTER REGISTER*****************/
#define Pointer_0  0x00   //Convertion register
#define Pointer_1  0x01   //Config register
#define Pointer_2  0x02   //Lo_thresh register
#define Pointer_3  0x03   //Hi_thresh register

/************CONFIG REGISTER*****************/
#define OS_0   0x0000
#define OS_1   0x8000

#define MUX_0  0x0000  //AINp=AIN0, AINn=AIN1
#define MUX_1  0x1000  //AINp=AIN0, AINn=AIN3
#define MUX_2  0x2000  //AINp=AIN1, AINn=AIN3
#define MUX_3  0x3000  //AINp=AIN2, AINn=AIN3
#define MUX_4  0x4000  //AINp=AIN0, AINn=GND
#define MUX_5  0x5000  //AINp=AIN1, AINn=GND
#define MUX_6  0x6000  //AINp=AIN2, AINn=GND
#define MUX_7  0x7000  //AINp=AIN3, AINn=GND

#define PGA_0  0x0000   //FS=6.144V
#define PGA_1  0x0200   //FS=4.096V
#define PGA_2  0x0400   //FS=2.048V
#define PGA_3  0x0600   //FS=1.024V
#define PGA_4  0x0800   //FS=0.512V
#define PGA_5  0x0A00   //FS=0.256V
#define PGA_6  0x0C00   //FS=0.256V
#define PGA_7  0x0E00   //FS=0.256V

#define MODE_0 0x0000
#define MODE_1 0x0100

#define DR_0   0x0000   //Data Rate = 8
#define DR_1   0x0020   //Data Rate = 16
#define DR_2   0x0040   //Data Rate = 32
#define DR_3   0x0060   //Data Rate = 64
#define DR_4   0x0080   //Data Rate = 128
#define DR_5   0x00A0   //Data Rate = 250
#define DR_6   0x00C0   //Data Rate = 475
#define DR_7   0x00E0   //Data Rate = 860

#define COMP_MODE_0  0x0000
#define COMP_MODE_1  0x0010

#define COMP_POL_0   0x0000
#define COMP_POL_1   0x0008

#define COMP_LAT_0   0x0000
#define COMP_LAT_1   0x0040

#define COMP_QUE_0   0x0000
#define COMP_QUE_1   0x0001
#define COMP_QUE_2   0x0002
#define COMP_QUE_3   0x0003

//*************ADDR Initial********************/
#define ADDRESS    ADDRESS_0     //ADDR PIN ->GND
#define ADDRESS_W  ADDRESS|0x00  //写地址
#define ADDRESS_R  ADDRESS|0x01  //读地址

/*************Config Initial*********************/
#define OS         OS_1
#define MUX_A0     MUX_4      //AINp=AIN0, AINn=GND
#define MUX_A1     MUX_5      //AINp=AIN1, AINn=GND
#define MUX_A2     MUX_6      //AINp=AIN2, AINn=GND
#define MUX_A3     MUX_7      //AINp=AIN3, AINn=GND
#define MUX_D0     MUX_0      //AINp=AIN0, AINn=AIN1
#define MUX_D1     MUX_1      //AINp=AIN0, AINn=AIN3
#define MUX_D2     MUX_2      //AINp=AIN1, AINn=AIN3
#define MUX_D3     MUX_3      //AINp=AIN2, AINn=AIN3

#define PGA        PGA_1      //FS=4.096V
#define MODE       MODE_1     //Continuous conversion mode
#define DR         DR_7       //Data Rate = 860
#define COMP_QUE   COMP_QUE_3

void Delay_us_15 (void);
void Delay_ms_1 (void);          //功    能:延时
void Start(void);                  //功    能:完成IIC的起始条件操作
void Stop(void);                  //功    能:完成IIC的终止条件操作
void ACK(void);                      //功    能:完成IIC的主机应答操作
void NACK(void);                  //功    能:完成IIC的主机无应答操作
unsigned char Check(void);//功    能:检查从机的应答操作
void Write_1_Byte(unsigned char DataByte);                                                                    //写 1个字节
unsigned char Write_N_Byte(unsigned char *writebuffer,unsigned char n);                //写 N个字节
unsigned char Read_1_Byte(void);                                                                                        //读 1个字节
void Read_N_Byte(unsigned int *readbuff,unsigned char n);                                        //读 N个字节
void InitADS1115(bit S_MUX_0, bit S_MUX_1);                                                                //ADS1115初始化
void WriteWord(void);                                                                                                        //写
void ReadWord(void);                                                                                                        //读
unsigned int ADS1115(bit S_MUX_0, bit S_MUX_1);                                                        //ADS1115取值

/*--------------------------------------------------------------------------------------------------------------------------------*/
/*--*********************************【 主函数 】*******************************--*/
/*-------------------------------------------------------------------------------------------------------------------------------*/
void main()
{
        unsigned int result;
       
        lcd_system_reset();                 //LCD1602 初始化
        //lcd_bad_check();                         //LCD1602 坏点检查
       
        while(1)
        {       
                result = ADS1115(0,0);        //ADS1115取值_AIN0
                //result = ADS1115(0,1);        //ADS1115取值_AIN1
                //result = ADS1115(1,0);        //ADS1115取值_AIN2
                //result = ADS1115(1,1);        //ADS1115取值_AIN3

                LcdDisp(result);                //LCD1602显示电压值
        }       
}
/*--------------------------------------------------------------------------------------------------------------------------------*/
/*--****************************************************************************--*/
/*-------------------------------------------------------------------------------------------------------------------------------*/


void LcdDisp(uint num)                           /************LCD显示*************/
{
        uint i=0;

        for (i=0;i<16;i++)
        {
                lcd_char_write(i,0,Lcd_Dis1_table);  //显示框架
        }
        Num_to_Disp(num);
        for(i = 6; i < 13; i++)
        {
                lcd_char_write(i,0,pos_char_table);  //显示电压
        }                                                                                                  
        delay_1ms(100);
}

void Num_to_Disp(uint Num)                   /******LCD显示数据处理*****/ //Start_1-Over_1:显示电压值,Start_2-Over_2:显示ADS1115输出数值
{                                                                                                                                                     
        float NUM;                                                                                                               //Start_1
        int xx, yy, zz, zzz,zzzz;


                if(Num>0x7fff)                                                                       //单通道显示负数
                {
                        Num = ~Num + 1;
                        pos_char_table[6] = num_char_table[17];                        //显示负号
                }
                else
                {
                        pos_char_table[6] = num_char_table[16];       
                }
                ;
                NUM = (Num  / (float)Accuracy) * VCC;                                //ADS1115取值 = Accuracy × (Vin / VCC)

       
                xx = (int)NUM;
                yy = (int)((NUM - (float)(xx)) * 10);
                zz = (int)((NUM - (float)(xx)) * 100)%10;
                zzz = (int)((NUM - (float)(xx)) * 1000)%10;
                zzzz = (int)((NUM - (float)(xx)) * 10000)%10;

                //pos_char_table[6] = num_char_table[xx / 10];                    //电压值十位
                pos_char_table[7]= num_char_table[xx % 10];                            //电压值个位
                pos_char_table[9]= num_char_table[yy];                                    //电压值小数点后一位
                pos_char_table[10]= num_char_table[zz];                                     //电压值小数点后两位
                pos_char_table[11]= num_char_table[zzz];                             //电压值小数点后三位   
                pos_char_table[12]= num_char_table[zzzz];                             //电压值小数点后四位   //Over_1                  
       

/*        pos_char_table[6] = num_char_table[Num / 10000];                                                   //Start_2
        pos_char_table[7] = num_char_table[(Num % 10000) / 1000];       
        pos_char_table[8]= num_char_table[((Num % 10) % 1000) / 100];       
        pos_char_table[9]= num_char_table[(Num / 10) % 10];                       
        pos_char_table[10]= num_char_table[Num % 10];                                                           //Over_2                           */
       
}

void delay_1ms(uchar x)                           /*******1MS为单位的延时程序******/
{
    uchar j;
    while(x--){
        for(j=0;j<125;j++)
            {;}
        }   
}

/*------------------------以下为ADS1115模块端口函数定义--------------------------*/

void Delay_us_15 (void)           /*延时程序*/
{
    unsigned char i;

    for(i = 0;i < 10;i++)
      _nop_();
}
void Delay_ms_1 (void)
{
        unsigned char i;
        for(i = 100;i > 0;i--) _nop_();
}       
///*******************************************
//函数名称:Start
//功    能:完成IIC的起始条件操作
//参    数:无
//返回值  :无
//********************************************/
void Start(void)
{
        SCL=1;
        SDA=1;
        Delay_us_15 ();
                SDA=0;
        Delay_us_15 ();
                SCL=0;
        Delay_us_15 ();
}
//
///*******************************************
//函数名称:Stop
//功    能:完成IIC的终止条件操作
//参    数:无
//返回值  :无
//********************************************/
void Stop(void)
{
        SDA=0;
        Delay_us_15 ();
        SCL=1;
        Delay_us_15 ();
                SDA=1;
        Delay_us_15 ();
}
///*******************************************
//函数名称:ACK
//功    能:完成IIC的主机应答操作
//参    数:无
//返回值  :无
//********************************************/
void ACK(void)
{        //        uchar i=0;
        SDA=0;
        _nop_(); _nop_();
        SCL=1;
        //        for(i=0;i<100;i++)
        Delay_us_15 ();
                 
        SCL=0;
                _nop_(); _nop_();
                _nop_(); _nop_();
                SDA=1;
        Delay_us_15 ();                  
}
//*******************************************
//函数名称:NACK
//功    能:完成IIC的主机无应答操作
//参    数:无
//返回值  :无
//********************************************/
void NACK(void)
{
        SDA=1;
        _nop_(); _nop_();
        SCL=1;
        Delay_us_15 ();
        SCL=0;
        _nop_(); _nop_();
        SDA=0;   
        Delay_us_15 ();     
}
//**********检查应答信号函数******************/
///*如果返回值为1则证明有应答信号,反之没有*/
///*******************************************
//函数名称:Check
//功    能:检查从机的应答操作
//参    数:无
//返回值  :从机是否有应答:1--有,0--无
//********************************************/
unsigned char Check(void)
{
    unsigned char slaveack;

    SDA=1;
    _nop_(); _nop_();
    SCL=1;
    _nop_(); _nop_();
    _nop_(); _nop_();
    slaveack = SDA;   //读入SDA数值
    SCL=0;
    Delay_us_15 ();

    if(slaveack)    return FALSE;
    else            return TRUE;
}

/***************Write a Byte****************/
void Write_1_Byte(unsigned char DataByte)
{
        int i;

        for(i=0;i<8;i++)
        {
                if(DataByte&0x80)  //if((DataByte<<i)&0x80)
                  SDA=1;
                else
                  SDA=0;
        Delay_us_15 ();
                SCL=1;
        Delay_us_15 ();
        SCL=0;
        Delay_us_15 ();
        DataByte <<= 1;
        }
        SDA=1;
        _nop_();
}
/***************Write N Byte****************/
unsigned char Write_N_Byte(unsigned char *writebuffer,unsigned char n)
{
        int i;

        for(i=0;i<n;i++)
        {
                Write_1_Byte(*writebuffer);
                if(Check())                                //检查从机是否应答
                {
                        writebuffer ++;
                }
                else
                {
                        Stop();                                //未应答则结束发送
                    return FALSE;
                }
        }
        Stop();
        return TRUE;
}

//***************Read a Byte****************/
unsigned char Read_1_Byte(void)
{
    unsigned char data_Value = 0, FLAG, i;
       
    for(i=0;i<8;i++)
    {

//        SDA=1;
//        Delay_us_15 ();
    SCL=1;
        Delay_us_15 ();
        FLAG=SDA;
        data_Value <<= 1;
        if( FLAG)
           data_Value |= 0x01;

    SCL=0;
    Delay_us_15 ();
    }
    return data_Value;
}

//***************Read N Byte****************/
void Read_N_Byte(unsigned int*readbuff, unsigned char n)
{
        unsigned char i;
       
        for(i=0;i<n;i++)
        {
                readbuff=Read_1_Byte();
                if(i==n-1)
                        NACK();  //不连续读字节
                else
                        ACK(); //连续读字节
        }
        Stop();

}
//*****************初始化******************/
void InitADS1115(bit S_MUX_0, bit S_MUX_1)
{

       
        if (S_MUX_0 == 0 && S_MUX_1 == 0)                                        //AIN0                2014年3月8日21:41:50修改MUX_A0 成差分A0A1输入
        Config = OS+MUX_D0+PGA+DR+COMP_QUE+MODE;
        if (S_MUX_0 == 0 && S_MUX_1 == 1)                                         //AIN1
        Config = OS+MUX_A1+PGA+DR+COMP_QUE+MODE;
        if (S_MUX_0 == 1 && S_MUX_1 == 0)                                        //AIN2
        Config = OS+MUX_A2+PGA+DR+COMP_QUE+MODE;
        if (S_MUX_0 == 1 && S_MUX_1 == 1)                                        //AIN3
        Config = OS+MUX_A3+PGA+DR+COMP_QUE+MODE;

    Writebuff[0]=ADDRESS_W;
    Writebuff[1]=Pointer_1;
    Writebuff[2]=Config/256;
    Writebuff[3]=Config%256;

    Readbuff[0]=ADDRESS_W;
    Readbuff[1]=Pointer_0;

    Readbuff[2]=ADDRESS_R;
}

//***************Write a Word***********************/
void WriteWord(void)
{
     int t;
     Start();   //写入4个字节
     do
     {
          t=Write_N_Byte(Writebuff,4);
     }while(t==0);
}
//***************Read Word***********************/
void ReadWord(void)
{
    int t;
    Start();  //写入2个字节
    do
    {
      t=Write_N_Byte(Readbuff,2);
    }while(t==0);

    Start();   //写入2个字节
    do
    {
      t=Write_N_Byte(&Readbuff[2],1);
    }while(t==0);

    Read_N_Byte(Result,2);  //读出2个字节

}
//***************ADS1115********************/
unsigned int ADS1115(bit S_MUX_0, bit S_MUX_1)
{
    InitADS1115(S_MUX_0, S_MUX_1);
    WriteWord();
    Delay_ms_1();
    ReadWord();
       
    D_ADS=Result[0]*256+Result[1];  //转换的数字量

          return D_ADS;
}

使用特权

评论回复
板凳
coody| | 2014-3-11 11:33 | 只看该作者
那你先读二进制码看看

使用特权

评论回复
地板
ayb_ice| | 2014-3-11 12:29 | 只看该作者
应该是模拟时序的问题吧
另外看ADC配置对了没有

使用特权

评论回复
5
guizhong282|  楼主 | 2014-3-11 15:48 | 只看该作者
coody 发表于 2014-3-11 11:33
那你先读二进制码看看

读出来就是FFFF

使用特权

评论回复
6
guizhong282|  楼主 | 2014-3-11 15:49 | 只看该作者
ayb_ice 发表于 2014-3-11 12:29
应该是模拟时序的问题吧
另外看ADC配置对了没有

我觉得是模拟时序的问题,但是又找不出来,明明采集正电压时是正常的

使用特权

评论回复
7
ayb_ice| | 2014-3-11 16:05 | 只看该作者
guizhong282 发表于 2014-3-11 15:49
我觉得是模拟时序的问题,但是又找不出来,明明采集正电压时是正常的

也极有可能是配置的问题
仔细对着PDF看一下

使用特权

评论回复
8
coody| | 2014-3-11 17:55 | 只看该作者
时序不对

使用特权

评论回复
9
guizhong282|  楼主 | 2014-3-11 19:12 | 只看该作者
本帖最后由 guizhong282 于 2014-3-11 19:18 编辑

源程序有bug,应将Write_N_Byte内的stop()移到 WriteWord()内,就正常了,不过很可疑为啥正电压时不会出错,
可以结贴了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

14

帖子

0

粉丝