lgpio
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <gpiod.h>
/* ==== 硬件与采样参数 ==== */
#define SPI_DEV "/dev/spidev0.0" // CE0,您可以根据需要改为 "/dev/spidev0.1"
#define SPI_SPEED 1000000 // 设置为 1 MHz
#define SPI_BITS 8
#define SPI_MODE_ SPI_MODE_1 // ADS1263: CPOL=0, CPHA=1
#define GPIOCHIP "gpiochip0"
#define GPIO_DRDY 17 // 数据就绪信号,物理 11 (BCM 17)
#define GPIO_RESET 18 // 复位信号,物理 12 (BCM 18)
#define GPIO_CS 22 // 片选信号,物理 15 (BCM 22)
#define CH_SEL 0 // AIN0
#define AINCOM_CODE 0x0B // AINCOM 编码
#define VREF 6 // 参考电压(请按实测改)
#define DRATE 0x0D // 最快档
#define REF_AVDD 0x24 // 参考: AVDD/AVSS
/* ==== ADS1263 寄存器和命令 ==== */
#define REG_ID 0x00
#define REG_MODE0 0x03
#define REG_MODE1 0x04
#define REG_MODE2 0x05
#define REG_INPMUX 0x06
#define REG_REFMUX 0x0F
#define CMD_RESET 0x06
#define CMD_START1 0x08
#define CMD_STOP1 0x0A
#define CMD_RDATA1 0x12
#define CMD_RREG 0x20
#define CMD_WREG 0x40
/* ==== 句柄 ==== */
static int spi_fd = -1;
static struct gpiod_chip *chip = NULL;
static struct gpiod_line *drdy=NULL, *rst=NULL, *cs=NULL;
static volatile sig_atomic_t stop_flag = 0;
static void on_sigint(int x){ (void)x; stop_flag = 1; }
/* ==== 小工具 ==== */
static void msleep(int ms){
struct timespec ts={ .tv_sec=ms/1000, .tv_nsec=(ms%1000)*1000000L };
nanosleep(&ts,NULL);
}
/* ==== SPI(软件CS)==== */
static int spi_write(const uint8_t *tx, size_t n){
struct spi_ioc_transfer tr = {0};
tr.tx_buf = (unsigned long)tx; tr.len = n;
tr.speed_hz = SPI_SPEED; tr.bits_per_word = SPI_BITS;
gpiod_line_set_value(cs, 0);
int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
gpiod_line_set_value(cs, 1);
return ret;
}
static int spi_write_then_read(const uint8_t *tx, size_t tn, uint8_t *rx, size_t rn){
struct spi_ioc_transfer tr[2] = {0};
tr[0].tx_buf=(unsigned long)tx; tr[0].len=tn;
tr[1].rx_buf=(unsigned long)rx; tr[1].len=rn;
tr[0].speed_hz=tr[1].speed_hz=SPI_SPEED;
tr[0].bits_per_word=tr[1].bits_per_word=SPI_BITS;
gpiod_line_set_value(cs, 0);
int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(2), tr);
gpiod_line_set_value(cs, 1);
return ret;
}
/* ==== 基本读写(索引已修正)==== */
static int write_cmd(uint8_t c){ return spi_write(&c,1); }
static int write_reg(uint8_t reg, uint8_t val){
uint8_t tx[3] = { (uint8_t)(CMD_WREG|reg), 0x00, val };
int r = spi_write(tx,3);
msleep(1); // 让配置生效
return r;
}
/* 读寄存器:回读 1 字节即可(rx[0] 就是寄存器值) */
static int read_reg(uint8_t reg, uint8_t *out){
uint8_t tx[2] = { (uint8_t)(CMD_RREG|reg), 0x00 };
uint8_t rx[1] = {0};
if (spi_write_then_read(tx,2,rx,1) < 0) return -1;
*out = rx[0];
return 0;
}
/* DRDY 轮询 */
static int wait_drdy_low(void){
struct timespec ts={0,20000}; // 20us
for(int i=0;i<10000 && !stop_flag;i++){
if(gpiod_line_get_value(drdy)==0) return 0;
nanosleep(&ts,NULL);
}
return -1;
}
/* 读取 32位数据:回读 6 字节,rx[1..4] 为 data(索引修正) */
static int read_data32(int32_t *out){
uint8_t cmd = CMD_RDATA1, rx[6]={0};
if (spi_write_then_read(&cmd,1,rx,sizeof(rx)) < 0) return -1;
int32_t val = ((int32_t)rx[1] << 24) | ((int32_t)rx[2] << 16) |
((int32_t)rx[3] << 8) | (int32_t)rx[4];
*out = val;
return 0;
}
/* ==== 初始化 ==== */
static int setup_spi(void){
spi_fd = open(SPI_DEV,O_RDWR);
if (spi_fd<0){ perror("open spidev"); return -1; }
uint8_t mode=SPI_MODE_, bits=SPI_BITS; uint32_t hz=SPI_SPEED;
if (ioctl(spi_fd,SPI_IOC_WR_MODE,&mode)<0){ perror("SPI_IOC_WR_MODE"); return -1; }
if (ioctl(spi_fd,SPI_IOC_WR_BITS_PER_WORD,&bits)<0){ perror("SPI_IOC_WR_BITS"); return -1; }
if (ioctl(spi_fd,SPI_IOC_WR_MAX_SPEED_HZ,&hz)<0){ perror("SPI_IOC_WR_MAX_SPEED_HZ"); return -1; }
return 0;
}
static int setup_gpio(void){
chip = gpiod_chip_open_by_name(GPIOCHIP);
if(!chip){ perror("gpiod_chip_open_by_name"); return -1; }
drdy = gpiod_chip_get_line(chip,GPIO_DRDY);
rst = gpiod_chip_get_line(chip,GPIO_RESET);
cs = gpiod_chip_get_line(chip,GPIO_CS);
if (!drdy||!rst||!cs){ fprintf(stderr,"get_line failed\n"); return -1; }
if (gpiod_line_request_input(drdy,"drdy")<0){ perror("req drdy"); return -1; }
if (gpiod_line_request_output(rst,"reset",1)<0){ perror("req reset"); return -1; }
if (gpiod_line_request_output(cs,"cs",1)<0){ perror("req cs"); return -1; }
return 0;
}
static void cleanup_all(void){
if (drdy) gpiod_line_release(drdy);
if (rst) gpiod_line_release(rst);
if (cs) gpiod_line_release(cs);
if (chip) gpiod_chip_close(chip);
if (spi_fd>=0) close(spi_fd);
}
/* ==== 配置:单端 AIN0 对 AINCOM,快速档 ==== */
static void config_adc(void){
write_reg(REG_MODE2, (uint8_t)(0x80 | (0<<4) | (DRATE & 0x0F))); // MODE2: 快速档
write_reg(REG_MODE1, 0x00); // 轻滤波
write_reg(REG_MODE0, 0x00); // 短延时
write_reg(REG_REFMUX, REF_AVDD);
write_reg(REG_INPMUX, (uint8_t)((CH_SEL<<4) | AINCOM_CODE));
msleep(5);
}
/* ==== 主程序:1 秒平均,终端每秒刷新一行,CSV 同步写入 ==== */
int main(void){
signal(SIGINT, on_sigint);
if (setup_spi()<0 || setup_gpio()<0){ cleanup_all(); return 1; }
/* 硬复位 + 命令复位 */
gpiod_line_set_value(rst,0); msleep(5);
gpiod_line_set_value(rst,1); msleep(20);
write_cmd(CMD_RESET); msleep(20);
uint8_t id=0;
if (read_reg(REG_ID,&id)==0) printf("ID=0x%02X\n", id);
else printf("ID 读取失败\n");
config_adc();
write_cmd(CMD_START1);
FILE *fp = fopen("data_log.csv","w");
if(!fp){ perror("fopen data_log.csv"); write_cmd(CMD_STOP1); cleanup_all(); return 1; }
fprintf(fp,"time_s,voltage_avg_V,samples\n");
/* 丢弃几笔启动瞬态 */
for (int i=0;i<3;i++){ if(wait_drdy_low()==0){ int32_t d; read_data32(&d);} }
time_t start = time(NULL);
time_t sec_t = start;
double acc = 0.0;
unsigned n = 0;
printf("动态采集 AIN0 对 AINCOM,1秒均值显示,结果写入 data_log.csv(Ctrl+C 退出)\n");
while(!stop_flag){
if (wait_drdy_low()==0){
int32_t raw;
if (read_data32(&raw)==0){
double v = (raw / 2147483647.0) * VREF; // 满幅 2^31-1
acc += v; n++;
}
}
time_t now = time(NULL);
if (now != sec_t){ // 换秒:输出上一秒均值
double t = difftime(sec_t, start); // 上一秒时间戳
double mean = n ? (acc / n) : 0.0;
printf("\rAIN0(1s均值) = %8.6f V 采样: %u 点 t=%.0fs", mean, n, t);
fflush(stdout);
fprintf(fp,"%.0f,%.6f,%u\n", t, mean, n);
fflush(fp);
sec_t = now;
acc = 0.0; n = 0;
}
}
write_cmd(CMD_STOP1);
printf("\n已停止采集;数据保存在 data_log.csv\n");
fclose(fp);
cleanup_all();
return 0;
}
sysfs 接口库代码(使用 spidev 和 sysfs,适用于旧系统)
库安装
sudo apt install libgpiod-dev
main.c
// build: sudo make
// run: sudo ./ads1263
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <time.h>
#include <errno.h>
/********* 引脚(BCM 编号) *********/
#define PIN_DRDY 17 // 输入
#define PIN_RESET 18 // 输出
#define PIN_CS 22 // 输出(软CS)
/********* ADS1263 命令与寄存器 *********/
#define CMD_RESET 0x06
#define CMD_START1 0x08
#define CMD_STOP1 0x0A
#define CMD_RDATA1 0x12
#define CMD_RREG 0x20
#define CMD_WREG 0x40
#define REG_MODE2 0x05
#define REG_INPMUX 0x06
#define REG_REFMUX 0x0F
// 参考:AVDD-AVSS
#define REF_AVDD 0x24
// 单端:AINx+ 对 AINCOM-
#define AINCOM 0x0A
/********* SPI 配置 *********/
static const char *SPI_PATH = "/dev/spidev0.0";
static const uint32_t SPI_SPEED = 1000000; // 1 MHz
static const uint8_t SPI_BITS = 8;
static uint8_t SPI_MODE = SPI_MODE_1 | SPI_NO_CS; // 模式1,禁用硬件CS,用GPIO22做软CS
static int spi_fd = -1;
/********* sysfs GPIO 工具函数 *********/
static int gpio_export(int pin){
int fd = open("/sys/class/gpio/export", O_WRONLY);
if(fd<0) return -1;
char buf[16];
int n = snprintf(buf,sizeof(buf),"%d",pin);
write(fd, buf, n);
close(fd);
// 等待目录就绪
char path[64];
for(int i=0;i<50;i++){
snprintf(path,sizeof(path),"/sys/class/gpio/gpio%d/direction",pin);
if(access(path,F_OK)==0) return 0;
usleep(2000);
}
return 0;
}
static void gpio_unexport(int pin){
int fd = open("/sys/class/gpio/unexport", O_WRONLY);
if(fd<0) return;
char buf[16];
int n = snprintf(buf,sizeof(buf),"%d",pin);
write(fd, buf, n);
close(fd);
}
static int gpio_set_dir(int pin, const char* dir){
char path[64];
snprintf(path,sizeof(path),"/sys/class/gpio/gpio%d/direction",pin);
int fd = open(path, O_WRONLY);
if(fd<0) return -1;
write(fd, dir, strlen(dir));
close(fd);
return 0;
}
static int gpio_write(int pin, int val){
char path[64];
snprintf(path,sizeof(path),"/sys/class/gpio/gpio%d/value",pin);
int fd = open(path, O_WRONLY);
if(fd<0) return -1;
if(val) write(fd,"1",1); else write(fd,"0",1);
close(fd);
return 0;
}
static int gpio_read(int pin){
char path[64];
char v='1';
snprintf(path,sizeof(path),"/sys/class/gpio/gpio%d/value",pin);
int fd = open(path, O_RDONLY);
if(fd<0) return -1;
read(fd,&v,1);
close(fd);
return (v=='0')?0:1;
}
/********* 微延时 *********/
static inline void delay_us(unsigned int us){
struct timespec ts;
ts.tv_sec = us/1000000;
ts.tv_nsec = (us%1000000)*1000;
nanosleep(&ts,NULL);
}
/********* SPI 基础 *********/
static int spi_open(){
spi_fd = open(SPI_PATH, O_RDWR);
if(spi_fd<0){ perror("open spidev"); return -1; }
if(ioctl(spi_fd, SPI_IOC_WR_MODE, &SPI_MODE)<0){ perror("SPI_IOC_WR_MODE"); return -1; }
if(ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &SPI_BITS)<0){ perror("SPI_IOC_WR_BITS"); return -1; }
if(ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &SPI_SPEED)<0){ perror("SPI_IOC_WR_SPEED"); return -1; }
return 0;
}
static void spi_close(){
if(spi_fd>=0) close(spi_fd);
spi_fd=-1;
}
static int spi_xfer(uint8_t *tx, uint8_t *rx, uint32_t len){
struct spi_ioc_transfer tr = {0};
tr.tx_buf = (unsigned long)tx;
tr.rx_buf = (unsigned long)rx;
tr.len = len;
tr.speed_hz = SPI_SPEED;
tr.bits_per_word = SPI_BITS;
int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
if(ret<0){ perror("SPI_IOC_MESSAGE"); return -1; }
return 0;
}
/********* 片选 *********/
static inline void cs_low(){ gpio_write(PIN_CS, 0); }
static inline void cs_high(){ gpio_write(PIN_CS, 1); }
/********* ADS1263 基础 *********/
static int write_cmd(uint8_t cmd){
uint8_t tx[1] = { cmd };
cs_low();
int r = spi_xfer(tx, NULL, 1);
cs_high();
delay_us(50);
return r;
}
static int write_reg(uint8_t reg, uint8_t val){
uint8_t tx[3] = { (uint8_t)(CMD_WREG | reg), 0x00, val };
cs_low();
int r = spi_xfer(tx, NULL, 3);
cs_high();
delay_us(50);
return r;
}
static int wait_drdy(double timeout_s){
const uint64_t deadline_ns = (uint64_t)(timeout_s*1e9);
struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t t0 = (uint64_t)ts.tv_sec*1000000000ull + ts.tv_nsec;
for(;;){
int lev = gpio_read(PIN_DRDY);
if(lev==0) return 0;
delay_us(100);
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t now = (uint64_t)ts.tv_sec*1000000000ull + ts.tv_nsec;
if(now - t0 > deadline_ns) break;
}
return -1;
}
// RDATA1 返回顺序:STATUS(1) + DATA(4) + CRC(1)
// 我们发送 1+6 共7字节,rx[1..5] 有效,其中 rx[2..5] 是 32bit 数据
static int32_t read_data(){
uint8_t tx[7] = { CMD_RDATA1, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
uint8_t rx[7] = {0};
cs_low();
spi_xfer(tx, rx, 7);
cs_high();
int32_t val = ((int32_t)rx[2]<<24) | ((int32_t)rx[3]<<16) | ((int32_t)rx[4]<<8) | ((int32_t)rx[5]);
return val;
}
static void select_single_ended(uint8_t pos_ain){
write_reg(REG_REFMUX, REF_AVDD);
write_reg(REG_INPMUX, (uint8_t)((pos_ain<<4) | AINCOM));
delay_us(20); // MUX 建立时间
}
static void ads_reset_pulse(){
// RESET 为低脉冲再拉高
gpio_write(PIN_RESET, 0);
delay_us(1000);
gpio_write(PIN_RESET, 1);
delay_us(5000);
}
static void init_ads1263(){
ads_reset_pulse();
write_cmd(CMD_RESET);
usleep(50000);
// MODE2:0x8D(高数据率/低延迟,保持与参考算法一致)
write_reg(REG_MODE2, 0x8D);
}
/********* 算法:码->电压 *********/
static inline double code_to_volt(int32_t code, double vref, int gain){
// 32位有符号,参考算法:code / 2^31 * (vref/gain)
return ((double)code / 2147483648.0) * (vref / gain);
}
int main(void){
// 导出并配置 GPIO
gpio_export(PIN_DRDY);
gpio_export(PIN_RESET);
gpio_export(PIN_CS);
gpio_set_dir(PIN_DRDY, "in");
gpio_set_dir(PIN_RESET, "out");
gpio_set_dir(PIN_CS, "out");
gpio_write(PIN_CS, 1);
gpio_write(PIN_RESET, 1);
// 打开 SPI
if(spi_open()<0){
fprintf(stderr,"open spidev failed\n");
return 1;
}
printf("ADS1263 initialized.\n");
init_ads1263();
printf("Reset complete.\n");
const double vref = 5.32; // 按你的实际 AVDD 或外参电压
const int gain = 1;
// 预选通道并启动
select_single_ended(0);
write_cmd(CMD_START1);
printf("Started sampling...\n");
// 丢弃第一帧
if(wait_drdy(0.5)==0) (void)read_data();
int32_t code[4]={0};
for(;;){
// AIN0..3 轮询
for(int ch=0; ch<4; ch++){
select_single_ended((uint8_t)ch);
if(wait_drdy(0.5)==0) code[ch] = read_data();
}
double v0 = code_to_volt(code[0], vref, gain);
double v1 = code_to_volt(code[1], vref, gain);
double v2 = code_to_volt(code[2], vref, gain);
double v3 = code_to_volt(code[3], vref, gain);
printf("\rAIN0= %.6f V AIN1= %.6f V AIN2= %.6f V AIN3= %.6f V ", v0,v1,v2,v3);
fflush(stdout);
// 轻微节流
usleep(1000);
}
// 不会到达
write_cmd(CMD_STOP1);
spi_close();
gpio_unexport(PIN_DRDY);
gpio_unexport(PIN_RESET);
gpio_unexport(PIN_CS);
return 0;
}
makefile
CC = gcc
CFLAGS = -Wall -O2
LDFLAGS=
TARGET = ads1263
SRC = main.c
OBJ = $(SRC:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) $(OBJ) -o $@ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJ) $(TARGET)
pigpio 库 (兼容性一般)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pigpio.h>
#include <time.h>
// 引脚定义 (BCM)
#define PIN_DRDY 17 // BCM17 (Data Ready)
#define PIN_RESET 18 // BCM18 (Reset)
#define PIN_CS 22 // BCM22 (Chip Select)
// 命令与寄存器
#define CMD_RESET 0x06
#define CMD_START1 0x08
#define CMD_STOP1 0x0A
#define CMD_RDATA1 0x12
#define CMD_RREG 0x20
#define CMD_WREG 0x40
#define REG_MODE2 0x05
#define REG_INPMUX 0x06
#define REG_REFMUX 0x0F
// 参考选择:AVDD-AVSS
#define REF_AVDD 0x24
// AIN 编码
#define AINCOM 0x0A
// 初始化 SPI 设置
#define SPI_CHANNEL 0
#define SPI_SPEED 500000 // 500 kHz(适当减慢 SPI 时钟频率)
#define SPI_BITS 8
// 初始化 ADS1263
void init_ads1263(int spi_handle){
uint8_t tx[3] = {CMD_RESET, 0x00, 0x00};
gpioWrite(PIN_CS, 0);
spiWrite(spi_handle, (char*)tx, 3);
gpioWrite(PIN_CS, 1);
gpioDelay(50000); // 延时50000微秒,等待重置完成
}
// 选择单端模式
void select_single_ended(int spi_handle, uint8_t pos_ain){
uint8_t tx[3] = {REG_REFMUX, REF_AVDD, 0x00};
gpioWrite(PIN_CS, 0);
spiWrite(spi_handle, (char*)tx, 3);
gpioWrite(PIN_CS, 1);
tx[0] = REG_INPMUX;
tx[1] = (pos_ain << 4) | AINCOM;
gpioWrite(PIN_CS, 0);
spiWrite(spi_handle, (char*)tx, 3);
gpioWrite(PIN_CS, 1);
gpioDelay(20000); // MUX切换延时
}
// 读取数据
int32_t read_data(int spi_handle){
uint8_t tx[7] = {CMD_RDATA1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t rx[7];
gpioWrite(PIN_CS, 0);
spiXfer(spi_handle, (char*)tx, (char*)rx, 7);
gpioWrite(PIN_CS, 1);
int32_t val = ((int32_t)rx[2] << 24) | ((int32_t)rx[3] << 16) |
((int32_t)rx[4] << 8) | ((int32_t)rx[5]);
return val;
}
// 计算电压
double calculate_voltage(int32_t raw_data, double vref, int gain) {
return ((double)raw_data / 2147483648.0) * (vref / gain);
}
// 等待数据准备好
int wait_drdy(double timeout_s){
uint64_t t0 = gpioTick();
while(1){
if (gpioRead(PIN_DRDY) == 0) {
printf("Data is ready!\n"); // Debug: Data is ready
return 0;
}
if ((gpioTick() - t0) > (timeout_s * 1000000)) break;
}
printf("Timeout while waiting for data!\n"); // Debug: Timeout
return -1;
}
int main(void){
if (gpioInitialise() < 0) {
printf("GPIO initialization failed\n");
return 1;
}
// 设置引脚
gpioSetMode(PIN_DRDY, PI_INPUT);
gpioSetMode(PIN_RESET, PI_OUTPUT);
gpioSetMode(PIN_CS, PI_OUTPUT);
gpioWrite(PIN_CS, 1); // 拉高CS
gpioWrite(PIN_RESET, 1); // 拉高RESET
// 打开SPI通道
int spi_handle = spiOpen(SPI_CHANNEL, SPI_SPEED, 0);
if (spi_handle < 0) {
printf("Failed to open SPI\n");
gpioTerminate();
return 1;
}
printf("ADS1263 initialized.\n");
init_ads1263(spi_handle);
printf("Reset complete.\n");
// 参考电压和增益
const double vref = 3.3; // 确保参考电压为 5V
const int gain = 1; // 假设增益为1
// 选择 AIN0 并启动
select_single_ended(spi_handle, 0);
uint8_t tx[1] = {CMD_START1};
gpioWrite(PIN_CS, 0);
spiWrite(spi_handle, (char*)tx, 1);
gpioWrite(PIN_CS, 1);
printf("Started sampling...\n");
// 丢弃第一帧
if (wait_drdy(0.5) == 0) (void)read_data(spi_handle);
// 采集数据并计算电压
int32_t code = read_data(spi_handle);
double voltage = calculate_voltage(code, vref, gain);
// 输出电压
printf("AIN0 Voltage: %.6f V\n", voltage);
// 停止采样
tx[0] = CMD_STOP1;
gpioWrite(PIN_CS, 0);
spiWrite(spi_handle, (char*)tx, 1);
gpioWrite(PIN_CS, 1);
spiClose(spi_handle);
gpioTerminate();
return 0;
}
测试SPI程序
// ads1263_single_ce0.c
// Raspberry Pi 5 + ADS1263 单通道采集 AIN0 对 AINCOM 电压
// 使用 SPI0 + CE0 (GPIO8, 物理24) 作为硬件片选
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#define DEV "/dev/spidev0.0" // SPI0, CE0
#define VREF 2.5 // 内部参考 2.5V
#define SPI_SPEED 1000000 // 1 MHz
#define SPI_MODE SPI_MODE_1
static int spi_xfer(int fd, const void* tx, void* rx, size_t len) {
struct spi_ioc_transfer tr = {0};
tr.tx_buf = (unsigned long)tx;
tr.rx_buf = (unsigned long)rx;
tr.len = len;
tr.speed_hz = SPI_SPEED;
tr.bits_per_word = 8;
return ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
}
static void wreg(int fd, uint8_t addr, uint8_t val) {
uint8_t tx[3] = { 0x40 | (addr & 0x1F), 0x00, val };
spi_xfer(fd, tx, NULL, 3);
}
static uint8_t rreg(int fd, uint8_t addr) {
uint8_t tx[3] = { 0x20 | (addr & 0x1F), 0x00, 0x00 }, rx[3] = {0};
spi_xfer(fd, tx, rx, 3);
return rx[2];
}
int main(void) {
int fd = open(DEV, O_RDWR);
if (fd < 0) { perror("open spidev"); return 1; }
uint8_t mode = SPI_MODE;
uint8_t bits = 8;
uint32_t speed = SPI_SPEED;
ioctl(fd, SPI_IOC_WR_MODE, &mode);
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
// 基本命令
uint8_t cmd_reset = 0x06, cmd_sdatac = 0x11, cmd_start = 0x08, cmd_stop = 0x0A, cmd_rdata1 = 0x12;
// 1) 复位 + 停止连续读
spi_xfer(fd, &cmd_reset, NULL, 1);
usleep(20000);
spi_xfer(fd, &cmd_sdatac, NULL, 1);
usleep(2000);
// 2) 内部参考 2.5V,PGA=1,最快档,AIN0 vs AINCOM
wreg(fd, 0x0F, 0x00); // REFMUX: internal 2.5V
usleep(50000);
wreg(fd, 0x04, 0x00); // MODE1: PGA=1
wreg(fd, 0x03, 0x00); // MODE0: 默认
wreg(fd, 0x05, 0x80 | 0x0A); // MODE2: 连续转换 + 数据率档(0x0A=约2.5kSPS)
wreg(fd, 0x06, (0 << 4) | 0x0A); // INPMUX: AIN0 vs AINCOM
// 3) 启动转换
spi_xfer(fd, &cmd_start, NULL, 1);
// 4) 读取若干次电压
printf("Start reading AIN0 vs AINCOM ...\n");
for (int i = 0; i < 20; i++) {
usleep(5000); // 简单延时等待 DRDY
uint8_t tx = cmd_rdata1, rx[5] = {0};
spi_xfer(fd, &tx, NULL, 1);
spi_xfer(fd, NULL, rx, 5);
int32_t raw = ((int32_t)rx[1] << 24) | ((int32_t)rx[2] << 16) | ((int32_t)rx[3] << 8) | rx[4];
double volt = (double)raw / 2147483648.0 * VREF;
printf("V = %.6f V\n", volt);
}
// 5) 停止转换
spi_xfer(fd, &cmd_stop, NULL, 1);
close(fd);
return 0;
}
Makefile
# makefile (libgpiod v1)
CC = gcc
CFLAGS = -Wall -O2 -std=c99 -g $(shell pkg-config --cflags libgpiod)
LDFLAGS = $(shell pkg-config --libs libgpiod)
TARGET = ads1263_reader
SRC = main_v1.c
all: $(TARGET)
$(TARGET): $(SRC)
$(CC) $(CFLAGS) -o $@ $(SRC) $(LDFLAGS)
clean: ; rm -f $(TARGET) *.o

树莓派5 使用默认SPI0
// ads1263_dyn_ain0.c
// RPi5 + ADS1263, SPI0-CE0(硬件CS) + libgpiod(v1)
// 测 0--5V 单端:AIN0 对 AINCOM(0x0B),参考=AVDD,VREF_VOLTS=实测AVDD
#define _POSIX_C_SOURCE 200809L
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <gpiod.h>
/* ===== 可调参数 ===== */
#define DEV_SPI "/dev/spidev0.0"
#define SPI_MODE_ SPI_MODE_1
#define SPI_SPEED_HZ 1000000
#define VREF_VOLTS 5.15 // <= 请改成你实测的 AVDD(例如万用表测得)
#define DRATE_CODE 0x0A // 数据率档位(0x0A≈10kSPS,0x0D≈38kSPS)
#define UI_HZ 10 // 屏幕刷新频率(仅显示)
#define ALPHA 0.2 // 显示用 IIR 去抖权重 0..1(0 = 无去抖)
/* GPIO (BCM) */
#define GPIO_DRDY 17 // 物理11
#define GPIO_RESET 18 // 物理12
/* ADS1263 命令/寄存器 */
#define CMD_RESET 0x06
#define CMD_SDATAC 0x11
#define CMD_START1 0x08
#define CMD_STOP1 0x0A
#define CMD_RDATA1 0x12
#define CMD_RREG 0x20
#define CMD_WREG 0x40
#define CMD_SYOCAL 0x16 // 可选:系统偏移校准(输入短接时)
#define CMD_SYGCAL 0x17 // 可选:系统增益校准(输入满量程时)
#define REG_ID 0x00
#define REG_INTERFACE 0x02
#define REG_MODE0 0x03
#define REG_MODE1 0x04
#define REG_MODE2 0x05
#define REG_INPMUX 0x06
#define REG_REFMUX 0x0F
#define AINCOM_CODE 0x0B // !!! AINCOM 正确编码是 0x0B
static volatile int g_stop = 0;
static void on_sigint(int s){ (void)s; g_stop = 1; }
static void msleep(unsigned ms){
struct timespec ts={ms/1000,(ms%1000)*1000000UL}; nanosleep(&ts,NULL);
}
/* ==== SPI ==== */
static int spi_open(const char* dev, uint8_t mode, uint32_t speed){
int fd=open(dev,O_RDWR); if(fd<0){ perror("open spidev"); return -1; }
uint8_t bits=8;
if(ioctl(fd,SPI_IOC_WR_MODE,&mode)<0){ perror("SPI_IOC_WR_MODE"); close(fd); return -1; }
if(ioctl(fd,SPI_IOC_WR_BITS_PER_WORD,&bits)<0){ perror("SPI_IOC_WR_BITS_PER_WORD"); close(fd); return -1; }
if(ioctl(fd,SPI_IOC_WR_MAX_SPEED_HZ,&speed)<0){ perror("SPI_IOC_WR_MAX_SPEED_HZ"); close(fd); return -1; }
return fd;
}
static int spi_xfer(int fd, const void* tx, void* rx, size_t len, uint32_t speed){
struct spi_ioc_transfer tr={0};
tr.tx_buf=(unsigned long)tx; tr.rx_buf=(unsigned long)rx;
tr.len=len; tr.speed_hz=speed; tr.bits_per_word=8;
return ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
}
static int spi_wr_then_rd(int fd, const void* tx, size_t n_tx, void* rx, size_t n_rx, uint32_t speed){
struct spi_ioc_transfer tr[2]; memset(tr,0,sizeof(tr));
tr[0].tx_buf=(unsigned long)tx; tr[0].len=n_tx; tr[0].speed_hz=speed; tr[0].bits_per_word=8;
tr[1].rx_buf=(unsigned long)rx; tr[1].len=n_rx; tr[1].speed_hz=speed; tr[1].bits_per_word=8;
return ioctl(fd, SPI_IOC_MESSAGE(2), tr);
}
/* ==== libgpiod v1 (DRDY/RESET) ==== */
static struct gpiod_chip* chip=NULL;
static struct gpiod_line* line_drdy=NULL;
static struct gpiod_line* line_rst=NULL;
static struct gpiod_chip* open_chip_auto(void){
for(int i=0;i<8;i++){
char name[16]; snprintf(name,sizeof(name),"gpiochip%d",i);
struct gpiod_chip* c=gpiod_chip_open_by_name(name);
if(!c) continue;
struct gpiod_line *t1=gpiod_chip_get_line(c,GPIO_DRDY);
struct gpiod_line *t2=gpiod_chip_get_line(c,GPIO_RESET);
if(t1&&t2) return c;
gpiod_chip_close(c);
}
return NULL;
}
static int gpio_setup(void){
chip=open_chip_auto();
if(!chip){ fprintf(stderr,"找不到包含 GPIO%d/%d 的 gpiochip\n",GPIO_DRDY,GPIO_RESET); return -1; }
line_drdy=gpiod_chip_get_line(chip,GPIO_DRDY);
line_rst =gpiod_chip_get_line(chip,GPIO_RESET);
if(!line_drdy||!line_rst){ perror("gpiod_chip_get_line"); return -1; }
if(gpiod_line_request_input(line_drdy,"drdy")<0){ perror("req drdy"); return -1; }
if(gpiod_line_request_output(line_rst,"rst",1)<0){ perror("req rst"); return -1; }
gpiod_line_set_value(line_rst,1);
return 0;
}
static void gpio_cleanup(void){
if(line_drdy) gpiod_line_release(line_drdy);
if(line_rst) gpiod_line_release(line_rst);
if(chip) gpiod_chip_close(chip);
}
static int wait_drdy_low(unsigned timeout_ms){
unsigned el=0;
while(el<=timeout_ms){
int v=gpiod_line_get_value(line_drdy);
if(v<0){ perror("get DRDY"); return -1; }
if(v==0) return 0;
msleep(1); el++;
}
return -2;
}
/* ==== ADS1263 基本读写 ==== */
static int wreg(int spifd, uint8_t addr, uint8_t val){
uint8_t tx[3]={ (uint8_t)(CMD_WREG|(addr&0x1F)), 0x00, val };
return spi_xfer(spifd,tx,NULL,sizeof(tx),SPI_SPEED_HZ);
}
static int rreg(int spifd, uint8_t addr, uint8_t* out){
uint8_t tx[3]={ (uint8_t)(CMD_RREG|(addr&0x1F)), 0x00, 0x00 }, rx[3]={0};
int r=spi_xfer(spifd,tx,rx,sizeof(rx),SPI_SPEED_HZ);
if (r < 0) return r;
*out = rx[2];
return 0;
}
static int cmd1(int spifd, uint8_t c){ return spi_xfer(spifd,&c,NULL,1,SPI_SPEED_HZ); }
/* ==== 初始化(0--5V 单端)====
- 关闭状态/CRC,RDATA1=4字节
- 参考=AVDD(REFMUX=0x24),VREF_VOLTS=实测AVDD
- PGA=1,连续模式,指定数据率
- AIN0 vs AINCOM(0x0B)
*/
static int ads_init_0to5v(int spifd){
gpiod_line_set_value(line_rst,0); msleep(5);
gpiod_line_set_value(line_rst,1); msleep(10);
if(cmd1(spifd,CMD_RESET)<0){ perror("RESET"); return -1; } msleep(20);
if(cmd1(spifd,CMD_SDATAC)<0){ perror("SDATAC"); return -1; } msleep(2);
if(wreg(spifd,REG_INTERFACE,0x00)<0){ perror("INTERFACE"); return -1; } // 无状态/CRC
if(wreg(spifd,REG_REFMUX,0x24)<0){ perror("REFMUX"); return -1; } // 参考=AVDD
if(wreg(spifd,REG_MODE1,0x00)<0){ perror("MODE1"); return -1; } // PGA=1
if(wreg(spifd,REG_MODE0,0x00)<0){ perror("MODE0"); return -1; } // 默认
if(wreg(spifd,REG_MODE2,(uint8_t)(0x80 | (0<<4) | (DRATE_CODE & 0x0F)))<0){ perror("MODE2"); return -1; } // 连续+速率
if(wreg(spifd,REG_INPMUX,(uint8_t)((0<<4)|AINCOM_CODE))<0){ perror("INPMUX"); return -1; } // AIN0 vs AINCOM
msleep(2);
// 回读确认
uint8_t id,ifc,rm,m2,im;
rreg(spifd,REG_ID,&id);
rreg(spifd,REG_INTERFACE,&ifc);
rreg(spifd,REG_REFMUX,&rm);
rreg(spifd,REG_MODE2,&m2);
rreg(spifd,REG_INPMUX,&im);
fprintf(stderr,"ID=0x%02X IF=0x%02X REFMUX=0x%02X MODE2=0x%02X INPMUX=0x%02X (VREF=%.3fV)\n",
id,ifc,rm,m2,im,VREF_VOLTS);
if(cmd1(spifd,CMD_START1)<0){ perror("START1"); return -1; }
return 0;
}
/* 读一次:等待 DRDY -> RDATA1 -> 4字节数据(大端,有符号32位) */
static int ads_read_once(int spifd, int32_t* praw){
int w=wait_drdy_low(500); if(w!=0) return w;
uint8_t cmd=CMD_RDATA1, rx[4]={0};
if(spi_wr_then_rd(spifd,&cmd,1,rx,sizeof(rx),SPI_SPEED_HZ)<0){ perror("RDATA1"); return -1; }
int32_t raw=((int32_t)rx[0]<<24)|((int32_t)rx[1]<<16)|((int32_t)rx[2]<<8)|rx[3];
*praw=raw;
return 0;
}
static inline double raw_to_v(int32_t raw){
// ±VREF 满量程(PGA=1,32位二补码,2^31 刻度)
return ((double)raw/2147483648.0)*VREF_VOLTS;
}
/* 时间工具 */
static inline double now_s(void){
struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
return (double)ts.tv_sec + ts.tv_nsec*1e-9;
}
int main(void){
signal(SIGINT, on_sigint);
setvbuf(stdout, NULL, _IONBF, 0);
int spifd=spi_open(DEV_SPI, SPI_MODE_, SPI_SPEED_HZ);
if(spifd<0) return 1;
if(gpio_setup()<0){ close(spifd); return 1; }
if(ads_init_0to5v(spifd)<0){ gpio_cleanup(); close(spifd); return 1; }
fprintf(stderr,"动态单行显示,Ctrl+C 退出。\n");
double t0 = now_s(), t_last_ui = t0;
unsigned long samp_cnt = 0;
int32_t last_raw = 0;
double last_v = 0.0;
double disp_v = 0.0; // 显示用 IIR 去抖
while(!g_stop){
int32_t code=0;
int r=ads_read_once(spifd,&code);
if(r==0){
last_raw = code;
last_v = raw_to_v(code);
samp_cnt++;
// IIR 去抖(仅显示)
if (samp_cnt == 1 || ALPHA <= 0.0) disp_v = last_v;
else disp_v = ALPHA*last_v + (1.0-ALPHA)*disp_v;
double t = now_s();
if(t - t_last_ui >= 1.0 / UI_HZ){
double elapsed = t - t0;
double sps = (elapsed > 0.0) ? (samp_cnt / elapsed) : 0.0;
printf("\r\033[2KAIN0 vs AINCOM RAW=0x%08X V=% .6f V V(AVG)=% .6f V SPS=%.1f",
(uint32_t)last_raw, last_v, disp_v, sps);
fflush(stdout);
t_last_ui = t;
}
}else if(r==-2){
printf("\r\033[2KAIN0 vs AINCOM [DRDY timeout] 上次RAW=0x%08X V=% .6f V",
(uint32_t)last_raw, last_v);
fflush(stdout);
}else{
printf("\r\033[2KAIN0 vs AINCOM [read error] 上次RAW=0x%08X V=% .6f V",
(uint32_t)last_raw, last_v);
fflush(stdout);
}
}
cmd1(spifd,CMD_STOP1);
printf("\n");
gpio_cleanup(); close(spifd);
return 0;
}

