STM32F103 驱动 DAC8760 数模转换芯片(电流 / 电压输出)实战教程
本文详细介绍了基于STM32F103的DAC8760数模转换芯片驱动开发方法。DAC8760是一款16位高精度DAC芯片,支持4-20mA电流和0-5V/0-10V电压输出,适用于工业控制等场景。文章从硬件连接(包括引脚定义和注意事项)、代码实现(包含SPI通信、寄存器配置、电流/电压输出转换等核心功能)到使用示例进行了完整阐述。重点讲解了异常处理、校准功能等关键技术点,并提供了常见问题解决方案。
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 电压输出,代码模块化程度高,可直接移植到工业控制、传感器变送等项目中。核心要点:
- 模拟 SPI 时序需严格匹配 DAC8760 的通信要求;
- 输出范围通过控制寄存器配置,需根据场景选择;
- 异常处理(无数据、超限)保证工业场景稳定性;
- 校准功能可提升输出精度,适配高精度需求。
完整代码已上传至 Gitee/GitHub(可自行补充仓库地址),欢迎交流指正!
扩展建议
- 改用硬件 SPI 通信,提升传输效率;
- 添加输出值缓存,减少频繁写寄存器;
- 实现多通道输出(DAC8760 支持多通道扩展);
- 结合 ADC 采集反馈,实现闭环校准。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)