ADS1115 器件是兼容 IIC 的 16 位高精度低功耗模數轉換器 (ADC),采用超小型無引線 X2QFN-10 封裝和 VSSOP-10 封裝。ADS111x 器件采用了低漂移電壓基準和振蕩器。ADS1114 和 ADS1115 還采用可編程增益放大器(PGA)和數字比較器。這些特性加以較寬的工作電源電壓范圍使得 ADS1115 非常適合功率與空間受限的傳感器測量。
ADS111x 可在數據速率高達每秒 860 個樣本 (SPS) 的情況下執(zhí)行轉換。PGA 可提供從 ±256mV 到±6.144V 的輸入范圍,從而實現精準的大小信號測量。ADS1115 具有 一個輸入多路復用器 (MUX),可實現兩次差動輸入測量或四次單端輸入測量。在ADS1115 中可使用數字比較器進行欠壓和過壓檢測。ADS1115既可在連續(xù)轉換模式下工作,也可在單沖模式下工作。在單沖模式下,這些器件可在一次轉換后自動斷電;因此顯著降低了空閑期間的功耗。
02?規(guī)格參數
工作電壓:2.0-5.5V
工作電流:150uA
采集精度:16位
采集通道:4通道
控制方式:IIC
管腳數量:10 Pin(2.54mm間距排針)
以上信息見廠家資料文件
03移植過程
我們的目標是將例程移植至CW32F030C8T6開發(fā)板上【實現4路ADC采集電壓功能】。首先要獲取資料,查看數據手冊應如何實現讀取數據,再移植至我們的工程。
3.1查看資料
ADS1115是采用的IIC通信,所以首先要了解IIC的地址與時序,再確定根據寄存器的設置。
器件地址
器件地址的設置見下表:
說明:當模塊上的ADDR引腳接入GND時,其器件地址為1001000,最后一位數據是讀寫位。
時序
下圖是讀時序,步驟是:
IIC起始信號?->?發(fā)送器件地址+0(寫)?->?等待模塊應答?->?應答后發(fā)送寄存器地址?->?等待模塊應答?->?重新發(fā)送起始信號?->?發(fā)送器件地址+1(讀)?->?等待模塊應答?->?應答后讀取高8位數據?->?讀取完畢主機發(fā)送應答信號?->?讀取低8位數據?->?讀取完畢主機發(fā)送應答信號?->?發(fā)送IIC停止信號
下圖是寫時序,步驟是:
IIC起始信號?->?發(fā)送器件地址+0(寫)?->?等待模塊應答?->?應答后發(fā)送寄存器地址?->?等待模塊應答?->?應答后寫入高8位數據?->?等待模塊應答?->?寫入低8位數據?->?等待模塊應答?->?發(fā)送IIC停止信號
寄存器說明
ADS1115有四個寄存器,可通過IIC接口使用地址指針進入。
地址0X00為轉換寄存器,它包含最后一次轉換的結果。
地址0X01為配置寄存器,用于更改ADS1115的工作模式和查詢設備狀態(tài)。
另外兩個寄存器,Lo_thresh和Hi_thresh,設置用于比較器函數的閾值,我們用不到。
配置寄存器有16位,用于控制工作模式、輸入選擇、數據速率、滿量程范圍和比較器模式。
第15位:OS,讀操作時可以知道當前設備的工作狀態(tài);寫操作時可以設置單次轉換。本文配置為1(必須為斷電模式下,當對OS寫1時,設備會進入上電模式并完成一次數據轉換,然后會自動將OS置0)
第14-12位:MUX為輸入多路復用器,對輸入模式進行選擇,如下圖有八種輸入模式,分別是四種差分與四種單端輸入,本文配置為A0單端輸入(0x04)。(單端輸入就是測量的數據有兩個引腳,一個輸出一個地。將測量的輸出接入A0引腳,測量的地與ADS1115共地)
第11-9位:PGA為可編程增益放大器,設置FSR(滿刻度的范圍),本文配置為±4.096V(0x01)后面電壓計算公式與這個有關。
第8位:MODE選擇持續(xù)轉換模式與單次轉換模式(單次轉換模式需要OS位觸發(fā)),本文配置為連續(xù)轉換模式(0x00)
第7-5位:DR配置data rate數據傳輸速率,本文配置為128SPS(0x04)
第4-2位:對比較器的配置,我們不使用,默認為0即可(0x00) 第1-0位:本位配置為關閉比較器并將ALERT/RDY引腳設置為高阻抗模式(0x03)
最終得到的配置結果為1100_0010_1000_0011(0xC283)。
當前配置的是A0的引腳,我們后續(xù)獲取數據也是從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();//重新發(fā)送起始信號
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();//發(fā)送停止信號
//數據整合
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
* 函 數 說 明:主機發(fā)送應答
* 函 數 形 參: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寫一個字節(jié)
* 函 數 形 參: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個字節(jié)
* 函 數 形 參:無
* 函 數 返 回:讀出的1個字節(jié)數據
* 作 者: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 1rn");
return 1;
}
IIC_Write(add);
if( IIC_Wait_Ack() == 1 )
{
printf("error 2rn");
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();//重新發(fā)送起始信號
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();//發(fā)送停止信號
//數據整合
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;
}
?
在文件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(); // 開發(fā)板初始化
uart1_init(115200); // 串口1波特率115200
ADS1115_GPIO_Init();
printf("demo startrn");
while(1)
{
//當前設置最大量程為4.096V
printf("A0 = %.4frn", ReadADS1115(0x00) );//讀取A0的值
delay_ms(1000);
}
}
移植現象:將A0接入GND、3.3V和5V。
模塊移植成功案例代碼:
鏈接:https://pan.baidu.com/s/1A6SRdtHRT5N7uUNE6Y08YQ?pwd=LCKF
提取碼:LCKF