MCP4822 概述

MCP4822 是 Microchip Technology 公司推出的一款 12 位双通道数模转换器(DAC),具有 SPI 接口和内部电压基准。该芯片广泛应用于工业控制、音频处理、自动化测试设备等领域。

主要特性

  • 分辨率:12 位,提供高精度模拟输出。
  • 通道数:双通道,可独立控制。
  • 输出电压范围:0V 至 4.096V(内部基准)或 0V 至 Vref(外部基准)。
  • 通信接口:SPI 兼容,支持 20 MHz 时钟频率。
  • 低功耗:典型工作电流 400 µA,关断模式电流 1 µA。
  • 封装:PDIP-8、SOIC-8 和 MSOP-8。

引脚功能

  1. VDD:电源输入(2.7V 至 5.5V)。
  2. CS:片选信号(低电平有效)。
  3. SCK:SPI 时钟输入。
  4. SDI:SPI 数据输入。
  5. LDAC:加载 DAC 输入(同步更新输出)。
  6. VOUTA:通道 A 模拟输出。
  7. VOUTB:通道 B 模拟输出。
  8. VSS:地。

典型应用电路

  • 电源去耦:在 VDD 和 VSS 之间添加 0.1 µF 电容。
  • 基准电压:使用内部基准时,VREF 引脚需接 0.1 µF 电容;外部基准需稳定且低噪声。
  • SPI 连接:与微控制器(如 Arduino、STM32)的 SPI 引脚直接连接。

寄存器配置

MCP4822 的输入数据为 16 位,格式如下:

  • Bit 15:通道选择(0 = A,1 = B)。
  • Bit 14:增益选择(0 = 2x,1 = 1x)。
  • Bit 13:关断控制(0 = 输出启用,1 = 关断)。
  • Bit 12-0:12 位 DAC 数据(MSB 对齐)。

示例代码(Arduino):

#ifndef _SPI_H_
#define _SPI_H_

#include "stm32f10x.h"

#define MCP4822_SPI		SPI2

#define SPI_SCK_Pin		GPIO_Pin_13
#define SPI_SCK_Port	GPIOB

#define SPI_MISO_Pin	GPIO_Pin_14
#define SPI_MISO_Port	GPIOB

#define SPI_MOSI_Pin	GPIO_Pin_15
#define SPI_MOSI_Port	GPIOB

#define SPI_NSS_Pin		GPIO_Pin_12
#define SPI_NSS_Port	GPIOB

#define LDAC_Pin		GPIO_Pin_11
#define LDAC_Port		GPIOB

#define INDEX_V_CH		0		//通道A
#define INDEX_I_CH		1		//通道B

#define MCP4822_NSS_ON()		GPIO_ResetBits(SPI_NSS_Port, SPI_NSS_Pin)
#define MCP4822_NSS_OFF()		GPIO_SetBits(SPI_NSS_Port, SPI_NSS_Pin)

void MCP4822_SPI_Init(void);
uint8_t MCP4822_Send_Byte(uint8_t byte);
uint16_t MCP4822_Send_HalfWord(uint16 HalfWord);
void MCP4822_SetVoltage(uint8_t Index,uint16_t mVol);

#endif
#include "stm32f10x_spi.h"
#include "Spi.h"

/********************************************************************
  * 函数说明:初始化STM32外设,GPIO,时钟
  * 输    入:无
  * 返    回:无
  ******************************************************************/
void MCP4822_SPI_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef SPI_InitStructure;
	
	/* 使用的外设时钟使能 -------------------------------------------*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
	/* 配置驱动板引脚 --------------------------------------------*/

	/* 配置SPI_SCK------------------------------------------------*/
	GPIO_InitStructure.GPIO_Pin = SPI_SCK_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(SPI_SCK_Port, &GPIO_InitStructure);
	/* 配置SPI_MOSI----------------------------------------------*/
	GPIO_InitStructure.GPIO_Pin = SPI_MOSI_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(SPI_MOSI_Port, &GPIO_InitStructure);
	
	/* 配置SPI_MISO -------------------------------------------------*/
	GPIO_InitStructure.GPIO_Pin = SPI_MISO_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(SPI_MISO_Port, &GPIO_InitStructure);
	
	/* 配置SPI_NSS(片选1)-----------------------------------------*/
	GPIO_InitStructure.GPIO_Pin = SPI_NSS_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(SPI_NSS_Port, &GPIO_InitStructure);
	MCP4822_NSS_OFF();
	
	/* LDAC-----------------------------------------*/
	GPIO_InitStructure.GPIO_Pin = LDAC_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(LDAC_Port, &GPIO_InitStructure);
	GPIO_ResetBits(LDAC_Port, LDAC_Pin);

	/* 配置 SPI ------------------------------------------------------*/
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	
	SPI_Init(MCP4822_SPI, &SPI_InitStructure);
	/* 使能 SPI */
	SPI_Cmd(MCP4822_SPI, ENABLE);
}

/********************************************************************
  * 函数说明:发送/接收一个字节到SPI
  * 输    入:发送字节
  * 返    回:接收字节
  ******************************************************************/
uint8_t MCP4822_Send_Byte(uint8_t byte)
{
//  FM_NSS_ON();
	/* 等待数据寄存器空 */
    while(SPI_I2S_GetFlagStatus(MCP4822_SPI, SPI_I2S_FLAG_TXE) == RESET);

    /* 通过SPI2接口发送数据 */
    SPI_I2S_SendData(MCP4822_SPI, byte);

    /* 等待接收到一个字节的数据 */
    while(SPI_I2S_GetFlagStatus(MCP4822_SPI, SPI_I2S_FLAG_RXNE) == RESET);

//	FM_NSS_OFF();
    /* 返回接收的数据 */
    return SPI_I2S_ReceiveData(MCP4822_SPI);
}

uint16_t MCP4822_Send_HalfWord(uint16 HalfWord)
{
//  FM_NSS_ON();
	/* 等待数据寄存器空 */
    while(SPI_I2S_GetFlagStatus(MCP4822_SPI, SPI_I2S_FLAG_TXE) == RESET);

    /* 通过SPI2接口发送数据 */
    SPI_I2S_SendData(MCP4822_SPI, HalfWord);

    /* 等待接收到一个字节的数据 */
    while(SPI_I2S_GetFlagStatus(MCP4822_SPI, SPI_I2S_FLAG_RXNE) == RESET);

//	FM_NSS_OFF();
    /* 返回接收的数据 */
    return SPI_I2S_ReceiveData(MCP4822_SPI);
}

/*
bit 15 A/B: DAC A or DAC B Selection bit
1 = Write to DAC B
0 = Write to DAC A
bit 14 — Don’t Care
bit 13 GA: Output Gain Selection bit
1 = 1x (V OUT = V REF * D/4096)
0 = 2x (V OUT = 2 * V REF * D/4096), where internal V REF = 2.048V.
bit 12 SHDN: Output Shutdown Control bit
1 = Active mode operation. V OUT is available. ?
0 = Shutdown the selected DAC channel. Analog output is not available at the channel that was shut down.
V OUT pin is connected to 500 k???typical)?
bit 11-0 D11:D0: DAC Input Data bits. Bit x is ignored
*/
//通道和mV
void MCP4822_SetVoltage(uint8_t Index,uint16_t mVol)
{
	uint16_t mDta = mVol;
	//uint16_t m_value = mVol;//mVol/4.096*4095;
	//mDta = mVol;
	GPIO_SetBits(LDAC_Port, LDAC_Pin);
	
	mDta &= 0x0FFF;			//bit13=0则最大输出电压为4096mV
	
	if(Index == 1)			
	{
		mDta |= 0x8000;		//通道1输出
	}
	mDta |= 0x1000;			//打开输出
	
	MCP4822_NSS_ON();
	MCP4822_Send_HalfWord(mDta);
	MCP4822_NSS_OFF();
	
	GPIO_ResetBits(LDAC_Port, LDAC_Pin);
	__NOP();__NOP();
	GPIO_SetBits(LDAC_Port, LDAC_Pin);
}

常见问题

  • 输出噪声:确保电源和基准电压稳定,避免数字信号干扰模拟部分。
  • SPI 通信失败:检查时钟极性和相位(模式 0,0 或 1,1),确认片选信号时序。
  • 输出电压误差:校准 DAC 或使用外部基准以提高精度。

参考资料

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐