找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 47|回复: 3
打印 上一主题 下一主题
收起左侧

MCP4725(DAC)输出电压不变

[复制链接]
跳转到指定楼层
楼主
ID:322939 发表于 2026-4-21 10:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近用一款MCP4725(DAC)芯片去控制DC-DC输出电压范围,因为用PWM去控制和DC-DC输出电压不匹配,调参数太复杂了,改用DA芯片去控制,目前这芯片输出电压约1.63V不变,A0地址也换过还是不行,不知那位大佬用过?指点下。谢谢!
  1. #ifndef __MCP4725_H__
  2. #define __MCP4725_H__

  3. #include "STC8H.H"


  4. #define MCP4725_ADDR_W  0xC0  // A0接地 -> 0xC0; A0接VCC -> 0xC2
  5. #define VREF_MV         5000  // 参考电压(mV),通常为VDD=5V

  6. // 引脚定义
  7. sbit I2C_SCL = P2^1;
  8. sbit I2C_SDA = P2^0;

  9. // 函数声明
  10. void MCP4725_Init(void);
  11. void MCP4725_WriteVoltage(u16 voltage_mv);    // 电压值,单位mV
  12. void MCP4725_WriteDigital(u16 dac_code);      // 直接写入12位DAC码

  13. #endif
  14. 2. 源文件 mcp4725.c
  15. c
  16. #include "mcp4725.h"
  17. #include "intrins.h"

  18. // 微秒延时函数,适用于24MHz主频
  19. void delay_us(unsigned char us) {
  20.     unsigned char i, j;
  21.     do {
  22.         i = 2;
  23.         j = 3;
  24.         do {
  25.             while (--j);
  26.         } while (--i);
  27.     } while (--us);
  28. }

  29. // 设置SDA为输入模式 (释放总线,准备读取)
  30. void SDA_IN(void) {
  31.     P2M1 |= 0x01;   // P2.0 设置为输入模式 (M1=1, M0=0)
  32.     P2M0 &= ~0x01;
  33. }

  34. // 设置SDA为开漏输出模式 (可输出低电平或释放总线由外部上拉至高电平)
  35. void SDA_OUT(void) {
  36.     P2M1 &= ~0x01;  // P2.0 设置为开漏输出 (M1=0, M0=1)
  37.     P2M0 |= 0x01;
  38.     I2C_SDA = 1;    // 先释放总线
  39. }

  40. // I2C初始化 (设置SCL为开漏输出,SDA初始为开漏输出)
  41. void IIC_Init(void) {
  42.     // SCL: P2.1 开漏输出
  43.     P2M1 &= ~0x02;
  44.     P2M0 |= 0x02;
  45.     // SDA: P2.0 开漏输出
  46.     SDA_OUT();
  47.     I2C_SCL = 1;
  48.     I2C_SDA = 1;
  49. }

  50. // 产生起始信号
  51. void IIC_Start(void) {
  52.     SDA_OUT();
  53.     I2C_SDA = 1;
  54.     I2C_SCL = 1;
  55.     delay_us(5);
  56.     I2C_SDA = 0;
  57.     delay_us(5);
  58.     I2C_SCL = 0;
  59.     delay_us(5);
  60. }

  61. // 产生停止信号
  62. void IIC_Stop(void) {
  63.     SDA_OUT();
  64.     I2C_SCL = 0;
  65.     I2C_SDA = 0;
  66.     delay_us(5);
  67.     I2C_SCL = 1;
  68.     delay_us(5);
  69.     I2C_SDA = 1;
  70.     delay_us(5);
  71. }

  72. // 等待从机应答
  73. // 返回值: 0-应答成功, 1-应答失败
  74. bit IIC_Wait_Ack(void) {
  75.     unsigned char errTime = 0;
  76.     SDA_IN();           // 释放SDA,准备读取
  77.     I2C_SDA = 1;        // 先拉高总线(输入模式下写1无效,但保持兼容)
  78.     delay_us(2);
  79.     I2C_SCL = 1;
  80.     delay_us(2);
  81.     while (I2C_SDA) {   // 等待从机拉低SDA
  82.         errTime++;
  83.         if (errTime > 250) {
  84.             IIC_Stop();
  85.             return 1;
  86.         }
  87.     }
  88.     I2C_SCL = 0;
  89.     delay_us(2);
  90.     return 0;
  91. }

  92. // 发送一个字节,并返回应答状态
  93. // 返回值: 0-应答成功, 1-应答失败
  94. bit IIC_SendByte(unsigned char dat) {
  95.     unsigned char i;
  96.     SDA_OUT();
  97.     I2C_SCL = 0;
  98.     for (i = 0; i < 8; i++) {
  99.         I2C_SDA = (dat & 0x80) ? 1 : 0;
  100.         dat <<= 1;
  101.         delay_us(5);
  102.         I2C_SCL = 1;
  103.         delay_us(5);
  104.         I2C_SCL = 0;
  105.         delay_us(5);
  106.     }
  107.     return IIC_Wait_Ack();  // 等待应答并返回结果
  108. }

  109. // 读取一个字节,并决定是否发送ACK
  110. unsigned char IIC_ReadByte(bit ack) {
  111.     unsigned char i, receive = 0;
  112.     SDA_IN();
  113.     for (i = 0; i < 8; i++) {
  114.         I2C_SCL = 0;
  115.         delay_us(5);
  116.         I2C_SCL = 1;
  117.         delay_us(5);
  118.         receive <<= 1;
  119.         if (I2C_SDA) receive++;
  120.     }
  121.     // 发送应答或非应答
  122.     SDA_OUT();
  123.     I2C_SCL = 0;
  124.     delay_us(5);
  125.     I2C_SDA = ack ? 0 : 1;   // ack=1: 发送ACK(拉低); ack=0: 发送NACK(拉高)
  126.     delay_us(5);
  127.     I2C_SCL = 1;
  128.     delay_us(5);
  129.     I2C_SCL = 0;
  130.     I2C_SDA = 1;            // 释放总线
  131.     return receive;
  132. }

  133. // MCP4725初始化
  134. void MCP4725_Init(void) {
  135.     IIC_Init();
  136. }

  137. // 写入电压值 (单位: mV)
  138. void MCP4725_WriteVoltage(u16 voltage_mv) {
  139.     u16 dac_code;
  140.     u8 high_byte;
  141.    
  142.     // 限制电压范围
  143.     if (voltage_mv > VREF_MV) voltage_mv = VREF_MV;
  144.    
  145.     // 计算DAC码 (MCP4725输出与码值成正比)
  146.     dac_code = (u16)(4095L * voltage_mv / VREF_MV);
  147.    
  148.     // 准备快速写入模式的高字节 (命令字: 0x50 | 高4位数据)
  149.     high_byte = 0x50 | ((dac_code >> 8) & 0x0F);
  150.    
  151.     IIC_Start();
  152.     if (IIC_SendByte(MCP4725_ADDR_W)) {   // 地址无应答,退出
  153.         IIC_Stop();
  154.         return;
  155.     }
  156.     if (IIC_SendByte(high_byte)) {        // 高字节无应答
  157.         IIC_Stop();
  158.         return;
  159.     }
  160.     if (IIC_SendByte(dac_code & 0xFF)) {  // 低字节无应答
  161.         IIC_Stop();
  162.         return;
  163.     }
  164.     IIC_Stop();
  165. }

  166. // 直接写入12位DAC码
  167. void MCP4725_WriteDigital(u16 dac_code) {
  168.     u8 high_byte;
  169.     if (dac_code > 4095) dac_code = 4095;
  170.    
  171.     high_byte = 0x50 | ((dac_code >> 8) & 0x0F);
  172.    
  173.     IIC_Start();
  174.     if (IIC_SendByte(MCP4725_ADDR_W)) {
  175.         IIC_Stop();
  176.         return;
  177.     }
  178.     if (IIC_SendByte(high_byte)) {
  179.         IIC_Stop();
  180.         return;
  181.     }
  182.     if (IIC_SendByte(dac_code & 0xFF)) {
  183.         IIC_Stop();
  184.         return;
  185.     }
  186.     IIC_Stop();
  187. }
  188. ________________________________________

  189. #include "mcp4725.h"

  190. void main(void) {
  191.     // 系统初始化...
  192.     MCP4725_Init();
  193.    
  194.     while(1) {
  195.         MCP4725_WriteVoltage(2500);  // 输出2.5V
  196.         delay_ms(2000);
  197.         MCP4725_WriteVoltage(5000);  // 输出5.0V
  198.         delay_ms(2000);
  199.     }
  200. }


复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:401564 发表于 2026-4-21 11:32 | 只看该作者
先用放大镜看一下这个芯片的丝印,再根据丝印去更改从机地址,它的从机地址并不是固定的,规格书中有说明的
回复

使用道具 举报

板凳
ID:322939 发表于 2026-4-21 11:53 | 只看该作者
芯片丝印是AJAH,地址:有的是0xC0,有的是0x60,也试过都不行
回复

使用道具 举报

地板
ID:401564 发表于 2026-4-21 15:34 | 只看该作者
那没办法了,只能一步一步的验证了,你可以把延时改成1秒的,然后每个时钟加一个闪灯的代码
然后8个时钟后,验证从机有没有应答,应答里面用死循环,没有应答就是从机的问题,一步一步排查你也可以参考我这个5年前写的,4725可以支持高速IIC,对延时要求不高
MCP4725.rar (1.25 KB, 下载次数: 0)

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表