专栏名称: 武汉芯源半导体
武汉芯源半导体有限公司,于2018年8月28日成立,注册资本伍仟万元,为上市公司武汉力源信息技术股份有限公司全资子公司,专业负责自研芯片的研发、设计、推广、销售及技术服务相关业务。
目录
相关文章推荐
左右为篮  ·  一件T恤过冬!?90鹅绒小白T,防风抗寒超抗 ... ·  19 小时前  
左右为篮  ·  突发!JB禁赛! ·  昨天  
江南都市报  ·  冲撞裁判!CBA开出重磅罚单!赵睿道歉 ·  2 天前  
江南都市报  ·  冲撞裁判!CBA开出重磅罚单!赵睿道歉 ·  2 天前  
左右为篮  ·  泸州老窖疯了?! ·  3 天前  
左右为篮  ·  校园女神!这是什么逆天身材啊 ·  3 天前  
51好读  ›  专栏  ›  武汉芯源半导体

【CW32模块使用】ADS1115多路模数转换器

武汉芯源半导体  · 公众号  ·  · 2024-11-12 10:28

正文

ADS1115 器件是兼容 IIC 的 16 位高精度低功耗模数转换器 (ADC),采用超小型无引线 X2QFN-10 封装和 VSSOP-10 封装。ADS111x 器件采用了低漂移电压基准和振荡器。ADS1114 和 ADS1115 还采用可编程增益放大器(PGA)和数字比较器。这些特性加以较宽的工作电源电压范围使得 ADS1115 非常适合功率与空间受限的传感器测量。

ADS111x 可在数据速率高达每秒 860 个样本 (SPS) 的情况下执行转换。PGA 可提供从 ±256mV 到±6.144V 的输入范围,从而实现精准的大小信号测量。ADS1115 具有 一个输入多路复用器 (MUX),可实现两次差动输入测量或四次单端输入测量。在ADS1115 中可使用数字比较器进行欠压和过压检测。ADS1115既可在连续转换模式下工作,也可在单冲模式下工作。在单冲模式下,这些器件可在一次转换后自动断电;因此显著降低了空闲期间的功耗。
01
模块来源

>>>

模块实物展示


02
 规格参数

>>>

工作电压:2.0-5.5V

工作电流:150uA

采集精度:16位

采集通道:4通道

控制方式:IIC

管脚数量:10 Pin(2.54mm间距排针)

以上信息见厂家资料文件

03
移植过程

>>>

我们的目标是将例程移植至CW32F030C8T6开发板上【实现4路ADC采集电压功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。

3.1
查看资料

ADS1115是采用的IIC通信,所以首先要了解IIC的地址与时序,再确定根据寄存器的设置。

器件地址

器件地址的设置见下表:

说明:当模块上的ADDR引脚接入GND时,其器件地址为1001000,最后一位数据是读写位。

时序

下图是读时序,步骤是:

IIC起始信号 -> 发送器件地址+0(写) -> 等待模块应答 -> 应答后发送寄存器地址 -> 等待模块应答 -> 重新发送起始信号 -> 发送器件地址+1(读) -> 等待模块应答 -> 应答后读取高8位数据 -> 读取完毕主机发送应答信号 -> 读取低8位数据 -> 读取完毕主机发送应答信号 -> 发送IIC停止信号

下图是写时序,步骤是:

IIC起始信号 -> 发送器件地址+0(写) -> 等待模块应答 -> 应答后发送寄存器地址 -> 等待模块应答 -> 应答后写入高8位数据 -> 等待模块应答 -> 写入低8位数据 -> 等待模块应答 -> 发送IIC停止信号

寄存器说明

ADS1115有四个寄存器,可通过IIC接口使用地址指针进入。

  • 地址0X00为转换寄存器,它包含最后一次转换的结果。

  • 地址0X01为配置寄存器,用于更改ADS1115的工作模式和查询设备状态。

  • 另外两个寄存器,Lo_thresh和Hi_thresh,设置用于比较器函数的阈值,我们用不到。

配置寄存器有16位,用于控制工作模式、输入选择、数据速率、满量程范围和比较器模式。

第15位:OS,读操作时可以知道当前设备的工作状态;写操作时可以设置单次转换。本文配置为1(必须为断电模式下,当对OS写1时,设备会进入上电模式并完成一次数据转换,然后会自动将OS置0)

第14-12位:MUX为输入多路复用器,对输入模式进行选择,如下图有八种输入模式,分别是四种差分与四种单端输入,本文配置为A0单端输入(0x04)。(单端输入就是测量的数据有两个引脚,一个输出一个地。将测量的输出接入A0引脚,测量的地与ADS1115共地)

第11-9位:PGA为可编程增益放大器,设置FSR(满刻度的范围),本文配置为±4.096V(0x01)后面电压计算公式与这个有关。

第8位:MODE选择持续转换模式与单次转换模式(单次转换模式需要OS位触发),本文配置为连续转换模式(0x00)

第7-5位:DR配置data rate数据传输速率,本文配置为128SPS(0x04)

第4-2位:对比较器的配置,我们不使用,默认为0即可(0x00) 第1-0位:本位配置为关闭比较器并将ALERT/RDY引脚设置为高阻抗模式(0x03)

最终得到的配置结果为1100_0010_1000_0011(0xC283)。

当前配置的是A0的引脚,我们后续获取数据也是从A0引脚读取。

16位转换寄存器以二进制的补码格式保存最后一次转换的结果。需要注意的是,在上电之后,转换寄存器被清除为0,并保持为0,直到第一次转换完成。

实现代码说明

读取到的ADC值如何换算为电压?

以PGA设置为4.96V为例。

电压 = 采集到的ADC值 * 分辨率

分辨率 = 测量电压范围 / (2^AD位数-1) = 4.096 / 2的15次方 = 0.000125V

分辨率也可以在数据手册中查看,见右图。其中125uV = 0.125mV = 0.000125V。


/****************************************************************** * 函 数 名 称: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);}
/****************************************************************** * 函 数 名 称: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;}


3.2
引脚选择

接线表


3.3
移植至工程

工程模板参考入门手册的工程模板

移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为bsp_ads1115.c与bsp_ads1115.h。这里不再过多讲述,移植完成后面修改相关代码。

在文件bsp_ads1115.c中,编写如下代码。

/* * Change Logs: * Date           Author       Notes * 2024-06-20     LCKFB-LP    first version */
#include "bsp_ads1115.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_InitStruct; // GPIO初始化结构体
RCC_ADS1115_ENABLE(); // 使能GPIO时钟
GPIO_InitStruct.Pins = GPIO_SCL|GPIO_SDA; // GPIO引脚 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 输出速度高 GPIO_Init(PORT_ADS1115, &GPIO_InitStruct); // 初始化
//写入配置参数 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配置 //215次方=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;}


在文件bsp_ads1115.h中,编写如下代码。

/* * Change Logs: * Date           Author       Notes * 2024-06-20     LCKFB-LP    first version */#ifndef _BSP_ADS1115_H_#define _BSP_ADS1115_H_
#include "board.h"
#define RCC_ADS1115_ENABLE() __RCC_GPIOB_CLK_ENABLE()#define PORT_ADS1115 CW_GPIOB
#define GPIO_SCL GPIO_PIN_8#define GPIO_SDA GPIO_PIN_9
//SDA输入模式#define SDA_IN() { \ GPIO_InitTypeDef GPIO_InitStruct; \ GPIO_InitStruct.Pins = GPIO_SDA; \ GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; \ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; \ GPIO_Init(PORT_ADS1115, &GPIO_InitStruct); \ }//SDA输出模式#define SDA_OUT() { \ GPIO_InitTypeDef GPIO_InitStruct; \ GPIO_InitStruct.Pins = GPIO_SDA; \ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; \ GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; \ GPIO_Init(PORT_ADS1115, &GPIO_InitStruct); \ }
#define SCL(BIT) GPIO_WritePin( PORT_ADS1115, GPIO_SCL, BIT?GPIO_Pin_SET:GPIO_Pin_RESET )#define SDA(BIT) GPIO_WritePin( PORT_ADS1115, GPIO_SDA, BIT?GPIO_Pin_SET:GPIO_Pin_RESET )#define GETSDA() GPIO_ReadPin( 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


04
移植验证

>>>

在自己工程中的main主函数中,编写如下。

/* * Change Logs: * Date           Author       Notes * 2024-06-20     LCKFB-LP    first version */#include "board.h"#include "stdio.h"#include "bsp_uart.h"#include "bsp_ads1115.h"
int32_t main(void){ board_init(); // 开发板初始化
uart1_init(115200); // 串口1波特率115200
ADS1115_GPIO_Init();
printf("demo start\r\n"); while(1) { //当前设置最大量程为4.096V printf("A0 = %.4f\r\n", ReadADS1115(0x00) );//读取A0的值 delay_ms(1000); }}

移植现象:将A0接入GND、3.3V和5V。

模块移植成功案例代码:

链接:https://pan.baidu.com/s/1A6SRdtHRT5N7uUNE6Y08YQ?pwd=LCKF

提取码:LCKF


END

往期回顾

REVIEW

【产品应用】CW32电动工具产品开源

【产品应用】基于CW32的智能充电宝(方案开源)

【产品应用】CW-W88水泵通用控制板设计方案(已开源)

【产品应用】基于CW32的角磨机控制器产品方案

【产品方案】基于CW32F030C8的低压无刷风机无感控制器

【产品方案】基于CW32的无刷直流空心杯电机有感控制驱动方案

【产品方案】基于CW32的无刷直流空心杯电机无感方波控制驱动方案

从0到1,开启产品级智能硬件设计之路!

CW32生态社区(WX)群




扫码加入QQ群

3群| 610403240

获取资料及“开发者扶持计划”第一手资讯