移植bot4cj

This commit is contained in:
qing committed 2026-07-28 12:44:07 +08:00
1 parent 7803843155
commit 78ad3e6d57
76 files changed
+14468

No files matched your search

+471
View File
@@ -0,0 +1,471 @@
/**
* 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;
}