【RV1103】AD4115实现8通道ADC采样,MQTT数据传输,1K采样率

1.驱动程序

官方的驱动,内核太老了,话说他们这也不知道更新一下,费劲

提供源码ad4115_driver.cpp

复制代码
#include "ad4115_driver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <errno.h>
#include <time.h>

// ============ 寄存器地址 ============
#define AD4115_REG_COMMS         0x00
#define AD4115_REG_STATUS        0x00
#define AD4115_REG_ADC_MODE      0x01
#define AD4115_REG_INTERFACE_MODE 0x02
#define AD4115_REG_DATA          0x04
#define AD4115_REG_GPIO          0x06
#define AD4115_REG_ID            0x07
#define AD4115_REG_CH(x)         (0x10 + (x))
#define AD4115_REG_SETUP(x)      (0x20 + (x))
#define AD4115_REG_FILTER(x)     (0x28 + (x))

// ============ 常量定义 ============
#define AD4115_ID                0x38D0
#define AD4115_ID_MASK           0xFFF0
#define AD4115_CH_ENABLE         0x8000

// ============ 差分通道 INPUT 编码表(关键修复!)===========
static const uint16_t diff_input_codes[8] = {
    0x001,  // CH0: VIN0+, VIN1-
    0x043,  // CH1: VIN2+, VIN3-
    0x085,  // CH2: VIN4+, VIN5-
    0x0C7,  // CH3: VIN6+, VIN7-
    0x109,  // CH4: VIN8+, VIN9-
    0x14B,  // CH5: VIN10+, VIN11-
    0x18D,  // CH6: VIN12+, VIN13-
    0x1CF   // CH7: VIN14+, VIN15-
};

// ============ 数据速率配置 ============
static const ad4115_data_rate_t ad4115_data_rates[] = {
    {0,  24845000, "24.845 MSPS"},
    {1,  24845000, "24.845 MSPS"},
    {2,  20725000, "20.725 MSPS"},
    {3,  20725000, "20.725 MSPS"},
    {4,  15564000, "15.564 MSPS"},
    {5,  13841000, "13.841 MSPS"},
    {6,  10390000, "10.390 MSPS"},
    {7,  10390000, "10.390 MSPS"},
    {8,   4994000, "4.994 MSPS"},
    {9,   2499000, "2.499 MSPS"},
    {10,  1000000, "1.000 MSPS"},
    {11,   500000, "500 kSPS"},
    {12,   395500, "395.5 kSPS"},
    {13,   200000, "200 kSPS"},
    {14,   100000, "100 kSPS"},
    {15,    59890, "59.89 kSPS"},
    {16,    49920, "49.92 kSPS"},
    {17,    20000, "20 kSPS"},     // ✅ 推荐:8 通道=每通道 2.5kSPS
    {18,    16660, "16.66 kSPS"},
    {19,    10000, "10 kSPS"},
    {20,     5000, "5 kSPS"},
    {21,     2500, "2.5 kSPS"},
    {22,     2500, "2.5 kSPS"}
};

// ============ SPI 传输函数 ============
static int spi_transfer(ad4115_dev_t *dev, uint8_t *tx_buf, uint8_t *rx_buf, uint32_t len) {
    if (!dev || dev->spi_fd < 0) {
        return -1;
    }
    
    struct spi_ioc_transfer transfer;
    memset(&transfer, 0, sizeof(transfer));
    
    transfer.tx_buf = (unsigned long)tx_buf;
    transfer.rx_buf = (unsigned long)rx_buf;
    transfer.len = len;
    transfer.speed_hz = dev->speed_hz;
    transfer.delay_usecs = 0;
    transfer.bits_per_word = dev->bits_per_word;
    transfer.cs_change = 0;
    
    int ret = ioctl(dev->spi_fd, SPI_IOC_MESSAGE(1), &transfer);
    if (ret < 0) {
        perror("SPI transfer failed");
    }
    return ret;
}

// ============ 设备复位(关键修复!)===========
static int ad4115_reset(ad4115_dev_t *dev) {
    // 发送 64 个时钟周期的复位序列(CS=0, DIN=1)
    uint8_t reset_buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    uint8_t rx_buf[8] = {0};
    
    int ret = spi_transfer(dev, reset_buf, rx_buf, 8);
    if (ret < 0) {
        return -1;
    }
    
    // 等待 500µs 让 LDO 稳定(数据手册要求)
    usleep(1000);
    return 0;
}

// ============ 读取寄存器 ============
static int ad4115_read_register(ad4115_dev_t *dev, uint8_t reg, uint8_t size, uint32_t *value) {
    uint8_t tx_buf[5] = {0};
    uint8_t rx_buf[5] = {0};
    
    tx_buf[0] = 0x40 | (reg & 0x3F);
    
    int ret = spi_transfer(dev, tx_buf, rx_buf, size + 1);
    if (ret != (size + 1)) {
        return -1;
    }
    
    *value = 0;
    for (int i = 0; i < size; i++) {
        *value = (*value << 8) | rx_buf[i + 1];
    }
    usleep(1); // 短暂延时,避免死等占用总线
    return 0;
}

// ============ 写入寄存器 ============
static int ad4115_write_register(ad4115_dev_t *dev, uint8_t reg, uint8_t size, uint32_t value) {
    uint8_t tx_buf[5] = {0};
    uint8_t rx_buf[5] = {0};
    
    tx_buf[0] = reg & 0x3F;
    
    for (int i = 0; i < size; i++) {
        tx_buf[size - i] = (value >> (8 * i)) & 0xFF;
    }
    
    int ret = spi_transfer(dev, tx_buf, rx_buf, size + 1);
    if (ret != (size + 1)) {
        return -1;
    }
    usleep(1); // 短暂延时,避免死等占用总线
    return 0;
}

// ============ 通道配置(关键修复!)===========
static int ad4115_configure_channel(ad4115_dev_t *dev, int channel) {
    if (channel < 0 || channel >= AD4115_MAX_CHANNELS) {
        return -1;
    }
    
    // 通道配置寄存器格式(16 位):
    // Bit 15: CH_EN (1=启用)
    // Bits 14-12: SETUP_SEL (选择 Setup 0)
    // Bits 11-10: Reserved
    // Bits 9-0: INPUT[9:0] (差分输入编码)
    
    uint16_t channel_config = AD4115_CH_ENABLE |        // 启用通道
                              (0 << 12) |               // 使用 Setup 0
                              diff_input_codes[channel]; // 正确的差分输入编码
    
    int ret = ad4115_write_register(dev, AD4115_REG_CH(channel), 2, channel_config);
    if (ret < 0) {
        return ret;
    }
    
    dev->channels_enabled[channel] = true;
    return 0;
}

// ============ 设备初始化(完整修复)===========
ad4115_dev_t* ad4115_init(const char* spi_device, uint32_t speed_hz) {
    ad4115_dev_t* dev = (ad4115_dev_t*)malloc(sizeof(ad4115_dev_t));
    if (!dev) {
        return NULL;
    }
    
    memset(dev, 0, sizeof(ad4115_dev_t));
    
    dev->spi_fd = open(spi_device, O_RDWR);
    if (dev->spi_fd < 0) {
        perror("Failed to open SPI device");
        free(dev);
        return NULL;
    }
    
    dev->speed_hz = speed_hz;
    dev->mode = SPI_MODE_3;  // AD4115 使用 SPI Mode 3
    dev->bits_per_word = 8;
    
    if (ioctl(dev->spi_fd, SPI_IOC_WR_MODE, &dev->mode) < 0) {
        perror("Failed to set SPI mode");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    if (ioctl(dev->spi_fd, SPI_IOC_WR_BITS_PER_WORD, &dev->bits_per_word) < 0) {
        perror("Failed to set SPI bits per word");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    if (ioctl(dev->spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &dev->speed_hz) < 0) {
        perror("Failed to set SPI speed");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    // ============ 设备复位(关键!)===========
    printf("正在复位 AD4115...\n");
    if (ad4115_reset(dev) < 0) {
        printf("复位失败!\n");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    // ============ 读取设备 ID ============
    uint32_t id;
    if (ad4115_read_register(dev, AD4115_REG_ID, 2, &id) < 0) {
        printf("读取 ID 失败!\n");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    dev->device_id = id & AD4115_ID_MASK;
    printf("设备 ID: 0x%04X\n", dev->device_id);
    
    if (dev->device_id != AD4115_ID) {
        printf("ID 不匹配!期望 0x%04X, 实际 0x%04X\n", AD4115_ID, dev->device_id);
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    // ============ ADC 模式配置 ============
    // Bit 15: REF_EN = 1 (启用内部参考)
    // Bits 6-4: Mode = 000 (连续转换模式)
    // Bits 3-2: CLOCKSEL = 00 (内部振荡器)
    uint32_t adc_mode = (1 << 15) |  // REF_EN
                        (0 << 6);    // 连续转换模式
    
    if (ad4115_write_register(dev, AD4115_REG_ADC_MODE, 2, adc_mode) < 0) {
        printf("配置 ADC 模式失败!\n");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    // ============ 接口模式配置(连续转换模式)===========
    // Bit 6: DATA_STAT = 1 (读取数据时附加状态寄存器)
    // Bit 7: CONTREAD = 0 (不使用连续读模式)
    uint32_t if_mode = (1 << 6)|(0 << 7);  // 只启用 DATA_STAT
    if (ad4115_write_register(dev, AD4115_REG_INTERFACE_MODE, 2, if_mode) < 0) {
        printf("配置接口模式失败!\n");
        close(dev->spi_fd);
        free(dev);
        return NULL;
    }
    
    // ============ Setup 配置(关键修复!)===========
    // Setup Configuration Register 0 (0x20)
    // Bit 12: BI_UNIPOLAR = 1 (双极性)
    // Bits 9-8: INBUF = 11 (启用输入缓冲器) ⚠️ 必须启用!
    // Bits 5-4: REF_SEL = 10 (内部参考)
    uint32_t setup_reg = (1 << 12) |   // Bit 12: BI_UNIPOLAR = 1 (双极性)
                        (3 << 8) |    // Bits 9-8: INBUF = 11 (输入缓冲器使能)
                        (2 << 4) |    // Bits 5-4: REF_SEL = 10 (内部参考)
                        (1 << 5);     // Bit 5: REFBUF0+ = 1 (参考缓冲使能)
    
    for(uint8_t i=0;i<8;i++)
    {
        if (ad4115_write_register(dev, AD4115_REG_SETUP(i), 2, setup_reg) < 0) {
            printf("配置 Setup 失败!\n");
            close(dev->spi_fd);
            free(dev);
            return NULL;
        }
    }
    
    // ============ 滤波器配置 ============
    uint32_t filter_reg = (dev->data_rate_index & 0x1F);
    for(uint8_t i=0;i<8;i++)
    {
        if (ad4115_write_register(dev, AD4115_REG_FILTER(i), 2, filter_reg) < 0) {
            printf("配置滤波器失败!\n");
            close(dev->spi_fd);
            free(dev);
            return NULL;
        }
    }
    
    dev->num_channels = AD4115_MAX_CHANNELS;
    
    printf("AD4115 初始化成功:SPI=%dHz, ID=0x%04X\n", speed_hz, dev->device_id);
    return dev;
}

// ============ 设置数据速率 ============
ad4115_error_t ad4115_set_data_rate(ad4115_dev_t* dev, int rate_index) {
    if (!dev) {
        return AD4115_ERROR_INIT;
    }
    
    if (rate_index < 0 || rate_index >= AD4115_NUM_DATA_RATES) {
        return AD4115_ERROR_CHANNEL;
    }
    
    uint32_t filter_reg = (rate_index & 0x1F);
    for(uint8_t i=0;i<8;i++)
    {
        if (ad4115_write_register(dev, AD4115_REG_FILTER(i), 2, filter_reg) < 0) {
            return AD4115_ERROR_SPI;
        }
    }
    
    dev->data_rate_index = rate_index;
    return AD4115_SUCCESS;
}

// ============ 设备反初始化 ============
void ad4115_deinit(ad4115_dev_t* dev) {
    if (dev) {
        if (dev->spi_fd >= 0) {
            close(dev->spi_fd);
        }
        free(dev);
    }
}

// ============ 读取传感器 ID ============
uint16_t ad4115_get_sensor_id(ad4115_dev_t* dev) {
    if (!dev) return 0;
    return dev->device_id;
}

// ============ 启用指定通道 ============
ad4115_error_t ad4115_enable_channel(ad4115_dev_t* dev, int channel) {
    if (!dev || channel < 0 || channel >= AD4115_MAX_CHANNELS) {
        return AD4115_ERROR_CHANNEL;
    }
    
    if (dev->channels_enabled[channel]) {
        return AD4115_SUCCESS;
    }
    
    if (ad4115_configure_channel(dev, channel) < 0) {
        return AD4115_ERROR_INIT;
    }
    
    return AD4115_SUCCESS;
}

// ============ 禁用指定通道 ============
ad4115_error_t ad4115_disable_channel(ad4115_dev_t* dev, int channel) {
    if (!dev || channel < 0 || channel >= AD4115_MAX_CHANNELS) {
        return AD4115_ERROR_CHANNEL;
    }
    
    if (!dev->channels_enabled[channel]) {
        return AD4115_SUCCESS;
    }
    
    if (ad4115_write_register(dev, AD4115_REG_CH(channel), 2, 0) < 0) {
        return AD4115_ERROR_SPI;
    }
    
    dev->channels_enabled[channel] = false;
    return AD4115_SUCCESS;
}

// ============ 启用所有通道 ============
ad4115_error_t ad4115_enable_all_channels(ad4115_dev_t* dev) {
    if (!dev) {
        return AD4115_ERROR_INIT;
    }
    
    for (int channel = 0; channel < AD4115_MAX_CHANNELS; channel++) {
        ad4115_error_t ret = ad4115_enable_channel(dev, channel);
        if (ret != AD4115_SUCCESS) {
            return ret;
        }
    }
    
    return AD4115_SUCCESS;
}

// ============ 禁用所有通道 ============
ad4115_error_t ad4115_disable_all_channels(ad4115_dev_t* dev) {
    if (!dev) {
        return AD4115_ERROR_INIT;
    }
    
    for (int channel = 0; channel < AD4115_MAX_CHANNELS; channel++) {
        ad4115_error_t ret = ad4115_disable_channel(dev, channel);
        if (ret != AD4115_SUCCESS) {
            return ret;
        }
    }
    
    return AD4115_SUCCESS;
}

// ============ 获取当前数据速率 ============
unsigned int ad4115_get_data_rate(ad4115_dev_t* dev) {
    if (!dev || dev->data_rate_index < 0 || dev->data_rate_index >= AD4115_NUM_DATA_RATES) {
        return 0;
    }
    
    // 多通道模式下使用每通道速率
    return ad4115_data_rates[dev->data_rate_index].rate_sps / 8;
}

// ============ 读取所有通道数据(严格按你的要求重写 + 调试日志)===========
ad4115_error_t ad4115_read_all_channels(ad4115_dev_t* dev, ad4115_sample_t* sample) {
    if (!dev || !sample) {
        return AD4115_ERROR_INIT;
    }
    
    int valid_channels = 0;
    
    // 循环读取每个通道的数据
    for (int i = 0; i < AD4115_MAX_CHANNELS; i++) {
        // ==========================================
        // 1. 手动轮询状态寄存器 (0x00),获取 RDY 和通道号
        // ==========================================
        uint8_t tx_stat[1] = {0x40}; // 0x40 | 0x00 (读状态寄存器命令)
        uint8_t rx_stat[2] = {0};    // 1字节命令响应 + 1字节状态值
        uint8_t channel_id = 0;
        int is_ready = 0;
        int poll_cnt = 0;
        const int max_polls = 1000;  // 超时保护 (~50ms)
        
        while (!is_ready && poll_cnt < max_polls) {
            if (spi_transfer(dev, tx_stat, rx_stat, 2) == 2) {
                uint8_t status = rx_stat[1];
                
                if ((status & 0x80) == 0) { // RDY Bit 7 = 0 表示转换完成
                    is_ready = 1;
                    channel_id = status & 0x0F; // Bits[3:0] 为当前通道号
                }
            }
            poll_cnt++;
        }
        
        if (!is_ready) {
            #if AD4115_DEBUG == 1
            printf("[DBG] ✗ Loop %d: TIMEOUT after %d polls, skipping\n", i, poll_cnt);
            #endif
            continue; // 超时跳过本次,继续读下一个
        }
        
        // ==========================================
        // 2. 读取数据寄存器 (0x04)
        // ==========================================
        #if AD4115_DEBUG == 1
        printf("[DBG] Loop %d: Reading DATA register (ch_id=%d)...\n", i, channel_id);
        #endif
        // 注意:因 IFMODE 中 DATA_STAT=1,DOUT 会先输出 8位状态,再输出 24位数据
        // 共 4 字节有效载荷。SPI 总传输长度 = 1(命令) + 4(载荷) = 5
        uint8_t tx_data[1] = {0x44}; // 读数据寄存器命令
        uint8_t rx_data[5] = {0};    // 接收缓冲区
        
        if (spi_transfer(dev, tx_data, rx_data, 5) != 5) {
            printf("[DBG] ✗ Loop %d: SPI transfer failed!\n", i);
            continue; // SPI 传输失败,跳过
        }
        
        // 调试:打印原始接收数据
        #if AD4115_DEBUG == 1
        printf("[DBG]   rx_data raw: [%02X][%02X][%02X][%02X][%02X]\n",
               rx_data[0], rx_data[1], rx_data[2], rx_data[3], rx_data[4]);
        #endif
        
        // ==========================================
        // 3. 解析 24 位 ADC 数据
        // ==========================================
        // rx_data[0]: 命令发送期间的返回字节(无效)
        // rx_data[1]: 状态寄存器(与步骤1一致,此处忽略)
        // rx_data[2]: 数据高8位 (D23-D16)
        // rx_data[3]: 数据中8位 (D15-D8)
        // rx_data[4]: 数据低8位 (D7-D0)
        int32_t raw_value = ((int32_t)rx_data[2] << 16) |
                           ((int32_t)rx_data[3] << 8)  |
                           ((int32_t)rx_data[4]);
        
        // 24位有符号数符号扩展至32位
        if (raw_value & 0x800000) {
            raw_value |= 0xFF000000;
        }
        
        // ==========================================
        // 4. 存入结构体
        // ==========================================
        #if AD4115_DEBUG == 1
        printf("[DBG]   Storing to sample->channels[%d]: valid=true\n", channel_id);
        #endif
        sample->raw_data[channel_id] = raw_value;
        sample->valid[channel_id] = true;
        valid_channels++;
    }
    
    return (valid_channels > 0) ? AD4115_SUCCESS : AD4115_ERROR_READ;
}

// ============ 转储所有寄存器(调试用)===========
ad4115_error_t ad4115_dump_all_registers(ad4115_dev_t* dev) {
    if (!dev) {
        return AD4115_ERROR_INIT;
    }

    printf("\n========== AD4115 寄存器转储 ==========\n");
    printf("时间:%ld\n", time(NULL));
    printf("------------------------------------------\n");

    // 定义寄存器信息:地址、名称、字节数
    struct {
    uint8_t addr;
    const char* name;
    uint8_t size;
    } reg_info[] = {
    {0x00, "STATUS", 1},
    {0x01, "ADCMODE", 2},
    {0x02, "IFMODE", 2},
    {0x03, "REGCHECK", 3},
    {0x04, "DATA", 3},
    {0x06, "GPIOCON", 2},
    {0x07, "ID", 2},
    // Channel Registers 0-15
    {0x10, "CH0", 2}, {0x11, "CH1", 2}, {0x12, "CH2", 2}, {0x13, "CH3", 2},
    {0x14, "CH4", 2}, {0x15, "CH5", 2}, {0x16, "CH6", 2}, {0x17, "CH7", 2},
    {0x18, "CH8", 2}, {0x19, "CH9", 2}, {0x1A, "CH10", 2}, {0x1B, "CH11", 2},
    {0x1C, "CH12", 2}, {0x1D, "CH13", 2}, {0x1E, "CH14", 2}, {0x1F, "CH15", 2},
    // Setup Configuration Registers 0-7
    {0x20, "SETUPCON0", 2}, {0x21, "SETUPCON1", 2}, {0x22, "SETUPCON2", 2}, {0x23, "SETUPCON3", 2},
    {0x24, "SETUPCON4", 2}, {0x25, "SETUPCON5", 2}, {0x26, "SETUPCON6", 2}, {0x27, "SETUPCON7", 2},
    // Filter Configuration Registers 0-7
    {0x28, "FILTCON0", 2}, {0x29, "FILTCON1", 2}, {0x2A, "FILTCON2", 2}, {0x2B, "FILTCON3", 2},
    {0x2C, "FILTCON4", 2}, {0x2D, "FILTCON5", 2}, {0x2E, "FILTCON6", 2}, {0x2F, "FILTCON7", 2},
    // Offset Registers 0-7
    {0x30, "OFFSET0", 3}, {0x31, "OFFSET1", 3}, {0x32, "OFFSET2", 3}, {0x33, "OFFSET3", 3},
    {0x34, "OFFSET4", 3}, {0x35, "OFFSET5", 3}, {0x36, "OFFSET6", 3}, {0x37, "OFFSET7", 3},
    // Gain Registers 0-7
    {0x38, "GAIN0", 3}, {0x39, "GAIN1", 3}, {0x3A, "GAIN2", 3}, {0x3B, "GAIN3", 3},
    {0x3C, "GAIN4", 3}, {0x3D, "GAIN5", 3}, {0x3E, "GAIN6", 3}, {0x3F, "GAIN7", 3},
    };

    int total_regs = sizeof(reg_info) / sizeof(reg_info[0]);
    int success_count = 0;
    int fail_count = 0;

    for (int i = 0; i < total_regs; i++) {
    uint32_t value = 0;
    int ret = ad4115_read_register(dev, reg_info[i].addr, reg_info[i].size, &value);

    if (ret == 0) {
    success_count++;
    // 根据寄存器大小格式化输出
    if (reg_info[i].size == 1) {
    printf("0x%02X %-12s: 0x%02X\n", reg_info[i].addr, reg_info[i].name, value);
    } else if (reg_info[i].size == 2) {
    printf("0x%02X %-12s: 0x%04X\n", reg_info[i].addr, reg_info[i].name, value);
    } else {
    printf("0x%02X %-12s: 0x%06X\n", reg_info[i].addr, reg_info[i].name, value);
    }
    } else {
    fail_count++;
    printf("0x%02X %-12s: READ FAILED\n", reg_info[i].addr, reg_info[i].name);
    }
    }

    printf("------------------------------------------\n");
    printf("总计:%d 个寄存器,成功:%d, 失败:%d\n", total_regs, success_count, fail_count);
    printf("==========================================\n\n");

    return (fail_count > 0) ? AD4115_ERROR_READ : AD4115_SUCCESS;
}

ad4115_driver.h

复制代码
#ifndef AD4115_DRIVER_H
#define AD4115_DRIVER_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#define AD4115_MAX_CHANNELS 8
#define AD4115_SPI_SPEED_HZ 10000000      // 10MHz SPI
#define AD4115_NUM_DATA_RATES 23
#define AD4115_DEFAULT_DATA_RATE 7       // 10kSPS 总速率 = 1.25kSPS/通道
#define AD4115_DEBUG 0

// 所有通道数据
typedef struct {
    int32_t raw_data[AD4115_MAX_CHANNELS];
    bool valid[AD4115_MAX_CHANNELS];
} ad4115_sample_t;

// 设备句柄
typedef struct {
    int spi_fd;
    uint32_t speed_hz;
    uint8_t mode;
    uint8_t bits_per_word;
    uint16_t device_id;
    int num_channels;
    int data_rate_index;
    bool channels_enabled[AD4115_MAX_CHANNELS];
} ad4115_dev_t;

// 错误码
typedef enum {
    AD4115_SUCCESS = 0,
    AD4115_ERROR_INIT = -1,
    AD4115_ERROR_SPI = -2,
    AD4115_ERROR_CHANNEL = -3,
    AD4115_ERROR_READ = -4,
    AD4115_ERROR_TIMEOUT = -5
} ad4115_error_t;

// 数据速率信息结构
typedef struct {
    int index;
    unsigned int rate_sps;
    const char* description;
} ad4115_data_rate_t;

#ifdef __cplusplus
extern "C" {
#endif

ad4115_dev_t* ad4115_init(const char* spi_device, uint32_t speed_hz);
void ad4115_deinit(ad4115_dev_t* dev);

ad4115_error_t ad4115_enable_channel(ad4115_dev_t* dev, int channel);
ad4115_error_t ad4115_disable_channel(ad4115_dev_t* dev, int channel);
ad4115_error_t ad4115_enable_all_channels(ad4115_dev_t* dev);
ad4115_error_t ad4115_disable_all_channels(ad4115_dev_t* dev);

ad4115_error_t ad4115_set_data_rate(ad4115_dev_t* dev, int rate_index);
unsigned int ad4115_get_data_rate(ad4115_dev_t* dev);
ad4115_error_t ad4115_read_all_channels(ad4115_dev_t* dev, ad4115_sample_t* sample);

uint16_t ad4115_get_sensor_id(ad4115_dev_t* dev);
ad4115_error_t ad4115_dump_all_registers(ad4115_dev_t* dev) ;

#ifdef __cplusplus
}
#endif

#endif

2.驱动验证

提供一个测试代码,用于验证驱动是否正常

复制代码
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include "ad4115_driver.h"

volatile sig_atomic_t keep_running = 1;

void signal_handler(int sig) {
    if (sig == SIGINT) {
        keep_running = 0;
    }
}

int main() {
    printf("=== AD4115 差分通道高速采样程序 ===\n");
    printf("输出:ADC 原始数据(24 位有符号)\n");
    printf("停止:按 Ctrl+C\n");
    
    signal(SIGINT, signal_handler);
    
    // 初始化设备
    ad4115_dev_t* adc = ad4115_init("/dev/spidev0.0", AD4115_SPI_SPEED_HZ);
    if (!adc) {
        printf("错误:无法初始化 AD4115!\n");
        return -1;
    }
    
    // 启用所有通道
    if (ad4115_enable_all_channels(adc) != AD4115_SUCCESS) {
        printf("错误:启用通道失败\n");
        ad4115_deinit(adc);
        return -1;
    }
    
    // 设置数据速率
    if (ad4115_set_data_rate(adc, AD4115_DEFAULT_DATA_RATE) != AD4115_SUCCESS) {
        printf("错误:设置数据速率失败\n");
        ad4115_deinit(adc);
        return -1;
    }
    
    printf("开始高速采样...\n");
    printf("------------------------------------------------\n");

    unsigned long sample_count = 0;
    int error_count = 0;
    struct timespec start_time, current_time;
    clock_gettime(CLOCK_MONOTONIC, &start_time);
    
    int print_every = 1000;  // 每 1000 次打印一次

    while (keep_running) {
        ad4115_sample_t sample;
        if (ad4115_read_all_channels(adc, &sample) == AD4115_SUCCESS) {
            sample_count++;

            // 减少打印频率
            if (sample_count % print_every == 0) {
                printf("Sample %lu: ", sample_count);
                for (int ch = 0; ch < AD4115_MAX_CHANNELS; ch++) {
                    printf("CH%d:%11d ", ch, sample.raw_data[ch]);
                }
                printf("\n");
            }
        } else {
            error_count++;
            if (error_count % 10 == 0) {
                printf("采样失败!错误计数:%d\n", error_count);
            }
        }
    }

    // 最终统计
    clock_gettime(CLOCK_MONOTONIC, &current_time);
    double total_elapsed = (current_time.tv_sec - start_time.tv_sec) +
                           (current_time.tv_nsec - start_time.tv_nsec) / 1000000000.0;
    double total_sample_rate = sample_count / total_elapsed;
    
    printf("\n=== 采样结束 ===\n");
    printf("总采样数:%lu\n", sample_count);
    printf("总耗时:%.3f 秒\n", total_elapsed);
    printf("平均总采样率:%.1f SPS\n", total_sample_rate * 8);
    printf("平均每通道采样率:%.1f Hz\n", total_sample_rate);
    printf("错误数:%d\n", error_count);
    
    // 打印配置信息
    printf("\n=== 配置信息 ===\n");
    printf("传感器 ID: 0x%04X\n", ad4115_get_sensor_id(adc));
    printf("SPI 速度:%u Hz\n", AD4115_SPI_SPEED_HZ);
    printf("数据速率索引:%d\n", AD4115_DEFAULT_DATA_RATE);
    printf("通道映射:\n");
    for (int i = 0; i < 8; i++) {
        printf("  CH%d: AIN%d+/AIN%d-\n", i, i*2, i*2+1);
    }
    
    printf("\n>>> 初始化完成,转储寄存器配置 <<<\n");
    ad4115_dump_all_registers(adc);
    ad4115_deinit(adc);
    printf("程序结束。\n");
    
    return 0;
}

效果如下

复制代码
=== AD4115 差分通道高速采样程序 ===
输出:ADC 原始数据(24 位有符号)
停止:按 Ctrl+C
正在复位 AD4115...
设备 ID: 0x38D0
AD4115 初始化成功:SPI=10000000Hz, ID=0x38D0
开始高速采样...
------------------------------------------------
Sample 1000: CH0:    -119296 CH1:    -163327 CH2:    -236798 CH3:    1064195 CH4:    -243708 CH5:     -61179 CH6:    -128506 CH7:    -145401
Sample 2000: CH0:    -116736 CH1:    -172543 CH2:    -236030 CH3:    1022467 CH4:    -241404 CH5:     -61691 CH6:    -126202 CH7:    -138489
Sample 3000: CH0:    -122880 CH1:    -163839 CH2:    -242686 CH3:    1056259 CH4:    -241404 CH5:     -73723 CH6:    -121850 CH7:    -136185
Sample 4000: CH0:    -113664 CH1:    -162815 CH2:    -254206 CH3:    1044995 CH4:    -231420 CH5:     -66811 CH6:    -116730 CH7:    -147449
Sample 5000: CH0:    -123648 CH1:    -173055 CH2:    -255998 CH3:    1012483 CH4:    -240124 CH5:     -63227 CH6:    -132346 CH7:    -147961
Sample 6000: CH0:    -132352 CH1:    -179711 CH2:    -240894 CH3:    1031939 CH4:    -239868 CH5:     -71931 CH6:    -153850 CH7:    -139001

=== 采样结束 ===
总采样数:6611
总耗时:5.123 秒
平均总采样率:10324.3 SPS
平均每通道采样率:1290.5 Hz
错误数:0

=== 配置信息 ===
传感器 ID: 0x38D0
SPI 速度:10000000 Hz
数据速率索引:7
通道映射:
  CH0: AIN0+/AIN1-
  CH1: AIN2+/AIN3-
  CH2: AIN4+/AIN5-
  CH3: AIN6+/AIN7-
  CH4: AIN8+/AIN9-
  CH5: AIN10+/AIN11-
  CH6: AIN12+/AIN13-
  CH7: AIN14+/AIN15-

>>> 初始化完成,转储寄存器配置 <<<

========== AD4115 寄存器转储 ==========
时间:1777216333
------------------------------------------
0x00 STATUS      : 0x07
0x01 ADCMODE     : 0x8000
0x02 IFMODE      : 0x0040
0x03 REGCHECK    : 0x000000
0x04 DATA        : 0x7FFBED
0x06 GPIOCON     : 0x0800
0x07 ID          : 0x38DE
0x10 CH0         : 0x8001
0x11 CH1         : 0x8043
0x12 CH2         : 0x8085
0x13 CH3         : 0x80C7
0x14 CH4         : 0x8109
0x15 CH5         : 0x814B
0x16 CH6         : 0x818D
0x17 CH7         : 0x81CF
0x18 CH8         : 0x0001
0x19 CH9         : 0x0001
0x1A CH10        : 0x0001
0x1B CH11        : 0x0001
0x1C CH12        : 0x0001
0x1D CH13        : 0x0001
0x1E CH14        : 0x0001
0x1F CH15        : 0x0001
0x20 SETUPCON0   : 0x1320
0x21 SETUPCON1   : 0x1320
0x22 SETUPCON2   : 0x1320
0x23 SETUPCON3   : 0x1320
0x24 SETUPCON4   : 0x1320
0x25 SETUPCON5   : 0x1320
0x26 SETUPCON6   : 0x1320
0x27 SETUPCON7   : 0x1320
0x28 FILTCON0    : 0x0007
0x29 FILTCON1    : 0x0007
0x2A FILTCON2    : 0x0007
0x2B FILTCON3    : 0x0007
0x2C FILTCON4    : 0x0007
0x2D FILTCON5    : 0x0007
0x2E FILTCON6    : 0x0007
0x2F FILTCON7    : 0x0007
0x30 OFFSET0     : 0x800000
0x31 OFFSET1     : 0x800000
0x32 OFFSET2     : 0x800000
0x33 OFFSET3     : 0x800000
0x34 OFFSET4     : 0x800000
0x35 OFFSET5     : 0x800000
0x36 OFFSET6     : 0x800000
0x37 OFFSET7     : 0x800000
0x38 GAIN0       : 0x554BF0
0x39 GAIN1       : 0x554BF0
0x3A GAIN2       : 0x554BF0
0x3B GAIN3       : 0x554BF0
0x3C GAIN4       : 0x554BF0
0x3D GAIN5       : 0x554BF0
0x3E GAIN6       : 0x554BF0
0x3F GAIN7       : 0x554BF0
------------------------------------------
总计:55 个寄存器,成功:55, 失败:0
==========================================

3.通过MQTT进行网络传输

时域效果

频域效果(嗯,家里的电源该换了~~)

相关推荐
weixin_568996061 小时前
Cgo 中正确设置 C 结构体回调函数指针的完整方案
jvm·数据库·python
嵌入式×边缘AI:打怪升级日志1 小时前
DS18B20 Linux 驱动开发实战:从时序图到温度读取的保姆级教学
linux·驱动开发
橘颂TA2 小时前
【Linux】自旋锁
linux·开发语言·数据库·c++
LiAo_1996_Y2 小时前
mysql如何限制特定存储过程执行权限_MySQL存储过程安全访问
jvm·数据库·python
knight_9___2 小时前
LLM工具调用面试篇1
开发语言·人工智能·python·面试·agent
2601_956139422 小时前
快消品品牌全案公司哪家强
大数据·人工智能·python
源码之家2 小时前
Python股票数据分析与预测系统 大数据项目
大数据·python·机器学习·数据挖掘·数据分析·股票·可视化
一脸dio样7542 小时前
第5章 保护模式进阶,向内核迈进
linux·开发语言
甄心爱学习2 小时前
【项目实训(个人5)】
python·github