STM32-SPI-ADS8691数据采集系统
目录
一、引言
这段代码通过配置STM32F1系列微控制器的SPI2接口,实现了与 ADS8691 模数转换器的通信,完成了模拟信号的采集与数字转换。代码结构清晰,功能完善,适用于多种需要高精度ADC数据采集的嵌入式应用场景。
这段代码包括两个主要部分:spi.h 和 spi.c,以及 ADS8691.h 和 ADS8691.c。它们共同实现了通过STM32F1微控制器的SPI2接口与ADS8691模数转换器(ADC)进行通信,以采集和处理模拟信号。
二、代码架构
1、SPI驱动部分 (spi.h 和 spi.c)
1>目标
配置和控制STM32F1系列微控制器上的SPI2接口,支持16位和32位数据的发送与接收。
2>主要功能
- SPI2_Init函数 :
- 启用SPI2和相关GPIO外设时钟。
- 配置GPIOB的Pin13(SCK)、Pin15(MOSI)和Pin14(MISO)引脚为SPI通信模式。
- 初始化SPI2模块,配置时钟极性、相位、数据大小等参数。
- SPI2_TransmitReceive16函数 :
- 通过SPI2发送16位数据并接收响应。
- SPI2_TransmitReceive32函数 :
- 通过SPI2发送32位数据并接收响应。
- 将32位数据拆分为高16位和低16位,分两次传输。
3>特点
- 支持全双工通信,允许多次连续的数据传输。
- 配置灵活,支持不同的数据大小和通信模式。
2、ADS8691传感器驱动部分 (ADS8691.h 和 ADS8691.c)
1>目标
通过SPI2接口控制ADS8691 ADC模块,配置其工作参数,并读取模拟信号的数字转换结果。
2>主要功能
- ADS8691_Init函数 :
○ 初始化SPI2接口。
○ 通过发送一系列命令完成ADS8691的复位和量程配置。
○ 验证初始化是否成功,确保ADS8691处于正确的工作状态。 - ADS8691_SetRange函数 :
○ 发送命令设置ADS8691的输入量程范围(如1.25倍基准电平)。 - ADS8691_ReadADC函数 :
○ 通过SPI2接口读取ADS8691的ADC转换结果(18位数据)。
○ 数据处理:右移14位,提取有效的18位数据。 - ADS8691_ReadADC_Multiple函数 :
○ 以指定的频率,连续读取多组ADC数据。
○ 计算采样间隔,确保采样均匀分布。
3>特点
- 提供灵活的配置选项,支持不同的量程范围。
- 支持单次和多次数据采集,满足不同场景需求。
- 通过移位操作,确保ADC数据的正确解析。
3、代码整体功能
1>系统功能
• 初始化SPI2接口和ADS8691 ADC模块。
• 配置ADC的量程范围。
• 读取模拟信号的数字转换结果。
• 支持单次和连续多次数据采集,可配置采样频率。
2>应用场景
• 工业自动化:采集和监控模拟信号。
• 智能硬件:如温度、压力传感器的数据采集。
• 数据采集系统:实时监控和记录多路模拟信号。
三、源码分享
1、spi.h
// spi.h
#ifndef SPI_H
#define SPI_H
#include "stm32f10x.h"
/* SPI初始化函数 */
void SPI2_Init(void);
/* 通过SPI2同时发送和接收16位数据 */
uint16_t SPI2_TransmitReceive16(uint16_t data);
/* 通过SPI2同时发送和接收32位数据 */
uint32_t SPI2_TransmitReceive32(uint32_t data);
#endif // SPI_H
2、spi.c
// spi.c
#include "SPI.h"
/*********************************************************************************
* @ 函数名 :SPI2_Init
* @ 功能说明:SPI初始化函数
* @ 参数 :无
* @ 返回值 :无
********************************************************************************/
void SPI2_Init(void) {
SPI_InitTypeDef SPI_InitStructure; // 定义 SPI 初始化结构体
GPIO_InitTypeDef GPIO_InitStructure; // 定义 GPIO 初始化结构体
/* 启用 SPI2 和 GPIOB 的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 开启 GPIOB 外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); // 开启 SPI2 外设时钟
/* 配置 PB13 (SCK) 和 PB15 (MOSI) 引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15; // 配置引脚 PB13 和 PB15
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速度为 50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 配置为复用推挽模式 (用于 SPI)
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIO
/* 配置 PB14 (MISO) 引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; // 配置引脚 PB14
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置为浮空输入模式 (接收数据)
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIO
/* 配置 PB12 (CS) 引脚 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // 配置引脚 PB12 (片选信号 CS)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置为推挽输出模式 (手动控制 CS)
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIO
/* 配置 SPI2 模块的基本参数 */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 配置为全双工模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 设置为主机模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; // 数据帧大小设置为 16 位
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 时钟空闲状态为低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 数据在第 1 个时钟沿采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 软件管理 NSS 信号 (手动控制 CS 引脚)
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 设置时钟分频为 16 分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 数据从高位开始传输
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC 校验多项式设置为 7 (一般不用)
SPI_Init(SPI2, &SPI_InitStructure); // 初始化 SPI2 模块
/* 启用 SPI2 模块 */
SPI_Cmd(SPI2, ENABLE); // 使能 SPI2
}
/*********************************************************************************
* @ 函数名 :SPI2_TransmitReceive16
* @ 功能说明:通过 SPI2 发送和接收 16 位数据
* @ 参数 :
* - uint16_t data: 要发送的 16 位数据
* @ 返回值 :
* - uint16_t: 接收到的 16 位数据
********************************************************************************/
uint16_t SPI2_TransmitReceive16(uint16_t data) {
uint16_t received_data = 0; // 定义变量存储接收到的数据
/* 等待发送缓冲区为空 */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); // SPI_I2S_FLAG_TXE 标志表示发送缓冲区空(可以发送数据)
/* 发送数据 */
SPI_I2S_SendData(SPI2, data); // SPI_I2S_SendData 将数据写入 SPI 的发送数据寄存器
/* 等待接收完成 */
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); // SPI_I2S_FLAG_RXNE 标志表示接收缓冲区非空(数据已经接收到)
/* 从接收数据寄存器读取接收到的数据 */
received_data = SPI_I2S_ReceiveData(SPI2);
/* 返回接收到的数据 */
return received_data;
}
/*********************************************************************************
* @ 函数名 :SPI2_TransmitReceive32
* @ 功能说明:通过 SPI2 发送和接收 32 位数据
* @ 参数 :
* - uint32_t data: 要发送的 32 位数据
* @ 返回值 :
* - uint32_t: 接收到的 32 位数据
*********************************************************************************/
uint32_t SPI2_TransmitReceive32(uint32_t data) {
uint16_t high = (data >> 16) & 0xFFFF; // 提取高 16 位
uint16_t low = data & 0xFFFF; // 提取低 16 位
uint32_t received_data = 0; // 用于存储接收到的 32 位数据
/* 发送高 16 位并接收高 16 位数据 */
received_data |= ((uint32_t)SPI2_TransmitReceive16(high)) << 16;
/* 发送低 16 位并接收低 16 位数据 */
received_data |= SPI2_TransmitReceive16(low);
return received_data; // 返回接收到的 32 位数据
}
3、ADS8691.h
// ADS8691.h
#ifndef ADS8691_H
#define ADS8691_H
#include "stm32f10x.h"
#include "delay.h"
/* 定义操作 ADS8691 的指令或寄存器地址 */
#define RST_PWRCRL 0xD0046900 // 重置电源控制寄存器,执行复位操作
#define RST_PWRCRL_N 0xD0040000 // 停止复位电源控制寄存器,结束复位操作
#define RANGE_SEL_3 0xD0140008 // 设置输入范围为 3 * Vref
#define RANGE_SEL_2_5 0xD0140009 // 设置输入范围为 2.5 * Vref
#define RANGE_SEL_1_5 0xD014000A // 设置输入范围为 1.5 * Vref
#define RANGE_SEL_1_25 0xD014000B // 设置输入范围为 1.25 * Vref
#define READ_RANGE 0xC8140000 // 读取当前输入范围的命令
#define RANGE_GET_1_25 0x000B0000 // 读取到的值对应于 1.25 * Vref 的范围
#define READ_ADC 0x0 // 用于读取 ADC 转换结果的命令
/* 初始化ADS8691 */
uint8_t ADS8691_Init(void);
/* 配置基准电平 */
void ADS8691_SetRange(uint32_t range_command);
/* 读取ADC数据 */
uint32_t ADS8691_ReadADC(void);
/* 在一段频率内均匀地采取多次ADC */
void ADS8691_ReadADC_Multiple(uint32_t *adc_values, uint32_t count, uint32_t HZ);
#endif // ADS8691_H
4、ADS8691.c
// ADS8691.c
#include "ADS8691.h"
#include "spi.h"
#include "ads8691.h"
#include "spi.h"
/* 定义CS引脚操作 */
#define CS_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_12) // 将 CS 引脚拉低(置为低电平)以选择从设备,启动通信
#define CS_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_12) // 将 CS 引脚拉高(置为高电平)以取消选择从设备,结束通信
/*********************************************************************************
* @函数名 :ADS8691_Init
* @功能说明:初始化 ADS8691 ADC 芯片,完成 SPI 接口初始化和基本配置。
* @参数 :无
* @返回值 :返回错误码
*********************************************************************************/
uint8_t ADS8691_Init(void) {
SPI2_Init(); // 初始化 SPI 接口,用于与 ADS8691 芯片通信。
CS_HIGH(); // 拉高 CS 引脚,确保设备处于非选中状态。
/* 重置 ADS8691,进入默认状态 */
ADS8691_SetRange(RST_PWRCRL); // 设置重置命令 1
ADS8691_SetRange(RST_PWRCRL_N); // 设置重置命令 2
ADS8691_SetRange(RANGE_SEL_1_25); // 配置 ADS8691 的量程范围为 1.25 倍基准电平
/* 校验ADS是否初始化成功 */
CS_LOW(); // 拉低CS引脚
SPI2_TransmitReceive32(READ_RANGE); // 发送读取命令
CS_HIGH(); // 拉高CS引脚
delay_us(10); // 增加延时
CS_LOW(); // 拉低CS引脚
uint32_t adc_value = SPI2_TransmitReceive32(0); // 接收基准电压值
CS_HIGH(); // 拉高CS引脚
/* 校验电压 */
if(adc_value != RANGE_GET_1_25) // 检查读出来的基准电压是否等于设置的基准电压
return -1;
return 0;
}
/*********************************************************************************
* @函数名 :ADS8691_SetRange
* @功能说明:向 ADS8691 芯片发送范围配置命令,设置输入量程范围。
* @参数 :
* @range_command :要发送的32位范围设置命令,例如:
* - RST_PWRCRL: 复位命令 1
* - RST_PWRCRL_N: 复位命令 2
* - RANGE_SEL_1_25:1.25倍基准电压量程
* - RANGE_SEL_3: 3倍基准电压量程等。
* @返回值 :无
* @注意事项:
* - CS 引脚在通信前需要拉低,通信结束后需要拉高。
* - 该函数依赖 SPI2 接口以及 GPIO 配置,需提前初始化。
*********************************************************************************/
void ADS8691_SetRange(uint32_t range_command) {
CS_LOW(); // 拉低CS引脚
SPI2_TransmitReceive32(range_command); // 发送命令
CS_HIGH(); // 拉高CS引脚
}
/*********************************************************************************
* @函数名 :ADS8691_ReadADC
* @功能说明:读取 ADS8691 芯片的 ADC 转换结果。
* @参数 :无
* @返回值 :
* @adc_value :读取到的 18 位 ADC 转换结果,单位为无符号 32 位整数。
* @注意事项:
* - CS 引脚在通信前需要拉低,通信结束后需要拉高。
* - 在调用此函数之前,需要确保 ADS8691 已正确初始化。
*********************************************************************************/
uint32_t ADS8691_ReadADC(void) {
uint32_t adc_value = 0;
CS_LOW(); // 拉低CS引脚,选择 ADS8691 设备
adc_value = SPI2_TransmitReceive32(READ_ADC) >> 14; // 发送读取命令并获取数据,高位对齐
CS_HIGH(); // 拉高CS引脚,释放 ADS8691 设备
return adc_value; // 返回 18 位有效的 ADC 转换值
}
/*********************************************************************************
* @函数名 :ADS8691_ReadADC_Multiple
* @功能说明:高速读取 ADS8691 芯片的 ADC 转换结果,支持批量读取。
* @参数 :
* - uint32_t *adc_values: 存储读取结果的数组指针。
* - uint32_t count: 要读取的 ADC 值数量。
* @返回值 :无
* @注意事项:
* - 调用前,确保 `adc_values` 数组大小足够存储读取结果。
* - 在调用此函数之前,需要确保 ADS8691 已正确初始化。
*********************************************************************************/
void ADS8691_ReadADC_Multiple(uint32_t *adc_values, uint32_t count, uint32_t HZ) {
double time;
time = ((1 / (double)HZ) / (double)count) * 1000 * 1000; // 通过频率和需要采样的点数来计算每个采样点之间的间隔时间,将采样均匀到周期内, 微秒级别
for (uint32_t i = 0; i < count; i++) {
CS_LOW(); // 拉低 CS 引脚,启动通信
adc_values[i] = SPI2_TransmitReceive32(READ_ADC) >> 14; // 发送读取命令并接收数据,高位对齐
CS_HIGH(); // 拉高 CS 引脚,结束通信
delay_us(time);
}
}