基于STM32F103的MCP4822驱动代码
MCP4822芯片基本STM32F103的驱动代码
·
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。
引脚功能
- VDD:电源输入(2.7V 至 5.5V)。
- CS:片选信号(低电平有效)。
- SCK:SPI 时钟输入。
- SDI:SPI 数据输入。
- LDAC:加载 DAC 输入(同步更新输出)。
- VOUTA:通道 A 模拟输出。
- VOUTB:通道 B 模拟输出。
- 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 或使用外部基准以提高精度。
参考资料
- MCP4822 数据手册(Microchip)
- 应用笔记 AN1078(SPI 接口设计指南)
更多推荐



所有评论(0)