【STM32-SPI-ADS8691数据采集系统】

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值