欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32F407单片机移植ADS1115驱动程序

程序员文章站 2022-07-03 14:23:23
...

    最近一个工程项目需要使用ADS1115采集电压,网上研究了一下,测试成功,期间走了很多弯路,为避免后来的研究者重走我的老路,特分享给大家。

注:网上很多ADS1115驱动程序移植到STM32F407单片机上虽然可以采集到电压,但是采集的电压有问题,大部分程序只能采集到高8位,采集不到低8位(低8位始终为0),用万用表添加电压信号,只有当电压变化幅度在0.2V---0.3V以上时,采集的码值才会发生变化。

        本程序经过测试,电压只要变化幅度在0.01V,采集的码值都会发生变化,以下数据是我的实测值(码值)。

//0V=5  1V=731  2V=1457  3V=2184  4V=2910  5V=3636

一、ADS1115概况

ADS1115是德州仪器推出的具有IIC接口的16位ADC转换器,超小型X2QFN或VSSOP 封装,低功耗(20uA),宽电压输入2.0V-5.5V,可编程数据转换速率8SPS-860SPS,四个单端输入或两个差分输入。可应用于,电池电压电流检测,低速便携式仪表以及温度测量系统中。

                                                                                 STM32F407单片机移植ADS1115驱动程序

                                                                                            VSSOP封装的ADS1115顶部视图         

                                                                      STM32F407单片机移植ADS1115驱动程序

二、引脚功能

引脚名称 类型 描述
ADDR 数字量输入 I2C 丛机地址选择
AIN0 模拟量输入 模拟量输入0通道
AIN1 模拟量输入 模拟量输入1通道
AIN2 模拟量输入 模拟量输入2通道
AIN3 模拟量输入 模拟量输入3通道
ALERT/RDY 数字量输出 比较器输出或转换就绪
GND 模拟量 接地
SCL 数字量输入 IIC时钟
SDA 数字量输入/输出 IIC数据线
VDD 模拟量 VCC(2.0V-5.5V)

 三、功能介绍

1、量程与分辨率

                                                             STM32F407单片机移植ADS1115驱动程序

                                                                                                   不同量程下对应的最小分辨率

2、采样速率与转换时间

采样速率可以由中的DR[2:0]位来控制,AD转换可以在一个周期内完成,因此转换时间为1/DR。

3、数字比较器(本次实验不使用)

 ADS1115具有可编程的数字比较器,可以在ALERT/RD引脚上发出警报。Config寄存器中的COMP_MODE位将比较器配置为传统比较器或窗口比较器。 在传统的比较器模式下,当转换数据超过高阈值寄存器(Hi_thresh)中设置的限制时,ALERT / RDY引脚将置为有效(默认为低电平有效)。 然后,仅当转换数据降至低阈值寄存器(Lo_thresh)中设置的限制以下时,比较器才会置为无效。 在窗口比较器模式下,当转换数据超过Hi_thresh寄存器或低于Lo_thresh寄存器值时,ALERT / RDY引脚将置为有效。

       在窗口模式或传统比较器模式下,均可将比较器配置为在被配置寄存器中的COMP_LAT位置位后锁存。即使输入信号未超出阈值寄存器的范围,此设置也将保留断言。只能通过发出SMBus警报响应或读取转换寄存器来清除此锁存的断言。可以通过Config寄存器中的COMP_POL位将ALERT / RDY引脚配置为高电平有效或低电平有效。
       两种比较器模式只有在一定数量的连续读数超过阈值寄存器中设置的阈值(Hi_thresh和Lo_thresh)之后,比较器也可以配置为**ALERT / RDY引脚。 Config寄存器中的COMP_QUE [1:0]位将比较器配置为在**ALERT / RDY引脚之前等待超过阈值的一,二或四个读数。 COMP_QUE [1:0]位还可以禁用比较器功能,并将ALERT / RDY引脚置于高电平状态。

4、操作模式

ADS1115由两种模式,连续转换和单次转换,由其中的MODE位选择相应的工作模式。

(1)、单次转换

当其中的MODE 位设置为1时,ADS1115进入掉电状态,并以单次转换模式工作,首次上电时,此状态时ADS的默认状态。尽管进入了掉电模式,但设备仍会响应命令。 ADS1115保持此掉电状态,直到将1写入中的操作状态(OS)位。当OS位有效时,器件将在大约25μs的时间内上电,将OS位复位为0,并开始单次转换。当转换的数据准备好后,设备会再次掉电。正在进行的转换时将1写入OS位无效。要切换到连续转换模式,请将0写入MODE中的MODE位。

(2)、连续转换

在连续转换模式(MODE位设置为0)下,ADS1115连续执行转换。转换完成后,ADS1115将结果放入转换寄存器,并立即开始另一次转换。配置新的设置时,当前正在进行的转换将使用先前的设置完成转换。此后,将开始使用新的设置进行连续转换。要切换到单次转换模式,请向配置寄存器的MODE位写入1或复位设备。

四、IIC地址的选择

        ADS1115具有一个地址引脚ADDR,用于设置器件的I2C地址。 该引脚可以是连接到GND,VDD,SDA或SCL,因此可以通过一对IIC引脚选择四个不同的地址。
 一般我们将地址位接GND,1001000,最后一位是确定IIC的写/读状态,写的时候是1,读的时候是0.所以slave address读写地址是0x90/0x91(10010000/10010001)

                                                             STM32F407单片机移植ADS1115驱动程序

上表是ADDR引脚连接和对应的从机地址 ,可以看到当ADDR连接到GND时,从器件的写地址=0x90,从器件的读地址=0x91。

五、ADS1115读写时序

        要从ADS1115访问特定的寄存器,主机必须首先写一个适当的值到地址指针寄存器中的地址指针位P [1:0]。在从机地址字节,低R / W位和成功的从机确认之后,直接写入地址指针寄存器。写入地址指针寄存器后,从机应答,而主机发出STOP或重复的START条件。从ADS1115读取时,写入位P [1:0]的前一个值确定要读取的寄存器。要更改读取哪个寄存器,必须将新值写入P [1:0]。要将新值写入P [1:0],主机发出R / W位为低的从机地址字节,后跟地址指针寄存器字节。主机不必发送其他数据,并且可以发出STOP条件。如果需要重复读取同一寄存器,则无需连续发送地址指针寄存器,因为ADS1115会存储P [1:0]的值,直到被写操作修改为止。

                                         STM32F407单片机移植ADS1115驱动程序

                                                                                                       ADS1115读取时序图 

读时序操作步骤:
   1.发送写地址给ADS1115(0x90);
   2.向地址指针寄存器写数据,后两位有效,只能写0x00,0x01,0x02,0x03;
   3.发送读地址给ADS1115(0x91);
   4.读取ADS1115的数据(两个字节,MSB先行);

                                   STM32F407单片机移植ADS1115驱动程序 

                                                                                                           写ADS1115的时序图 

写时序操作步骤:
   1.发送写地址给ADS1115(0x90);
   2.向地址指针寄存器写数据,后两位有效,只能写0x00,0x01,0x02,0x03;
   3.发送数据给ADS1115(高位在前)

六、数据格式

        ADS1115以二进制补码格式提供16位数据。 正满量程(+ FS)输入时,输出的AD值代码为7FFFh,负满量程(-FS)输入时,输出的AD值代码为8000h。这些代码的输出为了提示超量程的提示。

                                                   STM32F407单片机移植ADS1115驱动程序

七、地址指针寄存器(pointer register

        pointer register寄存器只有最后两位(BIT1和BIT0)有效,最后两位(BIT1和BIT0)指向了ADS1115的4个功能寄存器地址的地址。说白了,pointer register寄存器类似于C语言的指针,它指向了另外4个寄存器的地址。

                                                           STM32F407单片机移植ADS1115驱动程序

        pointer register寄存器的指向地址参见下表

                                                                STM32F407单片机移植ADS1115驱动程序

(1)、当pointer register的后两位(BIT1和BIT0)= 0 0 ,代表conversion register(转换寄存器)。

(2)、当pointer register的后两位(BIT1和BIT0)= 0 1 ,代表config register(配置寄存器),即:表示往芯片中写配置字节(例如:转换通道、单次转换还是连续转换,转换电压范围、采样速度等等)。

(3)、当pointer register的后两位(BIT1和BIT0)= 1 0 ,代表Lo_thresh register(阀值比较器高字节寄存器)

(4)、当pointer register的后两位(BIT1和BIT0)= 1 1 ,代表Hi_thresh register(阀值比较器高字节寄存器)

八、转换寄存器(conversion register)

        当地址寄存器的BIT1,BIT0=00时,为转换寄存器(只读)。

        16位转换寄存器包含二进制二进制补码格式的最后一次转换结果。 上电后,转换寄存器清除为0,并保持0直到第一次转换完成。

STM32F407单片机移植ADS1115驱动程序

        16位转换寄存器

STM32F407单片机移植ADS1115驱动程序

九、配置寄存器

        当地址寄存器的BIT1,BIT0=01时,为配置寄存器。16位配置寄存器用于控制工作模式,输入选择,数据速率,满量程范围和比较器模式。配置寄存器详细描述参见下表:

bit 字段 类型 复位后值 描述
[15] OS 读/写 1H 运行状态或单次转换开始
该位确定设备的运行状态。
仅在掉电状态下才能编写OS,而在进行转换时则无效。
写时:
0:无效
1:开始单次转换(处于掉电状态)
读时::
0:设备正在进行转换
1:转换空闲
[14:12] MUX[2:0] 读/写 0H 输入多路复用器配置
这些位配置输入多路复用器
000:AINP = AIN0和AINN = AIN1(默认)
001 : AINP = AIN0 and AINN = AIN3
010 : AINP = AIN1 and AINN = AIN3
011 : AINP = AIN2 and AINN = AIN3
100 : AINP = AIN0 and AINN = GND
101 : AINP = AIN1 and AINN = GND
110 : AINP = AIN2 and AINN = GND
111 : AINP = AIN3 and AINN = GND
[11:9] PGA[2:0] 读/写 2H 可编程的增益放大器(量程的选择 )
这些位设置可编程增益放大器的FSR。
000 : FSR = ±6.144 V(1)
001 : FSR = ±4.096 V(1)
010 : FSR = ±2.048 V (default)
011 : FSR = ±1.024 V
100 : FSR = ±0.512 V
101 : FSR = ±0.256 V
110 : FSR = ±0.256 V
111 : FSR = ±0.256 V
[8] MODE 读/写 1H 设备运行方式
该位控制操作模式。
0:连续转换模式
1:单次模式或掉电状态(默认)
[7:5] DR[2:0] 读/写 4H 转换速率
这些位控制转换速率
000:8 SPS
001:16 SPS
010:32 SPS
011:64 SPS
100:128 SPS(默认)
101:250 SPS
110:475 SPS
111:860 SPS
[4] COMP_MODE 读/写 0H 比较器模式
该位控制比较器工作
0:传统比较器(默认)
1:窗口比较器
[3] COMP_POL 读/写 0H 比较器极性
该位控制ALERT / RDY引脚的极性
0:低电平有效(默认)
1:高电平有效
[2] COMP_LAT 读/写 0H 锁存比较器
该位控制ALERT / RDY引脚在被置为有效后锁存,还是在转换后处于上限和下限阈值范围之内清零。
0:非锁存比较器。 置位后ALERT / RDY引脚不锁存(默认)
1:锁存比较器。 置为有效的ALERT / RDY引脚保持锁存状态,直到转换数据由主服务器或适当的SMBus警报响应读取由主机发送。 设备以其地址响应,它是最低的当前声明ALERT / RDY总线的地址。
[2:0] COMP_QUE[1:0] 读/写 3H 比较器置位和禁用
这些位执行两个功能。 设置为11时,比较器被禁用,ALERT / RDY引脚被设置为高阻抗状态。 当设置为任何其他值时,将启用ALERT / RDY引脚和比较器功能,并且该设置值确定连续的转换次数超过在声明ALERT / RDY引脚之前所需的上限或下限阈值
00:一次转换后断言
01:两次转换后置位
10:四次转换后置位
11:禁用比较器并将ALERT / RDY引脚设置为高阻抗(默认)

十、Lo_thresh和Hi_thresh寄存器

       比较器使用的上下阈值以二进制补码格式存储在两个16位寄存器。 比较器为数字比较器。 因此,只要更改PGA设置,就必须更新这两个寄存器中的值(使能比较器前提下)。 通过将Hi_thresh寄存器MSB设置为1并将Lo_thresh寄存器MSB设置为0,要使用ALERT / RDY引脚的比较器功能,Hi_thresh寄存器值必须始终大于 Lo_thresh寄存器值。

STM32F407单片机移植ADS1115驱动程序

                                                                                                  Lo_thresh寄存器

STM32F407单片机移植ADS1115驱动程序

                                                                                                      Hi_thresh寄存器

STM32F407单片机移植ADS1115驱动程序

                                                                                                        两个阈值寄存器描述

十一、编程流程

ADS1115编程分为三步(注:Lo_thresh和Hi_thresh寄存器可以不用设置,使用默认值即可)。

第一步:设置配置寄存器

               1)写入0x90(从机地址)

               2)写入0x01(配置寄存器地址)

               3)写入高字节(配置寄存器的高8位)

               4)写入低字节(配置寄存器的低8位)

第二步:设置转换寄存器

               1)写入0x90(从机地址)

               2)写入0x00(转换寄存器地址)

第三步:读取转换结果

               1)写入0x91(从机地址)

               2)读转换结果高字节

               3)读转换结果低字节

十二、源程序

1、IIC.H

///
//从器件地址

#define  ADS1115_WR_DEVICE_ADDR	 	0x90       //  ADS1115写从器件地址=0x90
#define  ADS1115_RE_DEVICE_ADDR 	0x91       //  ADS1115读从器件地址=0x91


///
//寄存器地址
///
#define  CONVERSION_REG_ADDR 0x00	//  转换寄存器地址
#define  CONFIG_REG_ADDR  0x01   	//  配置寄存器地址
#define  LOTH_REG  0x02				//  最低阀值寄存器地址
#define  HITH_REG  0x03				//  最高阀值寄存器地址

2、IIC.C


#define  RCC_ADS1115_I2C_PORT 			RCC_AHB1Periph_GPIOC
#define GPIO_ADS1115_I2C_PORT			GPIOC
#define GPIO_ADS1115_I2C_SCL_Pin		GPIO_Pin_0
#define GPIO_ADS1115_I2C_SDA_Pin		GPIO_Pin_1



#define ADS1115_I2C_SCL_1()  	GPIO_SetBits(			GPIO_ADS1115_I2C_PORT, GPIO_ADS1115_I2C_SCL_Pin)	// SCL = 1
#define ADS1115_I2C_SCL_0()  	GPIO_ResetBits(			GPIO_ADS1115_I2C_PORT, GPIO_ADS1115_I2C_SCL_Pin)	// SCL = 0
#define ADS1115_I2C_SDA_1()  	GPIO_SetBits(			GPIO_ADS1115_I2C_PORT, GPIO_ADS1115_I2C_SDA_Pin)	// SDA = 1
#define ADS1115_I2C_SDA_0()  	GPIO_ResetBits(			GPIO_ADS1115_I2C_PORT, GPIO_ADS1115_I2C_SDA_Pin)	// SDA = 0
#define ADS1115_I2C_SDA_READ()  GPIO_ReadInputDataBit(	GPIO_ADS1115_I2C_PORT, GPIO_ADS1115_I2C_SDA_Pin)	// 读SDA口线状态
#define ADS1115_I2C_SCL_READ()  GPIO_ReadInputDataBit(	GPIO_ADS1115_I2C_PORT, GPIO_ADS1115_I2C_SCL_Pin)	// 读SCL口线状态





void ADS1115_bsp_InitI2C(void)
{	
	GPIO_InitTypeDef GPIO_InitStructure;

	
	RCC_AHB1PeriphClockCmd(RCC_ADS1115_I2C_PORT, ENABLE);	/* 打开GPIO时钟 */
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;;  	//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		//开漏输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	
	GPIO_InitStructure.GPIO_Pin =  GPIO_ADS1115_I2C_SCL_Pin | GPIO_ADS1115_I2C_SDA_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_ADS1115_I2C_PORT, &GPIO_InitStructure);
	// 给一个停止信号, 复位I2C总线上的所有设备到待机模式
	ADS1115_i2c_Stop();
}



void ADS1115_SDA_INPUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;  		//输入模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		//开漏输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	
	GPIO_InitStructure.GPIO_Pin =  GPIO_ADS1115_I2C_SDA_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_ADS1115_I2C_PORT , &GPIO_InitStructure);
}



void ADS1115_SDA_OUTPUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;;  	//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		//开漏输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;	
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_InitStructure.GPIO_Pin =  GPIO_ADS1115_I2C_SDA_Pin;
	GPIO_Init(GPIO_ADS1115_I2C_PORT , &GPIO_InitStructure);
}




void ADS1115_i2c_Delay(void)
{
	uint8_t i;

	for (i = 0; i < 30; i++);
}



void ADS1115_delay_us(uint8_t time)
{
	uint8_t i;
	
	
	for (i = 0 ; i < time ; i++)
	{
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
	}
}



void ADS1115_i2c_Start(void)
{
	/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */	
	ADS1115_SDA_OUTPUT();
	ADS1115_I2C_SDA_1();	
	ADS1115_delay_us(20);	
	ADS1115_I2C_SCL_1();
	ADS1115_delay_us(50);		
	ADS1115_I2C_SDA_0();	//START:when CLK is high,DATA change from high to low 
	ADS1115_delay_us(50);	
	ADS1115_I2C_SCL_0();	//钳住I2C总线,准备发送或接收数据 
	ADS1115_delay_us(10);
}



void ADS1115_i2c_Stop(void)
{
	/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */	
	ADS1115_SDA_OUTPUT();
	ADS1115_I2C_SDA_0();	//STOP:when CLK is high DATA change form low to high
	ADS1115_delay_us(20);
	
	ADS1115_I2C_SCL_1();
	ADS1115_delay_us(50);
	ADS1115_I2C_SDA_1();
	ADS1115_delay_us(30);
}




//SCL在高电平期间,SDA被从设备拉为低电平表示应答
void ADS1115_i2c_Ack(void)
{
	ADS1115_SDA_OUTPUT();
	ADS1115_I2C_SDA_0();	/* CPU驱动SDA = 0 */
	ADS1115_delay_us(20);

	ADS1115_I2C_SCL_1();	/* CPU产生1个时钟 */
	ADS1115_delay_us(50);
	ADS1115_I2C_SCL_0();	//清时钟线,钳住I2C总线以便继续接收
	ADS1115_delay_us(10);
	
	ADS1115_I2C_SDA_1();	/* CPU释放SDA总线 */	
}



void ADS1115_i2c_NOAck(void)
{
	ADS1115_SDA_OUTPUT();
	ADS1115_I2C_SDA_1();	/* CPU驱动SDA = 1 */
	ADS1115_delay_us(20);
	
	ADS1115_I2C_SCL_1();	/* CPU产生1个时钟 */
	ADS1115_delay_us(50);	//时钟低电平周期大于4μ
	ADS1115_I2C_SCL_0();	//清时钟线,钳住I2C总线以便继续接收
	ADS1115_delay_us(30);
	
	ADS1115_I2C_SDA_0();
	ADS1115_delay_us(15);	
}




BOOL ADS1115_i2c_WaitAck(void)
{
	uint8_t ucErrTime = 0x00;
	
	
	ADS1115_SDA_INPUT();
	ADS1115_I2C_SDA_1();
	ADS1115_delay_us(30);
	
	ADS1115_I2C_SCL_1();	/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
	ADS1115_delay_us(30);		
	while (ADS1115_I2C_SDA_READ())
	{
		ucErrTime++;
		if (ucErrTime>250)
		{
			ADS1115_I2C_SCL_0();
			ADS1115_delay_us(30);
			ADS1115_i2c_Stop();
			return (FALSE);
		}
	}
	ADS1115_I2C_SCL_0();
	ADS1115_delay_us(30);		
	return (TRUE);
}




void ADS1115_i2c_SendByte(uint8_t _ucByte)
{
	uint8_t i;

	
	ADS1115_SDA_OUTPUT();
	//ADS1115_delay_us(10);	
	/* 先发送字节的高位bit7 */
	for (i = 0; i < 8; i++)
	{
		
		if (_ucByte & 0x80)
			ADS1115_I2C_SDA_1();
		else
			ADS1115_I2C_SDA_0();

		_ucByte <<= 1;	/* 左移一个bit */
		
		ADS1115_delay_us(10);		
		ADS1115_I2C_SCL_1();
		ADS1115_delay_us(30);
		ADS1115_I2C_SCL_0();
		ADS1115_delay_us(10);
	}
	
	ADS1115_I2C_SDA_1();
	ADS1115_delay_us(10);
}



uint8_t ADS1115_i2c_ReadByte(void)
{
	uint8_t i;
	uint8_t value = 0x00;

	/* 读到第1个bit为数据的bit7 */	
	for (i = 0; i < 8; i++)
	{
		ADS1115_SDA_OUTPUT();
		ADS1115_I2C_SDA_1();
		ADS1115_delay_us(20);
		
		ADS1115_I2C_SCL_1();//置时钟线为低,准备接收数据位
		ADS1115_delay_us(50);//时钟低电平周期大于4.7us
		ADS1115_SDA_INPUT();
		ADS1115_delay_us(10);
		value <<= 1;
		
		if (ADS1115_I2C_SDA_READ())
			value++;
		ADS1115_delay_us(10);
		ADS1115_I2C_SCL_0();
		ADS1115_delay_us(10);
	}
	return value;
}

3、ADS1115.C

uint8_t BUF[2]; 
int16_t Ai_Value[4];



//
//ADS1115的操作分3步骤。
//步骤1、向配置寄存器0x01写入配置,先写高8位,再写低8位
//H_CMD :命令字高8位(通道,量程,转换模式)
//L_CMD : 命令字低8位(采样率设置 比较模式 有效电平 信号输出锁存)
//
BOOL ADS1115_Confight(uint8_t w_device_addr , uint8_t register_addr , uint8_t H_CMD , uint8_t L_CMD)
{
	ADS1115_i2c_Start();
	ADS1115_i2c_SendByte(w_device_addr);
	if (!ADS1115_i2c_WaitAck())
	{
		ADS1115_i2c_Stop();
		return (FALSE);
	}
	ADS1115_i2c_SendByte(register_addr) ;
	ADS1115_i2c_WaitAck();
	ADS1115_delay_us(50);
	
	ADS1115_i2c_SendByte(H_CMD);
	ADS1115_i2c_WaitAck();
	ADS1115_i2c_SendByte(L_CMD);
	ADS1115_i2c_WaitAck();
	ADS1115_i2c_Stop();
	return (TRUE);
}



//
//步骤2、写入指针寄存器0x00,准备读取电压
//
BOOL ADS1115_PointRegister(uint8_t w_device_addr , uint8_t register_addr)
{
	ADS1115_i2c_Start();
	ADS1115_i2c_SendByte(w_device_addr);
	if (!ADS1115_i2c_WaitAck())
	{
		ADS1115_i2c_Stop();
		return (FALSE);
	}
	ADS1115_i2c_SendByte(register_addr);
	ADS1115_i2c_WaitAck();
	ADS1115_i2c_Stop();
	return (TRUE);
}



//
//步骤3、读取电压数据
//
BOOL ADS1115_Read_AD(uint8_t r_device_addr)
{  	
  	ADS1115_i2c_Start();
  	ADS1115_i2c_SendByte(r_device_addr);
  	if (!ADS1115_i2c_WaitAck())
	{
		ADS1115_i2c_Stop();
		return (TRUE);
	}
	
	BUF[0] = ADS1115_i2c_ReadByte();
	ADS1115_i2c_Ack();				//需要应答	
	BUF[1] = ADS1115_i2c_ReadByte();
	ADS1115_i2c_NOAck();			//读取最后一个字节,不应答
	ADS1115_i2c_Stop();
	return (TRUE);
}



//
//AD转换中单通道单次转换模式,是只进行一次AD转换吗?
//它和单通道多次转换有什么区别? 单次转换是指进行一次转换前需要你给一次指令。
//连续转换的话开启后自动连续进行转换,转换的数据连续进行更新。
//如果你采用单次转换,就需要不断发送转换的命令,读取结果,再发转换命令,再读,也就是循环!
//如果连续转换开启的话,就在程序中循环读就可以了。
///
//警告:通道转换之间必须至少要延时5毫秒;否则采集不准确。
//
int16_t ADS1115_Read_ADC(uint8_t channel)
{
	uint8_t H_CMD = 0x00;
	uint8_t L_CMD = 0x82;
	int16_t tempData;
	

	switch (channel)
	{
		case 0:
			H_CMD = 0xC2;	//bit[15]=OS=1:开始单次转换
							//bit[14:12]=MUX[2:0]=100 : AINP = AIN0 and AINN = GND
							//bit[11:9]=PGA[2:0]=001 : FSR = ±4.096 V(1)
							//bit[8]=MODE=1:单次模式或掉电状态
			break;

		case 1:
			H_CMD = 0xD2;	//bit[15]=OS=1:开始单次转换
							//bit[14:12]=MUX[2:0]=101 : AINP = AIN1 and AINN = GND
							//bit[11:9]=PGA[2:0]=001 : FSR = ±4.096 V(1)
							//bit[8]=MODE=1:单次模式或掉电状态
			break;
		
		case 2:
			H_CMD = 0xE2;	//bit[15]=OS=1:开始单次转换
							//bit[14:12]=MUX[2:0]=110 : AINP = AIN2 and AINN = GND
							//bit[11:9]=PGA[2:0]=001 : FSR = ±4.096 V(1)
							//bit[8]=MODE=1:单次模式或掉电状态
			break;

		case 3:
			H_CMD = 0xF2;	//bit[15]=OS=1:开始单次转换
							//bit[14:12]=MUX[2:0]=111 : AINP = AIN3 and AINN = GND
							//bit[11:9]=PGA[2:0]=001 : FSR = ±4.096 V(1)
							//bit[8]=MODE=1:单次模式或掉电状态
			break;		
	}//switch (channel)
	
	L_CMD = 0x82;	//bit[7:5]=DR[2:0]=100:128 SPS(默认)
					//bit[4]=COMP_MODE=0:传统比较器(默认)
					//bit[3]=COMP_POL=0:低电平有效(默认)
					//bit[2]=COMP_LAT=0:非锁存比较器。 置位后ALERT / RDY引脚不锁存(默认)
					//bit[2:0]=COMP_QUE[1:0]=10:四次转换后置位
	
	ADS1115_Confight(ADS1115_WR_DEVICE_ADDR , CONFIG_REG_ADDR , H_CMD , L_CMD);
	ADS1115_delay_us(200);	// 延时一定时间,防止通道切换互相影响 	
	ADS1115_PointRegister(ADS1115_WR_DEVICE_ADDR , CONVERSION_REG_ADDR);
	ADS1115_delay_us(200);	
	ADS1115_Read_AD(ADS1115_RE_DEVICE_ADDR);
	tempData = (int16_t)(BUF[0] << 8) + (int16_t)BUF[1];
	return (tempData);

}



void ADS1115(void)
{
	static uint8_t ADS1115_Channel_no = 0x00;
	int16_t tempData;
	
	
	tempData = ADS1115_Read_ADC(ADS1115_Channel_no);
	//当前周期读出的是上周期的采样结果
	switch (ADS1115_Channel_no)
	{
		case 0:
			Ai_Value[3] = tempData;		//0V=-1,0  1V=727  2V=1453  3V=2182  4V=2911  5V=3639
			break;
		case 1:
			Ai_Value[0] = tempData;		//0V=5  1V=731  2V=1457  3V=2184  4V=2910  5V=3636
			break;
		case 2:
			Ai_Value[1] = tempData;		//0V=5  1V=732  2V=1459  3V=2186  4V=2914  5V=3641
			break;
		case 3:
			Ai_Value[2] = tempData;		//0V=4   1V=728  2V=1452  3V=2176  4V=2900  5V=3623
			break;
	}//switch (ADS1115_Channel_no)
	
	ADS1115_Channel_no++;
	if (ADS1115_Channel_no >= 4)
		ADS1115_Channel_no = 0x00;	
}
	

注意事项

  • 对于多通道采样,每次通道切换时,应当等待几毫秒的时间后再进行采样,否则采样的数据可能不稳定或者发生通道间干扰。

 

 

感谢:

作者:特维斯的电磁炉
链接:https://www.jianshu.com/p/e0b448995316
来源:简书

相关标签: 传感器 ADS1115