#include "ADS1256_soft.h" #include "cmsis_os.h" #include "gpio.h" /** ****************************************************************************** * @file ADS1256.c ****************************************************************************** * @attention * ADS1256模块 * +5V <------ 5.0V 5V供电 * GND ------- GND 地 * DRDY ------> PA11 准备就绪 低准备好 高未准备好 * CS <------ PB12 SPI_CS 低有效,操作完拉高 * DIN <------ PB15 SPI_MOSI * DOUT ------> PB14 SPI_MISO * SCLK <------ PB13 SPI时钟 * GND ------- GND 地 * PDWN <------ VDD 掉电控制 常高 * RST <------ PA8 复位信号 常高,拉低再拉高生效复位 * * ADS1256基本特性: * 1、模拟部分供电5V; * 2、SPI数字接口电平:3.3V * 3、PGA设置范围: 1、2、4、8、16、32、64、 * 4、参考电压2.5V (推荐缺省的,外置的) * 5、输入电压范围:PGA = 1 时, 可输入正负5V * 6. 自动校准 (当设置了PGA,BUF使能、数据采样率时,会启动自校准) * 7. 输入的缓冲器可设置启用和关闭(一般选启用) * 外部晶振频率 = 7.68MHz, * 时钟频率 tCLK = 1/7.68M = 0.13uS * 输出数据周期 tDATA = 1 / 30K = 0.033mS (按30Ksps计算) * 对SPI的时钟速度要求: (ads1256.pdf page 6) * 最快 4个tCLK = 0.52uS * 最慢 10个tDATA = 0.3mS (按 30Ksps 计算) * SCL高电平和低电平持续时间最小 200ns * RREG, WREG, RDATA 命令之后,需要延迟 4 * tCLK = 0.52uS; * RDATAC, RESET, SYNC 命令之后,需要延迟 24 * tCLK = 3.12uS; * 实际测试,在3.3V上电后, 及时不做任何配置,ADS125的DRDY 口线即开始输出脉冲信号(2.6us高,33.4低,频率30KHz) ****************************************************************************** */ //extern SPI_HandleTypeDef ADS1256_SPI_HANDLE; // 软件SPI发送单字节(模式1,CPOL=0, CPHA=1) static void SoftSPI_WriteByte(uint8_t data) { for (uint8_t i = 0; i < 8; i++) { SOFT_SPI_SCK_LOW(); // 设置MOSI if (data & 0x80) SOFT_SPI_MOSI_HIGH(); else SOFT_SPI_MOSI_LOW(); data <<= 1; for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz // 产生时钟上升沿(从机采样) SOFT_SPI_SCK_HIGH(); for (volatile uint8_t j = 0; j < 40; j++); // ~200ns @80MHz } SOFT_SPI_SCK_LOW(); // 保持空闲状态为低 } // 软件SPI接收单字节 static uint8_t SoftSPI_ReadByte(void) { uint8_t data = 0; for (uint8_t i = 0; i < 8; i++) { data <<= 1; SOFT_SPI_SCK_HIGH(); // 插入小延时(确保数据稳定) for (volatile uint32_t j = 0; j < 40; j++); if (SOFT_SPI_MISO_READ()) data |= 0x01; SOFT_SPI_SCK_LOW(); for (volatile uint32_t j = 0; j < 40; j++); } return data; } static void ADS1256_SendCommand(uint8_t cmd) { ADS1256_CS_LOW(); for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz // HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, &cmd, 1, SPI_TIMEOUT); SoftSPI_WriteByte(cmd); for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz ADS1256_CS_HIGH(); } void ADS1256_WriteRegister(uint8_t reg, uint8_t value) { uint8_t tx[3]; tx[0] = ADS1256_CMD_WREG | (reg & 0x0F); tx[1] = 0x00; // write 1 register tx[2] = value; ADS1256_CS_LOW(); for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz // HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, tx, 3, SPI_TIMEOUT); for (uint8_t i = 0; i < 40; i++) SoftSPI_WriteByte(tx[i]); ADS1256_CS_HIGH(); osDelay(2); } uint8_t ADS1256_ReadRegister(uint8_t reg) { uint8_t tx[2] = { ADS1256_CMD_RREG | (reg & 0x0F), 0x00 }; uint8_t rx = 0; ADS1256_CS_LOW(); for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz // HAL_SPI_Transmit(&ADS1256_SPI_HANDLE, tx, 2, SPI_TIMEOUT); SoftSPI_WriteByte(tx[0]); SoftSPI_WriteByte(tx[1]); osDelay(2); // HAL_SPI_Receive(&ADS1256_SPI_HANDLE, &rx, 1, SPI_TIMEOUT); rx = SoftSPI_ReadByte(); for (uint8_t m = 0; m < 40; m++){} // ~400ns @80MHz ADS1256_CS_HIGH(); return rx; } bool ADS1256_ReadData(int32_t* out) { // 读取数据(需判断 DRDY 是否为低) uint8_t rx[3]; if (HAL_GPIO_ReadPin(ADS1256_DRDY_GPIO_PORT, ADS1256_DRDY_PIN) != GPIO_PIN_RESET) { return false; } ADS1256_CS_LOW(); // HAL_SPI_Receive(&ADS1256_SPI_HANDLE, rx, 3, SPI_TIMEOUT); rx[0] = SoftSPI_ReadByte(); rx[1] = SoftSPI_ReadByte(); rx[2] = SoftSPI_ReadByte(); ADS1256_CS_HIGH(); *out = ((int32_t)rx[0] << 16) | ((int32_t)rx[1] << 8) | rx[2]; if (*out & 0x800000) *out |= 0xFF000000; // Sign extend if negative return true; } void ADS1256_Reset(void) { // 复位 HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_RESET); osDelay(5); HAL_GPIO_WritePin(GPIOB, ADS_SYNC_PDWN_Pin, GPIO_PIN_SET); osDelay(5); ADS1256_RST_LOW(); osDelay(5); ADS1256_RST_HIGH(); osDelay(5); ADS1256_SendCommand(ADS1256_CMD_RESET); osDelay(5); } uint8_t ADS1256_ReadID(void) { // 读取芯片 ID(高 4 位) ID高4位应该是0x03 ADS1256_SendCommand(ADS1256_CMD_SYNC); ADS1256_SendCommand(ADS1256_CMD_WAKEUP); osDelay(1); uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS); return (status >> 4) & 0x0F; // 屏蔽低4位 } void ADS1256_SetChannel(uint8_t mux) { // 设置输入通道(MUX 寄存器值) ADS1256_WriteRegister(ADS1256_REG_MUX, mux); ADS1256_SendCommand(ADS1256_CMD_SYNC); ADS1256_SendCommand(ADS1256_CMD_WAKEUP); } void ADS1256_SetGain(ADS1256_Gain_t gain) { // 设置增益 uint8_t adcon = ADS1256_ReadRegister(ADS1256_REG_ADCON); adcon &= 0xF8; adcon |= (gain & 0x07); ADS1256_WriteRegister(ADS1256_REG_ADCON, adcon); } void ADS1256_SetDataRate(ADS1256_DataRate_t dr) { // 设置采样率 ADS1256_WriteRegister(ADS1256_REG_DRATE, (uint8_t)dr); } void ADS1256_StartConversion(void) { // 启动一次转换 ADS1256_SendCommand(ADS1256_CMD_SYNC); ADS1256_SendCommand(ADS1256_CMD_WAKEUP); ADS1256_SendCommand(ADS1256_CMD_RDATA); } float ADS1256_ConvertToVoltage(int32_t raw, float vref, int gain) { return ((float)raw / 8388608.0f) * (vref / gain); // V = (raw / 2的23次方)* (vref / gain) 单位V } void ADS1256_SetClockSource(uint8_t useInternal) // CLK = 0:使用外部晶振 1:使用内部晶振 { if (useInternal > 1) return; uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS); if (useInternal) status |= (1 << 2); // CLK = 1:使用内部晶振 else status &= ~(1 << 2); // CLK = 0:使用外部晶振 ADS1256_WriteRegister(ADS1256_REG_STATUS, status); } bool ADS1256_IsUsingExternalClock(void) { uint8_t status = ADS1256_ReadRegister(ADS1256_REG_STATUS); return (status & (1 << 3)) != 0; // CLKSTAT } void ADS1256_Init(void) { // 初始化 ADS1256 // ADS1256_Reset(); // osDelay(50); ADS1256_SetClockSource(0); // 0使用外部晶振 1内部晶振 ADS1256_WriteRegister(ADS1256_REG_STATUS, 0x06); // 0x06 0000 0 110 自动校准开启(ACAL = 1), 输入缓冲器关闭(BUFEN = 0) ADS1256_WriteRegister(ADS1256_REG_ADCON, 0x20); // 0x20 时钟输出禁用(CLKOUT = 00), 增益为1倍(输入是几mV,增益增大至8) ADS1256_SetDataRate(ADS1256_DR_1000SPS); // ADS1256_DR_1000SPS ADS1256_SetChannel(ADS1256_MUX_AIN1_AINCOM); // AIN1 - AINCOM ADS1256_SendCommand(ADS1256_CMD_SELFCAL);// 启动自动增益和偏移校准 必须最后执行该指令 }