又是一个充实的周末,窗外阳光正好,而我却选择与电路板为伴。今天的主角是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的开发道路上少走弯路,更快地实现自己的项目目标。

嵌入式开发就像一场探险,每个芯片都是一片新大陆。保持好奇心,享受解决问题的过程,你会发现这不仅是一份工作,更是一种创造的艺术。祝各位在技术的道路上越走越远!


希望本文对大家有帮助,上文若有不妥之处,欢迎指正

分享决定高度,学习拉开差距

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐