STM32开发项目:ADS1115的驱动与使用

STM32开发项目:ADS1115的驱动与使用日期作者版本说明2020.09.24TaoV0.0完成主体内容的撰写目录ADS1115介绍驱动源码头文件源文件使用指南基本步骤注意事项ADS1115介绍ADS1115是具有PGA、振荡器、电压基准、比较器的16位、860SPS、4通道Δ-ΣADC,数据通过一个I2C兼容型串行接口进行传输。有关它的详细说明可以参考官方数据手册。驱动源码头文件#ifndef__ADS1115_H__#define__ADS1115_H__#include…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

日期 作者 版本 说明
2020.09.24 Tao V1.0 发布第一版文档
2020.10.20 Tao V1.1 改进了void ADS1115_RefreshAllChannel()函数的实现,增加了出错检查机制
2020.11.30 Tao V1.2 增加了使用RTOS时的ADS1115应用说明

ADS1115介绍

ADS1115是具有 PGA、振荡器、电压基准、比较器的 16 位、860SPS、4 通道 Δ-Σ ADC,数据通过一个 I2C 兼容型串行接口进行传输。有关它的详细说明可以参考官方数据手册

驱动源码

头文件

#ifndef __ADS1115_H__
#define __ADS1115_H__

#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"

#ifdef ADS1115
#include "i2c_virtual.h"

#define ADS1115_SCL_PORT 'A'
#define ADS1115_SCL_PIN 6

#define ADS1115_SDA_PORT 'A'
#define ADS1115_SDA_PIN 5

#define Accuracy 32768 //ADC单端输入15位精度
#define ADS1115_ADDRESS_0 0x90 //ADDR PIN ->GND
#define ADS1115_ADDRESS_1 0x92 //ADDR PIN ->VDD
#define ADS1115_ADDRESS_2 0x94 //ADDR PIN ->SDA
#define ADS1115_ADDRESS_3 0x96 //ADDR PIN ->SCL

//*************ADDR Initial********************/
#define ADS1115_ADDRESS ADS1115_ADDRESS_0 //ADDR PIN ->GND
#define ADS1115_ADDRESS_W ADS1115_ADDRESS|0x00 //write address
#define ADS1115_ADDRESS_R ADS1115_ADDRESS|0x01 //read address

/************POINTER REGISTER*****************/
#define ADS1115_Pointer_ConverReg 0x00 //Convertion register
#define ADS1115_Pointer_ConfigReg 0x01 //Config register
#define ADS1115_Pointer_LoThreshReg 0x02 //Lo_thresh register
#define ADS1115_Pointer_HiThreshReg 0x03 //Hi_thresh register

/************CONFIG REGISTER*****************/

//Bit[15]
#define ADS1115_OS_OperationalStatus 0x0000 //No Effect
#define ADS1115_OS_SingleConverStart 0x8000 //Begin a single conversion
//Bits[14:12]
#define ADS1115_MUX_Differ_01 0x0000 //AINp=AIN0, AINn=AIN1(default)
#define ADS1115_MUX_Differ_03 0x1000 //AINp=AIN0, AINn=AIN3
#define ADS1115_MUX_Differ_13 0x2000 //AINp=AIN1, AINn=AIN3
#define ADS1115_MUX_Differ_23 0x3000 //AINp=AIN2, AINn=AIN3
#define ADS1115_MUX_Channel_0 0x4000 //AINp=AIN0, AINn=GND
#define ADS1115_MUX_Channel_1 0x5000 //AINp=AIN1, AINn=GND
#define ADS1115_MUX_Channel_2 0x6000 //AINp=AIN2, AINn=GND
#define ADS1115_MUX_Channel_3 0x7000 //AINp=AIN3, AINn=GND
//Bits[11:9]
#define ADS1115_PGA_6144 0x0000 //FS=6.144V
#define ADS1115_PGA_4096 0x0200 //FS=4.096V
#define ADS1115_PGA_2048 0x0400 //FS=2.048V(default)
#define ADS1115_PGA_1024 0x0600 //FS=1.024V
#define ADS1115_PGA_0512 0x0800 //FS=0.512V
#define ADS1115_PGA_0256 0x0A00 //FS=0.256V
//Bit[8]
#define ADS1115_MODE_ContinuConver 0x0000 //Continuous conversion mode
#define ADS1115_MODE_SingleConver 0x0100 //Power-down single-shot mode(default)
//Bits[7:5]
#define ADS1115_DataRate_8 0x0000 //Data Rate = 8
#define ADS1115_DataRate_16 0x0020 //Data Rate = 16
#define ADS1115_DataRate_32 0x0040 //Data Rate = 32
#define ADS1115_DataRate_64 0x0060 //Data Rate = 64
#define ADS1115_DataRate_128 0x0080 //Data Rate = 128(default)
#define ADS1115_DataRate_250 0x00A0 //Data Rate = 250
#define ADS1115_DataRate_475 0x00C0 //Data Rate = 475
#define ADS1115_DataRate_860 0x00E0 //Data Rate = 860
//Bit[4]
#define ADS1115_COMP_MODE_0 0x0000 //Traditional comparator with hysteresis
#define ADS1115_COMP_MODE_1 0x0010 //Window comparator
//Bit[3]
#define ADS1115_COMP_POL_0 0x0000 //Active low
#define ADS1115_COMP_POL_1 0x0008 //Active high
//Bit[2]
#define ADS1115_COMP_LAT_0 0x0000 //Non-latching comparator
#define ADS1115_COMP_LAT_1 0x0004 //Latching comparator
//Bits[1:0]
#define ADS1115_COMP_QUE_0 0x0000 //Assert after one conversion
#define ADS1115_COMP_QUE_1 0x0001 //Assert after two conversion
#define ADS1115_COMP_QUE_2 0x0002 //Assert after four conversion
#define ADS1115_COMP_QUE_3 0x0003 //Disable Comparator

typedef struct
{ 
   
    u16 OS;
    u16 MUX;
    u16 PGA;
    u16 MODE;
    u16 DataRate;
    u16 COMP_MODE;
    u16 COMP_POL;
    u16 COMP_LAT;
    u16 COMP_QUE;
} ADS1115_InitTypeDefine;

extern int16_t ADS1115_RawData[4];

void ADS1115_Init();
void ADS1115_UserConfig1();
void ADS1115_UserConfig2();
u8 ADS1115_Config(ADS1115_InitTypeDefine* ADS1115_InitStruct);

u8 ADS1115_ReadRawData(int16_t* rawData);
void ADS1115_ScanChannel(uint8_t channel);
float ADS1115_RawDataToVoltage(int16_t rawData);

float ADS1115_GetVoltage();
float ADS1115_GetAverageVoltage(uint16_t num);

void ADS1115_RefreshAllChannel();

#endif
#endif

Jetbrains全家桶1年46,售后保障稳定

源文件

#include "ads1115.h"

#ifdef ADS1115

static ADS1115_InitTypeDefine ADS1115_InitType;

/** * 可供外部调用的全局变量,记录了ADS1115采样的原始16位数据。调用void ADS1115_RefreshAllChannel( )函数可以刷新这个变量。 * 通过定义宏ADS1115_USE_FILTER,可以将ADS1115的轮询采样数据经过滑动滤波后,保存到ADS1115_RawData[]中。 * 通过float ADS1115_RawDataToVoltage(int16_t rawData)函数可以将ADS1115_RawData[]换算成对应的电压值。 */
int16_t ADS1115_RawData[4] = { 
   0};


/** * @brief 完成芯片控制端口初始化,并设置初始状态 */
void ADS1115_Init()
{ 
   
	I2C_Virtual_ConfigPort(ADS1115_SDA_PORT, ADS1115_SDA_PIN, ADS1115_SCL_PORT, ADS1115_SCL_PIN);
}


/** * @brief Configuration of ADS1115, single-shot */
void ADS1115_UserConfig1()
{ 
   
	ADS1115_InitType.COMP_LAT = ADS1115_COMP_LAT_0;
	ADS1115_InitType.COMP_MODE = ADS1115_COMP_MODE_0;
	ADS1115_InitType.COMP_POL = ADS1115_COMP_POL_0;
	ADS1115_InitType.DataRate = ADS1115_DataRate_475;
	ADS1115_InitType.MODE = ADS1115_MODE_SingleConver;
	ADS1115_InitType.MUX = ADS1115_MUX_Channel_0;
	ADS1115_InitType.OS = ADS1115_OS_SingleConverStart;
	ADS1115_InitType.PGA = ADS1115_PGA_4096;

	ADS1115_Config(&ADS1115_InitType);
}


/** * @brief Configuration of ADS1115, continuous conversion */
void ADS1115_UserConfig2()
{ 
   
	ADS1115_InitType.COMP_LAT = ADS1115_COMP_LAT_0;
	ADS1115_InitType.COMP_MODE = ADS1115_COMP_MODE_0;
	ADS1115_InitType.COMP_POL = ADS1115_COMP_POL_0;
	ADS1115_InitType.DataRate = ADS1115_DataRate_475;
	ADS1115_InitType.MODE = ADS1115_MODE_ContinuConver;
	ADS1115_InitType.MUX = ADS1115_MUX_Channel_0;
	ADS1115_InitType.OS = ADS1115_OS_OperationalStatus;
	ADS1115_InitType.PGA = ADS1115_PGA_4096;

	ADS1115_Config(&ADS1115_InitType);
}


/** * @brief 配置ADS1115 * @param ADS1115_InitStruct: 用来配置ADS1115的结构体变量指针 * @return 配置结果 * @arg: fail * @arg: success */
u8 ADS1115_Config(ADS1115_InitTypeDefine *ADS1115_InitStruct)
{ 
   
	u16 Config;
	u8 Writebuff[2];

	Config = ADS1115_InitStruct->OS + ADS1115_InitStruct->MUX + ADS1115_InitStruct->PGA + ADS1115_InitStruct->MODE
			+ ADS1115_InitStruct->DataRate + ADS1115_InitStruct->COMP_MODE + ADS1115_InitStruct->COMP_POL
			+ ADS1115_InitStruct->COMP_LAT + ADS1115_InitStruct->COMP_QUE;

	Writebuff[0] = (unsigned char) ((Config >> 8) & 0xFF);
	Writebuff[1] = (unsigned char) (Config & 0xFF);

	I2C_Virtual_Start();					//启动总线
	I2C_Virtual_SendByte(ADS1115_ADDRESS_W);		//发送器件地址(写)

	if (I2C_Virtual_ack == 0)
		return (0);

	I2C_Virtual_SendByte(ADS1115_Pointer_ConfigReg);		//发送寄存器地址

	if (I2C_Virtual_ack == 0)
		return (0);

	I2C_Virtual_SendByte(Writebuff[0]);		//发送数据

	if (I2C_Virtual_ack == 0)
		return (0);

	I2C_Virtual_SendByte(Writebuff[1]);		//发送数据

	if (I2C_Virtual_ack == 0)
		return (0);

	I2C_Virtual_Stop();

	return (1);
}



/** * @brief 读取ADS1115当前通道下的原始数据 * @param rawData: 传入一个int16_t整型变量的指针,ADS1115的原始数据将保存在这个变量中 * @return 读取结果 * @arg 0: fail * @arg 1: success */
uint8_t ADS1115_ReadRawData(int16_t *rawData)
{ 
   
	unsigned char Result[2];

	I2C_Virtual_Start();															//启动总线
	I2C_Virtual_SendByte(ADS1115_ADDRESS_W);					//发送器件地址(写)

	if (I2C_Virtual_ack == 0)
		return (0);

	I2C_Virtual_SendByte(ADS1115_Pointer_ConverReg); 	//发送寄存器地址

	if (I2C_Virtual_ack == 0)
		return (0);

	I2C_Virtual_Stop();
	delay_us(10);
	I2C_Virtual_Start();											//写寄存器之后需要重新启动总线

	I2C_Virtual_SendByte(ADS1115_ADDRESS_R);						//发送器件地址(读)

	if (I2C_Virtual_ack == 0)
		return (0);

	Result[0] = I2C_Virtual_RcvByte();		//接收数据
	I2C_Virtual_Ack();			//发送就答位
	Result[1] = I2C_Virtual_RcvByte();
	I2C_Virtual_NoAck();			//发送非应位
	I2C_Virtual_Stop(); 			//结束总线

	*rawData = (int16_t) (((Result[0] << 8) & 0xFF00) | (Result[1] & 0xFF));

	return 1;
}


/** * @brief Switch the channel of ADS1115 * @param channel */
void ADS1115_ScanChannel(uint8_t channel)
{ 
   
	switch (channel)
	{ 
   
	case 0:
		ADS1115_InitType.MUX = ADS1115_MUX_Channel_0;
		break;
	case 1:
		ADS1115_InitType.MUX = ADS1115_MUX_Channel_1;
		break;
	case 2:
		ADS1115_InitType.MUX = ADS1115_MUX_Channel_2;
		break;
	case 3:
		ADS1115_InitType.MUX = ADS1115_MUX_Channel_3;
		break;
	default:
		break;
	}

	ADS1115_Config(&ADS1115_InitType);
}


/** * @brief 将传感器的原始采样数据转化为电压数据, * 根据ADS1115_InitType结构体中包含的增益信息计算 * @param rawData: 待转换的原始数据 * @retval 返回经过计算的电压值 */
float ADS1115_RawDataToVoltage(int16_t rawData)
{ 
   
	float voltage;

	switch (ADS1115_InitType.PGA)
	{ 
   
	case ADS1115_PGA_0256:
		voltage = rawData * 0.0078125;
		break;

	case ADS1115_PGA_0512:
		voltage = rawData * 0.015625;
		break;

	case ADS1115_PGA_1024:
		voltage = rawData * 0.03125;
		break;

	case ADS1115_PGA_2048:
		voltage = rawData * 0.0625;
		break;

	case ADS1115_PGA_4096:
		voltage = rawData * 0.125;
		break;

	case ADS1115_PGA_6144:
		voltage = rawData * 0.1875;
		break;

	default:
		voltage = 0;
		break;
	}

	return voltage;
}


/** * @brief 直接获取ADS1115当前通道的电压采样值 * @return 电压采样值 */
float ADS1115_GetVoltage()
{ 
   
	int16_t rawData;

	ADS1115_ReadRawData(&rawData);

	return ADS1115_RawDataToVoltage(rawData);
}


/** * @brief 获取并计算ADC采样的平均电压值 * @param num: 计算平均值的数量 * @retval 电压采样的平均值 */
float ADS1115_GetAverageVoltage(uint16_t num)
{ 
   
	int32_t sum = 0;
	int16_t rawData;

	if(num == 0)
	{ 
   
		return ADS1115_GetVoltage( );
	}

	for(uint16_t i =0; i< num;i++)
	{ 
   
		ADS1115_ReadRawData(&rawData);
		sum += rawData;
	}

	return ADS1115_RawDataToVoltage(sum/num);
}

/** * @brief 刷新ADS1115全部通道的采样数据 * 由于ADS1115通道切换后需要等待较长时间数据才能够稳定, * 在进行多路数据采集的时候,切换通道后延时阻塞等待切换完成会占用过多的系统时间, * 因此需要在一个定时器中轮询采集ADS1115数据,每次采集完成后,切换到下一个通道 * 大幅度提高了系统工作的效率。 * * 调用此函数可以刷新全局变量ADS1115_RawData[4]的值。 * * 应当在一个定时器更新中断服务函数中周期性的调用此函数,更新周期最好小于200Hz */
void ADS1115_RefreshAllChannel()
{ 
   
	static uint8_t channel = 0;
	int16_t adcDataTemp = 0;

	//通道切换时可能有不确定的数据读出,因此需要将前1~2次读出的数据舍弃
	ADS1115_ReadRawData(&adcDataTemp);
	ADS1115_ReadRawData(&adcDataTemp);

	//读取数据返回正确,则将读到的数据写入ADS1115_RawData数组中
	if( ADS1115_ReadRawData(&adcDataTemp) !=0 )
	{ 
   
		ADS1115_RawData[channel] = adcDataTemp;
	}
	
	//ADS1115总共4个通道
	channel++;
	
	if(channel>ADS1115_MAX_CHANNEL-1)
		channel = 0;

	//结束采样后切换至下一通道
	ADS1115_ScanChannel(channel);
}
#endif

使用指南

基本步骤

  1. 初始化软件模拟I2C或者硬件I2C外设(以笔者编写的软件模拟I2C库为例)
	I2C_Virtual_ConfigPort(ADS1115_SDA_PORT, ADS1115_SDA_PIN, ADS1115_SCL_PORT, ADS1115_SCL_PIN);
	I2C_Virtual_SwitchBus(ADS1115_SDA_PORT, ADS1115_SDA_PIN, ADS1115_SCL_PORT, ADS1115_SCL_PIN);
  1. 初始化ADS1115芯片的配置。笔者在驱动库中提供了两种初始化配置函数void ADS1115_UserConfig1()void ADS1115_UserConfig2(),可以修改这两个函数中的配置参数后直接调用。
	ADS1115_UserConfig2();
  1. 设置或者切换ADS1115的通道(配置完ADS1115之后,可以设置一个初始通道)。
	ADS1115_ScanChannel(1);
  1. 根据项目的需要,选择采集原始数据然后在其他地方换算成电压数据,或者直接采集电压数据以及滤波后的电压数据。
	int16_t rawData = 0;
	float voltage = 0;
	
	//获取ADS1115采集的原始16位数据
	ADS1115_ReadRawData(&rawDAta);
	//将ADS1115采集的原始16位数据换算为实际电压值
	voltage = ADS1115_RawDataToVoltage(rawData);

	//直接获取ADS1115采集的电压数据
	voltage = ADS1115_GetVoltage();
	
	//直接获取ADS1115采集的电压数据(经过多次采样计算平均值)
	voltage = ADS1115_GetAverageVoltage(10);

注意事项

不使用实时操作系统

  • 对于多通道采样,每次通道切换时,应当等待几毫秒的时间后再进行采样,否则采样的数据可能不稳定或者发生通道间干扰。
	int32_t ADC_Temp_Filter[4] = { 
   0};
	float ADC_Temp[4] = { 
   0};
	
	for (uint8_t chan = 0; chan < 4; chan++)
	{ 
   
		ADS1115_ScanChannel(chan);
		delay_ms(5);
		ADS1115_ReadRawData(&dataTemp);
		//Keep 3 decimal places and filter
		ADC_Temp_Filter[chan] = (int32_t)(ADS1115_GetVoltage()*1000);
		ADC_Temp[chan] = Filter_MovingAverage(ADC_Temp_Filter[chan],chan)/1000.0;
	}
  • 由于多通道切换的通道稳定等待时间的存在,上面的代码耗时将会很长(>20ms)。如果在中断服务函数中执行了这些代码,将会导致单片机的性能严重下降。因此,需要考虑在定时器更新中断服务函数中周期性的调用void ADS1115_RefreshAllChannel()。每次调用将刷新一个通道的数据,四次调用便可以将全部通道的数据都刷新一遍,大大提高了代码的运行效率。示例如下:

    • 软件定时器1以40Hz的频率周期性的调用void ADS1115_RefreshAllChannel(),以获得10Hz的全通道数据刷新速度。
    • 软件定时器0以10Hz的频率处理ADS1115的原始采样数据(换算成电压、滤波、校正等)与其他传感器的数据。
    • 通过多个更新周期不同的定时器的配合,可以在无代码延时的情况下解决不同传感器数据采集速度不一致的问题,周期性的调用代替了延时等待。
/** * @brief 设置软件定时器,主要包括初始化与开启各个软件定时器 */
void User_SetupTimer()
{ 
   
	//Poll frequency of software timer is 1KHz

	//SW_Timer0 for refresh sensor data and modbus action. Freq. = 10Hz
	SoftwareTimer_Init(0, 100, User_SoftwareTimer0_Handler, -1);

	//SW_Timer1 for ads1115 data acquisition. Freq. = 40Hz
	SoftwareTimer_Init(1, 25, User_SoftwareTimer1_Handler, -1);

	//SW_Timer2 for RS485 scan. Freq. = 10Hz
	SoftwareTimer_Init(2, 100, User_SoftwareTimer2_Handler, -1);

	//SW_Timer3 for MTSICS. Freq. = 10Hz
	SoftwareTimer_Init(3, 100, User_SoftwareTimer3_Handler, -1);

	//SW_Timer4 for RS100 (Printer has not been used). Freq. = 10Hz
	SoftwareTimer_Init(4, 100, User_SoftwareTimer4_Handler, -1);

	SoftwareTimer_Enable(0);
	SoftwareTimer_Enable(1);
	SoftwareTimer_Enable(2);
	SoftwareTimer_Enable(3);
	SoftwareTimer_Enable(4);
}


/** * @brief 软件定时器1的更新服务函数 */
void User_SoftwareTimer0_Handler()
{ 
   
	User_RefreshData();
	User_RefreshAction();
}


/** * @brief 软件定时器2的更新服务函数 */
void User_SoftwareTimer1_Handler()
{ 
   
	ADS1115_RefreshAllChannel();
}

/** * @brief This function is called by timer update interrupt handler, which will be executed periodically. */
void User_RefreshData()
{ 
   
	for (uint8_t chan = 0; chan < 4; chan++)
	{ 
   
		ADC_Voltage[chan] = Filter_MovingAverage(ADS1115_Data[chan]*10,chan)/10.0;			//unit: mV, resolution: 0.1 mV
	}

	SensorData[0].value = OmronEC55_PV;
	SensorData[1].value = SGDAQ_PV;
	SensorData[2].value = (float)RS100_Count*0.0005;
	SensorData[3].value = MTSICS_Weight;

	//Pt100 - 1 PV (℃)
	SensorData[4].value = Pt100_RtoT(User_VoltageToResistance(ADC_Voltage[0]));
	SensorData[5].value = ADC_Voltage[1];
	SensorData[6].value = ADC_Voltage[2];
	SensorData[7].value = ADC_Voltage[3];

	//校正后的SGDAQ_PV
	SensorData[8].value = SensorData[1].value * HoldingReg_GetData(30) + HoldingReg_GetData(31);
}
  • 在两个或者多个ADS1115组合使用的情况下,对于多通道数据的采样处理应该遵循与上面相似的策略。以两个ADS1115通过软件模拟I2C组成的8通道数据采集功能为例:
volatile int16_t User_ADS1115Data[8];

/** * @brief 软件定时器2的服务函数 * 主要实现了两个ADS1115(总共8路)的数据采集功能。 */
void User_SoftwareTimer2_Handler()
{ 
   
	static uint8_t chan = 0;
	static uint8_t isData1Copyed = 0;
	static uint8_t isData2Copyed = 0;

	//Operate ADS1115-1
	if(chan < 4)
	{ 
   
		if(isData1Copyed == 0)
		{ 
   
			//将ADS1115-2采样的数据复制到User_ADS1115Data[]中
			for(uint8_t i = 0; i <4; i++)
			{ 
   
				User_ADS1115Data[i+4] = ADS1115_RawData[i];
			}
			isData1Copyed = 1;
			isData2Copyed = 0;
		}

		//切换I2C总线至ADS1115-1
		I2C_Virtual_SwitchBus(ADS1115_SDA_PORT, ADS1115_SDA_PIN, ADS1115_SCL_PORT, ADS1115_SCL_PIN);

		ADS1115_RefreshAllChannel();
	}
	//Operate ADS1115-2
	else
	{ 
   
		if(isData2Copyed == 0)
		{ 
   
			//将ADS1115-1采样的数据复制到User_ADS1115Data[]中
			for(uint8_t i = 0; i <4; i++)
			{ 
   
				User_ADS1115Data[i] = ADS1115_RawData[i];
			}
			isData2Copyed = 1;
			isData1Copyed = 0;
		}

		//切换I2C总线至ADS1115-2
		I2C_Virtual_SwitchBus(ADS1115_SDA_PORT_2, ADS1115_SDA_PIN_2, ADS1115_SCL_PORT_2, ADS1115_SCL_PIN_2);

		ADS1115_RefreshAllChannel();
	}

	chan++;
	if (chan > 7)
	{ 
   
		chan = 0;
	}
}

使用实时操作系统

在实时操作系统中使用延时函数时,任务调度器会自动切换执行低优先级任务,因此延时函数(由操作系统提供的API)不存在浪费CPU资源的问题。此时一般的做法是建立一个ADS1115的数据采集任务,在这个任务中轮询采集需要的数据。

void ADS1115Daq_task(void *pvParameters)
{ 
   
	int16_t adcDataTemp[4] = { 
   0};
	TickType_t ticks = xTaskGetTickCount();

	//配置ADS1115端口,由于采用了软件I2C通讯,因此可以直接调用虚拟I2C中的配置函数完成配置
	I2C_Virtual_ConfigPort(ADS1115_SDA_PORT, ADS1115_SDA_PIN, ADS1115_SCL_PORT, ADS1115_SCL_PIN);
	I2C_Virtual_SwitchBus(ADS1115_SDA_PORT, ADS1115_SDA_PIN, ADS1115_SCL_PORT, ADS1115_SCL_PIN);
	
	//使用内置的快速配置模板完成ADS1115的配置
	ADS1115_UserConfig2();

	while (1)
	{ 
   
		for (uint8_t chan = 0; chan < 4; chan++)
		{ 
   
			//设置ADS1115的采样通道
			ADS1115_ScanChannel(chan);
			//调用RTOS提供的API延时10ms
			vTaskDelay(10);

			if(ADS1115_ReadRawData(&adcDataTemp[chan])!=0)
			{ 
   
				//保留小数点后三位精度
				SensorData[chan].value = (float)(ADS1115_RawDataToVoltage(adcDataTemp[chan])*1000)/1000.0;
			}
		}
		//100ms 一个处理周期
		vTaskDelayUntil( &ticks, 100);
	}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/222887.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • boost lockfree queue-boost无锁队列「建议收藏」

    boost lockfree queue-boost无锁队列「建议收藏」例子如下:#include<iostream>#include<boost/lockfree/queue.hpp>intmain(){ boost::lockfree::queue<int,boost::lockfree::fixed_sized<false>>queue(128); for(inti=0;i<10000;i++) queue.push(i); while(!queue.empty())

  • Shell内值命令之exit「建议收藏」

    Shell内值命令之exit「建议收藏」Shell内值命令之exit介绍: exit用于退出当前shell环境进程结束运行,并且可以返回一个状态码.一般使用$?可以获取状态码.语法: 正确退出语法exit#默认返回状态码0,一般代表命令执行成功 错误退出语法exit非0数字#数字建议的范围0-255一般代表命令执行失败exit应用场景 1.结束当前shell进程 2.当shell进程执行出错退出时,可以返回不同的状态值代表不同的错误. 比如执行一个脚本文件里面操作一个文件时,可以返回1表示文件不存在,2表示

  • (图)春光明媚 姹紫嫣红

    (图)春光明媚 姹紫嫣红

  • winform使用SplitContainer控件[通俗易懂]

    winform使用SplitContainer控件[通俗易懂]在Windows资源管理器中,当把鼠标指针移动到TreeView控件和ListView控件之间时,可以左右拖动鼠标调整TreeView控件和ListView控件在主窗口中的大小比例,以适应不同显示内容的需要。我们可以使用SplitContainer控件实现这种功能。  可

  • HTML5移动端手机网站开发流程

    HTML5移动端手机网站开发流程最近一直在研究移动手机网站的开发,发现做手机网站没有想象中的那么难。为什么会这么说呢?我们试想下:我们连传统的PC网站都会做,难道连一个小小的手机网站难道都搞不定吗?其实手机网站就是一个微缩版的PC网站罢了!至于为什么觉得难、觉得无从下手。段亮觉得有以下几点:一、没有完整的思路和流程就像做网站的流程一样,如果你能知道它的流程,我相信就不会觉得做手机网站难!真正难的是你没有思

  • atitit.android模拟器使用报告

    atitit.android模拟器使用报告

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号