ADS1115 多路模数转换器
ADS1115 器件是兼容 IIC 的 16 位高精度低功耗模数转换器 (ADC),采用超小型无引线 X2QFN-10 封装和 VSSOP-10 封装。ADS111x 器件采用了低漂移电压基准和振荡器。ADS1114 和 ADS1115 还采用可编程增益放大器(PGA)和数字比较器。这些特性加以较宽的工作电源电压范围使得 ADS1115 非常适合功率与空间受限的传感器测量。
ADS111x 可在数据速率高达每秒 860 个样本 (SPS) 的情况下执行转换。PGA 可提供从 ±256mV 到 ±6.144V 的输入范围,从而实现精准的大小信号测量。ADS1115 具有 一个输入多路复用器 (MUX),可实现两次差动输入测量或四次单端输入测量。在 ADS1115 中可使用数字比较器进行欠压和过压检测。 ADS1115 既可在连续转换模式下工作,也可在单冲模式下工作。在单冲模式下,这些器件可在一次转换后自动断电;因此显著降低了空闲期间的功耗。
模块来源
采购链接:
ADS1115 超小型 16 位 模数转换器 ADC 4 通道
规格参数
工作电压: 2.0-5.5V
工作电流: 150uA
采集精度: 16 位
采集通道: 4 通道
控制方式: IIC
管脚数量:10 Pin(2.54mm 间距排针)
移植过程
我们的目标是在天空星 STM32F407 上能够实现 4 路 ADC 采集电压功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
查看资料
ADS1115 是采用的 IIC 通信,所以首先要了解 IIC 的地址与时序,再确定根据寄存器的设置。
(1)器件地址
器件地址的设置见下表。
说明:当模块上的 ADDR 引脚接入 GND 时,其器件地址为 1001000,最后一位数据是读写位。
BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0 |
---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 0 | 0 | 0 | R/W |
当模块上的 ADDR 引脚接入 VDD 时,其器件地址为 1001001,最后一位数据是读写位。
BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0 |
---|---|---|---|---|---|---|---|
1 | 0 | 0 | 1 | 0 | 0 | 1 | R/W |
本文以接入 GND 为地址。即后续的地址为 0X90。
(2)时序
下图是读时序,步骤是:
IIC 起始信号-> 发送器件地址 +0(写) -> 等待模块应答 -> 应答后发送寄存器地址 -> 等待模块应答 -> 重新发送起始信号 -> 发送器件地址 +1(读) -> 等待模块应答 -> 应答后读取高 8 位数据 -> 读取完毕主机发送应答信号 -> 读取低 8 位数据 -> 读取完毕主机发送应答信号 -> 发送 IIC 停止信号。
下图是写时序,步骤是:
IIC 起始信号-> 发送器件地址 +0(写) -> 等待模块应答 -> 应答后发送寄存器地址 -> 等待模块应答 -> 应答后写入高 8 位数据 -> 等待模块应答 -> 写入低 8 位数据 -> 等待模块应答 -> 发送 IIC 停止信号。
(3)寄存器说明
ADS1115 有四个寄存器,可通过 IIC 接口使用地址指针进入。
- 地址 0X00 为转换寄存器,它包含最后一次转换的结果。
- 地址 0X01 为配置寄存器,用于更改 ADS1115 的工作模式和查询设备状态。
- 另外两个寄存器,Lo_thresh 和 Hi_thresh,设置用于比较器函数的阈值,我们用不到。
16 位转换寄存器以二进制的补码格式保存最后一次转换的结果。需要注意的是,在上电之后,转换寄存器被清除为 0,并保持为 0,直到第一次转换完成。
(4)实现代码说明
读取到的 ADC 值如何换算为电压? 以 PGA 设置为 4.96V 为例。
/******************************************************************
* 函 数 名 称:WriteADS1115
* 函 数 说 明:向ADS1115的add地址写入dat数据
* 函 数 形 参: add写入寄存器地址
* dat_H写入的高8位数据
* dat_L写入的低8位数据
* 函 数 返 回:0写入成功
* 1写入器件地址无应答
* 2写入寄存器地址无应答
* 作 者:LC
* 备 注:器件地址=0X90
******************************************************************/
uint8_t WriteADS1115(uint8_t add,uint8_t dat_H,
uint8_t dat_L)
{
IIC_Start();//起始信号
IIC_Write(0x90);//器件地址
if( IIC_Wait_Ack() == 1 )
return 1;
IIC_Write(add);//寄存器地址
if( IIC_Wait_Ack() == 1 )
return 2;
IIC_Write(dat_H);//写入高8位
IIC_Wait_Ack();//等待应答
IIC_Write(dat_L);//写入低8位
IIC_Wait_Ack();//等待应答
IIC_Stop();//停止信号
return (0);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/******************************************************************
* 函 数 名 称:ReadADS1115
* 函 数 说 明:读取ADS1115的数据
* 函 数 形 参:add读取的寄存器地址
* 函 数 返 回:-1-读取失败 其他-读取成功
* 作 者:LC
* 备 注:无
******************************************************************/
float ReadADS1115(unsigned char add)
{
int i =0;
unsigned char dat[2]={0};
unsigned int num = 0;
float ret=0;
IIC_Start();//起始信号
IIC_Write(0x90);//器件地址+写
if( IIC_Wait_Ack() == 1 )
return -1;
IIC_Write(add);//寄存器地址
if( IIC_Wait_Ack() == 1 )
return -1;
do{
//超时判断
i++;
if( i > 20 ) return -1;
delay_1ms(1);
IIC_Start();//重新发送起始信号
IIC_Write(0x91);//器件地址+读
}while(IIC_Wait_Ack() == 1);
dat[0]=IIC_Read();//读高8位数据
IIC_Send_Ack(0);//应答
dat[1]=IIC_Read();//读低8位数据
IIC_Send_Ack(1);//非应答
IIC_Stop();//发送停止信号
//数据整合
num = ((dat[0]<<8) | (dat[1]));
//分辨率计算:测量电压范围/(2^AD位数-1)
// 分辨率= 4.096/2^15=0.000125
// 电压= 采集到的ADC值 * 分辨率
if(num>32768)
ret=(65535-num)*0.000125;
else
ret=num*0.000125;
return ret;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
引脚选择
移植至工程
空白工程下载:
移植步骤中的导入.c 和.h 文件与第二章的第 1 小节【DHT11 温湿度传感器】相同,只是将.c 和.h 文件更改为 bsp_ads1115.c 与 bsp_ads1115.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件 bsp_ads1115.c 中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-18 LCKFB-LP first version
*/
#include "bsp_ads1115.h"
#include "board.h"
#include "stdio.h"
/******************************************************************
* 函 数 名 称:ADS1115_GPIO_Init
* 函 数 说 明:对IIC引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:1100_0010_1000_0011 WriteADS1115(0x01,0xc2,0x83);
******************************************************************/
void ADS1115_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_ADS1115, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_SCL|GPIO_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(PORT_ADS1115, &GPIO_InitStructure);
//写入配置参数
WriteADS1115(0x01,0xC2,0x83);
}
/******************************************************************
* 函 数 名 称:IIC_Start
* 函 数 说 明:IIC起始信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Start(void)
{
SDA_OUT();
SDA(1);
delay_us(5);
SCL(1);
delay_us(5);
SDA(0);
delay_us(5);
SCL(0);
delay_us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Stop
* 函 数 说 明:IIC停止信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Stop(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
delay_us(5);
SDA(1);
delay_us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Send_Ack
* 函 数 说 明:主机发送应答
* 函 数 形 参:0应答 1非应答
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Send_Ack(unsigned char ack)
{
SDA_OUT();
SCL(0);
SDA(0);
delay_us(5);
if(!ack) SDA(0);
else SDA(1);
SCL(1);
delay_us(5);
SCL(0);
SDA(1);
}
/******************************************************************
* 函 数 名 称:IIC_Wait_Ack
* 函 数 说 明:等待从机应答
* 函 数 形 参:无
* 函 数 返 回:1=无应答 0=有应答
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned char IIC_Wait_Ack(void)
{
char ack = 0;
unsigned char ack_flag = 10;
SDA_IN();
SDA(1);
delay_us(5);
SCL(1);
delay_us(5);
while( (GETSDA()==1) && ( ack_flag ) )
{
ack_flag--;
delay_us(5);
}
if( ack_flag <= 0 )
{
IIC_Stop();
return 1;
}
else
{
SCL(0);
SDA_OUT();
}
return ack;
}
/******************************************************************
* 函 数 名 称:IIC_Write
* 函 数 说 明:IIC写一个字节
* 函 数 形 参:dat写入的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void IIC_Write(unsigned char dat)
{
int i = 0;
SDA_OUT();
SCL(0);//拉低时钟开始数据传输
for( i = 0; i < 8; i++ )
{
SDA( (dat & 0x80) >> 7 );
delay_us(2);
dat<<=1;
delay_us(6);
SCL(1);
delay_us(4);
SCL(0);
delay_us(4);
}
}
/******************************************************************
* 函 数 名 称:IIC_Read
* 函 数 说 明:IIC读1个字节
* 函 数 形 参:无
* 函 数 返 回:读出的1个字节数据
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned char IIC_Read(void)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
SCL(0);
delay_us(5);
SCL(1);
delay_us(5);
receive<<=1;
if( GETSDA() )
{
receive|=1;
}
delay_us(5);
}
return receive;
}
/******************************************************************
* 函 数 名 称:WriteADS1115
* 函 数 说 明:向ADS1115的add地址写入dat数据
* 函 数 形 参:add写入寄存器地址 dat_H写入的高8位数据 dat_L写入的低8位数据
* 函 数 返 回:0写入成功 1写入器件地址无应答 2写入寄存器地址无应答
* 3写入高8位数据无应答 4写入低8位数据无应答
* 作 者:LC
* 备 注:器件地址=0X90
******************************************************************/
uint8_t WriteADS1115(uint8_t add,uint8_t dat_H,uint8_t dat_L)
{
IIC_Start();
IIC_Write(0x90);
if( IIC_Wait_Ack() == 1 )
{
printf("error 1\r\n");
return 1;
}
IIC_Write(add);
if( IIC_Wait_Ack() == 1 )
{
printf("error 2\r\n");
return 2;
}
IIC_Write(dat_H);
IIC_Wait_Ack();
IIC_Write(dat_L);
IIC_Wait_Ack();
IIC_Stop();
return (0);
}
/******************************************************************
* 函 数 名 称:ReadADS1115
* 函 数 说 明:读取ADS1115的数据
* 函 数 形 参:add读取的寄存器地址
* 函 数 返 回:-1-读取失败 其他-读取成功
* 作 者:LC
* 备 注:无
******************************************************************/
float ReadADS1115(unsigned char add)
{
int i =0;
unsigned char dat[2]={0};
unsigned int num = 0;
float ret=0;
IIC_Start();//起始信号
IIC_Write(0x90);//器件地址+写
if( IIC_Wait_Ack() == 1 )
return -1;
IIC_Write(add);//寄存器地址
if( IIC_Wait_Ack() == 1 )
return -1;
do{
//超时判断
i++;
if( i > 20 ) return -1;
delay_ms(1);
IIC_Start();//重新发送起始信号
IIC_Write(0x91);//器件地址+读
}while(IIC_Wait_Ack() == 1);
dat[0]=IIC_Read();//读高8位数据
IIC_Send_Ack(0);//应答
dat[1]=IIC_Read();//读低8位数据
IIC_Send_Ack(1);//非应答
IIC_Stop();//发送停止信号
//数据整合
num = ((dat[0]<<8) | (dat[1]));
//数值计算取决于PGA配置
//2的15次方=32768
//设置的最大量程4.096
// if(num>32768)
// ret=((float)(65535-num)/32768.0)*4.096;
// else
// ret=((float)num/32768.0)*4.096;
//分辨率计算:测量电压范围/(2^AD位数-1)
// 分辨率= 4.096/2^15=0.000125
// 电压= 采集到的ADC值 * 分辨率
if(num>32768)
ret=(65535-num)*0.000125;
else
ret=num*0.000125;
return ret;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
在文件 bsp_ads1115.h 中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-18 LCKFB-LP first version
*/
#ifndef _BSP_ADS1115_H_
#define _BSP_ADS1115_H_
#include "stm32f4xx.h"
#define RCC_ADS1115 RCC_AHB1Periph_GPIOB
#define PORT_ADS1115 GPIOB
#define GPIO_SCL GPIO_Pin_8
#define GPIO_SDA GPIO_Pin_9
//SDA输入模式
#define SDA_IN() { GPIO_InitTypeDef GPIO_InitStructure; \
GPIO_InitStructure.GPIO_Pin = GPIO_SDA; \
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; \
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; \
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; \
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
GPIO_Init(PORT_ADS1115, &GPIO_InitStructure); \
}
//SDA输出模式
#define SDA_OUT() { GPIO_InitTypeDef GPIO_InitStructure; \
GPIO_InitStructure.GPIO_Pin = GPIO_SDA; \
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; \
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; \
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; \
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
GPIO_Init(PORT_ADS1115, &GPIO_InitStructure); \
}
#define SCL(BIT) GPIO_WriteBit( PORT_ADS1115, GPIO_SCL, BIT?Bit_SET:Bit_RESET )
#define SDA(BIT) GPIO_WriteBit( PORT_ADS1115, GPIO_SDA, BIT?Bit_SET:Bit_RESET )
#define GETSDA() GPIO_ReadInputDataBit( PORT_ADS1115, GPIO_SDA )
void ADS1115_GPIO_Init(void);
unsigned char WriteADS1115(unsigned char add,unsigned char dat_H,unsigned char dat_L);
float ReadADS1115(unsigned char add);
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
移植验证
在自己工程中的 main 主函数中,编写如下。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*
Change Logs:
* Date Author Notes
* 2024-03-18 LCKFB-LP first version
*/
#include "board.h"
#include "bsp_uart.h"
#include <stdio.h>
#include "bsp_ads1115.h"
int main(void)
{
board_init();
uart1_init(115200U);
ADS1115_GPIO_Init();
printf("demo start\r\n");
while(1)
{
//当前设置最大量程为4.096V
printf("A0 = %.4f\r\n", ReadADS1115(0x00) );//读取A0的值
delay_ms(1000);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
移植现象:将 A0 接入 GND、3.3V 和 5V。
代码下载
链接在开发板介绍
章节的离线资料下载!!