Files
blackbird/bot4cj/test/ads1256_linux.c
2026-07-28 12:44:07 +08:00

472 lines
15 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ads1256_linux.c
*
* Linux C 通过 SPI 采集 ADS1256 示例
* 适用平台: Raspberry Pi / 任何 Linux + SPI 设备
* 编译: gcc -o ads1256 ads1256_linux.c -lwiringPi (树莓派用 wiringPi)
* gcc -o ads1256 ads1256_linux.c (通用 /dev/spidev)
*
* ADS1256: TI 24位 8通道 ΔΣ ADC, 最高 30kSPS
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <time.h>
// ============================================================
// 配置参数 - 按需修改
// ============================================================
#define SPI_DEVICE "/dev/spidev0.0" // SPI 设备路径
#define SPI_SPEED 1920000 // SPI 时钟 (1.92MHz, ADS1256 最大支持 2MHz)
#define SPI_MODE 1 // SPI 模式: CPOL=0, CPHA=1 (模式1)
#define SPI_BITS 8 // 8 位传输
// ADS1256 片选用 GPIO (如果使用硬件 CS 则不需要)
// 若用 /dev/spidev 的硬件 CS, 这部分不需要手动控制
// #define CS_PIN 8 // 例如 wiringPi 的 GPIO 8
// ============================================================
// ADS1256 寄存器地址
// ============================================================
#define ADS1256_REG_STATUS 0x00
#define ADS1256_REG_MUX 0x01
#define ADS1256_REG_ADCON 0x02
#define ADS1256_REG_DRATE 0x03
#define ADS1256_REG_IO 0x04
#define ADS1256_REG_OFC0 0x05
#define ADS1256_REG_OFC1 0x06
#define ADS1256_REG_OFC2 0x07
#define ADS1256_REG_FSC0 0x08
#define ADS1256_REG_FSC1 0x09
#define ADS1256_REG_FSC2 0x0A
// ============================================================
// ADS1256 命令定义
// ============================================================
#define ADS1256_CMD_WAKEUP 0x00 // 退出待机
#define ADS1256_CMD_RDATA 0x01 // 读数据
#define ADS1256_CMD_RDATAC 0x03 // 连续读数据
#define ADS1256_CMD_SDATAC 0x0F // 停止连续读
#define ADS1256_CMD_RREG 0x10 // 读寄存器 (| 寄存器地址)
#define ADS1256_CMD_WREG 0x50 // 写寄存器 (| 寄存器地址)
#define ADS1256_CMD_SELFCAL 0xF0 // 自校准
#define ADS1256_CMD_SELFOCAL 0xF1 // 自失调校准
#define ADS1256_CMD_SELFGCAL 0xF2 // 自增益校准
#define ADS1256_CMD_SYSOCAL 0xF3 // 系统失调校准
#define ADS1256_CMD_SYSGCAL 0xF4 // 系统增益校准
#define ADS1256_CMD_SYNC 0xFC // 同步
#define ADS1256_CMD_STANDBY 0xFD // 待机
#define ADS1256_CMD_RESET 0xFE // 复位
// ============================================================
// ADS1256 数据速率 (DRATE 寄存器值)
// ============================================================
#define ADS1256_DRATE_30000 0xF0 // 30,000 SPS
#define ADS1256_DRATE_15000 0xE0 // 15,000 SPS
#define ADS1256_DRATE_7500 0xD0 // 7,500 SPS
#define ADS1256_DRATE_3750 0xC0 // 3,750 SPS
#define ADS1256_DRATE_2000 0xB0 // 2,000 SPS
#define ADS1256_DRATE_1000 0xA0 // 1,000 SPS
#define ADS1256_DRATE_500 0x90 // 500 SPS
#define ADS1256_DRATE_100 0x80 // 100 SPS
#define ADS1256_DRATE_60 0x70 // 60 SPS
#define ADS1256_DRATE_50 0x60 // 50 SPS
#define ADS1256_DRATE_30 0x50 // 30 SPS
#define ADS1256_DRATE_25 0x40 // 25 SPS
#define ADS1256_DRATE_15 0x30 // 15 SPS
#define ADS1256_DRATE_10 0x20 // 10 SPS
#define ADS1256_DRATE_5 0x10 // 5 SPS
// ============================================================
// PGA 增益 (ADCON 寄存器的低 3 位)
// ============================================================
#define ADS1256_PGA_1 0x00 // ±5V
#define ADS1256_PGA_2 0x01 // ±2.5V
#define ADS1256_PGA_4 0x02 // ±1.25V
#define ADS1256_PGA_8 0x03 // ±0.625V
#define ADS1256_PGA_16 0x04 // ±0.3125V
#define ADS1256_PGA_32 0x05 // ±0.15625V
#define ADS1256_PGA_64 0x06 // ±0.078125V
// 参考电压 (V)
#define ADS1256_VREF 2.5
// ============================================================
// 全局变量
// ============================================================
static int spi_fd = -1; // SPI 文件描述符
static uint8_t spi_txbuf[32];
static uint8_t spi_rxbuf[32];
// ============================================================
// SPI 初始化
// ============================================================
int spi_init(const char *device, uint32_t speed, uint8_t mode, uint8_t bits)
{
int ret;
spi_fd = open(device, O_RDWR);
if (spi_fd < 0) {
perror("打开 SPI 设备失败");
return -1;
}
// 设置 SPI 模式
ret = ioctl(spi_fd, SPI_IOC_WR_MODE, &mode);
if (ret < 0) {
perror("设置 SPI 模式失败");
close(spi_fd);
return -1;
}
// 设置位数
ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret < 0) {
perror("设置 SPI 位数失败");
close(spi_fd);
return -1;
}
// 设置速度
ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret < 0) {
perror("设置 SPI 速度失败");
close(spi_fd);
return -1;
}
// 读取并验证设置
uint8_t rb_mode, rb_bits;
uint32_t rb_speed;
ioctl(spi_fd, SPI_IOC_RD_MODE, &rb_mode);
ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &rb_bits);
ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &rb_speed);
printf("SPI 初始化完成: 模式=%d, 位数=%d, 速度=%d Hz\n",
rb_mode, rb_bits, rb_speed);
return 0;
}
// ============================================================
// SPI 收发 (全双工)
// ============================================================
int spi_transfer(uint8_t *tx, uint8_t *rx, int len)
{
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = (uint32_t)len,
.delay_usecs = 0,
.speed_hz = SPI_SPEED,
.bits_per_word = SPI_BITS,
.cs_change = 0,
};
int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 0) {
perror("SPI 传输失败");
}
return ret;
}
// ============================================================
// SPI 发送单字节
// ============================================================
static inline void spi_write_byte(uint8_t byte)
{
spi_txbuf[0] = byte;
spi_transfer(spi_txbuf, spi_rxbuf, 1);
}
// ============================================================
// SPI 读单字节
// ============================================================
static inline uint8_t spi_read_byte(void)
{
spi_txbuf[0] = 0xFF; // MOSI 发 0xFF 以产生时钟
spi_transfer(spi_txbuf, spi_rxbuf, 1);
return spi_rxbuf[0];
}
// ============================================================
// 等待 DRDY 引脚变低 (数据就绪)
//
// 注意: 这里用延时模拟等待,实际应接 GPIO 中断或轮询
// 若 DRDY 接了 GPIO (如 wiringPi 的 pin 25),可改为:
// while(digitalRead(DRDY_PIN));
// ============================================================
void wait_drdy(void)
{
// 实际项目中用 GPIO 轮询更准确
// 这里用延时估算
usleep(100); // 100us,根据采样率调整
}
// ============================================================
// ADS1256 复位
// ============================================================
void ads1256_reset(void)
{
spi_write_byte(ADS1256_CMD_RESET);
usleep(1000); // 等待复位完成
spi_write_byte(ADS1256_CMD_WAKEUP); // 退出待机
usleep(1000);
}
// ============================================================
// 写 ADS1256 寄存器
// ============================================================
void ads1256_write_reg(uint8_t reg, uint8_t value)
{
spi_write_byte(ADS1256_CMD_WREG | reg);
spi_write_byte(0x00); // 后续字节数 - 1 (0 = 1 byte)
spi_write_byte(value);
}
// ============================================================
// 读 ADS1256 寄存器
// ============================================================
uint8_t ads1256_read_reg(uint8_t reg)
{
spi_write_byte(ADS1256_CMD_RREG | reg);
spi_write_byte(0x00); // 后续字节数 - 1
return spi_read_byte();
}
// ============================================================
// 设置输入通道 (MUX 寄存器)
//
// mux:
// 单端模式: POS = channel, NEG = 0x08 (AINCOM)
// 差分模式: POS = channel_p, NEG = channel_n
// ============================================================
void ads1256_set_channel(uint8_t pos, uint8_t neg)
{
uint8_t mux = ((pos & 0x07) << 4) | (neg & 0x07);
ads1256_write_reg(ADS1256_REG_MUX, mux);
usleep(1);
}
// ============================================================
// ADS1256 初始化
// ============================================================
int ads1256_init(void)
{
printf("正在初始化 ADS1256...\n");
// 1. 复位 ADS1256
ads1256_reset();
usleep(10000);
// 2. 配置状态寄存器
// BIT7: ID (只读)
// BIT6: ID (只读)
// BIT5: ORDER = 0 (MSB 优先)
// BIT4: ACAL = 1 (自动校准)
// BIT3: BUFEN = 0 (关闭缓冲)
// BIT2: DRB = 0 (DRDY 低有效)
// BIT1-0: 保留
ads1256_write_reg(ADS1256_REG_STATUS, 0x14); // 0b00010100
// 3. 配置 MUX (默认: AIN0 + AINCOM)
ads1256_set_channel(0, 0x08);
// 4. 配置 ADCON (A/D 控制寄存器)
// BIT7-5: CLK1-0 = 00 (时钟输出关), SDCS = 0
// BIT4-3: 保留
// BIT2-0: PGA = 001 (增益 ×2)
ads1256_write_reg(ADS1256_REG_ADCON, ADS1256_PGA_2);
// 5. 设置数据速率 (1000 SPS)
ads1256_write_reg(ADS1256_REG_DRATE, ADS1256_DRATE_1000);
// 6. 自校准
printf("正在进行自校准...\n");
spi_write_byte(ADS1256_CMD_SELFCAL);
// 等待校准完成 (约 400ms @ 1000SPS)
usleep(500000);
printf("ADS1256 初始化完成!\n");
// 读寄存器验证
uint8_t status = ads1256_read_reg(ADS1256_REG_STATUS);
uint8_t mux = ads1256_read_reg(ADS1256_REG_MUX);
uint8_t adcon = ads1256_read_reg(ADS1256_REG_ADCON);
uint8_t drate = ads1256_read_reg(ADS1256_REG_DRATE);
printf("寄存器状态: STATUS=0x%02X, MUX=0x%02X, ADCON=0x%02X, DRATE=0x%02X\n",
status, mux, adcon, drate);
return 0;
}
// ============================================================
// 单次读取 24 位数据
//
// 返回: 24 位有符号整数 (二进制补码)
// ============================================================
int32_t ads1256_read_data(void)
{
uint8_t buf[3];
// 发送 RDATA 命令
wait_drdy();
spi_write_byte(ADS1256_CMD_RDATA);
// 读 3 字节 (24 位)
buf[0] = spi_read_byte();
buf[1] = spi_read_byte();
buf[2] = spi_read_byte();
// 组合成 32 位有符号数 (符号扩展)
int32_t value;
value = ((int32_t)buf[0] << 16) |
((int32_t)buf[1] << 8) |
((int32_t)buf[2]);
// 24 位有符号数符号扩展
if (value & 0x800000) {
value |= 0xFF000000;
}
return value;
}
// ============================================================
// 将原始值转换为电压
// ============================================================
double ads1256_raw_to_voltage(int32_t raw, uint8_t pga)
{
// ADS1256 满量程 = ±VREF / PGA
// 24 位: -2^23 ~ 2^23-1
double voltage = (double)raw * ADS1256_VREF / (double)(1 << 23) / (double)pga;
return voltage;
}
// ============================================================
// 读取指定单端通道
// ============================================================
int32_t ads1256_read_channel(uint8_t ch)
{
ads1256_set_channel(ch, 0x08); // AINch vs AINCOM
usleep(1);
// 发送 SYNC + WAKEUP 以启动转换
spi_write_byte(ADS1256_CMD_SYNC);
usleep(1);
spi_write_byte(ADS1256_CMD_WAKEUP);
// 等待转换完成 (根据采样率调整)
// 1000 SPS -> 约 1ms
usleep(2000);
return ads1256_read_data();
}
// ============================================================
// 读取指定差分通道
// ============================================================
int32_t ads1256_read_diff(uint8_t pos, uint8_t neg)
{
ads1256_set_channel(pos, neg);
usleep(1);
spi_write_byte(ADS1256_CMD_SYNC);
usleep(1);
spi_write_byte(ADS1256_CMD_WAKEUP);
usleep(2000);
return ads1256_read_data();
}
// ============================================================
// 连续扫描所有 8 个单端通道
// ============================================================
void ads1256_scan_all(void)
{
printf("\n===== 多通道扫描 =====\n");
for (int ch = 0; ch < 8; ch++) {
int32_t raw = ads1256_read_channel(ch);
double volts = ads1256_raw_to_voltage(raw, 2); // PGA=2
printf("通道 AIN%d: raw = %7d, 电压 = %+.6f V\n", ch, raw, volts);
}
}
// ============================================================
// SPI 关闭
// ============================================================
void spi_close(void)
{
if (spi_fd >= 0) {
close(spi_fd);
spi_fd = -1;
}
}
// ============================================================
// 毫秒延时
// ============================================================
void delay_ms(int ms)
{
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000L;
nanosleep(&ts, NULL);
}
// ============================================================
// 主函数
// ============================================================
int main(int argc, char *argv[])
{
printf("ADS1256 Linux SPI 采集示例\n");
printf("===========================\n\n");
// 1. 初始化 SPI
if (spi_init(SPI_DEVICE, SPI_SPEED, SPI_MODE, SPI_BITS) < 0) {
return 1;
}
// 2. 初始化 ADS1256
if (ads1256_init() < 0) {
spi_close();
return 1;
}
printf("\n===== 单通道测试 (AIN0) =====\n");
for (int i = 0; i < 10; i++) {
int32_t raw = ads1256_read_channel(0);
double volts = ads1256_raw_to_voltage(raw, 2);
printf("[%d] raw=%7d, voltage=%+.6f V\n", i, raw, volts);
delay_ms(10);
}
// 3. 扫描所有通道
ads1256_scan_all();
// 4. 差分模式示例 (AIN0 - AIN1)
printf("\n===== 差分测试 (AIN0 - AIN1) =====\n");
for (int i = 0; i < 5; i++) {
int32_t raw = ads1256_read_diff(0, 1);
double volts = ads1256_raw_to_voltage(raw, 2);
printf("[%d] raw=%7d, voltage=%+.6f V\n", i, raw, volts);
delay_ms(10);
}
// 5. 清理
spi_close();
printf("\n程序结束.\n");
return 0;
}