STM32F103微控制器驱动MCP4728四通道DAC的实现

一、硬件连接规范

1.1 引脚对应关系

MCP4728引脚 功能 STM32连接 说明
VDD 电源输入 3.3V 建议并联0.1μF和10μF滤波电容
VREF 参考电压输入 外部基准源 若使用内部基准则悬空
AGND 模拟地 GND 单独接地减少噪声
SDA I2C数据线 PB7 上拉电阻4.7kΩ
SCL I2C时钟线 PB6 上拉电阻4.7kΩ
CS 片选信号 PA4 低电平有效
LDAC 数据锁存 PA5 输出0时同步更新所有通道
XFER 传输控制 PA6 传输完成信号

1.2 电路设计要点

  • 电源滤波:在VDD和GND间添加10μF电解电容+0.1μF陶瓷电容
  • 信号完整性:SDA/SCL总线添加49.9Ω端接电阻
  • 电平匹配:STM32的I2C为开漏输出,需外部上拉

二、STM32软件配置

2.1 I2C初始化(HAL库)

// I2C1配置(400kHz)
void MX_I2C1_Init(void)
{
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 400000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;      // 主机模式
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  HAL_I2C_Init(&hi2c1);
}

// GPIO配置(PA4/PA5/PA6)
void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  __HAL_RCC_GPIOA_CLK_ENABLE();
  
  // CS引脚配置
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  // LDAC/XFER引脚配置
  GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

2.2 DAC写入函数

// 写入DAC通道(快速写模式)
HAL_StatusTypeDef MCP4728_Write(uint8_t channel, uint16_t value)
{
  uint8_t data[3] = {0x40 | (channel << 1), (value >> 4) & 0xFF, (value << 4) & 0xFF};
  
  // 拉低CS选中设备
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  
  // 发送数据
  HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, 0x60<<1, data, 3, 100);
  
  // 拉高CS释放总线
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  
  // 同步输出(拉低LDAC)
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
  HAL_Delay(1);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
  
  return status;
}

三、关键通信协议

3.1 快速写指令格式

指令字节 通道选择 数据高4位 数据低4位
0x40~0x47 DAC0~DAC3 4位MSB 4位LSB

3.2 EEPROM写入指令

// 写入EEPROM(需20ms保持时间)
HAL_StatusTypeDef MCP4728_EEPROM_Write(uint8_t channel, uint16_t value)
{
  uint8_t data[4] = {0x60 | (channel << 1), (value >> 4) & 0xFF, (value << 4) & 0xFF, 0x00};
  
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_I2C_Master_Transmit(&hi2c1, 0x60<<1, data, 4, 100);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  
  HAL_Delay(20); // 保持时间要求
  return HAL_OK;
}

四、完整测试代码

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_I2C1_Init();
  
  // 初始化DAC通道0为1.65V(参考电压2.048V时)
  MCP4728_Write(0, 0x800); // 12位值:0x800 = 2048/4096 * Vref
  
  while(1)
  {
    // 动态调整输出(示例:呼吸灯效果)
    for(uint16_t i=0; i<4095; i+=10){
      MCP4728_Write(0, i);
      HAL_Delay(10);
    }
    for(uint16_t i=4095; i>0; i-=10){
      MCP4728_Write(0, i);
      HAL_Delay(10);
    }
  }
}

五、调试与优化

5.1 常见问题解决

现象 解决方案
I2C无应答 检查SDA/SCL上拉电阻(建议4.7kΩ)
输出电压偏差 验证VREF稳定性(示波器监测)
EEPROM写入失败 延时不足(需≥20ms保持时间)

5.2 性能优化

  1. DMA传输:使用I2C DMA模式提升吞吐量

    // 启用I2C1 DMA
    __HAL_RCC_DMA1_CLK_ENABLE();
    hdma_i2c1_tx.Instance = DMA1_Channel6;
    HAL_DMA_Init(&hdma_i2c1_tx);
    __HAL_LINKDMA(&hi2c1, hdmatx, hdma_i2c1_tx);
    
  2. 中断处理:配置I2C中断提升实时性

    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    

六、扩展功能实现

6.1 多通道同步输出

// 同步写入4个通道(需硬件LDAC)
void MCP4728_Sync_Write(uint16_t val0, uint16_t val1, 
                       uint16_t val2, uint16_t val3)
{
  uint8_t data[13] = {0x40, val0>>4, val0<<4,
                     0x50, val1>>4, val1<<4,
                     0x60, val2>>4, val2<<4,
                     0x70, val3>>4, val3<<4};
  
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  HAL_I2C_Master_Transmit(&hi2c1, 0x60<<1, data, 13, 200);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 同步更新
  HAL_Delay(1);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}

6.2 校准功能实现

// 两点校准算法
void MCP4728_Calibrate(float v_min, float v_max)
{
  uint16_t code_min = (uint16_t)(4095 * v_min / VREF);
  uint16_t code_max = (uint16_t)(4095 * v_max / VREF);
  
  // 保存校准参数到EEPROM
  MCP4728_EEPROM_Write(0, code_min);
  MCP4728_EEPROM_Write(1, code_max);
}

参考代码 stm32f103 驱动mcp4728输出AO www.youwenfan.com/contentcnh/56268.html

七、参考电路图

STM32F103        MCP4728
--------         -------
PA4 (CS)  ------> CS
PB6 (SCL) ------> SCL
PB7 (SDA) ------> SDA
PA5 (LDAC)------> LDAC
PA6 (XFER)-----> XFER
3.3V ---------> VDD
GND ---------> AGND

八、性能指标

参数 典型值
输出电压范围 0-5V
更新速率 1kHz(连续)
INL(积分非线性) ±1 LSB
DNL(微分非线性) ±0.5 LSB
参考电压精度 ±0.1%

通过上述方案,开发者可快速实现STM32F103与MCP4728的完整通信系统。建议使用HAL库进行开发,并参考数据手册进行时序验证。

posted @ 2025-09-18 09:26  小前端攻城狮  阅读(34)  评论(0)    收藏  举报