ADS1115的使用
ADS1115概况
ads1115是一款低功耗16位的ADC
四路的输入,分别是:A0,A1,A2,A3
供电引脚:VDD
地:GND
与其他设备通信:SCL,SDA
地址:ADDR
比较器的结果输出:ALERT(简单应用一般用不到)
一般VDD与GND的压差为2-5.5V
ADDR接在不同的位置上时的地址是不同的
ADS1115与单片机的连线:
VDD——>单片机的3.3/5V
GND——>单片机的GND
ADDR——>一般与地相连
A0-3——>与输入的电压线相连
SCL,SDA——>单片机的SCL,SDA
ALERT——>悬空
IIC介绍
IIC是一种半双工通信协议,同一时间内只能收或者发。
一般有四种信号:开始信号,结束信号,nck信号,nack信号。
开始信号
开始信号为时钟线为高时拉低SDA线
表示IIC开始
正点原子代码:
void IIC_Start(void)
{
PB10OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
结束信号
结束信号为时钟线为高是拉高SDA
表示IIC通信结束
正点原子代码:
//产生IIC停止信号
void IIC_Stop(void)
{
//SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
ack信号
ack信号是产生一个应答信号,在接收到设备的信号后产生ack信号给发出的设备,让发出设备知道已经被接受了
正点原子代码:
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
PB10OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
nack信号
nack信号是不产生应答信号
正点原子代码:
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
//SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
读数据
读数据步骤
1.产生IIC开始信号
2.发送地址
3.发送读操作命令(2.3合在一起为8位)
4.等待接受应答
5.读数据
6.产生结束信号
写数据
1.产生IIC开始信号
2.发送地址
3.发送写操作命令(2.3合在一起为8位)
4.等待接受应答
5.写数据
6.产生结束信号
以上是IIC的大概介绍,只是让大家对下面的代码好理解
代码讲解
ADS1115的配置大概分为四步
一.对Lo_thresh 和 Hi_thresh 寄存器的配置
这个寄存器应该是配置读取的电压正负,如果读取正电压的话一般不用配置,我这里就没有对这个寄存器进行配置。
二.对config寄存器进行配置
对config寄存器配置需要几步
1.写入地址
2.通过操作pointer寄存器来指向config寄存器
3.写入config寄存器的高位
4.写入config寄存器的低位
void ads_init()
{
delay_init();
address_ads=address_gnd+write;
config=Pointer_1;
config_H=os_1+mux_7+fs_0+mode_0;//配置ads1115的模式(高位)
config_L=dr_7+comp_mode_0+comp_pol_0+comp_lat_0+comp_que_3;//配置ads1115的模式(低位)
IIC_Init();
IIC_Start();
/*写地址ads1115*/
IIC_Send_Byte(address_ads);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115数据,用pointer寄存器来配置config寄存器*/
IIC_Send_Byte(config);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115数据,写config寄存器高位*/
IIC_Send_Byte(config_H);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115数据,写config寄存器低位*/
IIC_Send_Byte(config_L);
IIC_Wait_Ack();
delay_ms(20);
IIC_Stop();
}
对于config寄存器,ti官网的数据手册里有
一般着重配置mux,pga,dr这几个寄存器
三.配置Conversion寄存器
这一步主要是用pointer指向conversion寄存器
void ads_read()
{
address_ads=address_gnd+write;
config_1=Pointer_0;
delay_init();
IIC_Init();
IIC_Start();
/*写地址ads1115*/
IIC_Send_Byte(address_ads);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115 配置寄存器*/
IIC_Send_Byte(config_1);
IIC_Wait_Ack();
delay_ms(20);
IIC_Stop();
}
这是pointer寄存器
四.开始读数据
这一步开始对ads1115里采样到的数据开始处理
float ads_write()
{
uart_init(9600);
delay_init();
address_ads_r=address_gnd+read;
IIC_Init();
IIC_Start();
/*写地址ads1115*/
IIC_Send_Byte(address_ads_r);
delay_ms(20);
IIC_Wait_Ack();
/*读取ADS1115的第一个字节*/
result_0=IIC_Read_Byte(1);
delay_ms(20);
/*读取ADS1115的第二个字节*/
result_1=IIC_Read_Byte(1);
IIC_Stop();
res_0=result_0;
res_1=result_1;
result=res_0*256+res_1;
/*返回读取到的数据*/
return result;
}
因为数据一共有16位所以分两次来读写。
数据处理:为了数据稳定我采用了滤波的方法,其实滤波与否影响不大。我采用了中位值平均滤波,这也是学长所建议的。
/*寻找数据最大值*/
float max_find(float a[10])
{
int j;
float max=-999;
for(j=0;j<10;j++)
{
if(a[j]>max)
max=a[j];
else
max=max;
}
return max;
}
/*寻找数据最小值*/
float min_find(float a[10])
{
int j;
float min=99999;
for(j=0;j<10;j++)
{
if(a[j]
min=a[j];
else
min=min;
}
return min;
}
/*中位值平均滤波算法*/
/*去除最高数,去除最低数取平均*/
float adv()
{
delay_init();
float value[10];
int i,max,min,count;
float sum;
for(i=0;i<10;i++)
{
delay_us(15);
value
=ads_write();
}
max=max_find(value);
min=min_find(value);
for(count=0;count<10;count++)
{
sum+=value[count];
}
sum=sum-max-min;
sum=sum/8;
return sum;
}
我定义了两个函数,一个是寻最大值,一个是寻最小值,最后删去这两个数取平均。
下面的函数是最终要调用到main主函数里的函数
/*最终返回到主函数的函数,在main函数里调用*/
float ads1115()
{
float tem,dianya;
tem=adv();
if(tem>=0x8000)
dianya=((float)(0xffff-tem)/32768.0)*6.144;
else
dianya=((float)tem/32768.0)*6.144;
delay_ms(10);
return dianya;
}
这就是整体代码的思路,其中IIC通信的部分我用了正点原子的库。
下面是我的.h文件
#ifndef _1115_H_
#define _1115_H_
#define address_gnd 0x90
#define read 0x01
#define write 0x00
#define Pointer_0 0x00
#define Pointer_1 0x01
#define os_1 0x80
#define os_0 0x00
#define mux_0 0x00 //AINp=AIN0, AINn=AIN1
#define mux_1 0x10 //AINp=AIN0, AINn=AIN3
#define mux_2 0x20 //AINp=AIN1, AINn=AIN3
#define mux_3 0x30 //AINp=AIN2, AINn=AIN3
#define mux_4 0x40 //AINp=AIN0 , AINn=GND
#define mux_5 0x50 //AINp=AIN1, AINn=GND
#define mux_6 0x60 //AINp=AIN2, AINn=GND
#define mux_7 0x70 //AINp=AIN3, AINn=GND 更改通道需要更改mux的值
#define fs_0 0x00 //FS=6.144V
#define fs_1 0x20 //FS=4.096V
#define fs_2 0x40 //FS=2.048V
#define fs_3 0x60 //FS=1.024V
#define fs_4 0x80 //FS=0.512V
#define fs_5 0xA0 //FS=0.256V
#define fs_6 0xC0 //FS=0.256V
#define fs_7 0xE0 //FS=0.256V
#define mode_0 0x00
#define mode_1 0x01
#define dr_0 0x00 //Data Rate = 8
#define dr_1 0x20 //Data Rate = 16
#define dr_2 0x40 //Data Rate = 32
#define dr_3 0x60 //Data Rate = 64
#define dr_4 0x80 //Data Rate = 128
#define dr_5 0xA0 //Data Rate = 250
#define dr_6 0xC0 //Data Rate = 475
#define dr_7 0xE0 //Data Rate = 860
#define comp_mode_0 0x00
#define comp_mode_1 0x10
#define comp_pol_0 0x00
#define comp_pol_1 0x08
#define comp_lat_0 0x00
#define comp_lat_1 0x40
#define comp_que_0 0x00
#define comp_que_1 0x01
#define comp_que_2 0x02
#define comp_que_3 0x03
float ads_write(void);
void ads_read(void);
void ads_init(void);
float adv(void);
float min_find(float value[10]);
float max_find(float value[10]);
float ads1115(void);
#endif
如果需要更改输入的端口的话可以选择更改MUX的部分
config_H=os_1+mux_7+fs_0+mode_0;//配置ads1115的模式(高位)
PS:ADDR接地时,地址数据是0x90
通过上面的配置就可以正常使用ADS1115了
这是我把输入接到3.3V上时所测得的数据。
ADS1115的使用
ADS1115概况
ads1115是一款低功耗16位的ADC
四路的输入,分别是:A0,A1,A2,A3
供电引脚:VDD
地:GND
与其他设备通信:SCL,SDA
地址:ADDR
比较器的结果输出:ALERT(简单应用一般用不到)
一般VDD与GND的压差为2-5.5V
ADDR接在不同的位置上时的地址是不同的
ADS1115与单片机的连线:
VDD——>单片机的3.3/5V
GND——>单片机的GND
ADDR——>一般与地相连
A0-3——>与输入的电压线相连
SCL,SDA——>单片机的SCL,SDA
ALERT——>悬空
IIC介绍
IIC是一种半双工通信协议,同一时间内只能收或者发。
一般有四种信号:开始信号,结束信号,nck信号,nack信号。
开始信号
开始信号为时钟线为高时拉低SDA线
表示IIC开始
正点原子代码:
void IIC_Start(void)
{
PB10OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
结束信号
结束信号为时钟线为高是拉高SDA
表示IIC通信结束
正点原子代码:
//产生IIC停止信号
void IIC_Stop(void)
{
//SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
ack信号
ack信号是产生一个应答信号,在接收到设备的信号后产生ack信号给发出的设备,让发出设备知道已经被接受了
正点原子代码:
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=0;
PB10OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
nack信号
nack信号是不产生应答信号
正点原子代码:
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=0;
//SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
读数据
读数据步骤
1.产生IIC开始信号
2.发送地址
3.发送读操作命令(2.3合在一起为8位)
4.等待接受应答
5.读数据
6.产生结束信号
写数据
1.产生IIC开始信号
2.发送地址
3.发送写操作命令(2.3合在一起为8位)
4.等待接受应答
5.写数据
6.产生结束信号
以上是IIC的大概介绍,只是让大家对下面的代码好理解
代码讲解
ADS1115的配置大概分为四步
一.对Lo_thresh 和 Hi_thresh 寄存器的配置
这个寄存器应该是配置读取的电压正负,如果读取正电压的话一般不用配置,我这里就没有对这个寄存器进行配置。
二.对config寄存器进行配置
对config寄存器配置需要几步
1.写入地址
2.通过操作pointer寄存器来指向config寄存器
3.写入config寄存器的高位
4.写入config寄存器的低位
void ads_init()
{
delay_init();
address_ads=address_gnd+write;
config=Pointer_1;
config_H=os_1+mux_7+fs_0+mode_0;//配置ads1115的模式(高位)
config_L=dr_7+comp_mode_0+comp_pol_0+comp_lat_0+comp_que_3;//配置ads1115的模式(低位)
IIC_Init();
IIC_Start();
/*写地址ads1115*/
IIC_Send_Byte(address_ads);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115数据,用pointer寄存器来配置config寄存器*/
IIC_Send_Byte(config);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115数据,写config寄存器高位*/
IIC_Send_Byte(config_H);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115数据,写config寄存器低位*/
IIC_Send_Byte(config_L);
IIC_Wait_Ack();
delay_ms(20);
IIC_Stop();
}
对于config寄存器,ti官网的数据手册里有
一般着重配置mux,pga,dr这几个寄存器
三.配置Conversion寄存器
这一步主要是用pointer指向conversion寄存器
void ads_read()
{
address_ads=address_gnd+write;
config_1=Pointer_0;
delay_init();
IIC_Init();
IIC_Start();
/*写地址ads1115*/
IIC_Send_Byte(address_ads);
IIC_Wait_Ack();
delay_ms(20);
/*写ADS1115 配置寄存器*/
IIC_Send_Byte(config_1);
IIC_Wait_Ack();
delay_ms(20);
IIC_Stop();
}
这是pointer寄存器
四.开始读数据
这一步开始对ads1115里采样到的数据开始处理
float ads_write()
{
uart_init(9600);
delay_init();
address_ads_r=address_gnd+read;
IIC_Init();
IIC_Start();
/*写地址ads1115*/
IIC_Send_Byte(address_ads_r);
delay_ms(20);
IIC_Wait_Ack();
/*读取ADS1115的第一个字节*/
result_0=IIC_Read_Byte(1);
delay_ms(20);
/*读取ADS1115的第二个字节*/
result_1=IIC_Read_Byte(1);
IIC_Stop();
res_0=result_0;
res_1=result_1;
result=res_0*256+res_1;
/*返回读取到的数据*/
return result;
}
因为数据一共有16位所以分两次来读写。
数据处理:为了数据稳定我采用了滤波的方法,其实滤波与否影响不大。我采用了中位值平均滤波,这也是学长所建议的。
/*寻找数据最大值*/
float max_find(float a[10])
{
int j;
float max=-999;
for(j=0;j<10;j++)
{
if(a[j]>max)
max=a[j];
else
max=max;
}
return max;
}
/*寻找数据最小值*/
float min_find(float a[10])
{
int j;
float min=99999;
for(j=0;j<10;j++)
{
if(a[j]
min=a[j];
else
min=min;
}
return min;
}
/*中位值平均滤波算法*/
/*去除最高数,去除最低数取平均*/
float adv()
{
delay_init();
float value[10];
int i,max,min,count;
float sum;
for(i=0;i<10;i++)
{
delay_us(15);
value
=ads_write();
}
max=max_find(value);
min=min_find(value);
for(count=0;count<10;count++)
{
sum+=value[count];
}
sum=sum-max-min;
sum=sum/8;
return sum;
}
我定义了两个函数,一个是寻最大值,一个是寻最小值,最后删去这两个数取平均。
下面的函数是最终要调用到main主函数里的函数
/*最终返回到主函数的函数,在main函数里调用*/
float ads1115()
{
float tem,dianya;
tem=adv();
if(tem>=0x8000)
dianya=((float)(0xffff-tem)/32768.0)*6.144;
else
dianya=((float)tem/32768.0)*6.144;
delay_ms(10);
return dianya;
}
这就是整体代码的思路,其中IIC通信的部分我用了正点原子的库。
下面是我的.h文件
#ifndef _1115_H_
#define _1115_H_
#define address_gnd 0x90
#define read 0x01
#define write 0x00
#define Pointer_0 0x00
#define Pointer_1 0x01
#define os_1 0x80
#define os_0 0x00
#define mux_0 0x00 //AINp=AIN0, AINn=AIN1
#define mux_1 0x10 //AINp=AIN0, AINn=AIN3
#define mux_2 0x20 //AINp=AIN1, AINn=AIN3
#define mux_3 0x30 //AINp=AIN2, AINn=AIN3
#define mux_4 0x40 //AINp=AIN0 , AINn=GND
#define mux_5 0x50 //AINp=AIN1, AINn=GND
#define mux_6 0x60 //AINp=AIN2, AINn=GND
#define mux_7 0x70 //AINp=AIN3, AINn=GND 更改通道需要更改mux的值
#define fs_0 0x00 //FS=6.144V
#define fs_1 0x20 //FS=4.096V
#define fs_2 0x40 //FS=2.048V
#define fs_3 0x60 //FS=1.024V
#define fs_4 0x80 //FS=0.512V
#define fs_5 0xA0 //FS=0.256V
#define fs_6 0xC0 //FS=0.256V
#define fs_7 0xE0 //FS=0.256V
#define mode_0 0x00
#define mode_1 0x01
#define dr_0 0x00 //Data Rate = 8
#define dr_1 0x20 //Data Rate = 16
#define dr_2 0x40 //Data Rate = 32
#define dr_3 0x60 //Data Rate = 64
#define dr_4 0x80 //Data Rate = 128
#define dr_5 0xA0 //Data Rate = 250
#define dr_6 0xC0 //Data Rate = 475
#define dr_7 0xE0 //Data Rate = 860
#define comp_mode_0 0x00
#define comp_mode_1 0x10
#define comp_pol_0 0x00
#define comp_pol_1 0x08
#define comp_lat_0 0x00
#define comp_lat_1 0x40
#define comp_que_0 0x00
#define comp_que_1 0x01
#define comp_que_2 0x02
#define comp_que_3 0x03
float ads_write(void);
void ads_read(void);
void ads_init(void);
float adv(void);
float min_find(float value[10]);
float max_find(float value[10]);
float ads1115(void);
#endif
如果需要更改输入的端口的话可以选择更改MUX的部分
config_H=os_1+mux_7+fs_0+mode_0;//配置ads1115的模式(高位)
PS:ADDR接地时,地址数据是0x90
通过上面的配置就可以正常使用ADS1115了
这是我把输入接到3.3V上时所测得的数据。
举报