为什么写进去的是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);