DAC8760 是一款高性能的 16 位数模转换芯片,支持 4-20mA 电流输出和 0-5V/0-10V 电压输出,广泛应用于工业控制、过程监测等场景。本文基于 STM32F103 单片机,从硬件连接、代码实现到功能调试,完整讲解 DAC8760 的驱动开发与使用方法。

一、DAC8760 核心特性

  • 16 位无失码 DAC,精度高;
  • 支持 4-20mA/0-20mA/0-24mA 电流输出,0-5V/0-10V 电压输出;
  • SPI 串行接口通信,适配单片机低速 / 高速通信需求;
  • 内置校准功能,输出精度可校准;
  • 工业级宽温范围,适配恶劣工业环境。

二、硬件连接(STM32F103 + DAC8760)

1. 引脚定义

本文采用 GPIO 模拟 SPI 通信(硬件 SPI 亦可,代码稍作修改即可),核心引脚映射如下:

STM32F103 引脚 DAC8760 引脚 功能说明
GPIOB_Pin_13 DIN 串行数据输入
GPIOB_Pin_14 SCLK 串行时钟
GPIOB_Pin_15 LATCH 数据锁存信号
GPIOB_Pin_9 DOUT 串行数据输出(读取寄存器用)

2. 硬件注意事项

  • DAC8760 的电源需稳定(推荐 ±15V 或 + 24V,根据输出类型选择);
  • 电流输出回路需接匹配负载,电压输出建议加电压跟随器;
  • SPI 通信引脚添加 10K 上拉电阻,提升抗干扰能力;
  • LATCH 引脚需上拉,确保空闲状态为高电平。

三、代码实现(基于 STM32F103)

1. 工程结构

plaintext

├── dac8760.h      // 寄存器定义、引脚宏、函数声明
├── dac8760.c      // 核心驱动函数(初始化、读写、输出控制)
├── config.h       // STM32底层配置(GPIO、时钟等,需自行适配)

2. 核心代码解析

(1)头文件 dac8760.h

定义引脚宏、输出范围宏、函数声明,核心代码如下:

c

运行

#ifndef _DAC8760_H
#define _DAC8760_H
#include "config.h"

// SPI通信引脚定义(GPIO模拟SPI)
#define DAC8760_DIN   GPIO_Pin_13 // DIN
#define DAC8760_SCK   GPIO_Pin_14 // SCLK
#define DAC8760_LAT   GPIO_Pin_15 // LATCH
#define DAC8760_SDO   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)  // DOUT

// 引脚操作宏
#define DIN_1         GPIO_SetBits(GPIOB, DAC8760_DIN)  
#define DIN_0         GPIO_ResetBits(GPIOB, DAC8760_DIN)
#define SCK_1         GPIO_SetBits(GPIOB, DAC8760_SCK)  
#define SCK_0         GPIO_ResetBits(GPIOB, DAC8760_SCK)
#define LAT_1         GPIO_SetBits(GPIOB, DAC8760_LAT)   
#define LAT_0         GPIO_ResetBits(GPIOB, DAC8760_LAT)

// 输出范围定义
#define V_0_5         0x000 // 电压输出0-5V
#define V_0_10        0x001 // 电压输出0-10V
#define I_4_20        0x05  // 电流输出4-20mA
#define I_0_20        0x06  // 电流输出0-20mA
#define I_0_24        0x07  // 电流输出0-24mA
#define Calen         0x20  // 使能校正功能

// 函数声明
extern void DAC8760_Init(void);        // 初始化
extern void DAC8760_Out(uint16_t dat); // 输出数据
extern void DAC8760_I(uint32_t Dis);   // 电流输出控制
extern void DAC8760_V(uint32_t Dis);   // 电压输出控制
void Transfer(uint16_t DA);            // 数据传输
void J_config(void);                   // 初始化配置

#endif
(2)驱动实现文件 dac8760.c

核心功能包括:SPI 数据读写、寄存器配置、电流 / 电压输出转换,完整代码如下:

c

运行

#include "config.h"
#include "dac8760.h"

// 全局变量(需根据实际场景配置距离上下限)
uint32_t Lrange = 0;   // 距离下限
uint32_t Hrange = 100000; // 距离上限
uint16_t Yrange = 0x8000; // 增益校准值
uint16_t Zrange = 0x0000; // 调零校准值

/********************* 寄存器配置函数 *********************/
void DAC8760_Config(void) 
{
    // 4~20mA输出配置(默认)
    DAC8760_Write(0x56,0x0001); // 复位所有寄存器
    DAC8760_Write(0x55,(1<<12)| I_4_20); // 控制寄存器:输出使能+4-20mA范围
    DAC8760_Write(0x57,0x00|Calen);      // 使能校准
    DAC8760_Write(0x01,0);               // 初始输出0
    // 校准配置
    DAC8760_Write(0x58,0x8000|Yrange);   // 增益校准
    DAC8760_Write(0x59,0x0|Zrange);      // 调零校准

    // 0-5V/0-10V电压输出配置(注释掉,按需启用)
    /*
    DAC8760_Write(0x56,0x0001);
    DAC8760_Write(0x55,(1<<12)| V_0_10); // 0-10V输出
    DAC8760_Write(0x57,0x00);
    DAC8760_Write(0x01,0);
    */
}

/********************* 初始化函数 *********************/
void DAC8760_Init(void)
{
    // 初始化GPIO(需在config.h中实现GPIO配置)
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    // DIN/SCK/LAT配置为推挽输出
    GPIO_InitStructure.GPIO_Pin = DAC8760_DIN | DAC8760_SCK | DAC8760_LAT;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // DOUT配置为上拉输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 初始化DAC8760寄存器
    DAC8760_Config();
}

/********************* 写寄存器函数 *********************/
void DAC8760_Write(uint8_t add,uint16_t dat)
{
    uint8_t i; 
    uint8_t h_8bit, l_8bit;

    h_8bit=(dat>>8)&0x00FF; // 高8位
    l_8bit=dat&0x00FF;     // 低8位

    LAT_0; // 拉低锁存,准备传输数据
    // 写8位地址
    for(i=8;i>0;i--)
    {  
        SCK_0; 
        if(add&0x80) DIN_1; 
        else DIN_0; 
        SCK_1; // 时钟上升沿锁存数据
        add<<=1; 
    }  
    // 写高8位数据
    for(i=8;i>0;i--)
    { 
        SCK_0;      
        if(h_8bit&0x80) DIN_1;
        else DIN_0;
        SCK_1;	
        h_8bit<<=1; 
    } 
    // 写低8位数据
    for(i=8;i>0;i--)
    {  
        SCK_0;  
        if(l_8bit&0x80) DIN_1;
        else DIN_0;
        SCK_1; 
        l_8bit<<=1;
    } 
    LAT_1; // 拉高锁存,数据生效
    DIN_1; // 空闲状态置高
}

/********************* 读寄存器函数 *********************/
uint16_t DAC8760_Read(uint16_t add)
{
    uint16_t i,dat=0;

    DAC8760_Write(0x02,add); // 发送读地址
    LAT_0;
    // 跳过低8位无效数据
    for(i=8;i>0;i--)
    {
        SCK_0;  
        __nop();  
        SCK_1; 
        __nop();
    } 
    // 读取16位有效数据
    dat=0;
    for(i=16;i>0;i--) 
    {  
        SCK_0;  
        dat<<=1;  
        SCK_1; 
        dat|=DAC8760_SDO; // 读取DOUT引脚状态
    }
    return dat;
}

/********************* 电流输出控制 *********************/
void DAC8760_I(uint32_t Dis)
{
    static uint16_t DAout;

    // 异常处理:测不到数据输出3.5mA
    if((Dis&0x80000000)==0x80000000)
    {
        DAout=0x2caf; // 3.5mA对应值
        DAC8760_Write(0x55,(1<<12)| I_0_20);
        Transfer(DAout);
    }
    // 超过上限:输出20mA
    else if(Dis>Hrange)
    {
        DAout=0xFFFF;
        DAC8760_Write(0x55,(1<<12)| I_4_20);
        Transfer(DAout);
    }
    // 低于下限:输出4mA
    else if(Dis<=Lrange)
    {
        DAout=1;
        DAC8760_Write(0x55,(1<<12)| I_4_20);
        Transfer(DAout);
    }
    // 正常范围:线性转换
    else
    {
        DAC8760_Write(0x55,(1<<12)| I_4_20);
        if(Dis<50000)
            DAout=((Dis-Lrange)*65535)/(Hrange-Lrange);
        else
            DAout=((Dis-Lrange)/5*65535)/((Hrange-Lrange)/5);
        Transfer(DAout);
    }
}

/********************* 电压输出控制 *********************/
void DAC8760_V(uint32_t Dis)
{
    static uint16_t DAout;

    // 异常处理:保持上一状态
    if((Dis&0x80000000)==0x80000000)
    {
        DAC8760_Write(0x55,(1<<12)| V_0_10);
        Transfer(DAout);
    }
    // 超过上限:输出10V
    else if(Dis>Hrange)
    {
        DAout=0xFFFF;
        DAC8760_Write(0x55,(1<<12)| V_0_10);
        Transfer(DAout);
    }
    // 低于下限:输出0V
    else if(Dis<=Lrange)
    {
        DAout=0x0;
        DAC8760_Write(0x55,(1<<12)| V_0_10);
        Transfer(DAout);
    }
    // 正常范围:线性转换
    else
    {
        DAC8760_Write(0x55,(1<<12)| V_0_10);
        if(Dis<50000)
            DAout=((Dis-Lrange)*65535)/(Hrange-Lrange);
        else
            DAout=((Dis-Lrange)/5*65535)/((Hrange-Lrange)/5);
        Transfer(DAout);
    }
}

/********************* 数据传输封装 *********************/
void Transfer(uint16_t DA)
{
    DAC8760_Write(0x01,DA); // 写数据寄存器
}

/********************* 初始化配置入口 *********************/
void J_config(void)
{
    DAC8760_Init(); // 调用初始化函数
}

// 其他函数(DAC8760_Out等)按需实现
void DAC8760_Out(uint16_t dat)
{
    DAC8760_Write(0x01,dat);
}

3. 关键函数说明

函数名 功能说明
DAC8760_Init() 初始化 GPIO 和 DAC8760 寄存器,配置默认输出模式
DAC8760_Write() 模拟 SPI 写寄存器,传输 8 位地址 + 16 位数据
DAC8760_Read() 读取 DAC8760 寄存器数据(用于校准 / 状态查询)
DAC8760_I() 距离数据转 4-20mA 电流输出,含异常处理(超限、无数据)
DAC8760_V() 距离数据转 0-10V 电压输出,逻辑与电流输出一致
Transfer() 封装数据寄存器写入,简化调用

四、使用示例

1. 基本使用流程

c

运行

#include "dac8760.h"

int main(void)
{
    // 系统初始化(时钟、串口等)
    SystemInit();
    
    // DAC8760初始化
    J_config();

    while(1)
    {
        // 示例1:输出4-20mA电流(距离数据10000)
        DAC8760_I(10000);
        
        // 示例2:输出0-10V电压(距离数据50000)
        // DAC8760_V(50000);
        
        delay_ms(100); // 延时刷新
    }
}

2. 输出范围校准

如果输出电流 / 电压存在偏差,可通过修改校准寄存器值调整:

c

运行

// 增益校准(0x58寄存器)
DAC8760_Write(0x58,0x8000|0x0100); // 微调增益
// 调零校准(0x59寄存器)
DAC8760_Write(0x59,0x00|0x0050);   // 微调零点

五、常见问题与解决

1. 无输出 / 输出异常

  • 检查 GPIO 引脚配置是否正确(推挽输出 / 上拉输入);
  • 确认 DAC8760 电源是否稳定,LATCH 引脚空闲状态是否为高;
  • 核对寄存器配置(输出使能位 DB12 是否置 1)。

2. 输出精度低

  • 启用校准功能(Calen 宏),调整增益 / 调零寄存器;
  • 确保 SPI 通信时序正确(时钟上升沿锁存数据);
  • 硬件端添加滤波电容,减少电源干扰。

3. 读取寄存器失败

  • 检查 DOUT 引脚是否配置为上拉输入;
  • 读操作前需先发送读地址,再读取数据;
  • 确认 LATCH 引脚时序是否匹配芯片手册。

六、总结

本文基于 STM32F103 实现了 DAC8760 的完整驱动,支持 4-20mA 电流和 0-5V/0-10V 电压输出,代码模块化程度高,可直接移植到工业控制、传感器变送等项目中。核心要点:

  1. 模拟 SPI 时序需严格匹配 DAC8760 的通信要求;
  2. 输出范围通过控制寄存器配置,需根据场景选择;
  3. 异常处理(无数据、超限)保证工业场景稳定性;
  4. 校准功能可提升输出精度,适配高精度需求。

完整代码已上传至 Gitee/GitHub(可自行补充仓库地址),欢迎交流指正!

扩展建议

  • 改用硬件 SPI 通信,提升传输效率;
  • 添加输出值缓存,减少频繁写寄存器;
  • 实现多通道输出(DAC8760 支持多通道扩展);
  • 结合 ADC 采集反馈,实现闭环校准。
Logo

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

更多推荐