手把手一起玩转AD5755:一款高性能、4通道、16位DAC芯片
又是一个充实的周末,窗外阳光正好,而我却选择与电路板为伴。今天的主角是ADI公司的AD5755——。在工业控制、测试测量和自动化领域,它扮演着至关重要的角色。经过两天的奋战,一个完整的AD5755控制系统终于诞生了——从STM32固件到PyQt上位机。现在把这些宝贵经验整理成文,希望能帮助各位小伙伴少走弯路。
又是一个充实的周末,窗外阳光正好,而我却选择与电路板为伴。今天的主角是ADI公司的AD5755——一款高性能、4通道、16位DAC芯片。在工业控制、测试测量和自动化领域,它扮演着至关重要的角色。经过两天的奋战,一个完整的AD5755控制系统终于诞生了——从STM32固件到PyQt上位机。现在把这些宝贵经验整理成文,希望能帮助各位小伙伴少走弯路。

一、AD5755芯片解析
AD5755是一款真正的16位精度、4通道数模转换器,具有以下突出特性:
- 高精度:16位分辨率,±0.1% FSR精度
- 多种输出范围:支持0-5V、0-10V、±5V、±10V等多种工业标准范围
- 片上诊断功能:包括开路检测、短路检测、温度监控等
- 灵活的接口:兼容SPI、QSPI、MICROWIRE和DSP接口
- 宽温度范围:-40°C至+105°C工业级工作温度

二、硬件设计
AD5755是一款四通道、16位精度、电流/电压输出的DAC芯片,支持多种输出范围。但要让它稳定工作,电源设计和外围电路至关重要。电源设计注意事项:
- 电源顺序很重要:必须保证DVDD在AVDD之前或同时上电,否则可能损坏芯片
- 去耦电容布局:每个电源引脚都需要就近放置0.1μF陶瓷电容,电源入口处添加10μF钽电容
- 地平面分割:模拟地和数字地单点连接,推荐使用磁珠或0Ω电阻连接
AD5755硬件电路板如图所示:

下图是stm32控制电路板,用于控制AD5755的各通道输出:

三、STM32下位机设计
STM32与AD5755通过SPI接口进行通信,SPI时序如下:

以下是AD5755的主要驱动函数:
/******************************************************************************
* @file : ad5755.c
* @brief : ad5755文件
* @version : v1.0
* @author : wuhailei
* @date : 2025-10-18
* @note : 版权所有 (c) 2025, wuhailei 保留所有权利
* @history :
* 版本|日期|作者|描述
* ----|----|----|----
* v1.0|2025-10-18|wuhailei|首次创建
******************************************************************************/
#include "ad5755.h"
#include "delay.h"
/******************************************************************************
* @function : AD5755_WriteRegister
* @brief : 向AD5755写24位寄存器数据
* @param : Code - 24位数据,包含地址和数据
* @return : 无
* @note : 使用SPI接口向AD5755写入24位寄存器值
* @author : wuhailei
* @date : 2025-10-18
******************************************************************************/
void AD5755_WriteRegister( uint32_t Code)
{
uint8_t i;
delay_us(1);
AD5755_SYNC_0; // 拉低SYNC,启动传输
delay_us(1);
for (i=0;i<24;i++) // 逐位发送24bit数据
{
if((Code&0x800000)==0x800000) // 判断最高位是否为1
AD5755_SDI_1; // 如果为1,SDI置高
else
AD5755_SDI_0;
delay_ns(5);
AD5755_SCLK_1;
delay_us(1);
AD5755_SCLK_0;
delay_us(1);
Code<<=1; // 左移,发送下一bit
}
delay_us(1);
AD5755_SYNC_1;
delay_us(1);
}
/******************************************************************************
* @function : AD5755_WriteReadRegister
* @brief : AD5755 24位数据读写寄存器函数
* @param : Code - 24位数据
* @return : uint32_t - 读取的24位数据
* @note : 使用SPI接口与AD5755进行24位数据的双向传输
* @author : wuhailei
* @date : 2025-10-18
******************************************************************************/
uint32_t AD5755_WriteReadRegister(uint32_t Code)
{
uint8_t i;
uint32_t result = 0;
delay_us(1);
AD5755_SYNC_0; // 拉低SYNC,启动传输
delay_us(1);
AD5755_SCLK_0;
delay_us(1);
for (i=0;i<24;i++) // 逐位发送24bit数据
{
if((Code&0x800000)==0x800000) // 判断最高位是否为1
AD5755_SDI_1; // 如果为1,SDI置高
else
AD5755_SDI_0;
delay_ns(5);
AD5755_SCLK_1;
delay_ns(50);
result<<=1; // 左移
if(AD5755_SDO) // 读取SDO引脚状态
result |= 0x000001; // 设置最低bit为1
delay_us(1);
AD5755_SCLK_0;
delay_us(1);
Code<<=1; // 左移,发送下一bit
}
delay_us(1);
AD5755_SYNC_1;
delay_us(1);
return result;
}
四、PyQt上位机设计
AD5755操作序列如下:

为了方便调试,使用pyqt开发了简单的上位机,如图所示:

核心程序ad5755.py:
"""
AD5755驱动模块
实现AD5755的寄存器操作和控制功能
基于AD5755数据手册编写
"""
import time
from typing import Dict, Any
class AD5755Driver:
"""AD5755驱动类"""
# 寄存器地址定义
REG_DAC_DATA = 0x00
REG_GAIN = 0x02
REG_OFFSET = 0x04
REG_CLEAR_CODE = 0x06
REG_CONTROL = 0x07
# 控制寄存器子地址
SUBREG_SLEW_RATE = 0x00
SUBREG_MAIN_CONTROL = 0x01
SUBREG_DAC_CONTROL = 0x02
SUBREG_DCDC_CONTROL = 0x03
SUBREG_SOFTWARE = 0x04
def __init__(self, serial_com):
self.serial_com = serial_com
self.current_channel = 0
def hardware_reset(self, port):
"""执行硬件复位"""
# 根据数据手册,RESET低电平脉冲至少20μs
self.serial_com.send_data(port, "00")
time.sleep(0.1) # 等待复位完成
def write_dcdc_control_register(self, port, config: Dict[str, Any]):
"""
写入DC-DC控制寄存器
根据数据手册表24-25
"""
# 构建寄存器值
register_value = 0x0000
# DC-DC补偿选择 (Bit 6)
register_value |= (config.get('compensation', 0) & 0x01) << 6
# DC-DC相位 (Bit 5-4)
register_value |= (config.get('phase', 0) & 0x03) << 4
# DC-DC频率 (Bit 3-2)
register_value |= (config.get('frequency', 1) & 0x03) << 2
# DC-DC最大电压 (Bit 1-0)
register_value |= (config.get('max_voltage', 0) & 0x03)
# 发送命令
self._write_control_register(port, self.SUBREG_DCDC_CONTROL, register_value)
def write_dac_control_register(self, port, config: Dict[str, Any]):
"""
写入DAC控制寄存器
根据数据手册表20-21
"""
channel = config.get('channel', 0)
register_value = 0x0000
# 寄存器类型标识 (Bit 15-13: 010)
register_value |= 0x4000
# INT_ENABLE (Bit 8)
register_value |= (config.get('int_enable', 0) & 0x01) << 8
# CLR_EN (Bit 7)
register_value |= (config.get('clr_en', 0) & 0x01) << 7
# OUTEN (Bit 6)
register_value |= (config.get('out_en', 0) & 0x01) << 6
# RSET (Bit 5)
register_value |= (config.get('rset', 0) & 0x01) << 5
# DC_DC (Bit 4)
register_value |= (config.get('dc_dc', 0) & 0x01) << 4
# OVRNG (Bit 3)
register_value |= (config.get('ovrng', 0) & 0x01) << 3
# 输出范围 (Bit 2-0)
register_value |= (config.get('range', 0) & 0x07) # 实际是3位 R2,R1,R0
# 发送命令到指定通道
self._write_register(port, self.REG_CONTROL, channel, register_value)
def write_main_control_register(self, port, config: Dict[str, Any]):
"""
写入主控制寄存器
根据数据手册表18-19
"""
register_value = 0x0000
# 寄存器类型标识 (Bit 15-13: 001)
register_value |= 0x1000
# POC (Bit 12)
register_value |= (config.get('poc', 0) & 0x01) << 12
# STATREAD (Bit 11)
register_value |= (config.get('statread', 0) & 0x01) << 11
# EWD (Bit 10)
register_value |= (config.get('ewd', 0) & 0x01) << 10
# WD1, WD0 (Bit 9-8)
register_value |= (config.get('wd_time', 0) & 0x03) << 8
# ShtCctLim (Bit 6)
register_value |= (config.get('shtcctlim', 0) & 0x01) << 6
# OUTEN_ALL (Bit 5)
register_value |= (config.get('outen_all', 0) & 0x01) << 5
# DCDC_All (Bit 4)
register_value |= (config.get('dcdc_all', 0) & 0x01) << 4
self._write_control_register(port, self.SUBREG_MAIN_CONTROL, register_value)
def set_voltage_output(self, port, channel: int, min_voltage: float, max_voltage: float, voltage: float):
"""设置电压输出"""
# 根据选择的输出范围计算DAC代码
# 这里需要根据实际范围进行转换
dac_code = self._voltage_to_code(min_voltage, max_voltage,voltage)
self._write_dac_data(port, channel, dac_code)
def set_current_output(self, port, channel: int, min_current: float, max_current: float, current: float):
"""设置电流输出"""
# 根据选择的输出范围计算DAC代码
dac_code = self._current_to_code(min_current, max_current, current)
self._write_dac_data(port, channel, dac_code)
def _voltage_to_code(self, min_voltage, max_voltage, voltage: float) -> int:
"""电压值转换为DAC代码"""
if voltage < min_voltage:
voltage = min_voltage
if voltage > max_voltage:
voltage = max_voltage
code = int(((voltage - min_voltage) / (max_voltage - min_voltage)) * 65535)
return max(0, min(65535, code))
def _current_to_code(self, min_current, max_current, current: float) -> int:
"""电流值转换为DAC代码"""
if current < min_current:
current = min_current
if current > max_current:
current = max_current
code = int(((current - min_current) / (max_current - min_current)) * 65535)
return max(0, min(65535, code))
def _write_dac_data(self, port, channel: int, data: int):
"""写入DAC数据寄存器"""
self._write_register(port, self.REG_DAC_DATA, channel, data)
def _write_register(self, port, reg_type: int, channel: int, data: int):
"""写入寄存器通用方法"""
# 构建24位SPI命令
command = self._build_spi_command(reg_type, channel, data)
# 通过串口发送命令
if self.serial_com.is_connected():
self.serial_com.send_data(port, "02"+command)
def _write_control_register(self, port, subreg: int, data: int):
"""写入控制寄存器"""
# 控制寄存器写入使用不同的格式
command = self._build_control_command(subreg, data)
if self.serial_com.is_connected():
self.serial_com.send_data(port, "02"+command)
def _build_spi_command(self, reg_type: int, channel: int, data: int) -> bytes:
"""
构建SPI命令
根据数据手册表8-10的24位格式
"""
# R/W位 (Bit 23): 0=写
command = 0x000000
# DUT地址 (Bit 22-21): 默认00
# 寄存器类型 (Bit 20-18)
command |= (reg_type & 0x07) << 18
# DAC通道地址 (Bit 17-16)
command |= (channel & 0x03) << 16
# 数据 (Bit 15-0)
command |= (data & 0xFFFF)
# 转换为3字节,然后格式化为十六进制字符串
byte_data = command.to_bytes(3, byteorder='big')
# 将每个字节转换为两位十六进制字符串,并用空格连接
hex_string = ' '.join(f'{byte:02X}' for byte in byte_data)
return hex_string
def _build_control_command(self, subreg: int, data: int) -> bytes:
"""
构建控制寄存器命令
根据数据手册表16格式
"""
command = 0x000000
# R/W位 (Bit 23): 0=写
# DUT地址 (Bit 22-21): 默认00
# 寄存器类型 (Bit 20-18): 111=控制寄存器
command |= 0x700000
# DAC通道地址 (Bit 17-16): 对于全局控制寄存器通常为00
# CREG位 (Bit 15-13): 子寄存器地址
command |= (subreg & 0x07) << 13
# 数据 (Bit 12-0)
command |= (data & 0x1FFF)
# 转换为3字节,然后格式化为十六进制字符串
byte_data = command.to_bytes(3, byteorder='big')
# 将每个字节转换为两位十六进制字符串,并用空格连接
hex_string = ' '.join(f'{byte:02X}' for byte in byte_data)
return hex_string
上位机使用教程,首先连接AD5755设备,下图中这样设置即可,选择串口,进行设备连接:

引脚使能模块对几个特殊引脚进行设置,如图:

设置DAC控制寄存器:

选择通道,并输出电压:

万用表测量输出,输出电压2V:

改变DAC控制寄存器,输出电流:

设置通道,输出指定电流值:

万用表测量输出电流:

单帧指令表如下:
| 具体操作 | 单帧指令 |
|---|---|
| 写并回读寄存器 | 01 00 80 00 |
| 写寄存器 | 02 1C 41 70 |
| 写寄存器 | 02 1C 41 75 |
| RESET引脚低电平 | 03 00 00 |
| RESET引脚高电平 | 03 00 01 |
| LDAC引脚低电平 | 03 01 00 |
| LDAC引脚高电平 | 03 01 01 |
| POC引脚低电平 | 03 02 00 |
| POC引脚高电平 | 03 02 01 |
| CLR引脚低电平 | 03 03 00 |
| CLR引脚高电平 | 03 03 01 |
| FAUL引脚低电平 | 03 04 00 |
| FAUL引脚高电平 | 03 04 01 |
| ALERT引脚低电平 | 03 05 00 |
| ALERT引脚高电平 | 03 05 01 |
完整的下位机程序、数据手册和上位机软件详见手把手一起玩转AD5755资源包

经过这个周末的奋战,我深刻体会到嵌入式开发是软硬件的完美结合。AD5755虽然只是一个DAC芯片,但要想充分发挥其性能,需要从电源设计、PCB布局、固件优化到上位机设计的全盘考虑。
调试的过程虽然充满挑战,但当看到四个通道按照预期精确输出时,那种成就感是无与伦比的。希望这篇详细的指南能帮助大家在AD5755的开发道路上少走弯路,更快地实现自己的项目目标。
嵌入式开发就像一场探险,每个芯片都是一片新大陆。保持好奇心,享受解决问题的过程,你会发现这不仅是一份工作,更是一种创造的艺术。祝各位在技术的道路上越走越远!
希望本文对大家有帮助,上文若有不妥之处,欢迎指正
分享决定高度,学习拉开差距
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)