听弦断|醉花烟 2023-12-06 17:32 采纳率: 0%
浏览 9
已结题

ADS1115写入配置后读取不一致,高8位少了一个位

为什么写进去的是0xC283,读出来确是0x4283,实验发现是第一个字节的最高位少了一个,只读取到7个位,用了别人的代码,一样是这个情况,

通过一位位的判断写入的数据和响应位,发现都是正常的,也就是配置的是什么,写入的也是一样的二进制数据,ADS1115每一步也都是响应了的,就是读取OS位时一直为0,导致写入的C2(11000010),读出来是42(01000010)

问题已解决,因为OS位是状态位,如果配置的是单次转换,需要等待一会再读取才是1,如果是连续模式,那么OS一直为0

IIC代码层


#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

/*引脚配置层*/

/**
  * 函    数:I2C写SCL引脚电平
  * 参    数:BitValue 协议层传入的当前需要写入SCL的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SCL为低电平,当BitValue为1时,需要置SCL为高电平
  */
void MyI2C_W_SCL(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);        //根据BitValue,设置SCL引脚的电平
    Delay_us(10);                                                //延时10us,防止时序频率超过要求
}

/**
  * 函    数:I2C写SDA引脚电平
  * 参    数:BitValue 协议层传入的当前需要写入SDA的电平,范围0~0xFF
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SDA为低电平,当BitValue非0时,需要置SDA为高电平
  */
void MyI2C_W_SDA(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);        //根据BitValue,设置SDA引脚的电平,BitValue要实现非0即1的特性
    Delay_us(10);                                                //延时10us,防止时序频率超过要求
}

/**
  * 函    数:I2C读SDA引脚电平
  * 参    数:无
  * 返 回 值:协议层需要得到的当前SDA的电平,范围0~1
  * 注意事项:此函数需要用户实现内容,当前SDA为低电平时,返回0,当前SDA为高电平时,返回1
  */
uint8_t MyI2C_R_SDA(void)
{
    uint8_t BitValue;
    BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);        //读取SDA电平
    Delay_us(10);                                                //延时10us,防止时序频率超过要求
    return BitValue;                                            //返回SDA电平
}

/**
  * 函    数:I2C初始化
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,实现SCL和SDA引脚的初始化
  */
void MyI2C_Init(void)
{
    /*开启时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);    //开启GPIOB的时钟
    
    /*GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);                    //将PB10和PB11引脚初始化为开漏输出
    
    /*设置默认电平*/
    GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);            //设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
}

/*协议层*/

/**
  * 函    数:I2C起始
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Start(void)
{
    MyI2C_W_SDA(1);                            //释放SDA,确保SDA为高电平
    MyI2C_W_SCL(1);                            //释放SCL,确保SCL为高电平
    MyI2C_W_SDA(0);                            //在SCL高电平期间,拉低SDA,产生起始信号
    MyI2C_W_SCL(0);                            //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
}

/**
  * 函    数:I2C终止
  * 参    数:无
  * 返 回 值:无
  */
void MyI2C_Stop(void)
{
    MyI2C_W_SDA(0);                            //拉低SDA,确保SDA为低电平
    MyI2C_W_SCL(1);                            //释放SCL,使SCL呈现高电平
    MyI2C_W_SDA(1);                            //在SCL高电平期间,释放SDA,产生终止信号
}

/**
  * 函    数:I2C发送一个字节
  * 参    数:Byte 要发送的一个字节数据
  * 返 回 值:无
  */
void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    for (i = 0; i < 8; i ++)                //循环8次,主机依次发送数据的每一位
    {
        MyI2C_W_SDA(Byte & (0x80 >> i));    //使用掩码的方式取出Byte的指定一位数据并写入到SDA线
        Delay_us(5);
        MyI2C_W_SCL(1);                        //释放SCL,从机在SCL高电平期间读取SDA
        MyI2C_W_SCL(0);                        //拉低SCL,主机开始发送下一位数据
    }
        
        MyI2C_W_SDA(1);
       
    
}

/**
  * 函    数:I2C接收一个字节
  * 参    数:无
  * 返 回 值:接收到的一个字节数据,范围:0x00~0xFF
  */
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i, Byte = 0x00;                    //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
    MyI2C_W_SDA(1);                            //接收前,主机先确保释放SDA,避免干扰从机的数据发送
    for (i = 0; i < 8; i ++)                //循环8次,主机依次接收数据的每一位
    {
        
        MyI2C_W_SCL(1);                        //释放SCL,主机机在SCL高电平期间读取SDA    
        if (MyI2C_R_SDA() == 1)
               {
               Byte |= (0x80 >> i);
            }    //读取SDA数据,并存储到Byte变量
                                                        //当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
        
        
        MyI2C_W_SCL(0);                        //拉低SCL,从机在SCL低电平期间写入SDA
    }
    return Byte;                            //返回接收到的一个字节数据
}

/**
  * 函    数:I2C发送应答位
  * 参    数:Byte 要发送的应答位,范围:0~1,0表示应答,1表示非应答
  * 返 回 值:无
  */
void MyI2C_SendAck(uint8_t AckBit)  //增加释放SDA
{
    MyI2C_W_SDA(AckBit);                    //主机把应答位数据放到SDA线
    MyI2C_W_SCL(1);                            //释放SCL,从机在SCL高电平期间,读取应答位
    MyI2C_W_SCL(0);                            //拉低SCL,开始下一个时序模块
      MyI2C_W_SDA(1);                                //释放SDA
}

/**
  * 函    数:I2C接收应答位
  * 参    数:无
  * 返 回 值:接收到的应答位,范围:0~1,0表示应答,1表示非应答
  */
uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;                            //定义应答位变量
    MyI2C_W_SDA(1);                            //接收前,主机先确保释放SDA,避免干扰从机的数据发送
    MyI2C_W_SCL(1);                            //释放SCL,主机机在SCL高电平期间读取SDA
    AckBit = MyI2C_R_SDA();                    //将应答位存储到变量里
    MyI2C_W_SCL(0);                            //拉低SCL,开始下一个时序模块
    MyI2C_W_SDA(1);    
    return AckBit;                            //返回定义应答位变量
}

ADS1115代码层

/**
  * 函    数:ADS1115写寄存器
  * 参    数:
  * 参    数:
  * 返 回 值:无
  */
void ADS1115_WriteReg(uint8_t Address,uint8_t Point_Address, uint8_t DataMSB,uint8_t DataMLB)
{
    MyI2C_Start();                    //I2C起始
    MyI2C_SendByte(Address);    //发送从机地址,读写位为0,表示即将写入
    while(MyI2C_ReceiveAck());                //接收应答
    MyI2C_SendByte(Point_Address);            //发送寄存器地址
    while(MyI2C_ReceiveAck());                //接收应答
    MyI2C_SendByte(DataMSB);            //发送要写入寄存器的数据
    while(MyI2C_ReceiveAck());                //接收应答
    MyI2C_SendByte(DataMLB);            //发送要写入寄存器的数据
    while(MyI2C_ReceiveAck());                //接收应答        
    MyI2C_Stop();                        //I2C终止
}

/**
  * 函    数:ADS1115读寄存器
  * 参    数:RegAddress 寄存器地址,范围:参考ADS1115手册的寄存器描述
  * 返 回 值:读取寄存器的数据,范围:0x00~0xFF
  */
uint16_t ADS1115_ReadReg(uint8_t Address)
{
    uint16_t Data;
    uint8_t temp1;    
    MyI2C_Start();                        //I2C重复起始
    MyI2C_SendByte(Address | 0x01);    //发送从机地址,读写位为1,表示即将读取
    while(MyI2C_ReceiveAck());                    //接收应答
    
    Data = MyI2C_ReceiveByte();            //接收指定寄存器的数据
    temp1=Data;
    //Data |=0x80;
    Data = (Data <<    8)&0xff00;//8位
    MyI2C_SendAck(0);                    //发送应答,给从机非应答,终止从机的数据输出
      Data+= MyI2C_ReceiveByte();
    MyI2C_SendAck(1);    
    MyI2C_Stop();                        //I2C终止
    OLED_ShowHexNum(4,1,Data,4);
    OLED_ShowHexNum(3,1,temp1,2);
    return Data;
}




void ADS1115_PointRegister(uint8_t ads_addr,uint8_t point)
{
    MyI2C_Start();                            //开启I2C 
    MyI2C_SendByte(ads_addr);                //发送设备地址
    while(MyI2C_ReceiveAck());
    MyI2C_SendByte(point);                    //发送寄存器配置信息
    while(MyI2C_ReceiveAck());
    MyI2C_Stop();                                //停止I2C

}

    

main里面

       ADS1115_WriteReg(0x90,0x01,0xC2,0x83);
    ADS1115_PointRegister(0x90,0x01);
    ADS1115_ReadReg(0x90);

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-12-06 20:07
    关注

    【相关推荐】



    • 你可以参考下这篇文章:ADS1115(ADC)16 位分辨率的高精度模数转换器的操作步骤
    • 除此之外, 这篇博客: ADS1191心电采集系统设计方案中的 (二)、ADS1191的时钟电路 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

      ADS1191提供两种不同的设备时钟方法:内部时钟振荡器和外部时钟。内部时钟非常适合低功耗、电池供电的系统。

      时钟选择由CLKSEL引脚和CLK_EN寄存器位控制。

      在这里插入图片描述

      在使用 外部时钟 时,将CLKSEL引脚拉低,外部时钟从CLK引脚输入。
      在使用 内部时钟振荡器 时,将CLKSEL引脚拉高。此时若寄存器中时钟使能位CLK_EN为1,则在CLK引脚输出内部时钟;若时钟使能位CLK_EN为0,则CLK引脚为3-state(不定态?高阻态?)。
      对于CLK引脚时钟输出作用的猜测:SPI多从机有两种实现方法:多NSS和菊花链。多NSS方式中,各个从机可以由主机统一提供时钟信号。而在菊花链方式中,使用每个从机的CLK引脚进行对外时钟输出,来为下一个从机提供时钟信号,更符合菊花链式的特点。

      在此,只有一个从机ADS1191,所以采用内部时钟(将CLKSEL引脚拉高),并编程将寄存器中时钟使能位CLK_EN置为0。
      采用内部时钟(将CLKSEL引脚拉高)的具体操作为,将CLKSEL引脚通过10k电阻上拉至数字VDD。由上表可知,在此时钟模式下,CLK引脚为3-state,引脚电平状态不能确定,因此参考其他设计,将CLK引脚经过10k电阻下拉为低电平。
      在这里插入图片描述
      在这里插入图片描述


    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 12月7日
  • 修改了问题 12月7日
  • 修改了问题 12月7日
  • 创建了问题 12月6日

悬赏问题

  • ¥15 mmocr的训练错误,结果全为0
  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀