文章目录
1. 前言
本篇中ADS1118模块的驱动是代码实现的SPI时序驱动,不是使用STM32单片机内部集成的SPI外设驱动。换句话说,使用时只需将驱动源码添加到HAL库或标准库工程中,就可以像使用库函数中的函数一样使用这个源码中的函数。本篇使用STM32CubeMX实现。
2. ADS1118模块简介
ADS1118模块是一款基于德州仪器(Texas Instruments)ADS1118芯片的高精度、超小型、低功耗模拟/数字转换器模块。该模块具有四个单端或两个差分输入通道,可通过SPI接口进行配置和控制。
该模块的输入通道可以选择不同的增益配置,从2/3 V/V到16 V/V,以适应不同的传感器信号幅值。此外,它还配备了内部参考电压源和温度传感器(这个温度传感器用来监测芯片的温度,确保系统正常的运行),并具有自动数据速率调整功能,可以根据应用程序要求自动调整采样速率以最大程度地降低功耗。
ADS1118模块还包含了额外的功能,如可编程比较器、数字滤波器和内部振荡器。这些功能可以通过SPI接口进行配置和控制,使得该模块可以满足各种应用的需求。例如,使用可编程比较器可以监视传感器输入并产生中断以触发系统操作。
此外,该模块还具有超小的尺寸和低功耗特点,使其非常适合嵌入式系统和便携式设备中使用。它的工作电压范围为2.0 ~ 5.5V,最大功耗为150μA,可以在电池供电的环境下长时间工作。
总之,ADS1118模块是一款高性能、灵活可配置、超小型和低功耗的模拟/数字转换器模块。它具有优秀的精度和实时响应特性,并且适用于各种需要高精度和低噪声的应用。
ADS1118正反面实物图:
3. 移植源码到工程
提前创建一个文件夹,用来存放工程(文件夹路径建议全英文)
打开STM32CubeMX,选择芯片(这里选择STM32F103ZET6),配置Debug,ST-LINK选择Serial Wire。
使能HSE和LSE,配置时钟频率为72M。
由于要使用OLED模块显示采集到的电压值,因此配置硬件IIC,这里使能IIC1,对应STM32F103ZET6引脚为PB6和PB7。
对STM32CubeMX驱动OLED有疑问的点击这里(内含OLED驱动源码提取方式)
创建工程名,配置编译环境。
这里用keil5编译,因此选择MDK-ARM-V5。
点击配置代码生成器并生成代码。
点击GENERATE CODE即可生成代码。
打开工程存放的位置。
移植ads1118相关的.h和.c文件到工程中。
相关文件提取方式:
关注微信公众号:码上芯路人
私信:模块驱动
说明:ads1118.h中是一些宏定义和ad相关的函数声明,ads1118.c中是ad相关函数的定义。
将ads1118.h、oled.h和oledfont.h文件复制到工程文件目录Ads1118_test\Core\Inc中
将oled.c和ads1118.c文件复制到工程文件目录Ads1118_test\Core\Src中
双击打开Ads1118_test\MDK-ARM目录中UVPROJX文件,按下图提示操作。
编译后oled.h和oledfont.h将被包含在oled.c目录下,ads1118.h将被包含在ads1118.c目录下。
下面介绍驱动函数。
4. 驱动源码中函数介绍
4.1 us延时函数
由于HAL库中没有延时微秒的函数,因此自己定义一个us延时函数。
函数声明如下:
void delay_us(uint32_t us);
- uint32_t us:需要延时的微秒数。
4.2 写入和读取ADS1118配置寄存器
函数声明如下:
int16_t Write_ADS1118(uint16_t config,uint8_t discardData)
- uint16_t config:一个16位无符号整数,表示要写入到ADS1118配置寄存器中的值。
- uint8_t discardData:一个8位无符号整数,如果为0,则在读取之前将之前读取的数据丢弃;如果不为0,则会保留之前的数据。
- 返回值为一个16位有符号整数,如果discardData为0,则为此次读取得到的结果;如果discardData不为0,则为0。
4.3 初始化ADS1118
函数声明如下:
void ADS1118_Init(void);
先将一些配置信息用位运算写入配置寄存器变量中(这些配置信息见ADS1118相关资料)。然后,配置硬件连接的若干个引脚和CS、MISO、SCLK和DIN引脚的初始状态,最后,使用int16_t Write_ADS1118函数向ADS1118写入初始配置信息。
4.4 测量电压函数
函数声明如下:
int16_t ADS_SEL_Read(uint8_t road,uint8_t Ref,uint8_t mode);
- uint8_t road:要测量的路数,取值范围为 0~7,分别代表了不同的电路连接方式。
0:AINP = AIN0 and AINN = AIN1 (默认)
1:AINP = AIN0 and AINN = AIN3
2:AINP = AIN1 and AINN = AIN3
3:AINP = AIN2 and AINN = AIN3
4:AINP = AIN0 and AINN = GND
5:AINP = AIN1 and AINN = GND
6:AINP = AIN2 and AINN = GND
7:AINP = AIN3 and AINN = GND - uint8_t Ref:参考电压的大小,其取值范围为 0~7,代表了不同的参考电压大小。
0:FS = ±6.144V(1)
1:FS = ±4.096V(1)
2:FS = ±2.048V(1)
3:FS = ±1.024V(1)
4:FS = ±0.512V(1)
5、6、7:FS = ±0.256V(1) - uint8_t mode:转换模式,其取值为 0 或 1,分别代表单次转换和连续转换两种模式。
- 返回值为16位的有符号整数,由于可以读取负电压,因此有效取值范围为:-2 ^ 15——+2 ^ 15。
5. 实验
说明:实验用到的ADS1118的源码中,配置的寄存器都是芯片手册上的默认值,如需修改配置的默认寄存器,参照芯片手册修改。
5.1 单通道采样
采集AIN1—CND和AIN2—GND两个通道的电压,这两个通道分别接两路直流电源输出的3V—GND和2V—GND,将采集的电压示数显示在OLED上,并调整两路直流电源输出的电压后再次观察OLED屏上采集的电压示数。
主函数内容如下:
#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include "oled.h"
#include "ads1118.h"
#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
float Volt_Value[2]={0,0};
unsigned char str_buff1[16];
unsigned char str_buff2[16];
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_Clear();
ADS1118_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//AN1
Volt_Value[0] = ADS_SEL_Read(5,1,0)*ADS1118_CONST_4_096V_LSB_mV/1000;
/*说明:由于采集一个通道时,ADS1118模块的采样率最高达到860次/s,默认值为128次/s,
采集两个通道时采样率会大打折扣,因此不能不间断的采样,切换通道采样时要延时合适的时间再切换通道采样*/
HAL_Delay(15);
//AN2
Volt_Value[1] = ADS_SEL_Read(6,1,0)*ADS1118_CONST_4_096V_LSB_mV/1000;
HAL_Delay(15);
//显示
sprintf((char*)str_buff1,"AIN1=%.3fV",Volt_Value[0]);
OLED_ShowString(0,0,str_buff1,16);
//显示
sprintf((char*)str_buff2,"AIN2=%.3fV",Volt_Value[1]);
OLED_ShowString(0,2,str_buff2,16);
}
/* USER CODE END 3 */
}
效果如下:
ADS1118_实验1_效果
5.2 差分通道采样
采集AIN0—AIN1和AIN2—AIN3两个通道的电压差值,这两个差分通道接线是AIN0—3V,AIN1—GND;AIN2—2V,AIN3—GND,最后将采集的差值电压示数显示在OLED上,并调整两路直流电源输出的电压后再次观察OLED屏上采集的差值电压示数。
主函数内容如下:
#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include "oled.h"
#include "ads1118.h"
#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
float Ain0_1=0;
float Ain2_3=0;
unsigned char str_buff1[16];
unsigned char str_buff2[16];
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_Clear();
ADS1118_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//AIN0-AIN1
Ain0_1 = ADS_SEL_Read(0,1,0)*ADS1118_CONST_4_096V_LSB_mV/1000;
//这里与单端采样相同,仍需要延时
HAL_Delay(15);
//AIN2-AIN3
Ain2_3 = ADS_SEL_Read(3,1,0)*ADS1118_CONST_4_096V_LSB_mV/1000;
HAL_Delay(15);
//显示
sprintf((char*)str_buff1,"AIN0_1=%.3fV",Ain0_1);
OLED_ShowString(0,0,str_buff1,16);
//显示
sprintf((char*)str_buff2,"AIN2_3=%.3fV",Ain2_3);
OLED_ShowString(0,2,str_buff2,16);
}
/* USER CODE END 3 */
}
效果如下:
ADS1118_实验2_效果
5.3 芯片温度监测
通过与芯片接触,监测芯片的温度变化。
主函数内容如下:
#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include "oled.h"
#include "ads1118.h"
#include "stdio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int16_t value = 0;
float temp=0;
unsigned char str_buff[16];
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
OLED_Clear();
ADS1118_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//向ADS1118写入0x409B命令,这个命令表示读取ADS1118芯片的温度(具体见芯片手册),将读取结果存储在value变量中。
value=Write_ADS1118(0x409B,0);//读取内部温度
/*由于ADS1118芯片返回的温度数据占用了16个比特(从最高位开始占用),
但实际有效数据只有14个比特,因此需要将其右移两位来获取正确的温度数据。*/
value>>=2;
//温度可能为负数,负数以补码形式存储,那么将其转换为负数
if(value&0x20000) value=-(~(value-1));
//转换为温度值。ADS1118_CONST_C_PER_BIT表示每个比特对应的温度值
temp = value*ADS1118_CONST_C_PER_BIT;
sprintf((char*)str_buff,"temp=%.3f",temp);
OLED_ShowString(0,0,str_buff,16);
OLED_ShowCHinese(89,0,2);
}
/* USER CODE END 3 */
}
效果如下:
ADS1118_实验3_效果
说明:当两个物体温度不同时,会发生热传递,热量会从高温物体流向低温物体,高温物体降温,低温物体逐渐升温,直到两者达到热平衡。到达平衡的过程需要一定时间。