This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] ADS1115:无法读取16位、只能读取 LSB 中的 MSB 8位、从而获得00或 ff 常量

Guru**** 2554480 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/882466/ads1115-unable-to-read-16-bit-able-to-read-only-msb-8-bit-in-lsb-getting-00-or-ff-constant

器件型号:ADS1115

JOSEPF WU 您好、

我使用的是 Atmel 8052微控制器 IC、希望您能为我提供帮助。 我已将 SCL 引脚连接到8052的端口1.0、 将 SDA 引脚连接到8052的端口1.1。 在程序中、您可以看到它。 我将从过去3天到4天进行这项工作。 我遵循了数据表中所示的相同时间图。 仍然无法读取16位。 我只获得正确的 MSB 8位数据、它会随着我更改输入电压而变化。 我将其称为正确的、因为它根据设定增益为7F。 当我将增益设置为 ±2.048时、我在2V 时得到7F。 因此、基本而言、我的半操作是绝对正确的。 即使我尝试在那里读取配置寄存器、我也会正确获得 MSB 8位。 我在这里没有遇到会影响 lsb 8位数据的错误。 请抽出一些时间并帮助我。

 

#include


sbit SCL=P1^0;
sbit SDA=P1^1;
sbit D7= B^7;//MSBbit


位标志=0、RT=1、位=0;
unsigned char i、ini_char、t、string、STX=02、CR=0x0D、AD1、AD2、AD3、AD4、DATA0、Data1、E、ADC_L、OK、ADS;
unsigned int ADC_M;
unsigned char check [5];
unsigned char 半字节[5];

void main();
void port_ini();
void serial_isr (void);
void go (ini_char);
void send_adc_reading();
void hex_TO_BCD();
void adc_write();
void ADC_WR ();
void SPI();
void ADCM();
void ADCL();


///---------------------------------------------------------
//---- 主要方案-----------------------
///---------------------------------------------------------
void main()

//
port_ini();
adc_write();
while (1)

adc_write();
如果(RT=0)

for (i=0;i<5;i++)

半字节[i]=check[i];

RT=1;
INI_CHAR=n半 字节[0];
GO (ini_char);


void port_ini()

EA=1;//all_interrupt_enable
ES=1;//serial_interrupt_enable
TMOD=0x20;//TIMER1模式2 (自动重新加载)
TH1=0xFD;//9600波特率
SCON=0x50;// REN 使能、8位1停止位
TR1=1;
SCL=1;
SDA=1;

void adc_write()

ADC_M=0x00;//清除以前的数据以收集新数据
ADC_L=0x00;//清除以前的数据以收集新数据

//写入操作

SCL=1;
SDA=1;
SDA=0;//start

B=0x90;//从地址+WR
ADC_WR ();
SCL=0;
SCL=1;

B=0x01;//配置寄存器
ADC_WR ();
SCL=0;
SCL=1;

B=0xC3;//OS=1、A0 CH、单次触发模式
ADC_WR ();
SCL=0;
SCL=1;
SCL=0;
SCL=0;
SCL=0;

B=0x83;//128SPS
ADC_WR ();
SCL=0;
SCL=1;

SCL=0;//停止
SCL=1;
SDA=1;//停止

TH0=0xDC;//DC
TL0=0x00;
tr0=1;
while (TF0=0);//延迟10ms
tr0=0;
TF0=0;

SCL=1;
SDA=1;
SDA=0;//start

//读取操作
B=0x90;//从地址+WR
ADC_WR ();
SCL=0;
SCL=1;

B=0x00;//转换寄存器
ADC_WR ();
SCL=0;
SCL=1;

SCL=0;
SCL=1;
SDA=1;//停止

SCL=1;
SDA=1;
SDA=0;//start

B=0x91;//从地址+RD
ADC_WR ();
SCL=0;
SCL=1;

ADCM();//调用 ADCM 子例程
SCL=0;
SCL=1;

SCL=0;
SCL=1;
SDA=1;//停止

E=ADC_M/256;//MSB
hex_TO_BCD();
AD4=Data1;
AD3=DATA0;
E=ADC_M%256;//LSB
hex_TO_BCD();
AD2=Data1;
AD1=DATA0;


空 ADC_WR ()

对于(i=0;i<8;i++)

SCL=0;
SDA=D7;
SCL=1;

b = B<<1;//将左 B reg 旋转到 MSB 以检测下一个位


空 ADCM()

for (i=0;i<16;i++)

SCL=0;//从模拟接收数字数据的高到低脉冲
如果(SDA=1)//首先旋转,则添加

ADC_M= ADC_M << 1;//每次旋转0都将在 LSB 处发生
ADC_M=ADC_M+1;

否则、如果(SDA=0)//仅旋转

ADC_M=ADC_M << 1;//每次旋转0都将在 LSB 处发生

SCL=1;


//


void ADCL()

for (i=0;i<8;i++)

SCL=0;//从模拟接收数字数据的高到低脉冲
如果(SDA=1)//首先旋转,则添加

ADC_L= ADC_L << 1;//每次旋转0都将在 LSB 处发生
ADC_L=ADC_L+1;

否则、如果(SDA=0)//仅旋转

ADC_L=ADC_L << 1;//每次旋转0都将在 LSB 发生

SCL=1;

SCL=0;
OK = 0;
SCL=1;

//

//---------------------------------- //
//---- 串行通信--- //
//---------------------------------- //
void serial_ISR (void)中断4.

if (Ri=1)//if RI 被置位

string=SBUF;//将 SBUF 的内容移动到字符串中
RI=0;//清除 RI 复位

if (string=cr)//如果检测到回车(cR=0x0D)

flag=0;//清除标志
T=0;//clear t
RT=0;

否则、如果(flag==1)//if 标志被置位

check[t]=string;//将数据传输到数组中
T++;//递增数组指针

否则、如果(STRING=STX && RT=1)//if STX=0x02被检测到并且 RT 被置位

flag=1;//设置标志1
T=0;//从0位置开始指针



//********


///--------------------------------
//---- 去 BYTE0,然后休息---
///--------------------------------
void go (int ini_char)//第一个接收到的 char

switch (ini_char)

案例"R"://if R

SEND_ADC_READING ();
中断;



//********

///--------------------------------
//---- SEND_ADC_READING ----------
///--------------------------------
void send_adc_reading()

SBUF= STX;
while (TI=0);
TI=0;
SBUF='R';
while (TI=0);
TI=0;
SBUF= AD4;
while (TI=0);
TI=0;
SBUF= AD3;
while (TI=0);
TI=0;
SBUF= AD2;
while (TI=0);
TI=0;
SBUF= AD1;
while (TI=0);
TI=0;
SBUF= CR;
while (TI=0);
TI=0;

//********

///-------------------------------- //
//---- 十六进制_至_BCD ---------------- //
///-------------------------------- //
void hex_TO_BCD ()

Data1=E/16;//6A/10=6 MSB
if (Data1>9)

Data1=Data1+0x37;

其他

Data1=Data1+0x30;

Data0=E%16;//A LSB
if (DATA0>9)

Data0=DATA0+0x37;

其他

Data0=DATA0+0x30;


//********

 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Snehal、

    您能否提供 I2C 通信的示波器快照或逻辑分析仪图、而不是读取您的代码(我不太喜欢)? 在尝试调试通信时、最好查看波形。

    我的第一个猜测是、您意外地在 MSB 和 LSB 数据之间的某个位置发送了一个停止条件。 我认为这会停止数据传输、之后您可能会得到 FF。

    吴约瑟

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Joseph:

    首先,谢谢你的答复。 我没有示波器、这是一个大问题。 我知道很难读取其他人编写的代码。 我将向您解释从写入操作到读取方式的程序。 我遵循了数据表中显示的相同时间图、您可以对其进行比较。 如果您仍有疑问或未收到任何问题、请回复我。

    SCL=1;
    SDA=1;
    SDA=0;        //启动条件

    B=0x90;        //从地址+WR
    ADC_WR ();    //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;
    SCL=1;        //9位额外一个时钟脉冲  

    B=0x01;       //config REG
    ADC_WR ();   //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;
    SCL=1;       //9位额外一个时钟脉冲  

    B=0xC3;      //os=1、A0 CH、单次触发模式
    ADC_WR ();   //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;
    SCL=1;        //9位额外一个时钟脉冲  
    SCL=0;        //extra SCL=0  
    SCL=0;        //extra SCL=0  
    SCL=0;        //extra SCL=0  //偶数我跳过这个额外的3次 SCL=0,然后我也会得到相同的 MSB 器件结果

    B=0x83;       //默认
    ADC_WR ();   //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;
    SCL=1;        //9位额外一个时钟脉冲

    SCL=0;      
    SCL=1;
    SDA=1;       //停止 条件

     //延迟10ms

    TH0=0xDC;   
    TL0=0x00;
    tr0=1;
    while (TF0=0);  
    tr0=0;
    TF0=0;

    //////////////////////////////////////////////////////////////////////////////////////////////////

    SCL=1;
    SDA=1;
    SDA=0;      //Start 条件

    //读取操作


    B=0x90;       //从地址+WR
    ADC_WR ();   //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;    
    SCL=1;       //9位额外一个时钟脉冲

    B=0x00;      //转换寄存器
    ADC_WR ();   //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;
    SCL=1;       //9位额外一个时钟脉冲

    SCL=0;
    SCL=1;
    SDA=1;      //停止 条件

    SCL=1;
    SDA=1;
    SDA=0;        //START 条件

    B=0x91;        //从地址+RD
    ADC_WR ();    //8位通过使[ SCL=0、(SAD 1或0)、SCL=1]进行发送
    SCL=0;
    SCL=1;        //9位额外一个时钟脉冲

    ADCM();      //一次读取16位[SCL=0、(16BITREG=SDA (将 SDA 值加载到 REG)、SCL=1]
    SCL=0;
    SCL=1;       //9位额外一个时钟脉冲

    SCL=0;
    SCL=1;
    SDA=1;       //停止 条件

     

    快速查看

    启动

    90

    01

    C383

    停下

    延迟10ms

    启动

    90

    00

    停下

    启动

    91.

    MSB+LSB

     

     

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Snehal、


    首先、我确实认为有必要使用示波器或逻辑分析仪。 了解器件和主器件之间的实际通信情况非常重要。

    查看您的代码、我没有发现任何具体的错误、但我不是编码专家、而且我根本没有进行太多的编码。 如果您使用8052对 I2C 接口进行编码、一定会有在线示例。 我建议您将 I2C 总线响应放入函数中、以便也可以轻松调用它们。 我在线上的一个有关8051上的 I2C 实现的快速示例中发现了这一点:

    #define SDA P0_0
    #define SCL P0_1

    空 I2CInit()

    SDA = 1;
    SCL = 1;


    空 I2CStart()

    SDA = 0;
    SCL = 0;


    空 I2CRestart()

    SDA = 1;
    SCL = 1;
    SDA = 0;
    SCL = 0;


    空 I2CStop()

    SCL = 0;
    SDA = 0;
    SCL = 1;
    SDA = 1;


    空 I2CAck()

    SDA = 0;
    SCL = 1;
    SCL = 0;
    SDA = 1;


    空 I2CNak()

    SDA = 1;
    SCL = 1;
    SCL = 0;
    SDA = 1;


    unsigned char I2Csend (unsigned char 数据)

    unsigned char i、ack_bit;
    对于(i = 0;i < 8;i++){
    如果((数据& 0x80)==0)
    SDA = 0;
    其他
    SDA = 1;
    SCL = 1;
    SCL = 0;
    数据<<=1;

    SDA = 1;
    SCL = 1;
    ACK_BIT = SDA;
    SCL = 0;
    返回 ack_bit;


    unsigned char I2CRead ()

    unsigned char i、Data=0;
    对于(i = 0;i < 8;i++){
    SCL = 1;
    IF (SDA)
    数据|=1;
    if (i<7)
    数据<<=1;
    SCL = 0;

    返回数据;


    吴约瑟

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Wu Joseph:

    您的代码肯定会对我有所帮助。 我将进行更改并告知您。 非常感谢您的回复。 抱歉、我再打开一个相同的查询。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Wu Joseph:

    我得到了16位数据的输出。 如果我共享我的更正代码、这将对其他人有所帮助。 非常感谢您的回答。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Snehal、

    如果您愿意分享您的代码、请这样做!

    我很高兴您能够从 ADC 中获取数据。 我现在将关闭此帖子、但如果您有其他问题、请启动新主题并发帖。

    吴约瑟

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Wu Joseph:

    当我尝试读取所有4个通道时、当我尝试更改任何通道时、其他通道读数会受到影响。 例如、当我旋转电位计时、我希望 仅看到该通道的变化、但在这里、我也可以看到下一个通道的波动。  

    ADC_CH=0x42;   //CH0 & PGA=±4.096 &模式连续转换
    adc_write();
    delay();//10ms
    adc_avg ();      //ADC 读取200次、然后除以200进行恒定读取
    delay();//10ms
    delay();//10ms

    ADC_CH=0x52;//CH1 & PGA=±4.096 &模式连续转换
    adc_write();
    delay();//10ms
    ADC_avg ();    //ADC 读取200次并除以200以获得恒定读取
    delay();//10ms
    delay();//10ms

    ADC_CH=0x62;//CH2 & PGA=±4.096 &模式连续转换
    adc_write();
    delay();//10ms
    ADC_avg ();    //ADC 读取200次并除以200以获得恒定读取
    delay();//10ms
    delay();//10ms

    ADC_CH=0x72;//CH3 & PGA=±4.096 &模式连续转换
    adc_write();
    delay();//10ms
    ADC_avg ();    //ADC 读取200次并除以200以获得恒定读取
    delay();//10ms
    delay();//10ms

    在这里、我要更改 ADC 通道编号、然后我要执行它的写入操作(我要写入91并读取转换寄存器) 200次(16位*200)、并将它除以200进行平均计算。   

    我正在使用连续模式、因此我假设不需要反复执行写操作。 建议我最好的方法。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Snehal、


    我不确定您是如何设置电路的、因此我不确定您正在测量什么以及如何驱动不同的输入。 您可能需要显示基本原理图以及为每种情况获取的数据值(包括所有原始数据、而不仅仅是平均值)。

    我要指出的一个问题是、在连续转换模式下更改通道并不是立即更改。 写入配置寄存器以启动新通道、器件完成正在进行的转换、然后在后续转换中更改配置。 因此、我通常建议对多通道测量使用单冲转换模式。


    吴约瑟