当前位置: 首页 > news >正文

ADS1256 DAC8532 树莓派5 适配

AD C 程序 最优采集 接近15K+

ads1256_capture_1s.c

#include <errno.h> #include <fcntl.h> #include <linux/spi/spidev.h> #include <lgpio.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <time.h> #include <unistd.h> #define RST_PIN 18 #define CS_PIN 22 #define CS1_PIN 23 #define DRDY_PIN 17 #define GPIO_CHIP 0 #define SPI_DEVICE "/dev/spidev0.0" #define SPI_SPEED_HZ 3000000 #define SAMPLE_COUNT 30000 #define VREF 5.0 #define REG_STATUS 0 #define REG_MUX 1 #define REG_ADCON 2 #define REG_DRATE 3 #define CMD_WAKEUP 0x00 #define CMD_RDATAC 0x03 #define CMD_SDATAC 0x0F #define CMD_RREG 0x10 #define CMD_WREG 0x50 #define CMD_SYNC 0xFC #define ADS1256_GAIN_1 0x00 #define ADS1256_30000SPS 0xF0 static int gpio_handle = -1; static int spi_fd = -1; typedef struct { int32_t raw; double voltage; } Sample; static int64_t monotonic_ns(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, &ts); return (int64_t)ts.tv_sec * 1000000000LL + ts.tv_nsec; } static void delay_ms(unsigned int ms) { usleep(ms * 1000); } static int gpio_write(int pin, int value) { return lgGpioWrite(gpio_handle, pin, value ? 1 : 0); } static int gpio_read(int pin) { return lgGpioRead(gpio_handle, pin); } static uint8_t spi_transfer_byte(uint8_t value) { uint8_t rx = 0xff; struct spi_ioc_transfer tr; memset(&tr, 0, sizeof(tr)); tr.tx_buf = (unsigned long)&value; tr.rx_buf = (unsigned long)&rx; tr.len = 1; tr.speed_hz = SPI_SPEED_HZ; tr.bits_per_word = 8; if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0) { fprintf(stderr, "spi transfer failed: %s\n", strerror(errno)); } return rx; } static int spi_transfer_buf(const uint8_t *tx, uint8_t *rx, size_t len) { struct spi_ioc_transfer tr; memset(&tr, 0, sizeof(tr)); tr.tx_buf = (unsigned long)tx; tr.rx_buf = (unsigned long)rx; tr.len = len; tr.speed_hz = SPI_SPEED_HZ; tr.bits_per_word = 8; return ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr); } static int wait_drdy_low(void) { for (int i = 0; i < 4000000; i++) { if (gpio_read(DRDY_PIN) == 0) { return 0; } } return 1; } static void ads_write_cmd(uint8_t cmd) { gpio_write(CS_PIN, 0); spi_transfer_byte(cmd); gpio_write(CS_PIN, 1); } static void ads_write_reg(uint8_t reg, uint8_t value) { gpio_write(CS_PIN, 0); spi_transfer_byte(CMD_WREG | reg); spi_transfer_byte(0x00); spi_transfer_byte(value); gpio_write(CS_PIN, 1); } static uint8_t ads_read_reg(uint8_t reg) { uint8_t value; gpio_write(CS_PIN, 0); spi_transfer_byte(CMD_RREG | reg); spi_transfer_byte(0x00); delay_ms(1); value = spi_transfer_byte(0xff); gpio_write(CS_PIN, 1); return value; } static void ads_reset(void) { gpio_write(RST_PIN, 1); delay_ms(200); gpio_write(RST_PIN, 0); delay_ms(200); gpio_write(RST_PIN, 1); } static int32_t read_continuous_sample(void) { uint8_t tx[3] = {0xff, 0xff, 0xff}; uint8_t rx[3] = {0xff, 0xff, 0xff}; uint32_t raw; gpio_write(CS_PIN, 0); if (spi_transfer_buf(tx, rx, sizeof(tx)) < 0) { fprintf(stderr, "spi sample read failed: %s\n", strerror(errno)); } gpio_write(CS_PIN, 1); raw = ((uint32_t)rx[0] << 16) | ((uint32_t)rx[1] << 8) | rx[2]; if (raw & 0x800000) { raw |= 0xff000000; } return (int32_t)raw; } static int init_gpio_spi(void) { gpio_handle = lgGpiochipOpen(GPIO_CHIP); if (gpio_handle < 0) { fprintf(stderr, "lgGpiochipOpen failed: %d\n", gpio_handle); return 1; } if (lgGpioClaimOutput(gpio_handle, 0, RST_PIN, 1) < 0 || lgGpioClaimOutput(gpio_handle, 0, CS_PIN, 1) < 0 || lgGpioClaimOutput(gpio_handle, 0, CS1_PIN, 1) < 0 || lgGpioClaimInput(gpio_handle, LG_SET_PULL_UP, DRDY_PIN) < 0) { fprintf(stderr, "claim GPIO failed; check no other ADC program is running\n"); return 1; } spi_fd = open(SPI_DEVICE, O_RDWR); if (spi_fd < 0) { fprintf(stderr, "open %s failed: %s\n", SPI_DEVICE, strerror(errno)); return 1; } uint8_t mode = SPI_MODE_1; uint8_t bits = 8; uint32_t speed = SPI_SPEED_HZ; if (ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) < 0 || ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0 || ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { fprintf(stderr, "configure spi failed: %s\n", strerror(errno)); return 1; } return 0; } static void cleanup(void) { if (spi_fd >= 0) { close(spi_fd); spi_fd = -1; } if (gpio_handle >= 0) { lgGpiochipClose(gpio_handle); gpio_handle = -1; } } static void ads_config_30ksps_channel0(void) { uint8_t status = (0 << 3) | (1 << 2) | (0 << 1); uint8_t mux = (0 << 4) | (1 << 3); uint8_t adcon = ADS1256_GAIN_1; wait_drdy_low(); gpio_write(CS_PIN, 0); spi_transfer_byte(CMD_WREG | REG_STATUS); spi_transfer_byte(0x03); spi_transfer_byte(status); spi_transfer_byte(mux); spi_transfer_byte(adcon); spi_transfer_byte(ADS1256_30000SPS); gpio_write(CS_PIN, 1); delay_ms(1); ads_write_reg(REG_MUX, mux); ads_write_cmd(CMD_SYNC); ads_write_cmd(CMD_WAKEUP); wait_drdy_low(); ads_write_cmd(CMD_RDATAC); } static int save_csv(const char *path, const Sample *samples, int count, double elapsed) { FILE *fp = fopen(path, "w"); if (!fp) { fprintf(stderr, "open output %s failed: %s\n", path, strerror(errno)); return 1; } fprintf(fp, "# ADS1256 one-second voltage capture\n"); fprintf(fp, "# channel,AIN0\n"); fprintf(fp, "# configured_sps,30000\n"); fprintf(fp, "# captured_samples,%d\n", count); fprintf(fp, "# elapsed_seconds,%.9f\n", elapsed); fprintf(fp, "# actual_sps,%.3f\n", count / elapsed); fprintf(fp, "index,raw,voltage\n"); for (int i = 0; i < count; i++) { fprintf(fp, "%d,%d,%.9f\n", i, samples[i].raw, samples[i].voltage); } fclose(fp); return 0; } int main(int argc, char **argv) { int64_t program_start = monotonic_ns(); const char *output_path = argc > 1 ? argv[1] : "ads1256_ain0_1s.csv"; Sample *samples = calloc(SAMPLE_COUNT, sizeof(Sample)); if (!samples) { fprintf(stderr, "calloc failed\n"); return 1; } if (init_gpio_spi() != 0) { cleanup(); free(samples); return 1; } printf("ADS1256 one-second voltage capture\n"); printf("Channel: AIN0, requested samples: %d, data rate register: 0x%02X\n", SAMPLE_COUNT, ADS1256_30000SPS); printf("SPI: %s mode1 %d Hz\n", SPI_DEVICE, SPI_SPEED_HZ); ads_reset(); if (wait_drdy_low() != 0) { fprintf(stderr, "DRDY timeout before ID read\n"); cleanup(); free(samples); return 1; } uint8_t id = ads_read_reg(REG_STATUS) >> 4; printf("Chip ID: %u %s\n", id, id == 3 ? "(OK)" : "(unexpected)"); if (id != 3) { cleanup(); free(samples); return 1; } ads_config_30ksps_channel0(); delay_ms(100); int64_t start = monotonic_ns(); int captured = 0; for (int i = 0; i < SAMPLE_COUNT; i++) { if (wait_drdy_low() != 0) { fprintf(stderr, "DRDY timeout at sample %d\n", i); break; } samples[i].raw = read_continuous_sample(); samples[i].voltage = samples[i].raw * VREF / 8388607.0; captured++; } int64_t end = monotonic_ns(); ads_write_cmd(CMD_SDATAC); double elapsed = (end - start) / 1000000000.0; double actual_sps = captured / elapsed; printf("Captured: %d real ADC voltage samples\n", captured); printf("Elapsed: %.6f sec\n", elapsed); printf("Actual capture rate: %.1f samples/sec\n", actual_sps); printf("First voltage: %.9f V\n", captured > 0 ? samples[0].voltage : 0.0); printf("Last voltage: %.9f V\n", captured > 0 ? samples[captured - 1].voltage : 0.0); int64_t save_start = monotonic_ns(); if (save_csv(output_path, samples, captured, elapsed) == 0) { int64_t save_end = monotonic_ns(); printf("Saved CSV after capture: %s\n", output_path); printf("Save elapsed: %.6f sec\n", (save_end - save_start) / 1000000000.0); } int64_t program_end = monotonic_ns(); printf("Program total elapsed: %.6f sec\n", (program_end - program_start) / 1000000000.0); cleanup(); free(samples); return 0; }

Makefile

CC = gcc CFLAGS = -O2 -Wall -I/home/pi/lg LDFLAGS = -L/home/pi/lg -Wl,-rpath,/home/pi/lg LIBS = -llgpio -lm TARGET = ads1256_capture_1s SRC = ads1256_capture_1s.c all: $(TARGET) $(TARGET): $(SRC) $(CC) $(CFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS) $(LIBS) clean: rm -f $(TARGET) *.o

DAC8532 最优DA输出

dac8532_max_da.c

#define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <gpiod.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> #define DAC8532_CHANNEL_A 0x30 #define DAC8532_CHANNEL_B 0x34 #define DEFAULT_SPI_DEV "/dev/spidev0.0" #define DEFAULT_GPIO_CHIP "gpiochip0" #define DEFAULT_CS_LINE 23 #define DEFAULT_SPI_HZ 24000000U #define DEFAULT_SECONDS 5.0 #define DEFAULT_VREF 3.3 static double now_seconds(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, &ts); return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; } static uint16_t volts_to_code(double volts, double vref) { if (volts <= 0.0) return 0; if (volts >= vref) return 65535; return (uint16_t)((volts * 65535.0 / vref) + 0.5); } static int spi_write_dac(int spi_fd, struct gpiod_line *cs, uint32_t speed_hz, uint8_t channel, uint16_t code) { uint8_t tx[3] = { channel, (uint8_t)(code >> 8), (uint8_t)(code & 0xff) }; struct spi_ioc_transfer tr; memset(&tr, 0, sizeof(tr)); tr.tx_buf = (uintptr_t)tx; tr.len = sizeof(tx); tr.speed_hz = speed_hz; tr.bits_per_word = 8; if (gpiod_line_set_value(cs, 0) < 0) return -1; if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr) < 1) return -1; if (gpiod_line_set_value(cs, 1) < 0) return -1; return 0; } static void usage(const char *argv0) { printf("Usage: sudo %s [seconds] [spi_hz] [channel] [vref]\n", argv0); printf(" seconds : test duration, default %.1f\n", DEFAULT_SECONDS); printf(" spi_hz : SPI clock, default %u\n", DEFAULT_SPI_HZ); printf(" channel : A or B, default A\n"); printf(" vref : DAC reference voltage, default %.3f V\n", DEFAULT_VREF); } int main(int argc, char **argv) { double seconds = DEFAULT_SECONDS; uint32_t speed_hz = DEFAULT_SPI_HZ; uint8_t channel = DAC8532_CHANNEL_A; const char *channel_name = "A"; double vref = DEFAULT_VREF; if (argc > 1) { if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { usage(argv[0]); return 0; } seconds = atof(argv[1]); } if (argc > 2) speed_hz = (uint32_t)strtoul(argv[2], NULL, 10); if (argc > 3) { if (argv[3][0] == 'B' || argv[3][0] == 'b') { channel = DAC8532_CHANNEL_B; channel_name = "B"; } } if (argc > 4) vref = atof(argv[4]); if (seconds <= 0.0 || speed_hz == 0 || vref <= 0.0) { usage(argv[0]); return 2; } int spi_fd = open(DEFAULT_SPI_DEV, O_RDWR); if (spi_fd < 0) { fprintf(stderr, "open %s failed: %s\n", DEFAULT_SPI_DEV, strerror(errno)); return 1; } uint8_t mode = SPI_MODE_1; uint8_t bits = 8; if (ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) < 0 || ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0 || ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz) < 0) { fprintf(stderr, "SPI setup failed: %s\n", strerror(errno)); close(spi_fd); return 1; } struct gpiod_chip *chip = gpiod_chip_open_by_name(DEFAULT_GPIO_CHIP); if (!chip) { fprintf(stderr, "open %s failed: %s\n", DEFAULT_GPIO_CHIP, strerror(errno)); close(spi_fd); return 1; } struct gpiod_line *cs = gpiod_chip_get_line(chip, DEFAULT_CS_LINE); if (!cs || gpiod_line_request_output(cs, "dac8532_max_da", 1) < 0) { fprintf(stderr, "request GPIO%d failed: %s\n", DEFAULT_CS_LINE, strerror(errno)); gpiod_chip_close(chip); close(spi_fd); return 1; } uint16_t low = volts_to_code(0.0, vref); uint16_t high = volts_to_code(vref, vref); printf("DAC8532 maximum DA update proof\n"); printf("SPI : %s mode1 %u Hz\n", DEFAULT_SPI_DEV, speed_hz); printf("CS : %s line GPIO%d\n", DEFAULT_GPIO_CHIP, DEFAULT_CS_LINE); printf("Channel : %s\n", channel_name); printf("Voltage : 0.000 V <-> %.3f V\n", vref); printf("Duration : %.3f sec\n", seconds); fflush(stdout); if (spi_write_dac(spi_fd, cs, speed_hz, channel, low) < 0 || spi_write_dac(spi_fd, cs, speed_hz, channel, high) < 0) { fprintf(stderr, "DAC warm-up write failed: %s\n", strerror(errno)); gpiod_line_release(cs); gpiod_chip_close(chip); close(spi_fd); return 1; } uint64_t updates = 0; double start = now_seconds(); double end_at = start + seconds; while (now_seconds() < end_at) { if (spi_write_dac(spi_fd, cs, speed_hz, channel, low) < 0 || spi_write_dac(spi_fd, cs, speed_hz, channel, high) < 0) { fprintf(stderr, "DAC write failed after %llu updates: %s\n", (unsigned long long)updates, strerror(errno)); break; } updates += 2; } double end = now_seconds(); double elapsed = end - start; double updates_per_sec = (double)updates / elapsed; double square_wave_hz = updates_per_sec / 2.0; spi_write_dac(spi_fd, cs, speed_hz, channel, low); printf("Result : %llu DAC updates in %.6f sec\n", (unsigned long long)updates, elapsed); printf("DA rate : %.1f updates/sec\n", updates_per_sec); printf("Wave proof: %.1f Hz square wave on DAC %s output\n", square_wave_hz, channel_name); printf("Note : this is real SPI writes to DAC8532, not a software counter only.\n"); FILE *report = fopen("dac8532_max_da_report.txt", "w"); if (report) { fprintf(report, "DAC8532 maximum DA update proof\n"); fprintf(report, "spi=%s mode=1 speed_hz=%u cs_gpio=%d channel=%s vref=%.6f\n", DEFAULT_SPI_DEV, speed_hz, DEFAULT_CS_LINE, channel_name, vref); fprintf(report, "updates=%llu elapsed_sec=%.9f da_updates_per_sec=%.3f square_wave_hz=%.3f\n", (unsigned long long)updates, elapsed, updates_per_sec, square_wave_hz); fclose(report); } gpiod_line_release(cs); gpiod_chip_close(chip); close(spi_fd); return 0; }

Makefile

CC := gcc CFLAGS := -O3 -Wall -Wextra LDLIBS := -lgpiod TARGET := dac8532_max_da .PHONY: all clean run all: $(TARGET) $(TARGET): dac8532_max_da.c $(CC) $(CFLAGS) $< -o $@ $(LDLIBS) run: $(TARGET) sudo ./$(TARGET) clean: rm -f $(TARGET) dac8532_max_da_report.txt

http://www.cnnetsun.cn/news/2526921.html

相关文章:

  • 明星产品 | 面向制造现场的双流体喷雾加湿解决方案
  • 如何用GalTransl实现Galgame自动化翻译:终极指南
  • 智慧校园软件选型避坑指南:为什么低价不等于高性价比?
  • 高效整合20+音乐平台音源:lxmusic-全平台无损音乐终极解决方案
  • 数据分析实战:女性身高体重线性与多项式回归建模复盘
  • 长期使用Taotoken Token Plan套餐在项目开发中的成本节省体会
  • 为什么92%的开发者用错Claude?3个致命误用场景与实时纠错工作流
  • 2026网盘天花板是谁?不谈噱头,只看同步、合规与协作:坚果云排第一
  • 3大核心功能让Windows 11重获新生:Win11Debloat系统优化实战指南
  • 开源胶片模拟革命:t3mujinpack如何用Hald CLUT技术为Darktable带来专业级胶片质感
  • KindEditor开源富文本编辑器:企业级内容创作的技术架构深度解析
  • Triton模型服务实战:从Notebook到高并发GPU推理
  • 洛雪音乐音源配置终极指南:5分钟打造你的专属音乐库
  • 别再踩坑了!Ubuntu 22.04 LTS 上 MySQL 5.7 保姆级安装与密码重置指南
  • 通过 TaoToken CLI 工具一键配置多开发环境下的模型密钥
  • 用动态主题建模挖掘科学文献中的真实研究趋势
  • SVGnest材料切割优化完全指南:5步实现智能矢量嵌套布局
  • 详解C++编译器优化技术
  • 如何用Godot RE Tools实现完整的Godot项目逆向工程恢复?
  • 5分钟实现游戏手柄控制PC的终极指南:Gopher360让你的客厅电脑焕然一新
  • C/C++高精度算法的实现
  • 告别仿真报错!手把手教你用Quartus II 18.1和ModelSim 10.5c创建第一个Testbench
  • 五分钟完成Node.js服务对接Taotoken多模型API的配置教程
  • Unity图表性能优化:从折线图到饼图的底层实现与避坑指南
  • 如何3分钟掌握AI智能填充:Fillinger终极实战指南
  • 大模型部署困境破局:Qwen模型ONNX格式转换与多平台部署实战
  • 新一代高性能SAR舰船智能检测数据集SSDD:从集中到分散的渐进式检测范式革新
  • 企业内训系统集成Taotoken实现多模型AI助教与可控的交互成本
  • 新手开发者首次接触 Taotoken 控制台的功能导览与核心操作
  • MATLAB机器人工具箱:从零到精通的机器人开发全攻略