[附源码] STM32F103C8T6+外接MCP4725 外部DAC

1 篇文章 0 订阅
1 篇文章 0 订阅

关于stm32f103c8t6的DAC

        STM32F103C8T6最小系统板是大家很常用的一款单片机,它内部有多个ADC模数转换通道,但并没有DAC数模转换功能,当需要进行数字量转换为模拟量时就需要借助外部DAC。    

关于MCP4725

        MCP4725是具有非易失性存储器的单通道12位缓冲电压输出DAC。用户可将配置寄存器位(2位)和DAC输入数据(12位)存储 到非易失性EEPROM (14位)存储器中。通过设置配置寄存器位可以把DAC配置成正常模式或节省功耗的关断模式。器件可以使用2线I2C兼容串行接口,且由电压范围为2.7V至5.5V的单电源供电。

         通过I2C总线外接MCP4725模块,从而弥补了STM32F103C8T6无DAC的不足。并且当用5V单电源供电时,其DAC通道可以输出5V的电压。

接线图

      

 VCC接3.3V,

GND接GND,

SCL接PB6,

SDA接PB7,

OUT,GND测试引脚

效果展示: 

电压误差值0.01V

 问题解答:

        如果你接线正确并运行代码后,用万用表测的电压为供电电压的一半,与实际应该输出的电压值不相符,修改MCP4725.C代码中的地址

        如果ADDR接VCC地址为:0xc2

        如果ADDR接GND地址为:0xc0

我使用的是这款,所以代码中的地址为0XC0

 代码:

I2C.C代码:
#include "stm32f10x.h"                  // Device header
#include "myIIC.h"
#include "delay.h"

/*引脚配置*/
#define MCP4725_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(x))
#define MCP4725_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_7, (BitAction)(x))
#define MCP4725_W_SDAIN			GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7)


//初始化IIC
void IIC_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	//使能GPIOB时钟
	   
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;         //PB6 ->SCL;  PB7->SDA
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 	//PB6,PB7 输出高,因为IIC空闲状态都是高电平
}

//SDA设置为输入
void SDA_IN (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

//SDA设置为输出
void SDA_OUT(void)
{ 
	GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线设置为输出
	MCP4725_W_SDA(1);	  	  
	MCP4725_W_SCL(1);
	Delay_us(10);
 	MCP4725_W_SDA(0);     //START:when CLK is high,DATA change form high to low 
	Delay_us(10);
	MCP4725_W_SCL(0);    //钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	MCP4725_W_SCL(0);
	MCP4725_W_SDA(0);//STOP:when CLK is high DATA change form low to high
 	Delay_us(10);
	MCP4725_W_SCL(1);
	MCP4725_W_SDA(1);//发送I2C总线结束信号
	Delay_us(10);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	MCP4725_W_SDA(1);
	Delay_us(2);	   
	MCP4725_W_SCL(1);
	Delay_us(2);	 
	while(MCP4725_W_SDAIN)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	MCP4725_W_SCL(0);//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	MCP4725_W_SCL(0);
	SDA_OUT();
	MCP4725_W_SDA(0);
	Delay_us(5);
	MCP4725_W_SCL(1);
	Delay_us(5);
	MCP4725_W_SCL(0);
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	MCP4725_W_SCL(0);
	SDA_OUT();
	MCP4725_W_SDA(1);
	Delay_us(5);
	MCP4725_W_SCL(1);
	Delay_us(5);
	MCP4725_W_SCL(0);
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
	MCP4725_W_SCL(0);//拉低时钟开始数据传输
    for(t=0;t<8;t++)    //开始准备信号线
    {              
		if((txd&0x80)>>7)
			MCP4725_W_SDA(1);
		else
			MCP4725_W_SDA(0);
		txd<<=1; 	  
		Delay_us(5);   //对TEA5767这三个延时都是必须的
		MCP4725_W_SCL(1);
		Delay_us(5); 
		MCP4725_W_SCL(0);
		Delay_us(5);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        MCP4725_W_SCL(0);
        Delay_us(5);
		MCP4725_W_SCL(1);
        receive<<=1;
        if(MCP4725_W_SDAIN)
		{receive++;  }
		Delay_us(4); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}
I2C.h
#ifndef __MYIIC_H
#define __MYIIC_H

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);			        //IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void SDA_IN(void);
void SDA_OUT(void);

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif
MCP4725.C代码:
#include "stm32f10x.h"                  // Device header

#include "MCP4725.h" 
#include "delay.h"


//初始化IIC接口
void MCP4725_Init(void)
{
	IIC_Init();
}

//使用快速模式写命令写DAC寄存器
void MCP4725_WriteData_Voltage(u16 Vout)   //电压单位mV
{
	u8 temp;
	u16 Dn;
	Dn = ( 4096 * Vout) / VREF_5V; //这里的VREF_5V宏定义为5000
	temp = (0x0F00 & Dn) >> 8;  //12位数据。0000XXXX XXXXXXXX 
	IIC_Start();
	IIC_Send_Byte(0XC0);      //器件寻址,器件代吗:1100; 地址位A2,A1,A0为 0 , 0 , 1;-> 1100 0010
    //这个地址0XC0或0XC1,根据自己购买的模块决定
    IIC_Wait_Ack();	 
    IIC_Send_Byte(temp); 	  //将高8位送到DAC寄存器
    IIC_Wait_Ack();	 
    IIC_Send_Byte(Dn);        //将低8位送到DAC寄存器
	IIC_Wait_Ack();	
    IIC_Stop();//产生一个停止条件  	
	Delay_ms(10);	
}
 
void MCP4725_WriteData_Digital(u16 data)   //12位数字量
{
    u8 data_H=0,data_L=0;
	data_H = ( 0x0F00 & data) >> 8;
	data_L = 0X00FF & data ;
	IIC_Start();
	IIC_Send_Byte(0XC0);      //器件寻址,器件代吗:1100; 地址位A2,A1,A0为 0 , 0 , 0;-> 1100 0010
    IIC_Wait_Ack();	 
    IIC_Send_Byte(data_H); 	
    IIC_Wait_Ack();	 
    IIC_Send_Byte(data_L);
	IIC_Wait_Ack();	
    IIC_Stop();//产生一个停止条件  	
	Delay_ms(10);	
}
MCP4725.h代码:
#ifndef __MCP4725_H
#define __MCP4725_H
#include "myIIC.h"   


#define VREF_5V      3260//这个数值根据自己给模块的供电电压而定

void MCP4725_Init(void);
void MCP4725_WriteData_Digital(u16 data);
void MCP4725_WriteData_Voltage(u16 Vout);

#endif

main.c代码:
#include "stm32f10x.h"                  // Device header
#include "Delay.h"

#include "MCP4725.H"
#include "myIIC.H"
 
int main(void)
{

	MCP4725_Init();
	
	while(1)
	{ 
		MCP4725_WriteData_Voltage(1500);
		
	}
}

实测过,代码绝对可用,初学者,还请多多关照!

  • 18
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
### 回答1: STM32F103C8T6是一种常用的32位ARM Cortex-M3微控制器单片机,它具有广泛的应用领域,包括工业控制、嵌入式系统和移动设备等。它采用72MHz的主频,内置了64KB闪存和20KB的SRAM,可通过多种接口(包括I²C、SPI和USART)与外部设备进行通信。此外,它还支持多种外设,如定时器、ADC和DAC等,以满足各种应用的需求。 MCP4725是一款数字到模拟转换器(DAC),常用于在微控制器中生成模拟输出信号。它是一款12位分辨率DAC芯片,具有内部EEPROM,能够存储用户配置的设置,即使在断电后也能保持。MCP4725通过I²C总线与微控制器通信,只需使用几个引脚便可实现高分辨率的模拟输出。它广泛应用于音频设备、仪器仪表和传感器校准等领域。 在使用STM32F103C8T6MCP4725时,可以通过STM32的I²C模块与MCP4725进行通信。首先,需要配置STM32的I²C端口,设置I²C的时钟频率和其他参数。然后,通过发送指令和数据,可以向MCP4725写入模拟输出值,控制模拟信号的幅度。此外,还可以通过读取MCP4725的内部EEPROM来读取之前保存的配置,实现断电后的数据保持。 总之,STM32F103C8T6MCP4725是两款功能强大的电子器件,通过它们可以实现复杂的控制和信号处理任务。这对于需要精确控制模拟信号的应用来说是非常有价值的,并且STM32F103C8T6MCP4725都具有良好的可扩展性和兼容性,使得它们可以灵活地应用于各种场景中。 ### 回答2: STM32F103C8T6 是一款基于ARM Cortex-M3内核的微控制器,具有丰富的外设资源和强大的处理能力。MCP4725 是一款数字到模拟转换器(DAC),能够将数字信号转换为模拟电压输出。下面是关于它们的一些回答: 1. STM32F103C8T6 是一款强大的微控制器,适用于各种应用场景。它具有高性能的CPU和丰富的外设资源,可以满足各种通信、控制和计算需求。同时,它还支持多种通信接口,如SPI、I2C和USART,方便与其他设备进行通信。 2. 对于MCP4725数字到模拟转换器,它可以将数字信号转换为模拟电压输出。这对于需要输出模拟电压的应用非常有用,如音频处理、传感器驱动和控制电路等。MCP4725还具有非常小的封装尺寸和低功耗特性,非常适合嵌入式系统的应用。 3. STM32F103C8T6 可以与 MCP4725 进行通信。我们可以通过STM32微控制器上的SPI或I2C接口来连接MCP4725,并使用相应的软件驱动程序来控制它。通过发送相应的指令和数据,STM32可以向MCP4725发送数字信号,MCP4725会将其转换为模拟电压输出,并将其送到相应的输出引脚上。这样就可以实现STM32MCP4725的通信和数据交换。 总而言之,STM32F103C8T6是一款功能强大的微控制器,MCP4725是一款实现数字到模拟转换功能的器件。通过将它们结合在一起,我们可以实现更复杂的电路和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值